[gtk/wip.win32.fixes: 16/20] Use native Windows API for converting keystrokes to characters
- From: Chun-wei Fan <fanchunwei src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip.win32.fixes: 16/20] Use native Windows API for converting keystrokes to characters
- Date: Wed, 30 Dec 2020 09:21:30 +0000 (UTC)
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]