diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c index b4c4c01986..12af9ccb96 100644 --- a/gdk/gdkevents.c +++ b/gdk/gdkevents.c @@ -585,7 +585,7 @@ gdk_event_new (GdkEventType type) return new_event; } -static gboolean +gboolean gdk_event_is_allocated (const GdkEvent *event) { if (event_hash) @@ -663,6 +663,11 @@ gdk_event_copy (const GdkEvent *event) new_private->source_device = private->source_device ? g_object_ref (private->source_device) : NULL; new_private->seat = private->seat; new_private->tool = private->tool; + +#ifdef GDK_WINDOWING_WIN32 + new_private->translation_len = private->translation_len; + new_private->translation = g_memdup (private->translation, private->translation_len * sizeof (private->translation[0])); +#endif } switch (event->any.type) @@ -767,6 +772,9 @@ gdk_event_free (GdkEvent *event) private = (GdkEventPrivate *) event; g_clear_object (&private->device); g_clear_object (&private->source_device); +#ifdef GDK_WINDOWING_WIN32 + g_free (private->translation); +#endif } switch (event->any.type) @@ -2564,4 +2572,4 @@ gdk_event_get_scancode (GdkEvent *event) private = (GdkEventPrivate *) event; return private->key_scancode; -} +} \ No newline at end of file diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h index 50ebdaa235..e2c1d10c9c 100644 --- a/gdk/gdkinternals.h +++ b/gdk/gdkinternals.h @@ -192,6 +192,11 @@ struct _GdkEventPrivate GdkSeat *seat; GdkDeviceTool *tool; guint16 key_scancode; + +#ifdef GDK_WINDOWING_WIN32 + gunichar2 *translation; + guint translation_len; +#endif }; typedef struct _GdkWindowPaint GdkWindowPaint; @@ -413,6 +418,10 @@ void gdk_event_set_scancode (GdkEvent *event, void gdk_event_set_seat (GdkEvent *event, GdkSeat *seat); +/* The IME IM module needs this symbol exported. */ +_GDK_EXTERN +gboolean gdk_event_is_allocated (const GdkEvent *event); + void _gdk_event_emit (GdkEvent *event); GList* _gdk_event_queue_find_first (GdkDisplay *display); void _gdk_event_queue_remove_link (GdkDisplay *display, diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index 7aef277c27..327d288bc7 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -2556,31 +2556,6 @@ gdk_event_translate (MSG *msg, API_CALL (GetKeyboardState, (key_state)); - ccount = 0; - - 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]; - - /* don't emit an event */ - return_val = TRUE; - break; - } - else - { - /* wait until an event is created */; - } - } - } - event = gdk_event_new ((msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN) ? GDK_KEY_PRESS : GDK_KEY_RELEASE); @@ -2595,6 +2570,39 @@ gdk_event_translate (MSG *msg, gdk_event_set_device (event, device_manager_win32->core_keyboard); gdk_event_set_source_device (event, device_manager_win32->system_keyboard); gdk_event_set_seat (event, gdk_device_get_seat (device_manager_win32->core_keyboard)); + + /* 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). */ + + if (gdk_event_is_allocated (event)) /* Should always be true */ + { + GdkEventPrivate *event_priv = (GdkEventPrivate*) event; + + MSG msg2; + 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; + + /* Ignore control sequences like Backspace */ + if (!g_unichar_iscntrl(c)) + { + /* Append character to translation string. */ + event_priv->translation_len ++; + event_priv->translation = g_realloc (event_priv->translation, event_priv->translation_len * sizeof (event_priv->translation[0])); + event_priv->translation[event_priv->translation_len - 1] = c; + } + + /* Remove message from queue */ + GetMessageW (&msg2, msg->hwnd, 0, 0); + } + } + if (HIWORD (msg->lParam) & KF_EXTENDED) { switch (msg->wParam) @@ -2623,42 +2631,12 @@ gdk_event_translate (MSG *msg, build_key_event_state (event, key_state); - 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; - - event->key.keyval = gdk_unicode_to_keyval ((leading - 0xD800) * 0x400 + wbuf[0] - 0xDC00 + 0x10000); - } - else - { - event->key.keyval = gdk_unicode_to_keyval (wbuf[0]); - } - } - else - { - gdk_keymap_translate_keyboard_state (_gdk_win32_display_get_keymap (display), - event->key.hardware_keycode, - event->key.state, - event->key.group, - &event->key.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), + event->key.hardware_keycode, + event->key.state, + event->key.group, + &event->key.keyval, + NULL, NULL, NULL); fill_key_event_string (event); diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index e1ef92096d..23f5b8d86c 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -240,14 +240,6 @@ struct _GdkWindowImplWin32 HICON hicon_big; HICON hicon_small; - /* 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 */ gint hint_flags; GdkGeometry hints; diff --git a/modules/input/gtkimcontextime.c b/modules/input/gtkimcontextime.c index 3ca7b5e661..8973b70113 100644 --- a/modules/input/gtkimcontextime.c +++ b/modules/input/gtkimcontextime.c @@ -27,13 +27,16 @@ #undef GTK_DISABLE_DEPRECATED #endif +#include "config.h" #include "gtkimcontextime.h" #include "imm-extra.h" #include "gdk/gdkkeysyms-compat.h" #include "gdk/win32/gdkwin32.h" +#include "gdk/win32/gdkprivate-win32.h" #include "gdk/gdkkeysyms.h" +#include "gdk/gdkinternals.h" #include @@ -59,10 +62,6 @@ typedef enum { GTK_WIN32_IME_FOCUS_BEHAVIOR_FOLLOW, } GtkWin32IMEFocusBehavior; -#define IS_DEAD_KEY(k) \ - ((k) >= GDK_dead_grave && (k) <= (GDK_dead_dasia+1)) - - struct _GtkIMContextIMEPrivate { /* When pretend_empty_preedit is set to TRUE, @@ -80,7 +79,6 @@ struct _GtkIMContextIMEPrivate * https://gitlab.gnome.org/GNOME/gtk/commit/c255ba68fc2c918dd84da48a472e7973d3c00b03 */ gboolean pretend_empty_preedit; - guint32 dead_key_keyval; GtkWin32IMEFocusBehavior focus_behavior; }; @@ -318,125 +316,30 @@ gtk_im_context_ime_set_client_window (GtkIMContext *context, g_return_if_fail (GDK_IS_WINDOW (context_ime->toplevel)); } -static gunichar -_gtk_im_context_ime_dead_key_unichar (guint keyval, - gboolean spacing) -{ - switch (keyval) - { -#define CASE(keysym, unicode, spacing_unicode) \ - case GDK_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) -{ - gchar 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, GdkEventKey *event) { GtkIMContextIME *context_ime; - gboolean retval = FALSE; - guint32 c; + GdkEventPrivate *event_priv; + gchar *utf8; g_return_val_if_fail (GTK_IS_IM_CONTEXT_IME (context), FALSE); g_return_val_if_fail (event, FALSE); - if (event->type == GDK_KEY_RELEASE) - return FALSE; - - if (event->state & GDK_CONTROL_MASK) - return FALSE; - context_ime = GTK_IM_CONTEXT_IME (context); - if (!context_ime->focus) + g_return_val_if_fail (gdk_event_is_allocated ((GdkEvent*)event), FALSE); + + event_priv = (GdkEventPrivate*) event; + if (event_priv->translation_len == 0) return FALSE; - if (!GDK_IS_WINDOW (context_ime->client_window)) - return FALSE; + utf8 = g_utf16_to_utf8 (event_priv->translation, event_priv->translation_len, NULL, NULL, NULL); + g_signal_emit_by_name (context_ime, "commit", utf8); + g_free (utf8); - if (event->keyval == GDK_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 (event->keyval); - - if (c) - { - _gtk_im_context_ime_commit_unichar (context_ime, c); - retval = TRUE; - } - else if (IS_DEAD_KEY (event->keyval)) - { - gunichar dead_key; - - dead_key = _gtk_im_context_ime_dead_key_unichar (event->keyval, FALSE); - - /* Emulate double input of dead keys */ - if (dead_key && event->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 = event->keyval; - } - - return retval; + return TRUE; } diff --git a/modules/input/imime.c b/modules/input/imime.c index d2943cf9cd..dea7ae12c7 100644 --- a/modules/input/imime.c +++ b/modules/input/imime.c @@ -30,7 +30,7 @@ static const GtkIMContextInfo ime_info = { NC_("input method menu", "Windows IME"), GETTEXT_PACKAGE, "", - "ja:ko:zh", + "*", }; static const GtkIMContextInfo *info_list[] = {