[gtk/wip.win32.fixes: 16/20] Use native Windows API for converting keystrokes to characters




commit 793014ffbddee873bea70735bcfe421a68fdaeb3
Author: Philip Zander <philip zander+gtk gmail com>
Date:   Tue Oct 27 16:59:30 2020 +0800

    Use native Windows API for converting keystrokes to characters
    
    Instead of using the incomplete GTK-internal emulation, use the WM_CHAR
    messages sent by Windows. Make the IME input method the default for all
    languages on Windows.

 gdk/win32/gdkevents-win32.c  |  88 +++++++++++-----------------------
 gdk/win32/gdksurface-win32.h |   8 ----
 gtk/gtkimcontextime.c        | 109 +++----------------------------------------
 3 files changed, 34 insertions(+), 171 deletions(-)
---
diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c
index dbdcab2c43..65a0d4cb4a 100644
--- a/gdk/win32/gdkevents-win32.c
+++ b/gdk/win32/gdkevents-win32.c
@@ -1745,6 +1745,7 @@ gdk_event_translate (MSG *msg,
   BYTE key_state[256];
   HIMC himc;
   WINDOWPOS *windowpos;
+  MSG msg2;
   gboolean ignore_leave;
 
   GdkEvent *event;
@@ -1925,33 +1926,30 @@ gdk_event_translate (MSG *msg,
 
       API_CALL (GetKeyboardState, (key_state));
 
-      ccount = 0;
+      keyval = GDK_KEY_VoidSymbol;
+      keycode = msg->wParam;
 
-      if (msg->wParam == VK_PACKET)
-       {
-         ccount = ToUnicode (VK_PACKET, HIWORD (msg->lParam), key_state, wbuf, 1, 0);
-         if (ccount == 1)
-           {
-             if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
-               {
-                 if (msg->message == WM_KEYDOWN)
-                   impl->leading_surrogate_keydown = wbuf[0];
-                 else
-                   impl->leading_surrogate_keyup = wbuf[0];
+      /* Get the WinAPI translation of the WM_KEY messages to characters.
+       *
+       *  The WM_CHAR messages are generated by a previous call to TranslateMessage() and always
+       * follow directly after the corresponding WM_KEY* messages.
+       * There could be 0 or more WM_CHAR messages following (for example dead keys don't generate
+       * WM_CHAR messages - they generate WM_DEAD_CHAR instead, but we are not interested in those
+       * messages).
+       */
+      while (PeekMessageW (&msg2, msg->hwnd, 0, 0, 0) && (msg2.message == WM_CHAR || msg2.message == 
WM_SYSCHAR))
+        {
+          /* The character is encoded in WPARAM as UTF-16. */
+          gunichar2 c = msg2.wParam;
 
-                 /* don't emit an event */
-                 return_val = TRUE;
-                 break;
-               }
-             else
-               {
-                 /* wait until an event is created */;
-               }
-           }
-       }
+          /* Ignore control sequences like Backspace */
+          if (!g_unichar_iscntrl(c))
+            keyval = gdk_unicode_to_keyval ((guint32) c);
 
-      keyval = GDK_KEY_VoidSymbol;
-      keycode = msg->wParam;
+          /* Remove message from queue */
+          GetMessageW (&msg2, msg->hwnd, 0, 0);
+
+        }
 
       if (HIWORD (msg->lParam) & KF_EXTENDED)
        {
@@ -1982,42 +1980,12 @@ gdk_event_translate (MSG *msg,
       state = build_key_event_state (key_state);
       group = get_active_group ();
 
-      if (msg->wParam == VK_PACKET && ccount == 1)
-       {
-         if (wbuf[0] >= 0xD800 && wbuf[0] < 0xDC00)
-           {
-             g_assert_not_reached ();
-           }
-         else if (wbuf[0] >= 0xDC00 && wbuf[0] < 0xE000)
-           {
-             wchar_t leading;
-
-              if (msg->message == WM_KEYDOWN)
-               leading = impl->leading_surrogate_keydown;
-             else
-               leading = impl->leading_surrogate_keyup;
-
-             keyval = gdk_unicode_to_keyval ((leading - 0xD800) * 0x400 + wbuf[0] - 0xDC00 + 0x10000);
-           }
-         else
-           {
-             keyval = gdk_unicode_to_keyval (wbuf[0]);
-           }
-       }
-      else
-       {
-         gdk_keymap_translate_keyboard_state (_gdk_win32_display_get_keymap (display),
-                                              keycode,
-                                              state,
-                                              group,
-                                              &keyval,
-                                              NULL, NULL, NULL);
-       }
-
-      if (msg->message == WM_KEYDOWN)
-       impl->leading_surrogate_keydown = 0;
-      else
-       impl->leading_surrogate_keyup = 0;
+  gdk_keymap_translate_keyboard_state (_gdk_win32_display_get_keymap (display),
+                                       keycode,
+                                       state,
+                                       group,
+                                      &keyval,
+                                       NULL, NULL, NULL);
 
   /* Only one release key event is fired when both shift keys are pressed together
      and then released. In order to send the missing event, press events for shift
diff --git a/gdk/win32/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h
index 5f45eb7662..6f3672e98d 100644
--- a/gdk/win32/gdksurface-win32.h
+++ b/gdk/win32/gdksurface-win32.h
@@ -235,14 +235,6 @@ struct _GdkWin32Surface
   /* The cursor that GDK set for this window via GdkDevice */
   GdkWin32HCursor *cursor;
 
-  /* When VK_PACKET sends us a leading surrogate, it's stashed here.
-   * Later, when another VK_PACKET sends a tailing surrogate, we make up
-   * a full unicode character from them, or discard the leading surrogate,
-   * if the next key is not a tailing surrogate.
-   */
-  wchar_t leading_surrogate_keydown;
-  wchar_t leading_surrogate_keyup;
-
   /* Window size hints */
   int hint_flags;
   GdkGeometry hints;
diff --git a/gtk/gtkimcontextime.c b/gtk/gtkimcontextime.c
index c8378c836e..f816ec5e91 100644
--- a/gtk/gtkimcontextime.c
+++ b/gtk/gtkimcontextime.c
@@ -61,9 +61,6 @@ typedef enum {
   GTK_WIN32_IME_FOCUS_BEHAVIOR_FOLLOW,
 } GtkWin32IMEFocusBehavior;
 
-#define IS_DEAD_KEY(k) \
-    ((k) >= GDK_KEY_dead_grave && (k) <= (GDK_KEY_dead_dasia+1))
-
 struct _GtkIMContextIMEPrivate
 {
   /* When pretend_empty_preedit is set to TRUE,
@@ -81,7 +78,6 @@ struct _GtkIMContextIMEPrivate
    *   https://gitlab.gnome.org/GNOME/gtk/commit/c255ba68fc2c918dd84da48a472e7973d3c00b03
    */
   gboolean pretend_empty_preedit;
-  guint32 dead_key_keyval;
   GtkWin32IMEFocusBehavior focus_behavior;
 };
 
@@ -278,86 +274,23 @@ gtk_im_context_ime_set_client_widget (GtkIMContext *context,
   context_ime->client_surface = client_surface;
 }
 
-static gunichar
-_gtk_im_context_ime_dead_key_unichar (guint    keyval,
-                                      gboolean spacing)
-{
-  switch (keyval)
-    {
-#define CASE(keysym, unicode, spacing_unicode) \
-      case GDK_KEY_dead_##keysym: return (spacing) ? spacing_unicode : unicode;
-
-      CASE (grave, 0x0300, 0x0060);
-      CASE (acute, 0x0301, 0x00b4);
-      CASE (circumflex, 0x0302, 0x005e);
-      CASE (tilde, 0x0303, 0x007e);    /* Also used with perispomeni, 0x342. */
-      CASE (macron, 0x0304, 0x00af);
-      CASE (breve, 0x0306, 0x02d8);
-      CASE (abovedot, 0x0307, 0x02d9);
-      CASE (diaeresis, 0x0308, 0x00a8);
-      CASE (hook, 0x0309, 0);
-      CASE (abovering, 0x030A, 0x02da);
-      CASE (doubleacute, 0x030B, 0x2dd);
-      CASE (caron, 0x030C, 0x02c7);
-      CASE (abovecomma, 0x0313, 0);         /* Equivalent to psili */
-      CASE (abovereversedcomma, 0x0314, 0); /* Equivalent to dasia */
-      CASE (horn, 0x031B, 0);  /* Legacy use for psili, 0x313 (or 0x343). */
-      CASE (belowdot, 0x0323, 0);
-      CASE (cedilla, 0x0327, 0x00b8);
-      CASE (ogonek, 0x0328, 0);        /* Legacy use for dasia, 0x314.*/
-      CASE (iota, 0x0345, 0);
-
-#undef CASE
-    default:
-      return 0;
-    }
-}
-
-static void
-_gtk_im_context_ime_commit_unichar (GtkIMContextIME *context_ime,
-                                    gunichar         c)
-{
-  char utf8[10];
-  int len;
-
-  if (context_ime->priv->dead_key_keyval != 0)
-    {
-      gunichar combining;
-
-      combining =
-        _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval,
-                                              FALSE);
-      g_unichar_compose (c, combining, &c);
-    }
-
-  len = g_unichar_to_utf8 (c, utf8);
-  utf8[len] = 0;
-
-  g_signal_emit_by_name (context_ime, "commit", utf8);
-  context_ime->priv->dead_key_keyval = 0;
-}
-
 static gboolean
 gtk_im_context_ime_filter_keypress (GtkIMContext *context,
                                     GdkEvent     *event)
 {
   GtkIMContextIME *context_ime;
-  gboolean retval = FALSE;
   guint32 c;
   GdkModifierType state;
   guint keyval;
+  gchar utf8[10];
+  int len;
+
 
   g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE);
   g_return_val_if_fail (event, FALSE);
 
-  if (gdk_event_get_event_type ((GdkEvent *) event) == GDK_KEY_RELEASE)
-    return FALSE;
-
   state = gdk_event_get_modifier_state ((GdkEvent *) event);
 
-  if (state & GDK_CONTROL_MASK)
-    return FALSE;
-
   context_ime = GTK_IM_CONTEXT_IME (context);
 
   if (!context_ime->focus)
@@ -368,41 +301,11 @@ gtk_im_context_ime_filter_keypress (GtkIMContext *context,
 
   keyval = gdk_key_event_get_keyval ((GdkEvent *) event);
 
-  if (keyval == GDK_KEY_space &&
-      context_ime->priv->dead_key_keyval != 0)
-    {
-      c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
-      context_ime->priv->dead_key_keyval = 0;
-      _gtk_im_context_ime_commit_unichar (context_ime, c);
-      return TRUE;
-    }
-
   c = gdk_keyval_to_unicode (keyval);
+  len = g_unichar_to_utf8 (c, utf8);
+  utf8[len] = 0;
 
-  if (c)
-    {
-      _gtk_im_context_ime_commit_unichar (context_ime, c);
-      retval = TRUE;
-    }
-  else if (IS_DEAD_KEY (keyval))
-    {
-      gunichar dead_key;
-
-      dead_key = _gtk_im_context_ime_dead_key_unichar (keyval, FALSE);
-
-      /* Emulate double input of dead keys */
-      if (dead_key && keyval == context_ime->priv->dead_key_keyval)
-        {
-          c = _gtk_im_context_ime_dead_key_unichar (context_ime->priv->dead_key_keyval, TRUE);
-          context_ime->priv->dead_key_keyval = 0;
-          _gtk_im_context_ime_commit_unichar (context_ime, c);
-          _gtk_im_context_ime_commit_unichar (context_ime, c);
-        }
-      else
-        context_ime->priv->dead_key_keyval = keyval;
-    }
-
-  return retval;
+  return TRUE;
 }
 
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]