diff options
-rw-r--r-- | include/cru/win/native/window.hpp | 5 | ||||
-rw-r--r-- | include/cru/win/string.hpp | 8 | ||||
-rw-r--r-- | src/win/native/window.cpp | 12 |
3 files changed, 23 insertions, 2 deletions
diff --git a/include/cru/win/native/window.hpp b/include/cru/win/native/window.hpp index a137463b..a27a3384 100644 --- a/include/cru/win/native/window.hpp +++ b/include/cru/win/native/window.hpp @@ -156,6 +156,11 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { Event<std::string> char_event_; Event<WindowNativeMessageEventArgs&> native_message_event_; + + // WM_CHAR may be sent twice successively with two utf-16 code units of + // surrogate pair when character is from supplementary planes. This field is + // used to save the previous one. + wchar_t last_wm_char_event_wparam_; }; class WinNativeWindowResolver : public WinNativeResource, diff --git a/include/cru/win/string.hpp b/include/cru/win/string.hpp index 3fdadbf8..b2bfd245 100644 --- a/include/cru/win/string.hpp +++ b/include/cru/win/string.hpp @@ -27,6 +27,14 @@ namespace cru::platform::win { std::string ToUtf8String(const std::wstring_view& string); std::wstring ToUtf16String(const std::string_view& string); +inline bool IsSurrogatePairLeading(wchar_t c) { + return c >= 0xD800 && c <= 0xDBFF; +} + +inline bool IsSurrogatePairTrailing(wchar_t c) { + return c >= 0xDC00 && c <= 0xDFFF; +} + using CodePoint = std::int32_t; constexpr CodePoint k_code_point_end = -1; diff --git a/src/win/native/window.cpp b/src/win/native/window.cpp index 6f66cb57..a0ac2f6f 100644 --- a/src/win/native/window.cpp +++ b/src/win/native/window.cpp @@ -404,8 +404,16 @@ void WinNativeWindow::OnKeyUpInternal(int virtual_code) { } void WinNativeWindow::OnCharInternal(wchar_t c) { - wchar_t s[2] = {c, 0}; - char_event_.Raise(platform::win::ToUtf8String(s)); + if (platform::win::IsSurrogatePairLeading(c)) { + last_wm_char_event_wparam_ = c; + return; + } else if (platform::win::IsSurrogatePairTrailing(c)) { + wchar_t s[3] = {last_wm_char_event_wparam_, c, 0}; + char_event_.Raise(platform::win::ToUtf8String(s)); + } else { + wchar_t s[2] = {c, 0}; + char_event_.Raise(platform::win::ToUtf8String(s)); + } } void WinNativeWindow::OnActivatedInternal() {} |