Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakahiro Shizuki <sntulix>2021-08-01 21:52:22 +0300
committerHarley Acheson <harley.acheson@gmail.com>2021-08-01 21:52:22 +0300
commit836aeebf70776791866c8cc82a0ca2ad7ffb8e4d (patch)
treed2d976c1d4b6b8951f514c2fbc08d7acd6b045b3 /intern/ghost
parent79277986c299eaa3df9364e6d9f2b88d2b4f2dea (diff)
IME Win32: Fix Duplicated Initial Character
When entering characters using IME on Windows, Japanese and Chinese will both usually result in the first keystroke being duplicated. The problem is that we are informed too late, after the first key is pressed, that we are IME composing. This patch ensures we are entering non-English characters using ImmGetConversionStatus() and then deals with editing keys (like arrows and backspace) on a per-language basis. see D11929 for more details. Differential Revision: https://developer.blender.org/D11929 Reviewed by Brecht Van Lommel
Diffstat (limited to 'intern/ghost')
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.cpp59
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.h18
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp16
3 files changed, 91 insertions, 2 deletions
diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp
index 112a266ae28..412f7e4276c 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.cpp
+++ b/intern/ghost/intern/GHOST_ImeWin32.cpp
@@ -34,6 +34,8 @@ GHOST_ImeWin32::GHOST_ImeWin32()
: is_composing_(false),
ime_status_(false),
input_language_id_(LANG_USER_DEFAULT),
+ conversion_modes_(IME_CMODE_ALPHANUMERIC),
+ sentence_mode_(IME_SMODE_NONE),
system_caret_(false),
caret_rect_(-1, -1, 0, 0),
is_first(true),
@@ -59,6 +61,63 @@ bool GHOST_ImeWin32::SetInputLanguage()
return ime_status_;
}
+WORD GHOST_ImeWin32::GetInputLanguage()
+{
+ return input_language_id_;
+}
+
+void GHOST_ImeWin32::UpdateConversionStatus(HWND window_handle)
+{
+ HIMC imm_context = ::ImmGetContext(window_handle);
+ if (imm_context) {
+ if (::ImmGetOpenStatus(imm_context)) {
+ ::ImmGetConversionStatus(imm_context, &conversion_modes_, &sentence_mode_);
+ }
+ else {
+ conversion_modes_ = IME_CMODE_ALPHANUMERIC;
+ sentence_mode_ = IME_SMODE_NONE;
+ }
+ ::ImmReleaseContext(window_handle, imm_context);
+ }
+ else {
+ conversion_modes_ = IME_CMODE_ALPHANUMERIC;
+ sentence_mode_ = IME_SMODE_NONE;
+ }
+}
+
+bool GHOST_ImeWin32::IsEnglishMode()
+{
+ return (conversion_modes_ & IME_CMODE_NOCONVERSION) ||
+ !(conversion_modes_ & (IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE));
+}
+
+bool GHOST_ImeWin32::IsImeKeyEvent(char ascii)
+{
+ if (!(IsEnglishMode())) {
+ /* In Chinese, Japanese, Korena, all alpha keys are processed by IME. */
+ if ((ascii >= 'A' && ascii <= 'Z') || (ascii >= 'a' && ascii <= 'z')) {
+ return true;
+ }
+ switch (PRIMARYLANGID(GetInputLanguage())) {
+ /* In Japanese, all symbolic characters are also processed by IME. */
+ case LANG_JAPANESE: {
+ if (ascii >= ' ' && ascii <= '~') {
+ return true;
+ }
+ break;
+ }
+ /* In Chinese, some symbolic characters are also processed by IME. */
+ case LANG_CHINESE: {
+ if (ascii && strchr("!\"$'(),.:;<>?[\\]^_`", ascii)) {
+ return true;
+ }
+ break;
+ }
+ }
+ }
+ return false;
+}
+
void GHOST_ImeWin32::CreateImeWindow(HWND window_handle)
{
/**
diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h
index 4af988aef6e..bcc4b6eef7c 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.h
+++ b/intern/ghost/intern/GHOST_ImeWin32.h
@@ -156,6 +156,18 @@ class GHOST_ImeWin32 {
*/
bool SetInputLanguage();
+ /* Returns the current input language id. */
+ WORD GetInputLanguage();
+
+ /* Saves the current conversion status. */
+ void UpdateConversionStatus(HWND window_handle);
+
+ /* Is the IME currently in conversion mode? */
+ bool IsEnglishMode();
+
+ /* Checks a key whether IME has to do handling. */
+ bool IsImeKeyEvent(char ascii);
+
/**
* Create the IME windows, and allocate required resources for them.
* Parameters
@@ -371,6 +383,12 @@ class GHOST_ImeWin32 {
*/
LANGID input_language_id_;
+ /* Current Conversion Mode Values. Retrieved with ImmGetConversionStatus. */
+ DWORD conversion_modes_;
+
+ /* Current Sentence Mode. Retrieved with ImmGetConversionStatus. */
+ DWORD sentence_mode_;
+
/**
* Represents whether or not the current input context has created a system
* caret to set the position of its IME candidate window.
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 694efaaaf03..60fd175dbf7 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -1219,6 +1219,12 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
ascii = utf8_char[0] & 0x80 ? '?' : utf8_char[0];
}
+#ifdef WITH_INPUT_IME
+ if (window->getImeInput()->IsImeKeyEvent(ascii)) {
+ return NULL;
+ }
+#endif /* WITH_INPUT_IME */
+
event = new GHOST_EventKey(system->getMilliSeconds(),
keyDown ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
window,
@@ -1419,6 +1425,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
system->handleKeyboardChange();
#ifdef WITH_INPUT_IME
window->getImeInput()->SetInputLanguage();
+ window->getImeInput()->UpdateConversionStatus(hwnd);
#endif
break;
}
@@ -1455,6 +1462,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
////////////////////////////////////////////////////////////////////////
// IME events, processed, read more in GHOST_IME.h
////////////////////////////////////////////////////////////////////////
+ case WM_IME_NOTIFY: {
+ /* Update conversion status when IME is changed or input mode is changed. */
+ if (wParam == IMN_SETOPENSTATUS || wParam == IMN_SETCONVERSIONMODE) {
+ window->getImeInput()->UpdateConversionStatus(hwnd);
+ }
+ break;
+ }
case WM_IME_SETCONTEXT: {
GHOST_ImeWin32 *ime = window->getImeInput();
ime->SetInputLanguage();
@@ -1466,8 +1480,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
case WM_IME_STARTCOMPOSITION: {
GHOST_ImeWin32 *ime = window->getImeInput();
eventHandled = true;
- /* remove input event before start comp event, avoid redundant input */
- eventManager->removeTypeEvents(GHOST_kEventKeyDown, window);
ime->CreateImeWindow(hwnd);
ime->ResetComposition(hwnd);
event = processImeEvent(GHOST_kEventImeCompositionStart, window, &ime->eventImeData);