aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/settings.json5
-rw-r--r--include/cru/platform/native/base.hpp1
-rw-r--r--include/cru/platform/native/input_method.hpp30
-rw-r--r--include/cru/win/native/input_method.hpp42
-rw-r--r--src/platform/native/CMakeLists.txt1
-rw-r--r--src/win/native/CMakeLists.txt2
-rw-r--r--src/win/native/dpi_util.hpp11
-rw-r--r--src/win/native/input_method.cpp75
-rw-r--r--src/win/native/window.cpp4
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)