[Bf-blender-cvs] [836aeebf707] master: IME Win32: Fix Duplicated Initial Character

Takahiro Shizuki noreply at git.blender.org
Sun Aug 1 20:53:31 CEST 2021


Commit: 836aeebf70776791866c8cc82a0ca2ad7ffb8e4d
Author: Takahiro Shizuki
Date:   Sun Aug 1 11:52:22 2021 -0700
Branches: master
https://developer.blender.org/rB836aeebf70776791866c8cc82a0ca2ad7ffb8e4d

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

===================================================================

M	intern/ghost/intern/GHOST_ImeWin32.cpp
M	intern/ghost/intern/GHOST_ImeWin32.h
M	intern/ghost/intern/GHOST_SystemWin32.cpp

===================================================================

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);



More information about the Bf-blender-cvs mailing list