diff options
author | crupest <crupest@outlook.com> | 2020-04-02 23:00:34 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-04-02 23:00:34 +0800 |
commit | ee61633d81cc9e34c3bd8b5fbfb6a5a25a1f3ea5 (patch) | |
tree | b2cf74e5ff45ebe5604bb3ffb189d2d2bd1406df | |
parent | 7fd9ca808c908c67d9bec2183034ad16ea86a912 (diff) | |
download | cru-ee61633d81cc9e34c3bd8b5fbfb6a5a25a1f3ea5.tar.gz cru-ee61633d81cc9e34c3bd8b5fbfb6a5a25a1f3ea5.tar.bz2 cru-ee61633d81cc9e34c3bd8b5fbfb6a5a25a1f3ea5.zip |
...
-rw-r--r-- | .vscode/settings.json | 5 | ||||
-rw-r--r-- | include/cru/platform/native/base.hpp | 1 | ||||
-rw-r--r-- | include/cru/platform/native/input_method.hpp | 30 | ||||
-rw-r--r-- | include/cru/win/native/input_method.hpp | 42 | ||||
-rw-r--r-- | src/platform/native/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/win/native/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/win/native/dpi_util.hpp | 11 | ||||
-rw-r--r-- | src/win/native/input_method.cpp | 75 | ||||
-rw-r--r-- | src/win/native/window.cpp | 4 |
9 files changed, 166 insertions, 5 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 1de11236..9b38e418 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,6 +66,9 @@ "xloctime": "cpp", "string_view": "cpp", "cassert": "cpp", - "gsl_util": "cpp" + "gsl_util": "cpp", + "multi_span": "cpp", + "span": "cpp", + "string_span": "cpp" } } diff --git a/include/cru/platform/native/base.hpp b/include/cru/platform/native/base.hpp index 5ebd98d6..883a9450 100644 --- a/include/cru/platform/native/base.hpp +++ b/include/cru/platform/native/base.hpp @@ -10,6 +10,7 @@ struct ICursorManager; struct IUiApplication; struct INativeWindow; struct INativeWindowResolver; +struct IInputMethodManager; struct Dpi { float x; diff --git a/include/cru/platform/native/input_method.hpp b/include/cru/platform/native/input_method.hpp new file mode 100644 index 00000000..ecc47fd8 --- /dev/null +++ b/include/cru/platform/native/input_method.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "../resource.hpp" +#include "base.hpp" +#include "cru/common/event.hpp" + +#include <memory> + +namespace cru::platform::native { +// It is a reference, so there is a ref count, remember to destroy it to release +// the ref after use. +struct IInputMethodContextRef : INativeResource { + // Reset composition string. Use this method to prepare typing. + virtual void Reset() = 0; + // Get the composition string. + virtual std::string GetCompositionString() = 0; + // Set the candidate window lefttop. Use this method to prepare typing. + virtual void SetCandidateWindowPosition(const Point& point); + // Triggered every time composition text changes, evet args is the new + // composition text. + virtual IEvent<std::string>* CompositionTextChangeEvent() = 0; + // User comfirmed compostition. Use this method to get the final input text. + virtual IEvent<std::string>* CharEvent() = 0; +}; + +struct IInputMethodManager : INativeResource { + // Get a reference of context of a window. + virtual std::unique_ptr<IInputMethodContextRef> GetContext( + INativeWindow* window) = 0; +}; +} // namespace cru::platform::native diff --git a/include/cru/win/native/input_method.hpp b/include/cru/win/native/input_method.hpp new file mode 100644 index 00000000..3ea16709 --- /dev/null +++ b/include/cru/win/native/input_method.hpp @@ -0,0 +1,42 @@ +#pragma once +#include "resource.hpp" + +#include "cru/platform/native/input_method.hpp" + +#include <imm.h> + +namespace cru::platform::native::win { +class WinNativeWindow; + +class WinInputMethodContextRef : public WinNativeResource, + public IInputMethodContextRef { + public: + WinInputMethodContextRef(WinNativeWindow* window); + + CRU_DELETE_COPY(WinInputMethodContextRef) + CRU_DELETE_MOVE(WinInputMethodContextRef) + + ~WinInputMethodContextRef() override; + + ::HIMC GetHandle() const { return handle_; } + + void Reset() override; + + std::string GetCompositionString() override; + + void SetCandidateWindowPosition(const Point& point) override; + + IEvent<std::string>* CompositionTextChangeEvent() override; + + IEvent<std::string>* CharEvent() override; + + private: + WinNativeWindow* window_; + + ::HWND window_handle_; + ::HIMC handle_; + + Event<std::string> composition_text_change_event_; + Event<std::string> char_event_; +}; +} // namespace cru::platform::native::win diff --git a/src/platform/native/CMakeLists.txt b/src/platform/native/CMakeLists.txt index c280ddd0..688f2890 100644 --- a/src/platform/native/CMakeLists.txt +++ b/src/platform/native/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(cru_platform_native STATIC target_sources(cru_platform_native PUBLIC ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/base.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/cursor.hpp + ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/input_method.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/keyboard.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/window.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/ui_application.hpp diff --git a/src/win/native/CMakeLists.txt b/src/win/native/CMakeLists.txt index 82994d67..521b32cf 100644 --- a/src/win/native/CMakeLists.txt +++ b/src/win/native/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(cru_win_native STATIC cursor.cpp god_window.cpp + input_method.cpp keyboard.cpp timer.cpp ui_application.cpp @@ -22,6 +23,7 @@ target_sources(cru_win_native PUBLIC ${CRU_WIN_NATIVE_INCLUDE_DIR}/cursor.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/exception.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/god_window.hpp + ${CRU_WIN_NATIVE_INCLUDE_DIR}/input_method.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/keyboard.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/resource.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/ui_application.hpp diff --git a/src/win/native/dpi_util.hpp b/src/win/native/dpi_util.hpp index d8c5610c..07b89a95 100644 --- a/src/win/native/dpi_util.hpp +++ b/src/win/native/dpi_util.hpp @@ -32,4 +32,15 @@ inline float PixelToDipX(const int pixel_x) { inline float PixelToDipY(const int pixel_y) { return DipToPixelInternal(pixel_y, GetDpi().y); } + +inline Point PiToDip(const POINT& pi_point) { + return Point(PixelToDipX(pi_point.x), PixelToDipY(pi_point.y)); +} + +inline POINT DipToPi(const Point& dip_point) { + POINT result; + result.x = DipToPixelX(dip_point.x); + result.y = DipToPixelY(dip_point.y); + return result; +} } // namespace cru::platform::native::win diff --git a/src/win/native/input_method.cpp b/src/win/native/input_method.cpp new file mode 100644 index 00000000..4edfdc5f --- /dev/null +++ b/src/win/native/input_method.cpp @@ -0,0 +1,75 @@ +#include "cru/win/native/input_method.hpp" + +#include "cru/common/logger.hpp" +#include "cru/win/exception.hpp" +#include "cru/win/native/window.hpp" +#include "cru/win/string.hpp" +#include "dpi_util.hpp" + +#include <vector> + +namespace cru::platform::native::win { +WinInputMethodContextRef::WinInputMethodContextRef(WinNativeWindow* window) + : window_(window) { + Expects(window); + + window_handle_ = window->GetWindowHandle(); + handle_ = ::ImmGetContext(window_handle_); + + // TODO: Events +} + +WinInputMethodContextRef::~WinInputMethodContextRef() { + ::ImmReleaseContext(window_handle_, handle_); +} + +void WinInputMethodContextRef::Reset() { + wchar_t s[1] = {L'\0'}; + + if (!::ImmSetCompositionStringW(handle_, SCS_SETSTR, static_cast<LPVOID>(s), + sizeof(s), static_cast<LPVOID>(s), + sizeof(s))) { + log::Warn( + "WinInputMethodContextRef: Failed to reset input method context."); + } +} + +std::string WinInputMethodContextRef::GetCompositionString() { + const auto length = + ::ImmGetCompositionStringW(handle_, GCS_RESULTREADSTR, NULL, 0) + + sizeof(wchar_t); + std::vector<std::byte> data(length); + const auto result = ::ImmGetCompositionStringW( + handle_, GCS_RESULTREADSTR, static_cast<LPVOID>(data.data()), length); + + if (result == IMM_ERROR_NODATA) { + return std::string{}; + } else if (result == IMM_ERROR_GENERAL) { + throw new platform::win::Win32Error(::GetLastError(), + "Failed to get composition string."); + } + + return platform::win::ToUtf8String( + std::wstring_view(reinterpret_cast<wchar_t*>(data.data()))); +} + +void WinInputMethodContextRef::SetCandidateWindowPosition(const Point& point) { + ::CANDIDATEFORM form; + form.dwIndex = 1; + form.dwStyle = CFS_CANDIDATEPOS; + form.ptCurrentPos = DipToPi(point); + + if (!::ImmSetCandidateWindow(handle_, &form)) + log::Debug( + "WinInputMethodContextRef: Failed to set input method candidate window " + "position."); +} + +IEvent<std::string>* WinInputMethodContextRef::CompositionTextChangeEvent() { + return &composition_text_change_event_; +} + +IEvent<std::string>* WinInputMethodContextRef::CharEvent() { + return &char_event_; +} +} // namespace cru::platform::native::win diff --git a/src/win/native/window.cpp b/src/win/native/window.cpp index 1b590026..6f66cb57 100644 --- a/src/win/native/window.cpp +++ b/src/win/native/window.cpp @@ -17,10 +17,6 @@ #include <windowsx.h> namespace cru::platform::native::win { -inline Point PiToDip(const POINT& pi_point) { - return Point(PixelToDipX(pi_point.x), PixelToDipY(pi_point.y)); -} - WinNativeWindow::WinNativeWindow(WinUiApplication* application, WindowClass* window_class, DWORD window_style, WinNativeWindow* parent) |