From 4f52775456eb9b76e9b1dfd673b0f873153d5dac Mon Sep 17 00:00:00 2001 From: Rimas Kudelis Date: Sun, 27 Nov 2016 12:07:59 +0200 Subject: [PATCH] Updated GTK2 to 2.24.31 (#1979) * Updated GTK2 to 2.24.31 Also added a few Windows-specific changes which didn't make it into this release, but were committed later. These make windows dead keys work as expected in GTK2 applications. * Removed explicit dependencies on `base-devel` pkgs Removed explicit dependencies on packages, on which `base-devel` depends. As requested by @Alexpux. --- .../0002-Fix-def-installation.all.patch | 10 - .../0013-fix-dead-keys-part-1.patch | 698 ++++++++ .../0014-fix-dead-keys-part-2.patch | 1454 +++++++++++++++++ .../0015-fix-dead-keys-part-3.patch | 641 ++++++++ .../0016-handle-pause-key-correctly.patch | 36 + mingw-w64-gtk2/PKGBUILD | 28 +- 6 files changed, 2849 insertions(+), 18 deletions(-) delete mode 100644 mingw-w64-gtk2/0002-Fix-def-installation.all.patch create mode 100644 mingw-w64-gtk2/0013-fix-dead-keys-part-1.patch create mode 100644 mingw-w64-gtk2/0014-fix-dead-keys-part-2.patch create mode 100644 mingw-w64-gtk2/0015-fix-dead-keys-part-3.patch create mode 100644 mingw-w64-gtk2/0016-handle-pause-key-correctly.patch diff --git a/mingw-w64-gtk2/0002-Fix-def-installation.all.patch b/mingw-w64-gtk2/0002-Fix-def-installation.all.patch deleted file mode 100644 index 673098e171..0000000000 --- a/mingw-w64-gtk2/0002-Fix-def-installation.all.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- gtk+-2.24.8/gdk/Makefile.am.orig 2011-11-10 21:38:03 +0400 -+++ gtk+-2.24.8/gdk/Makefile.am 2011-12-08 13:48:31 +0400 -@@ -262,6 +262,7 @@ - - if OS_WIN32 - install-def-file: gdk.def -+ test -z "$(DESTDIR)$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" - $(INSTALL) $(srcdir)/gdk.def $(DESTDIR)$(libdir)/gdk-win32-2.0.def - uninstall-def-file: - -rm $(DESTDIR)$(libdir)/gdk-win32-2.0.def diff --git a/mingw-w64-gtk2/0013-fix-dead-keys-part-1.patch b/mingw-w64-gtk2/0013-fix-dead-keys-part-1.patch new file mode 100644 index 0000000000..98ac6b4b54 --- /dev/null +++ b/mingw-w64-gtk2/0013-fix-dead-keys-part-1.patch @@ -0,0 +1,698 @@ +From 92e6c4575652109b44454ee78c79a7166d29ad77 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= + =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= +Date: Sat, 30 Jul 2016 20:30:28 +0000 +Subject: Backport some of the GTK3 changes to win32/gdkkeys + +This lays the foundation for backporting more invasive gdkkeys commits +from GTK3. + +https://bugzilla.gnome.org/show_bug.cgi?id=768722 +--- + gdk/gdk.symbols | 6 + + gdk/win32/Makefile.am | 1 + + gdk/win32/gdkkeys-win32.c | 305 +++++++++++++++++++++++++--------------------- + gdk/win32/gdkwin32.h | 6 + + gdk/win32/gdkwin32keys.h | 47 +++++++ + 5 files changed, 229 insertions(+), 136 deletions(-) + create mode 100644 gdk/win32/gdkwin32keys.h + +diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols +index d4f2072..b2bd9eb 100644 +--- a/gdk/gdk.symbols ++++ b/gdk/gdk.symbols +@@ -1282,6 +1282,12 @@ gdk_win32_hdc_release + gdk_win32_selection_add_targets + #endif + #endif ++ ++#if IN_HEADER(__GDK_WIN32_H__) ++#if IN_FILE(__GDK_KEYS_WIN32_C__) ++gdk_win32_keymap_get_type G_GNUC_CONST ++#endif ++#endif + #endif + + #ifdef GDK_WINDOWING_X11 +diff --git a/gdk/win32/Makefile.am b/gdk/win32/Makefile.am +index d57ad35..e3e4608 100644 +--- a/gdk/win32/Makefile.am ++++ b/gdk/win32/Makefile.am +@@ -55,6 +55,7 @@ libgdk_win32_la_SOURCES = \ + gdktestutils-win32.c \ + gdkvisual-win32.c \ + gdkwin32.h \ ++ gdkwin32keys.h \ + gdkwin32id.c \ + gdkwindow-win32.c \ + gdkwindow-win32.h \ +diff --git a/gdk/win32/gdkkeys-win32.c b/gdk/win32/gdkkeys-win32.c +index b70066e..dd4cb0c 100644 +--- a/gdk/win32/gdkkeys-win32.c ++++ b/gdk/win32/gdkkeys-win32.c +@@ -35,8 +35,25 @@ + #include "gdkprivate-win32.h" + #include "gdkinternals.h" + #include "gdkkeysyms.h" ++#include "gdkkeys.h" ++#include "gdkwin32keys.h" + +-#include "config.h" ++struct _GdkWin32KeymapClass ++{ ++ GdkKeymapClass parent_class; ++}; ++ ++struct _GdkWin32Keymap ++{ ++ GdkKeymap parent_instance; ++}; ++ ++G_DEFINE_TYPE (GdkWin32Keymap, gdk_win32_keymap, GDK_TYPE_KEYMAP) ++ ++static void ++gdk_win32_keymap_init (GdkWin32Keymap *keymap) ++{ ++} + + guint _gdk_keymap_serial = 0; + gboolean _gdk_keyboard_has_altgr = FALSE; +@@ -49,6 +66,8 @@ static GdkKeymap *default_keymap = NULL; + static guint *keysym_tab = NULL; + static wchar_t decimal_mark = 0; + ++#define KEY_STATE_SIZE 256 ++ + #ifdef G_ENABLE_DEBUG + static void + print_keysym_tab (void) +@@ -58,7 +77,7 @@ print_keysym_tab (void) + g_print ("keymap:%s%s\n", + _gdk_keyboard_has_altgr ? " (uses AltGr)" : "", + (gdk_shift_modifiers & GDK_LOCK_MASK) ? " (has ShiftLock)" : ""); +- for (vk = 0; vk < 256; vk++) ++ for (vk = 0; vk < KEY_STATE_SIZE; vk++) + { + gint state; + +@@ -84,158 +103,158 @@ handle_special (guint vk, + switch (vk) + { + case VK_CANCEL: +- *ksymp = GDK_Cancel; break; ++ *ksymp = GDK_KEY_Cancel; break; + case VK_BACK: +- *ksymp = GDK_BackSpace; break; ++ *ksymp = GDK_KEY_BackSpace; break; + case VK_TAB: + if (shift & 0x1) +- *ksymp = GDK_ISO_Left_Tab; ++ *ksymp = GDK_KEY_ISO_Left_Tab; + else +- *ksymp = GDK_Tab; ++ *ksymp = GDK_KEY_Tab; + break; + case VK_CLEAR: +- *ksymp = GDK_Clear; break; ++ *ksymp = GDK_KEY_Clear; break; + case VK_RETURN: +- *ksymp = GDK_Return; break; ++ *ksymp = GDK_KEY_Return; break; + case VK_SHIFT: + case VK_LSHIFT: +- *ksymp = GDK_Shift_L; break; ++ *ksymp = GDK_KEY_Shift_L; break; + case VK_CONTROL: + case VK_LCONTROL: +- *ksymp = GDK_Control_L; break; ++ *ksymp = GDK_KEY_Control_L; break; + case VK_MENU: + case VK_LMENU: +- *ksymp = GDK_Alt_L; break; ++ *ksymp = GDK_KEY_Alt_L; break; + case VK_PAUSE: +- *ksymp = GDK_Pause; break; ++ *ksymp = GDK_KEY_Pause; break; + case VK_ESCAPE: +- *ksymp = GDK_Escape; break; ++ *ksymp = GDK_KEY_Escape; break; + case VK_PRIOR: +- *ksymp = GDK_Prior; break; ++ *ksymp = GDK_KEY_Prior; break; + case VK_NEXT: +- *ksymp = GDK_Next; break; ++ *ksymp = GDK_KEY_Next; break; + case VK_END: +- *ksymp = GDK_End; break; ++ *ksymp = GDK_KEY_End; break; + case VK_HOME: +- *ksymp = GDK_Home; break; ++ *ksymp = GDK_KEY_Home; break; + case VK_LEFT: +- *ksymp = GDK_Left; break; ++ *ksymp = GDK_KEY_Left; break; + case VK_UP: +- *ksymp = GDK_Up; break; ++ *ksymp = GDK_KEY_Up; break; + case VK_RIGHT: +- *ksymp = GDK_Right; break; ++ *ksymp = GDK_KEY_Right; break; + case VK_DOWN: +- *ksymp = GDK_Down; break; ++ *ksymp = GDK_KEY_Down; break; + case VK_SELECT: +- *ksymp = GDK_Select; break; ++ *ksymp = GDK_KEY_Select; break; + case VK_PRINT: +- *ksymp = GDK_Print; break; ++ *ksymp = GDK_KEY_Print; break; + case VK_SNAPSHOT: +- *ksymp = GDK_Print; break; ++ *ksymp = GDK_KEY_Print; break; + case VK_EXECUTE: +- *ksymp = GDK_Execute; break; ++ *ksymp = GDK_KEY_Execute; break; + case VK_INSERT: +- *ksymp = GDK_Insert; break; ++ *ksymp = GDK_KEY_Insert; break; + case VK_DELETE: +- *ksymp = GDK_Delete; break; ++ *ksymp = GDK_KEY_Delete; break; + case VK_HELP: +- *ksymp = GDK_Help; break; ++ *ksymp = GDK_KEY_Help; break; + case VK_LWIN: +- *ksymp = GDK_Meta_L; break; ++ *ksymp = GDK_KEY_Meta_L; break; + case VK_RWIN: +- *ksymp = GDK_Meta_R; break; ++ *ksymp = GDK_KEY_Meta_R; break; ++ case VK_APPS: ++ *ksymp = GDK_KEY_Menu; break; + case VK_DECIMAL: + *ksymp = GDK_KEY_KP_Decimal; break; +- case VK_APPS: +- *ksymp = GDK_Menu; break; + case VK_MULTIPLY: +- *ksymp = GDK_KP_Multiply; break; ++ *ksymp = GDK_KEY_KP_Multiply; break; + case VK_ADD: +- *ksymp = GDK_KP_Add; break; ++ *ksymp = GDK_KEY_KP_Add; break; + case VK_SEPARATOR: +- *ksymp = GDK_KP_Separator; break; ++ *ksymp = GDK_KEY_KP_Separator; break; + case VK_SUBTRACT: +- *ksymp = GDK_KP_Subtract; break; ++ *ksymp = GDK_KEY_KP_Subtract; break; + case VK_DIVIDE: +- *ksymp = GDK_KP_Divide; break; ++ *ksymp = GDK_KEY_KP_Divide; break; + case VK_NUMPAD0: +- *ksymp = GDK_KP_0; break; ++ *ksymp = GDK_KEY_KP_0; break; + case VK_NUMPAD1: +- *ksymp = GDK_KP_1; break; ++ *ksymp = GDK_KEY_KP_1; break; + case VK_NUMPAD2: +- *ksymp = GDK_KP_2; break; ++ *ksymp = GDK_KEY_KP_2; break; + case VK_NUMPAD3: +- *ksymp = GDK_KP_3; break; ++ *ksymp = GDK_KEY_KP_3; break; + case VK_NUMPAD4: +- *ksymp = GDK_KP_4; break; ++ *ksymp = GDK_KEY_KP_4; break; + case VK_NUMPAD5: +- *ksymp = GDK_KP_5; break; ++ *ksymp = GDK_KEY_KP_5; break; + case VK_NUMPAD6: +- *ksymp = GDK_KP_6; break; ++ *ksymp = GDK_KEY_KP_6; break; + case VK_NUMPAD7: +- *ksymp = GDK_KP_7; break; ++ *ksymp = GDK_KEY_KP_7; break; + case VK_NUMPAD8: +- *ksymp = GDK_KP_8; break; ++ *ksymp = GDK_KEY_KP_8; break; + case VK_NUMPAD9: +- *ksymp = GDK_KP_9; break; ++ *ksymp = GDK_KEY_KP_9; break; + case VK_F1: +- *ksymp = GDK_F1; break; ++ *ksymp = GDK_KEY_F1; break; + case VK_F2: +- *ksymp = GDK_F2; break; ++ *ksymp = GDK_KEY_F2; break; + case VK_F3: +- *ksymp = GDK_F3; break; ++ *ksymp = GDK_KEY_F3; break; + case VK_F4: +- *ksymp = GDK_F4; break; ++ *ksymp = GDK_KEY_F4; break; + case VK_F5: +- *ksymp = GDK_F5; break; ++ *ksymp = GDK_KEY_F5; break; + case VK_F6: +- *ksymp = GDK_F6; break; ++ *ksymp = GDK_KEY_F6; break; + case VK_F7: +- *ksymp = GDK_F7; break; ++ *ksymp = GDK_KEY_F7; break; + case VK_F8: +- *ksymp = GDK_F8; break; ++ *ksymp = GDK_KEY_F8; break; + case VK_F9: +- *ksymp = GDK_F9; break; ++ *ksymp = GDK_KEY_F9; break; + case VK_F10: +- *ksymp = GDK_F10; break; ++ *ksymp = GDK_KEY_F10; break; + case VK_F11: +- *ksymp = GDK_F11; break; ++ *ksymp = GDK_KEY_F11; break; + case VK_F12: +- *ksymp = GDK_F12; break; ++ *ksymp = GDK_KEY_F12; break; + case VK_F13: +- *ksymp = GDK_F13; break; ++ *ksymp = GDK_KEY_F13; break; + case VK_F14: +- *ksymp = GDK_F14; break; ++ *ksymp = GDK_KEY_F14; break; + case VK_F15: +- *ksymp = GDK_F15; break; ++ *ksymp = GDK_KEY_F15; break; + case VK_F16: +- *ksymp = GDK_F16; break; ++ *ksymp = GDK_KEY_F16; break; + case VK_F17: +- *ksymp = GDK_F17; break; ++ *ksymp = GDK_KEY_F17; break; + case VK_F18: +- *ksymp = GDK_F18; break; ++ *ksymp = GDK_KEY_F18; break; + case VK_F19: +- *ksymp = GDK_F19; break; ++ *ksymp = GDK_KEY_F19; break; + case VK_F20: +- *ksymp = GDK_F20; break; ++ *ksymp = GDK_KEY_F20; break; + case VK_F21: +- *ksymp = GDK_F21; break; ++ *ksymp = GDK_KEY_F21; break; + case VK_F22: +- *ksymp = GDK_F22; break; ++ *ksymp = GDK_KEY_F22; break; + case VK_F23: +- *ksymp = GDK_F23; break; ++ *ksymp = GDK_KEY_F23; break; + case VK_F24: +- *ksymp = GDK_F24; break; ++ *ksymp = GDK_KEY_F24; break; + case VK_NUMLOCK: +- *ksymp = GDK_Num_Lock; break; ++ *ksymp = GDK_KEY_Num_Lock; break; + case VK_SCROLL: +- *ksymp = GDK_Scroll_Lock; break; ++ *ksymp = GDK_KEY_Scroll_Lock; break; + case VK_RSHIFT: +- *ksymp = GDK_Shift_R; break; ++ *ksymp = GDK_KEY_Shift_R; break; + case VK_RCONTROL: +- *ksymp = GDK_Control_R; break; ++ *ksymp = GDK_KEY_Control_R; break; + case VK_RMENU: +- *ksymp = GDK_Alt_R; break; ++ *ksymp = GDK_KEY_Alt_R; break; + } + } + +@@ -265,12 +284,12 @@ set_shift_vks (guchar *key_state, + } + + static void +-reset_after_dead (guchar key_state[256]) ++reset_after_dead (guchar key_state[KEY_STATE_SIZE]) + { +- guchar temp_key_state[256]; ++ guchar temp_key_state[KEY_STATE_SIZE]; + wchar_t wcs[2]; + +- memmove (temp_key_state, key_state, sizeof (key_state)); ++ memmove (temp_key_state, key_state, KEY_STATE_SIZE); + + temp_key_state[VK_SHIFT] = + temp_key_state[VK_CONTROL] = +@@ -288,39 +307,39 @@ handle_dead (guint keysym, + switch (keysym) + { + case '"': /* 0x022 */ +- *ksymp = GDK_dead_diaeresis; break; ++ *ksymp = GDK_KEY_dead_diaeresis; break; + case '\'': /* 0x027 */ +- *ksymp = GDK_dead_acute; break; +- case GDK_asciicircum: /* 0x05e */ +- *ksymp = GDK_dead_circumflex; break; +- case GDK_grave: /* 0x060 */ +- *ksymp = GDK_dead_grave; break; +- case GDK_asciitilde: /* 0x07e */ +- *ksymp = GDK_dead_tilde; break; +- case GDK_diaeresis: /* 0x0a8 */ +- *ksymp = GDK_dead_diaeresis; break; +- case GDK_degree: /* 0x0b0 */ +- *ksymp = GDK_dead_abovering; break; +- case GDK_acute: /* 0x0b4 */ +- *ksymp = GDK_dead_acute; break; +- case GDK_periodcentered: /* 0x0b7 */ +- *ksymp = GDK_dead_abovedot; break; +- case GDK_cedilla: /* 0x0b8 */ +- *ksymp = GDK_dead_cedilla; break; +- case GDK_breve: /* 0x1a2 */ +- *ksymp = GDK_dead_breve; break; +- case GDK_ogonek: /* 0x1b2 */ +- *ksymp = GDK_dead_ogonek; break; +- case GDK_caron: /* 0x1b7 */ +- *ksymp = GDK_dead_caron; break; +- case GDK_doubleacute: /* 0x1bd */ +- *ksymp = GDK_dead_doubleacute; break; +- case GDK_abovedot: /* 0x1ff */ +- *ksymp = GDK_dead_abovedot; break; ++ *ksymp = GDK_KEY_dead_acute; break; ++ case GDK_KEY_asciicircum: /* 0x05e */ ++ *ksymp = GDK_KEY_dead_circumflex; break; ++ case GDK_KEY_grave: /* 0x060 */ ++ *ksymp = GDK_KEY_dead_grave; break; ++ case GDK_KEY_asciitilde: /* 0x07e */ ++ *ksymp = GDK_KEY_dead_tilde; break; ++ case GDK_KEY_diaeresis: /* 0x0a8 */ ++ *ksymp = GDK_KEY_dead_diaeresis; break; ++ case GDK_KEY_degree: /* 0x0b0 */ ++ *ksymp = GDK_KEY_dead_abovering; break; ++ case GDK_KEY_acute: /* 0x0b4 */ ++ *ksymp = GDK_KEY_dead_acute; break; ++ case GDK_KEY_periodcentered: /* 0x0b7 */ ++ *ksymp = GDK_KEY_dead_abovedot; break; ++ case GDK_KEY_cedilla: /* 0x0b8 */ ++ *ksymp = GDK_KEY_dead_cedilla; break; ++ case GDK_KEY_breve: /* 0x1a2 */ ++ *ksymp = GDK_KEY_dead_breve; break; ++ case GDK_KEY_ogonek: /* 0x1b2 */ ++ *ksymp = GDK_KEY_dead_ogonek; break; ++ case GDK_KEY_caron: /* 0x1b7 */ ++ *ksymp = GDK_KEY_dead_caron; break; ++ case GDK_KEY_doubleacute: /* 0x1bd */ ++ *ksymp = GDK_KEY_dead_doubleacute; break; ++ case GDK_KEY_abovedot: /* 0x1ff */ ++ *ksymp = GDK_KEY_dead_abovedot; break; + case 0x1000384: /* Greek tonos */ +- *ksymp = GDK_dead_acute; break; +- case GDK_Greek_accentdieresis: /* 0x7ae */ +- *ksymp = GDK_Greek_accentdieresis; break; ++ *ksymp = GDK_KEY_dead_acute; break; ++ case GDK_KEY_Greek_accentdieresis: /* 0x7ae */ ++ *ksymp = GDK_KEY_Greek_accentdieresis; break; + default: + /* By default use the keysym as such. This takes care of for + * instance the dead U+09CD (BENGALI VIRAMA) on the ekushey +@@ -346,7 +365,7 @@ static void + update_keymap (void) + { + static guint current_serial = 0; +- guchar key_state[256]; ++ guchar key_state[KEY_STATE_SIZE]; + guint scancode; + guint vk; + gboolean capslock_tested = FALSE; +@@ -357,21 +376,21 @@ update_keymap (void) + current_serial = _gdk_keymap_serial; + + if (keysym_tab == NULL) +- keysym_tab = g_new (guint, 4*256); ++ keysym_tab = g_new (guint, 4*KEY_STATE_SIZE); + + memset (key_state, 0, sizeof (key_state)); + + _gdk_keyboard_has_altgr = FALSE; + gdk_shift_modifiers = GDK_SHIFT_MASK; + +- for (vk = 0; vk < 256; vk++) ++ for (vk = 0; vk < KEY_STATE_SIZE; vk++) + { + if ((scancode = MapVirtualKey (vk, 0)) == 0 && + vk != VK_DIVIDE) + keysym_tab[vk*4+0] = + keysym_tab[vk*4+1] = + keysym_tab[vk*4+2] = +- keysym_tab[vk*4+3] = GDK_VoidSymbol; ++ keysym_tab[vk*4+3] = GDK_KEY_VoidSymbol; + else + { + gint shift; +@@ -420,7 +439,7 @@ update_keymap (void) + { + guint keysym = gdk_unicode_to_keyval (wcs[0]); + +- /* It is a dead key, and it's has been stored in ++ /* It is a dead key, and it has been stored in + * the keyboard layout's state by + * ToAsciiEx()/ToUnicodeEx(). Yes, this is an + * incredibly silly API! Make the keyboard +@@ -456,7 +475,7 @@ update_keymap (void) + } + } + if (*ksymp == 0) +- *ksymp = GDK_VoidSymbol; ++ *ksymp = GDK_KEY_VoidSymbol; + } + key_state[vk] = 0; + +@@ -464,9 +483,9 @@ update_keymap (void) + * the mapping with Control+Alt is different. + */ + if (!_gdk_keyboard_has_altgr) +- if ((keysym_tab[vk*4 + 2] != GDK_VoidSymbol && ++ if ((keysym_tab[vk*4 + 2] != GDK_KEY_VoidSymbol && + keysym_tab[vk*4] != keysym_tab[vk*4 + 2]) || +- (keysym_tab[vk*4 + 3] != GDK_VoidSymbol && ++ (keysym_tab[vk*4 + 3] != GDK_KEY_VoidSymbol && + keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 3])) + _gdk_keyboard_has_altgr = TRUE; + +@@ -494,8 +513,8 @@ update_keymap (void) + if (ToAsciiEx (vk, scancode, key_state, + (LPWORD) chars, 0, _gdk_input_locale) == 1) + { +- if (chars[0] >= GDK_space && +- chars[0] <= GDK_asciitilde && ++ if (chars[0] >= GDK_KEY_space && ++ chars[0] <= GDK_KEY_asciitilde && + chars[0] == keysym_tab[vk*4 + 1]) + { + /* CapsLock acts as ShiftLock */ +@@ -516,7 +535,7 @@ gdk_keymap_get_for_display (GdkDisplay *display) + g_return_val_if_fail (display == gdk_display_get_default (), NULL); + + if (default_keymap == NULL) +- default_keymap = g_object_new (gdk_keymap_get_type (), NULL); ++ default_keymap = g_object_new (gdk_win32_keymap_get_type (), NULL); + + return default_keymap; + } +@@ -580,7 +599,7 @@ gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, + + update_keymap (); + +- for (vk = 0; vk < 256; vk++) ++ for (vk = 0; vk < KEY_STATE_SIZE; vk++) + { + gint i; + +@@ -605,7 +624,7 @@ gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, + #ifdef G_ENABLE_DEBUG + if (_gdk_debug_flags & GDK_DEBUG_EVENTS) + { +- gint i; ++ guint i; + + g_print ("gdk_keymap_get_entries_for_keyval: %#.04x (%s):", + keyval, gdk_keyval_name (keyval)); +@@ -648,7 +667,7 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, + g_return_val_if_fail (n_entries != NULL, FALSE); + + if (hardware_keycode <= 0 || +- hardware_keycode >= 256) ++ hardware_keycode >= KEY_STATE_SIZE) + { + if (keys) + *keys = NULL; +@@ -744,14 +763,14 @@ gdk_keymap_lookup_key (GdkKeymap *keymap, + + update_keymap (); + +- if (key->keycode >= 256 || ++ if (key->keycode >= KEY_STATE_SIZE || + key->group < 0 || key->group >= 2 || + key->level < 0 || key->level >= 2) + return 0; + + sym = keysym_tab[key->keycode*4 + key->group*2 + key->level]; + +- if (sym == GDK_VoidSymbol) ++ if (sym == GDK_KEY_VoidSymbol) + return 0; + else + return sym; +@@ -793,7 +812,7 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + if (keymap != NULL && keymap != gdk_keymap_get_default ()) + return FALSE; + +- if (hardware_keycode >= 256) ++ if (hardware_keycode >= KEY_STATE_SIZE) + return FALSE; + + if (group < 0 || group >= 2) +@@ -820,23 +839,23 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + * the key for those. + */ + if (shift_level == 1 && +- keyvals[group*2 + 1] == GDK_VoidSymbol && +- keyvals[group*2] != GDK_VoidSymbol) ++ keyvals[group*2 + 1] == GDK_KEY_VoidSymbol && ++ keyvals[group*2] != GDK_KEY_VoidSymbol) + { + shift_level = 0; + ignore_shift = TRUE; + } + + if (group == 1 && +- keyvals[2 + shift_level] == GDK_VoidSymbol && +- keyvals[0 + shift_level] != GDK_VoidSymbol) ++ keyvals[2 + shift_level] == GDK_KEY_VoidSymbol && ++ keyvals[0 + shift_level] != GDK_KEY_VoidSymbol) + { + group = 0; + ignore_group = TRUE; + } + +- if (keyvals[group *2 + shift_level] == GDK_VoidSymbol && +- keyvals[0 + 0] != GDK_VoidSymbol) ++ if (keyvals[group *2 + shift_level] == GDK_KEY_VoidSymbol && ++ keyvals[0 + 0] != GDK_KEY_VoidSymbol) + { + shift_level = 0; + group = 0; +@@ -847,11 +866,11 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + /* See whether the group and shift level actually mattered + * to know what to put in consumed_modifiers + */ +- if (keyvals[group*2 + 1] == GDK_VoidSymbol || ++ if (keyvals[group*2 + 1] == GDK_KEY_VoidSymbol || + keyvals[group*2 + 0] == keyvals[group*2 + 1]) + ignore_shift = TRUE; + +- if (keyvals[2 + shift_level] == GDK_VoidSymbol || ++ if (keyvals[2 + shift_level] == GDK_KEY_VoidSymbol || + keyvals[0 + shift_level] == keyvals[2 + shift_level]) + ignore_group = TRUE; + +@@ -891,7 +910,7 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + group, shift_level, tmp_modifiers, gdk_keyval_name (tmp_keyval))); + #endif + +- return tmp_keyval != GDK_VoidSymbol; ++ return tmp_keyval != GDK_KEY_VoidSymbol; + } + + void +@@ -907,3 +926,17 @@ gdk_keymap_map_virtual_modifiers (GdkKeymap *keymap, + /* FIXME: Is this the right thing to do? */ + return TRUE; + } ++ ++static void ++gdk_win32_keymap_finalize (GObject *object) ++{ ++} ++ ++static void ++gdk_win32_keymap_class_init (GdkWin32KeymapClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ ++ object_class->finalize = gdk_win32_keymap_finalize; ++ ++} +diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h +index 32777ad..d7ba5a0 100644 +--- a/gdk/win32/gdkwin32.h ++++ b/gdk/win32/gdkwin32.h +@@ -35,6 +35,12 @@ + #include + #include + ++#define __GDKWIN32_H_INSIDE__ ++ ++#include ++ ++#undef __GDKWIN32_H_INSIDE__ ++ + G_BEGIN_DECLS + + #ifdef INSIDE_GDK_WIN32 +diff --git a/gdk/win32/gdkwin32keys.h b/gdk/win32/gdkwin32keys.h +new file mode 100644 +index 0000000..c271d67 +--- /dev/null ++++ b/gdk/win32/gdkwin32keys.h +@@ -0,0 +1,47 @@ ++/* GDK - The GIMP Drawing Kit ++ * Copyright (C) 2010 Red Hat, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see . ++ */ ++ ++#ifndef __GDK_WIN32_KEYS_H__ ++#define __GDK_WIN32_KEYS_H__ ++ ++#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GDK_COMPILATION) ++#error "Only can be included directly." ++#endif ++ ++#include ++ ++G_BEGIN_DECLS ++ ++#ifdef GDK_COMPILATION ++typedef struct _GdkWin32Keymap GdkWin32Keymap; ++#else ++typedef GdkKeymap GdkWin32Keymap; ++#endif ++typedef struct _GdkWin32KeymapClass GdkWin32KeymapClass; ++ ++#define GDK_TYPE_WIN32_KEYMAP (gdk_win32_keymap_get_type()) ++#define GDK_WIN32_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WIN32_KEYMAP, GdkWin32Keymap)) ++#define GDK_WIN32_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_WIN32_KEYMAP, GdkWin32KeymapClass)) ++#define GDK_IS_WIN32_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WIN32_KEYMAP)) ++#define GDK_IS_WIN32_KEYMAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_WIN32_KEYMAP)) ++#define GDK_WIN32_KEYMAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_WIN32_KEYMAP, GdkWin32KeymapClass)) ++ ++GType gdk_win32_keymap_get_type (void); ++ ++G_END_DECLS ++ ++#endif /* __GDK_WIN32_KEYMAP_H__ */ +-- +cgit v0.12 + diff --git a/mingw-w64-gtk2/0014-fix-dead-keys-part-2.patch b/mingw-w64-gtk2/0014-fix-dead-keys-part-2.patch new file mode 100644 index 0000000000..7beaeadf2d --- /dev/null +++ b/mingw-w64-gtk2/0014-fix-dead-keys-part-2.patch @@ -0,0 +1,1454 @@ +From 0b06d401034bcbee3e1e50085769361d96a81aaf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= + =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= +Date: Sat, 30 Jul 2016 20:32:52 +0000 +Subject: GDK W32: Cache multiple keyboard layouts simultaneously + +This changes the group/level semantic. +Previously W32 backend used "group 0/1" to denote "AltGr OFF/ON" +and "level 0/1" to denote "Shift is OFF/ON". +Now "group" means "keyboard layout" and there can be up to 255 groups, +while AltGr and Shift are combined into a single level enum that +takes values between 0 and 4. +Unlike X, W32 doesn't do effective group overriding, meaning that +it will never tell the caller that a different group was actually +used (even for universal keys, such as Enter), because key symbol +table is completely fabricated and there's no point in trying to +save a few of kilobytes of RAM by not duplicating universal key +records for all groups. + +Also contains many whitespace changes (tab elimination, fixed +indentation) and cleanup (axed a few global variables, these are +now accessed via the default keymap). + +https://bugzilla.gnome.org/show_bug.cgi?id=768722 +--- + gdk/gdkkeyuni.c | 6 +- + gdk/win32/gdkevents-win32.c | 12 +- + gdk/win32/gdkkeys-win32.c | 1003 ++++++++++++++++++++++++++++-------------- + gdk/win32/gdkmain-win32.c | 1 + + gdk/win32/gdkprivate-win32.h | 10 +- + 5 files changed, 684 insertions(+), 348 deletions(-) + +diff --git a/gdk/gdkkeyuni.c b/gdk/gdkkeyuni.c +index 7cd8514..42577fe 100644 +--- a/gdk/gdkkeyuni.c ++++ b/gdk/gdkkeyuni.c +@@ -887,7 +887,11 @@ gdk_keyval_to_unicode (guint keyval) + + #if defined(GDK_WINDOWING_WIN32) + if (keyval == 0xffae) +- return (guint32) _gdk_win32_keymap_get_decimal_mark (); ++ { ++ GdkWin32Keymap *keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ ++ return (guint32) _gdk_win32_keymap_get_decimal_mark (keymap); ++ } + #endif + + /* binary search in table */ +diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c +index ccb583b..9b09edd 100644 +--- a/gdk/win32/gdkevents-win32.c ++++ b/gdk/win32/gdkevents-win32.c +@@ -634,6 +634,8 @@ static void + build_key_event_state (GdkEvent *event, + BYTE *key_state) + { ++ GdkWin32Keymap *keymap; ++ + event->key.state = 0; + + if (key_state[VK_SHIFT] & 0x80) +@@ -653,11 +655,13 @@ build_key_event_state (GdkEvent *event, + if (key_state[VK_XBUTTON2] & 0x80) + event->key.state |= GDK_BUTTON5_MASK; + +- if (_gdk_keyboard_has_altgr && ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ event->key.group = _gdk_win32_keymap_get_active_group (keymap); ++ ++ if (_gdk_win32_keymap_has_altgr (keymap) && + (key_state[VK_LCONTROL] & 0x80) && + (key_state[VK_RMENU] & 0x80)) + { +- event->key.group = 1; + event->key.state |= GDK_MOD2_MASK; + if (key_state[VK_RCONTROL] & 0x80) + event->key.state |= GDK_CONTROL_MASK; +@@ -666,7 +670,6 @@ build_key_event_state (GdkEvent *event, + } + else + { +- event->key.group = 0; + if (key_state[VK_CONTROL] & 0x80) + event->key.state |= GDK_CONTROL_MASK; + if (key_state[VK_MENU] & 0x80) +@@ -2217,6 +2220,7 @@ gdk_event_translate (MSG *msg, + { + case WM_INPUTLANGCHANGE: + _gdk_input_locale = (HKL) msg->lParam; ++ _gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (gdk_keymap_get_default ()), _gdk_input_locale); + _gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale); + GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT), + LOCALE_IDEFAULTANSICODEPAGE, +@@ -2336,7 +2340,7 @@ gdk_event_translate (MSG *msg, + } + } + else if (msg->wParam == VK_SHIFT && +- LOBYTE (HIWORD (msg->lParam)) == _scancode_rshift) ++ LOBYTE (HIWORD (msg->lParam)) == _gdk_win32_keymap_get_rshift_scancode (GDK_WIN32_KEYMAP (gdk_keymap_get_default ()))) + event->key.hardware_keycode = VK_RSHIFT; + + /* g_print ("ctrl:%02x lctrl:%02x rctrl:%02x alt:%02x lalt:%02x ralt:%02x\n", key_state[VK_CONTROL], key_state[VK_LCONTROL], key_state[VK_RCONTROL], key_state[VK_MENU], key_state[VK_LMENU], key_state[VK_RMENU]); */ +diff --git a/gdk/win32/gdkkeys-win32.c b/gdk/win32/gdkkeys-win32.c +index dd4cb0c..edc26b2 100644 +--- a/gdk/win32/gdkkeys-win32.c ++++ b/gdk/win32/gdkkeys-win32.c +@@ -38,6 +38,25 @@ + #include "gdkkeys.h" + #include "gdkwin32keys.h" + ++struct _GdkWin32KeyGroupOptions ++{ ++ /* character that should be used as the decimal separator */ ++ wchar_t decimal_mark; ++ ++ /* the bits that indicate level shift when set (usually Shift, sometimes also CapsLock) */ ++ GdkModifierType shift_modifiers; ++ ++ /* Scancode for the VK_RSHIFT */ ++ guint scancode_rshift; ++ ++ /* TRUE if Ctrl+Alt emulates AltGr */ ++ gboolean has_altgr; ++ ++ gboolean capslock_tested; ++}; ++ ++typedef struct _GdkWin32KeyGroupOptions GdkWin32KeyGroupOptions; ++ + struct _GdkWin32KeymapClass + { + GdkKeymapClass parent_class; +@@ -46,51 +65,108 @@ struct _GdkWin32KeymapClass + struct _GdkWin32Keymap + { + GdkKeymap parent_instance; ++ ++ /* length = what GetKeyboardLayoutList() returns, type = HKL. ++ * When it changes, recreate the keymap and repopulate the options. ++ */ ++ GArray *layout_handles; ++ ++ /* VirtualKeyCode -> gdk_keyval table ++ * length = 256 * length(layout_handles) * 2 * 2 ++ * 256 is the number of virtual key codes, ++ * 2x2 is the number of Shift/AltGr combinations (level), ++ * length(layout_handles) is the number of layout handles (group). ++ */ ++ guint *keysym_tab; ++ ++ /* length = length(layout_handles), type = GdkWin32KeyGroupOptions ++ * Kept separate from layout_handles because layout_handles is ++ * populated by W32 API. ++ */ ++ GArray *options; ++ ++ /* Index of a handle in layout_handles, ++ * at any point it should be the same handle as GetKeyboardLayout(0) returns, ++ * but GDK caches it to avoid calling GetKeyboardLayout (0) every time. ++ */ ++ guint8 active_layout; + }; + ++enum _GdkWin32KeyLevelState ++{ ++ GDK_WIN32_LEVEL_NONE = 0, ++ GDK_WIN32_LEVEL_SHIFT, ++ GDK_WIN32_LEVEL_ALTGR, ++ GDK_WIN32_LEVEL_SHIFT_ALTGR, ++ GDK_WIN32_LEVEL_COUNT ++}; ++ ++typedef enum _GdkWin32KeyLevelState GdkWin32KeyLevelState; ++ + G_DEFINE_TYPE (GdkWin32Keymap, gdk_win32_keymap, GDK_TYPE_KEYMAP) + ++guint _gdk_keymap_serial = 0; ++ ++static GdkKeymap *default_keymap = NULL; ++ ++#define KEY_STATE_SIZE 256 ++ ++static void update_keymap (GdkKeymap *gdk_keymap); ++ + static void + gdk_win32_keymap_init (GdkWin32Keymap *keymap) + { ++ keymap->layout_handles = g_array_new (FALSE, FALSE, sizeof (HKL)); ++ keymap->options = g_array_new (FALSE, FALSE, sizeof (GdkWin32KeyGroupOptions)); ++ keymap->keysym_tab = NULL; ++ keymap->active_layout = 0; ++ update_keymap (GDK_KEYMAP (keymap)); + } + +-guint _gdk_keymap_serial = 0; +-gboolean _gdk_keyboard_has_altgr = FALSE; +-guint _scancode_rshift = 0; +- +-static GdkModifierType gdk_shift_modifiers = GDK_SHIFT_MASK; +- +-static GdkKeymap *default_keymap = NULL; ++static void ++gdk_win32_keymap_finalize (GObject *object) ++{ ++ GdkWin32Keymap *keymap = GDK_WIN32_KEYMAP (object); + +-static guint *keysym_tab = NULL; +-static wchar_t decimal_mark = 0; ++ g_clear_pointer (&keymap->keysym_tab, g_free); ++ g_clear_pointer (&keymap->layout_handles, g_array_unref); ++ g_clear_pointer (&keymap->options, g_array_unref); + +-#define KEY_STATE_SIZE 256 ++ G_OBJECT_CLASS (gdk_win32_keymap_parent_class)->finalize (object); ++} + + #ifdef G_ENABLE_DEBUG + static void +-print_keysym_tab (void) ++print_keysym_tab (GdkWin32Keymap *keymap) + { +- gint vk; +- +- g_print ("keymap:%s%s\n", +- _gdk_keyboard_has_altgr ? " (uses AltGr)" : "", +- (gdk_shift_modifiers & GDK_LOCK_MASK) ? " (has ShiftLock)" : ""); +- for (vk = 0; vk < KEY_STATE_SIZE; vk++) ++ gint li; ++ GdkWin32KeyGroupOptions *options; ++ gint vk; ++ GdkWin32KeyLevelState level; ++ gint group_size = keymap->layout_handles->len; ++ ++ for (li = 0; li < group_size; li++) + { +- gint state; +- +- g_print ("%#.02x: ", vk); +- for (state = 0; state < 4; state++) +- { +- gchar *name = gdk_keyval_name (keysym_tab[vk*4 + state]); +- if (name == NULL) +- name = "(none)"; +- g_print ("%s ", name); +- } +- g_print ("\n"); +- } ++ options = &g_array_index (keymap->options, GdkWin32KeyGroupOptions, li); ++ g_print ("keymap %d (0x%p):%s%s\n", ++ li, g_array_index (keymap->layout_handles, HKL, li), ++ options->has_altgr ? " (uses AltGr)" : "", ++ (options->shift_modifiers & GDK_LOCK_MASK) ? " (has ShiftLock)" : ""); ++ ++ for (vk = 0; vk < KEY_STATE_SIZE; vk++) ++ { ++ g_print ("%#.02x: ", vk); ++ ++ for (level = 0; level < GDK_WIN32_LEVEL_COUNT; level++) ++ { ++ gchar *name = gdk_keyval_name (keymap->keysym_tab[vk * group_size * GDK_WIN32_LEVEL_COUNT + level]); ++ ++ g_print ("%s ", name ? name : "(none)"); ++ } ++ ++ g_print ("\n"); ++ } ++ } + } + #endif + +@@ -259,34 +335,38 @@ handle_special (guint vk, + } + + static void +-set_shift_vks (guchar *key_state, +- gint shift) ++set_level_vks (guchar *key_state, ++ GdkWin32KeyLevelState level) + { +- switch (shift) ++ switch (level) + { +- case 0: ++ case GDK_WIN32_LEVEL_NONE: + key_state[VK_SHIFT] = 0; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0; + break; +- case 1: ++ case GDK_WIN32_LEVEL_SHIFT: + key_state[VK_SHIFT] = 0x80; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0; + break; +- case 2: ++ case GDK_WIN32_LEVEL_ALTGR: + key_state[VK_SHIFT] = 0; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0x80; + break; +- case 3: ++ case GDK_WIN32_LEVEL_SHIFT_ALTGR: + key_state[VK_SHIFT] = 0x80; + key_state[VK_CONTROL] = key_state[VK_MENU] = 0x80; + break; ++ case GDK_WIN32_LEVEL_COUNT: ++ g_assert_not_reached (); ++ break; + } + } + + static void +-reset_after_dead (guchar key_state[KEY_STATE_SIZE]) ++reset_after_dead (guchar key_state[KEY_STATE_SIZE], ++ HKL handle) + { +- guchar temp_key_state[KEY_STATE_SIZE]; ++ guchar temp_key_state[KEY_STATE_SIZE]; + wchar_t wcs[2]; + + memmove (temp_key_state, key_state, KEY_STATE_SIZE); +@@ -297,7 +377,7 @@ reset_after_dead (guchar key_state[KEY_STATE_SIZE]) + + ToUnicodeEx (VK_SPACE, MapVirtualKey (VK_SPACE, 0), + temp_key_state, wcs, G_N_ELEMENTS (wcs), +- 0, _gdk_input_locale); ++ 0, handle); + } + + static void +@@ -353,181 +433,361 @@ handle_dead (guint keysym, + return current decimal mark as unicode character + */ + guint32 +-_gdk_win32_keymap_get_decimal_mark (void) ++_gdk_win32_keymap_get_decimal_mark (GdkWin32Keymap *keymap) + { +- if (decimal_mark) +- return (decimal_mark); ++ if (keymap != NULL && ++ keymap->layout_handles->len > 0 && ++ g_array_index (keymap->options, GdkWin32KeyGroupOptions, keymap->active_layout).decimal_mark) ++ return g_array_index (keymap->options, GdkWin32KeyGroupOptions, keymap->active_layout).decimal_mark; + +- return ((guint32) '.'); ++ return (guint32) '.'; ++} ++ ++static gboolean ++layouts_are_the_same (GArray *array, HKL *hkls, gint hkls_len) ++{ ++ gint i; ++ ++ if (hkls_len != array->len) ++ return FALSE; ++ ++ for (i = 0; i < hkls_len; i++) ++ if (hkls[i] != g_array_index (array, HKL, i)) ++ return FALSE; ++ ++ return TRUE; + } + + static void +-update_keymap (void) ++check_that_active_layout_is_in_sync (GdkWin32Keymap *keymap) + { +- static guint current_serial = 0; +- guchar key_state[KEY_STATE_SIZE]; +- guint scancode; +- guint vk; +- gboolean capslock_tested = FALSE; ++ HKL hkl; ++ HKL cached_hkl; ++ wchar_t hkl_name[KL_NAMELENGTH]; + +- if (keysym_tab != NULL && current_serial == _gdk_keymap_serial) ++ if (keymap->layout_handles->len <= 0) + return; + +- current_serial = _gdk_keymap_serial; ++ hkl = GetKeyboardLayout (0); ++ cached_hkl = g_array_index (keymap->layout_handles, HKL, keymap->active_layout); ++ ++ if (hkl != cached_hkl) ++ { ++ if (!GetKeyboardLayoutNameW (hkl_name)) ++ wcscpy_s (hkl_name, KL_NAMELENGTH, L"(NULL)"); ++ ++ g_warning ("Cached active layout #%d (0x%p) does not match actual layout %S, 0x%p", ++ keymap->active_layout, cached_hkl, hkl_name, hkl); ++ } ++} ++ ++static void ++update_keymap (GdkKeymap *gdk_keymap) ++{ ++ int hkls_len; ++ static int hkls_size = 0; ++ static HKL *hkls = NULL; ++ gboolean no_list; ++ static guint current_serial = 0; ++ gint i, group; ++ GdkWin32KeyLevelState level; ++ GdkWin32KeyGroupOptions *options; ++ GdkWin32Keymap *keymap = GDK_WIN32_KEYMAP (gdk_keymap); ++ gint keysym_tab_size; ++ ++ guchar key_state[KEY_STATE_SIZE]; ++ guint scancode; ++ guint vk; ++ guint *keygroup; ++ ++ if (keymap->keysym_tab != NULL && ++ current_serial == _gdk_keymap_serial) ++ return; ++ ++ no_list = FALSE; ++ hkls_len = GetKeyboardLayoutList (0, NULL); ++ ++ if (hkls_len <= 0) ++ { ++ hkls_len = 1; ++ no_list = TRUE; ++ } ++ else if (hkls_len > 255) ++ { ++ hkls_len = 255; ++ } ++ ++ if (hkls_size < hkls_len) ++ { ++ hkls = g_renew (HKL, hkls, hkls_len); ++ hkls_size = hkls_len; ++ } ++ ++ if (hkls_len != GetKeyboardLayoutList (hkls_len, hkls)) ++ { ++ if (!no_list) ++ return; ++ ++ hkls[0] = GetKeyboardLayout (0); ++ hkls_len = 1; ++ } ++ ++ if (layouts_are_the_same (keymap->layout_handles, hkls, hkls_len)) ++ { ++ check_that_active_layout_is_in_sync (keymap); ++ current_serial = _gdk_keymap_serial; ++ ++ return; ++ } ++ ++ GDK_NOTE (EVENTS, g_print ("\nHave %d keyboard layouts:", hkls_len)); ++ ++ for (i = 0; i < hkls_len; i++) ++ { ++ GDK_NOTE (EVENTS, g_print (" 0x%p", hkls[i])); ++ ++ if (GetKeyboardLayout (0) == hkls[i]) ++ { ++ wchar_t hkl_name[KL_NAMELENGTH]; ++ ++ if (!GetKeyboardLayoutNameW (hkl_name)) ++ wcscpy_s (hkl_name, KL_NAMELENGTH, L"(NULL)"); ++ ++ GDK_NOTE (EVENTS, g_print ("(active, %S)", hkl_name)); ++ } ++ } ++ ++ GDK_NOTE (EVENTS, g_print ("\n")); + +- if (keysym_tab == NULL) +- keysym_tab = g_new (guint, 4*KEY_STATE_SIZE); ++ keysym_tab_size = hkls_len * 256 * 2 * 2; + +- memset (key_state, 0, sizeof (key_state)); ++ if (hkls_len != keymap->layout_handles->len) ++ keymap->keysym_tab = g_renew (guint, keymap->keysym_tab, keysym_tab_size); + +- _gdk_keyboard_has_altgr = FALSE; +- gdk_shift_modifiers = GDK_SHIFT_MASK; ++ memset (keymap->keysym_tab, 0, keysym_tab_size); ++ g_array_set_size (keymap->layout_handles, hkls_len); ++ g_array_set_size (keymap->options, hkls_len); ++ ++ for (i = 0; i < hkls_len; i++) ++ { ++ options = &g_array_index (keymap->options, GdkWin32KeyGroupOptions, i); ++ ++ options->decimal_mark = 0; ++ options->shift_modifiers = GDK_SHIFT_MASK; ++ options->scancode_rshift = 0; ++ options->has_altgr = FALSE; ++ options->capslock_tested = FALSE; ++ ++ g_array_index (keymap->layout_handles, HKL, i) = hkls[i]; ++ ++ if (hkls[i] == _gdk_input_locale) ++ keymap->active_layout = i; ++ } + + for (vk = 0; vk < KEY_STATE_SIZE; vk++) + { +- if ((scancode = MapVirtualKey (vk, 0)) == 0 && +- vk != VK_DIVIDE) +- keysym_tab[vk*4+0] = +- keysym_tab[vk*4+1] = +- keysym_tab[vk*4+2] = +- keysym_tab[vk*4+3] = GDK_KEY_VoidSymbol; +- else +- { +- gint shift; +- +- if (vk == VK_RSHIFT) +- _scancode_rshift = scancode; +- +- key_state[vk] = 0x80; +- for (shift = 0; shift < 4; shift++) +- { +- guint *ksymp = keysym_tab + vk*4 + shift; +- +- set_shift_vks (key_state, shift); +- +- *ksymp = 0; +- +- /* First, handle those virtual keys that we always want +- * as special GDK_* keysyms, even if ToAsciiEx might +- * turn some them into a ASCII character (like TAB and +- * ESC). +- */ +- handle_special (vk, ksymp, shift); +- +- if ((*ksymp == 0) || ((vk == VK_DECIMAL) && (shift == 0))) +- { +- wchar_t wcs[10]; +- gint k; +- +- wcs[0] = wcs[1] = 0; +- k = ToUnicodeEx (vk, scancode, key_state, +- wcs, G_N_ELEMENTS (wcs), +- 0, _gdk_input_locale); ++ for (group = 0; group < hkls_len; group++) ++ { ++ options = &g_array_index (keymap->options, GdkWin32KeyGroupOptions, group); ++ scancode = MapVirtualKeyEx (vk, 0, hkls[group]); ++ keygroup = &keymap->keysym_tab[(vk * hkls_len + group) * GDK_WIN32_LEVEL_COUNT]; ++ ++ if (scancode == 0 && ++ vk != VK_DIVIDE) ++ { ++ for (level = GDK_WIN32_LEVEL_NONE; level < GDK_WIN32_LEVEL_COUNT; level++) ++ keygroup[level] = GDK_KEY_VoidSymbol; ++ ++ continue; ++ } ++ ++ if (vk == VK_RSHIFT) ++ options->scancode_rshift = scancode; ++ ++ key_state[vk] = 0x80; ++ ++ for (level = GDK_WIN32_LEVEL_NONE; level < GDK_WIN32_LEVEL_COUNT; level++) ++ { ++ guint *ksymp = &keygroup[level]; ++ ++ set_level_vks (key_state, level); ++ ++ *ksymp = 0; ++ ++ /* First, handle those virtual keys that we always want ++ * as special GDK_* keysyms, even if ToAsciiEx might ++ * turn some them into a ASCII character (like TAB and ++ * ESC). ++ */ ++ handle_special (vk, ksymp, level); ++ ++ if ((*ksymp == 0) || ++ ((vk == VK_DECIMAL) && (level == GDK_WIN32_LEVEL_NONE))) ++ { ++ wchar_t wcs[10]; ++ gint k; ++ guint keysym; ++ ++ wcs[0] = wcs[1] = 0; ++ k = ToUnicodeEx (vk, scancode, key_state, ++ wcs, G_N_ELEMENTS (wcs), ++ 0, hkls[group]); + #if 0 +- g_print ("ToUnicodeEx(%#02x, %d: %d): %d, %04x %04x\n", +- vk, scancode, shift, k, +- wcs[0], wcs[1]); ++ g_print ("ToUnicodeEx(%#02x, %d: %d): %d, %04x %04x\n", ++ vk, scancode, level, k, ++ wcs[0], wcs[1]); + #endif +- if ((vk == VK_DECIMAL) && (shift == 0)) +- { +- if (k == 1) +- decimal_mark = wcs[0]; +- } +- else if (k == 1) +- *ksymp = gdk_unicode_to_keyval (wcs[0]); +- else if (k == -1) +- { +- guint keysym = gdk_unicode_to_keyval (wcs[0]); +- +- /* It is a dead key, and it has been stored in +- * the keyboard layout's state by +- * ToAsciiEx()/ToUnicodeEx(). Yes, this is an +- * incredibly silly API! Make the keyboard +- * layout forget it by calling +- * ToAsciiEx()/ToUnicodeEx() once more, with the +- * virtual key code and scancode for the +- * spacebar, without shift or AltGr. Otherwise +- * the next call to ToAsciiEx() with a different +- * key would try to combine with the dead key. +- */ +- reset_after_dead (key_state); +- +- /* Use dead keysyms instead of "undead" ones */ +- handle_dead (keysym, ksymp); +- } +- else if (k == 0) +- { +- /* Seems to be necessary to "reset" the keyboard layout +- * in this case, too. Otherwise problems on NT4. +- */ +- reset_after_dead (key_state); +- } +- else +- { ++ switch (k) ++ { ++ case 1: ++ if ((vk == VK_DECIMAL) && (level == GDK_WIN32_LEVEL_NONE)) ++ options->decimal_mark = wcs[0]; ++ else ++ *ksymp = gdk_unicode_to_keyval (wcs[0]); ++ break; ++ case -1: ++ keysym = gdk_unicode_to_keyval (wcs[0]); ++ ++ /* It is a dead key, and it has been stored in ++ * the keyboard layout's state by ++ * ToAsciiEx()/ToUnicodeEx(). Yes, this is an ++ * incredibly silly API! Make the keyboard ++ * layout forget it by calling ++ * ToAsciiEx()/ToUnicodeEx() once more, with the ++ * virtual key code and scancode for the ++ * spacebar, without shift or AltGr. Otherwise ++ * the next call to ToAsciiEx() with a different ++ * key would try to combine with the dead key. ++ */ ++ reset_after_dead (key_state, hkls[group]); ++ ++ /* Use dead keysyms instead of "undead" ones */ ++ handle_dead (keysym, ksymp); ++ break; ++ case 0: ++ /* Seems to be necessary to "reset" the keyboard layout ++ * in this case, too. Otherwise problems on NT4. ++ */ ++ reset_after_dead (key_state, hkls[group]); ++ break; ++ default: + #if 0 +- GDK_NOTE (EVENTS, +- g_print ("ToUnicodeEx returns %d " +- "for vk:%02x, sc:%02x%s%s\n", +- k, vk, scancode, +- (shift&0x1 ? " shift" : ""), +- (shift&0x2 ? " altgr" : ""))); ++ GDK_NOTE (EVENTS, ++ g_print ("ToUnicodeEx returns %d " ++ "for vk:%02x, sc:%02x%s%s\n", ++ k, vk, scancode, ++ (shift&0x1 ? " shift" : ""), ++ (shift&0x2 ? " altgr" : ""))); + #endif +- } +- } +- if (*ksymp == 0) +- *ksymp = GDK_KEY_VoidSymbol; +- } +- key_state[vk] = 0; +- +- /* Check if keyboard has an AltGr key by checking if +- * the mapping with Control+Alt is different. +- */ +- if (!_gdk_keyboard_has_altgr) +- if ((keysym_tab[vk*4 + 2] != GDK_KEY_VoidSymbol && +- keysym_tab[vk*4] != keysym_tab[vk*4 + 2]) || +- (keysym_tab[vk*4 + 3] != GDK_KEY_VoidSymbol && +- keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 3])) +- _gdk_keyboard_has_altgr = TRUE; +- +- if (!capslock_tested) +- { +- /* Can we use this virtual key to determine the CapsLock +- * key behaviour: CapsLock or ShiftLock? If it generates +- * keysyms for printable characters and has a shifted +- * keysym that isn't just the upperacase of the +- * unshifted keysym, check the behaviour of VK_CAPITAL. +- */ +- if (g_unichar_isgraph (gdk_keyval_to_unicode (keysym_tab[vk*4 + 0])) && +- keysym_tab[vk*4 + 1] != keysym_tab[vk*4 + 0] && +- g_unichar_isgraph (gdk_keyval_to_unicode (keysym_tab[vk*4 + 1])) && +- keysym_tab[vk*4 + 1] != gdk_keyval_to_upper (keysym_tab[vk*4 + 0])) +- { +- guchar chars[2]; +- +- capslock_tested = TRUE; +- +- key_state[VK_SHIFT] = 0; +- key_state[VK_CONTROL] = key_state[VK_MENU] = 0; +- key_state[VK_CAPITAL] = 1; +- +- if (ToAsciiEx (vk, scancode, key_state, +- (LPWORD) chars, 0, _gdk_input_locale) == 1) +- { +- if (chars[0] >= GDK_KEY_space && +- chars[0] <= GDK_KEY_asciitilde && +- chars[0] == keysym_tab[vk*4 + 1]) +- { +- /* CapsLock acts as ShiftLock */ +- gdk_shift_modifiers |= GDK_LOCK_MASK; +- } +- } +- key_state[VK_CAPITAL] = 0; +- } +- } +- } ++ break; ++ } ++ } ++ ++ if (*ksymp == 0) ++ *ksymp = GDK_KEY_VoidSymbol; ++ } ++ ++ key_state[vk] = 0; ++ ++ /* Check if keyboard has an AltGr key by checking if ++ * the mapping with Control+Alt is different. ++ */ ++ if (!options->has_altgr) ++ if ((keygroup[GDK_WIN32_LEVEL_ALTGR] != GDK_KEY_VoidSymbol && ++ keygroup[GDK_WIN32_LEVEL_NONE] != keygroup[GDK_WIN32_LEVEL_ALTGR]) || ++ (keygroup[GDK_WIN32_LEVEL_SHIFT_ALTGR] != GDK_KEY_VoidSymbol && ++ keygroup[GDK_WIN32_LEVEL_SHIFT] != keygroup[GDK_WIN32_LEVEL_SHIFT_ALTGR])) ++ options->has_altgr = TRUE; ++ ++ if (!options->capslock_tested) ++ { ++ /* Can we use this virtual key to determine the CapsLock ++ * key behaviour: CapsLock or ShiftLock? If it generates ++ * keysyms for printable characters and has a shifted ++ * keysym that isn't just the upperacase of the ++ * unshifted keysym, check the behaviour of VK_CAPITAL. ++ */ ++ if (g_unichar_isgraph (gdk_keyval_to_unicode (keygroup[GDK_WIN32_LEVEL_NONE])) && ++ keygroup[GDK_WIN32_LEVEL_SHIFT] != keygroup[GDK_WIN32_LEVEL_NONE] && ++ g_unichar_isgraph (gdk_keyval_to_unicode (keygroup[GDK_WIN32_LEVEL_SHIFT])) && ++ keygroup[GDK_WIN32_LEVEL_SHIFT] != gdk_keyval_to_upper (keygroup[GDK_WIN32_LEVEL_NONE])) ++ { ++ guchar chars[2]; ++ ++ options->capslock_tested = TRUE; ++ ++ key_state[VK_SHIFT] = 0; ++ key_state[VK_CONTROL] = key_state[VK_MENU] = 0; ++ key_state[VK_CAPITAL] = 1; ++ ++ if (ToAsciiEx (vk, scancode, key_state, ++ (LPWORD) chars, 0, hkls[group]) == 1) ++ { ++ if (chars[0] >= GDK_KEY_space && ++ chars[0] <= GDK_KEY_asciitilde && ++ chars[0] == keygroup[GDK_WIN32_LEVEL_SHIFT]) ++ { ++ /* CapsLock acts as ShiftLock */ ++ options->shift_modifiers |= GDK_LOCK_MASK; ++ } ++ } ++ ++ key_state[VK_CAPITAL] = 0; ++ } ++ } ++ } + } +- GDK_NOTE (EVENTS, print_keysym_tab ()); +-} ++ ++ GDK_NOTE (EVENTS, print_keysym_tab (keymap)); ++ ++ check_that_active_layout_is_in_sync (keymap); ++ current_serial = _gdk_keymap_serial; ++} ++ ++guint8 ++_gdk_win32_keymap_get_rshift_scancode (GdkWin32Keymap *keymap) ++{ ++ if (keymap != NULL && ++ keymap->layout_handles->len > 0) ++ return g_array_index (keymap->options, GdkWin32KeyGroupOptions, keymap->active_layout).scancode_rshift; ++ ++ return 0; ++} ++ ++void ++_gdk_win32_keymap_set_active_layout (GdkWin32Keymap *keymap, ++ HKL hkl) ++{ ++ if (keymap != NULL && ++ keymap->layout_handles->len > 0) ++ { ++ gint group; ++ ++ for (group = 0; group < keymap->layout_handles->len; group++) ++ if (g_array_index (keymap->layout_handles, HKL, group) == hkl) ++ keymap->active_layout = group; ++ } ++} ++ ++gboolean ++_gdk_win32_keymap_has_altgr (GdkWin32Keymap *keymap) ++{ ++ if (keymap != NULL && ++ keymap->layout_handles->len > 0) ++ return g_array_index (keymap->options, GdkWin32KeyGroupOptions, keymap->active_layout).has_altgr; ++ ++ return FALSE; ++} ++ ++guint8 ++_gdk_win32_keymap_get_active_group (GdkWin32Keymap *keymap) ++{ ++ if (keymap != NULL && ++ keymap->layout_handles->len > 0) ++ return keymap->active_layout; ++ ++ return 0; ++} + + GdkKeymap* + gdk_keymap_get_for_display (GdkDisplay *display) +@@ -540,12 +800,10 @@ gdk_keymap_get_for_display (GdkDisplay *display) + return default_keymap; + } + +-PangoDirection +-gdk_keymap_get_direction (GdkKeymap *keymap) ++static PangoDirection ++get_hkl_direction (HKL hkl) + { +- update_keymap (); +- +- switch (PRIMARYLANGID (LOWORD ((DWORD) (gintptr) _gdk_input_locale))) ++ switch (PRIMARYLANGID (LOWORD ((DWORD) (gintptr) hkl))) + { + case LANG_HEBREW: + case LANG_ARABIC: +@@ -561,64 +819,115 @@ gdk_keymap_get_direction (GdkKeymap *keymap) + } + } + ++PangoDirection ++gdk_keymap_get_direction (GdkKeymap *gdk_keymap) ++{ ++ HKL active_hkl; ++ GdkWin32Keymap *keymap; ++ ++ if (gdk_keymap == NULL || gdk_keymap != gdk_keymap_get_default ()) ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ else ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap); ++ ++ update_keymap (GDK_KEYMAP (keymap)); ++ ++ if (keymap->layout_handles->len <= 0) ++ active_hkl = GetKeyboardLayout (0); ++ else ++ active_hkl = g_array_index (keymap->layout_handles, HKL, keymap->active_layout); ++ ++ return get_hkl_direction (active_hkl); ++} ++ + gboolean +-gdk_keymap_have_bidi_layouts (GdkKeymap *keymap) ++gdk_keymap_have_bidi_layouts (GdkKeymap *gdk_keymap) + { +- /* Should we check if the kayboard layouts switchable at the moment +- * cover both directionalities? What does the doc comment in +- * ../x11/gdkkeys-x11.c exactly mean? +- */ +- return FALSE; ++ GdkWin32Keymap *keymap; ++ gboolean have_rtl = FALSE; ++ gboolean have_ltr = FALSE; ++ gint group; ++ ++ if (gdk_keymap == NULL || gdk_keymap != gdk_keymap_get_default ()) ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ else ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap); ++ ++ update_keymap (GDK_KEYMAP (keymap)); ++ ++ for (group = 0; group < keymap->layout_handles->len; group++) ++ { ++ if (get_hkl_direction (g_array_index (keymap->layout_handles, HKL, group)) == PANGO_DIRECTION_RTL) ++ have_rtl = TRUE; ++ else ++ have_ltr = TRUE; ++ } ++ ++ return have_ltr && have_rtl; + } + + gboolean + gdk_keymap_get_caps_lock_state (GdkKeymap *keymap) + { ++ (void) keymap; ++ + return ((GetKeyState (VK_CAPITAL) & 1) != 0); + } + + gboolean +-gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, ++gdk_keymap_get_entries_for_keyval (GdkKeymap *gdk_keymap, + guint keyval, + GdkKeymapKey **keys, + gint *n_keys) + { + GArray *retval; + +- g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); ++ g_return_val_if_fail (gdk_keymap == NULL || GDK_IS_KEYMAP (gdk_keymap), FALSE); + g_return_val_if_fail (keys != NULL, FALSE); + g_return_val_if_fail (n_keys != NULL, FALSE); + g_return_val_if_fail (keyval != 0, FALSE); +- ++ + retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); + + /* Accept only the default keymap */ +- if (keymap == NULL || keymap == gdk_keymap_get_default ()) ++ if (gdk_keymap == NULL || gdk_keymap == gdk_keymap_get_default ()) + { + gint vk; +- +- update_keymap (); ++ GdkWin32Keymap *keymap; ++ ++ if (gdk_keymap == NULL) ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ else ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap); ++ ++ update_keymap (gdk_keymap); + + for (vk = 0; vk < KEY_STATE_SIZE; vk++) +- { +- gint i; +- +- for (i = 0; i < 4; i++) +- { +- if (keysym_tab[vk*4+i] == keyval) +- { +- GdkKeymapKey key; +- +- key.keycode = vk; +- +- /* 2 levels (normal, shift), two groups (normal, AltGr) */ +- key.group = i / 2; +- key.level = i % 2; +- +- g_array_append_val (retval, key); +- } +- } +- } ++ { ++ gint group; ++ ++ for (group = 0; group < keymap->layout_handles->len; group++) ++ { ++ GdkWin32KeyLevelState level; ++ ++ for (level = GDK_WIN32_LEVEL_NONE; level < GDK_WIN32_LEVEL_COUNT; level++) ++ { ++ guint *keygroup; ++ ++ keygroup = &keymap->keysym_tab[(vk * keymap->layout_handles->len + group) * GDK_WIN32_LEVEL_COUNT]; ++ ++ if (keygroup[level] == keyval) ++ { ++ GdkKeymapKey key; ++ ++ key.keycode = vk; ++ key.group = group; ++ key.level = level; ++ g_array_append_val (retval, key); ++ } ++ } ++ } ++ } + } + + #ifdef G_ENABLE_DEBUG +@@ -627,12 +936,12 @@ gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, + guint i; + + g_print ("gdk_keymap_get_entries_for_keyval: %#.04x (%s):", +- keyval, gdk_keyval_name (keyval)); ++ keyval, gdk_keyval_name (keyval)); + for (i = 0; i < retval->len; i++) +- { +- GdkKeymapKey *entry = (GdkKeymapKey *) retval->data + i; +- g_print (" %#.02x %d %d", entry->keycode, entry->group, entry->level); +- } ++ { ++ GdkKeymapKey *entry = (GdkKeymapKey *) retval->data + i; ++ g_print (" %#.02x %d %d", entry->keycode, entry->group, entry->level); ++ } + g_print ("\n"); + } + #endif +@@ -647,28 +956,33 @@ gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap, + *keys = NULL; + *n_keys = 0; + } +- ++ + g_array_free (retval, retval->len > 0 ? FALSE : TRUE); + + return *n_keys > 0; + } + + gboolean +-gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, ++gdk_keymap_get_entries_for_keycode (GdkKeymap *gdk_keymap, + guint hardware_keycode, + GdkKeymapKey **keys, + guint **keyvals, + gint *n_entries) + { +- GArray *key_array; +- GArray *keyval_array; ++ GArray *key_array; ++ GArray *keyval_array; ++ gint group; ++ GdkWin32Keymap *keymap; + +- g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); ++ g_return_val_if_fail (gdk_keymap == NULL || GDK_IS_KEYMAP (gdk_keymap), FALSE); + g_return_val_if_fail (n_entries != NULL, FALSE); + + if (hardware_keycode <= 0 || +- hardware_keycode >= KEY_STATE_SIZE) ++ hardware_keycode >= KEY_STATE_SIZE || ++ (keys == NULL && keyvals == NULL) || ++ (gdk_keymap != NULL && gdk_keymap != gdk_keymap_get_default ())) + { ++ /* Wrong keycode or NULL output arrays or wrong keymap */ + if (keys) + *keys = NULL; + if (keyvals) +@@ -677,43 +991,47 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, + *n_entries = 0; + return FALSE; + } +- ++ + if (keys) + key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey)); + else + key_array = NULL; +- ++ + if (keyvals) + keyval_array = g_array_new (FALSE, FALSE, sizeof (guint)); + else + keyval_array = NULL; +- +- /* Accept only the default keymap */ +- if (keymap == NULL || keymap == gdk_keymap_get_default ()) +- { +- gint i; + +- update_keymap (); ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ update_keymap (GDK_KEYMAP (keymap)); + +- for (i = 0; i < 4; i++) +- { +- if (key_array) ++ for (group = 0; group < keymap->layout_handles->len; group++) ++ { ++ GdkWin32KeyLevelState level; ++ ++ for (level = GDK_WIN32_LEVEL_NONE; level < GDK_WIN32_LEVEL_COUNT; level++) ++ { ++ if (key_array) + { + GdkKeymapKey key; +- ++ + key.keycode = hardware_keycode; +- +- key.group = i / 2; +- key.level = i % 2; +- ++ key.group = group; ++ key.level = level; + g_array_append_val (key_array, key); + } + + if (keyval_array) +- g_array_append_val (keyval_array, keysym_tab[hardware_keycode*4+i]); +- } ++ { ++ guint keyval = keymap->keysym_tab[(hardware_keycode * keymap->layout_handles->len + group) * GDK_WIN32_LEVEL_COUNT + level]; ++ ++ g_array_append_val (keyval_array, keyval); ++ } ++ } + } + ++ *n_entries = group * GDK_WIN32_LEVEL_COUNT; ++ + if ((key_array && key_array->len > 0) || + (keyval_array && keyval_array->len > 0)) + { +@@ -722,11 +1040,6 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, + + if (keyvals) + *keyvals = (guint*) keyval_array->data; +- +- if (key_array) +- *n_entries = key_array->len; +- else +- *n_entries = keyval_array->len; + } + else + { +@@ -735,8 +1048,6 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, + + if (keyvals) + *keyvals = NULL; +- +- *n_entries = 0; + } + + if (key_array) +@@ -748,28 +1059,29 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, + } + + guint +-gdk_keymap_lookup_key (GdkKeymap *keymap, ++gdk_keymap_lookup_key (GdkKeymap *gdk_keymap, + const GdkKeymapKey *key) + { + guint sym; ++ GdkWin32Keymap *keymap; + +- g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), 0); ++ g_return_val_if_fail (gdk_keymap == NULL || GDK_IS_KEYMAP (gdk_keymap), 0); + g_return_val_if_fail (key != NULL, 0); +- g_return_val_if_fail (key->group < 4, 0); +- ++ + /* Accept only the default keymap */ +- if (keymap != NULL && keymap != gdk_keymap_get_default ()) ++ if (gdk_keymap != NULL && gdk_keymap != gdk_keymap_get_default ()) + return 0; + +- update_keymap (); +- ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ update_keymap (GDK_KEYMAP (keymap)); ++ + if (key->keycode >= KEY_STATE_SIZE || +- key->group < 0 || key->group >= 2 || +- key->level < 0 || key->level >= 2) ++ key->group < 0 || key->group >= keymap->layout_handles->len || ++ key->level < 0 || key->level >= GDK_WIN32_LEVEL_COUNT) + return 0; +- +- sym = keysym_tab[key->keycode*4 + key->group*2 + key->level]; +- ++ ++ sym = keymap->keysym_tab[(key->keycode * keymap->layout_handles->len + key->group) * GDK_WIN32_LEVEL_COUNT + key->level]; ++ + if (sym == GDK_KEY_VoidSymbol) + return 0; + else +@@ -777,7 +1089,7 @@ gdk_keymap_lookup_key (GdkKeymap *keymap, + } + + gboolean +-gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, ++gdk_keymap_translate_keyboard_state (GdkKeymap *gdk_keymap, + guint hardware_keycode, + GdkModifierType state, + gint group, +@@ -786,15 +1098,15 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + gint *level, + GdkModifierType *consumed_modifiers) + { ++ GdkWin32Keymap *keymap; + guint tmp_keyval; +- guint *keyvals; +- gint shift_level; +- gboolean ignore_shift = FALSE; +- gboolean ignore_group = FALSE; +- +- g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE); +- g_return_val_if_fail (group < 4, FALSE); +- ++ guint *keygroup; ++ GdkWin32KeyLevelState shift_level; ++ GdkWin32KeyGroupOptions *options; ++ GdkModifierType modifiers = GDK_SHIFT_MASK | GDK_LOCK_MASK | GDK_MOD2_MASK; ++ ++ g_return_val_if_fail (gdk_keymap == NULL || GDK_IS_KEYMAP (gdk_keymap), FALSE); ++ + #if 0 + GDK_NOTE (EVENTS, g_print ("gdk_keymap_translate_keyboard_state: keycode=%#x state=%#x group=%d\n", + hardware_keycode, state, group)); +@@ -809,83 +1121,103 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + *consumed_modifiers = 0; + + /* Accept only the default keymap */ +- if (keymap != NULL && keymap != gdk_keymap_get_default ()) ++ if (gdk_keymap != NULL && gdk_keymap != gdk_keymap_get_default ()) + return FALSE; + + if (hardware_keycode >= KEY_STATE_SIZE) + return FALSE; + +- if (group < 0 || group >= 2) +- return FALSE; ++ keymap = GDK_WIN32_KEYMAP (gdk_keymap_get_default ()); ++ update_keymap (GDK_KEYMAP (keymap)); + +- update_keymap (); ++ if (group < 0 || group >= keymap->layout_handles->len) ++ return FALSE; + +- keyvals = keysym_tab + hardware_keycode*4; ++ options = &g_array_index (keymap->options, GdkWin32KeyGroupOptions, group); ++ keygroup = &keymap->keysym_tab[(hardware_keycode * keymap->layout_handles->len + group) * GDK_WIN32_LEVEL_COUNT]; + + if ((state & GDK_LOCK_MASK) && + (state & GDK_SHIFT_MASK) && +- ((gdk_shift_modifiers & GDK_LOCK_MASK) || +- (keyvals[group*2 + 1] == gdk_keyval_to_upper (keyvals[group*2 + 0])))) ++ ((options->shift_modifiers & GDK_LOCK_MASK) || ++ (keygroup[GDK_WIN32_LEVEL_SHIFT] == gdk_keyval_to_upper (keygroup[GDK_WIN32_LEVEL_NONE])))) + /* Shift always disables ShiftLock. Shift disables CapsLock for + * keys with lowercase/uppercase letter pairs. + */ +- shift_level = 0; +- else if (state & gdk_shift_modifiers) +- shift_level = 1; ++ shift_level = GDK_WIN32_LEVEL_NONE; ++ else if (state & options->shift_modifiers) ++ shift_level = GDK_WIN32_LEVEL_SHIFT; + else +- shift_level = 0; ++ shift_level = GDK_WIN32_LEVEL_NONE; + +- /* Drop group and shift if there are no keysymbols on +- * the key for those. +- */ +- if (shift_level == 1 && +- keyvals[group*2 + 1] == GDK_KEY_VoidSymbol && +- keyvals[group*2] != GDK_KEY_VoidSymbol) ++ if (shift_level == GDK_WIN32_LEVEL_NONE) + { +- shift_level = 0; +- ignore_shift = TRUE; ++ if (state & GDK_MOD2_MASK) ++ shift_level = GDK_WIN32_LEVEL_ALTGR; + } +- +- if (group == 1 && +- keyvals[2 + shift_level] == GDK_KEY_VoidSymbol && +- keyvals[0 + shift_level] != GDK_KEY_VoidSymbol) ++ else + { +- group = 0; +- ignore_group = TRUE; ++ if (state & GDK_MOD2_MASK) ++ shift_level = GDK_WIN32_LEVEL_SHIFT_ALTGR; + } + +- if (keyvals[group *2 + shift_level] == GDK_KEY_VoidSymbol && +- keyvals[0 + 0] != GDK_KEY_VoidSymbol) ++ /* Drop altgr and shift if there are no keysymbols on ++ * the key for those. ++ */ ++ if (keygroup[shift_level] == GDK_KEY_VoidSymbol) + { +- shift_level = 0; +- group = 0; +- ignore_group = TRUE; +- ignore_shift = TRUE; ++ switch (shift_level) ++ { ++ case GDK_WIN32_LEVEL_NONE: ++ case GDK_WIN32_LEVEL_ALTGR: ++ if (keygroup[GDK_WIN32_LEVEL_NONE] != GDK_KEY_VoidSymbol) ++ shift_level = GDK_WIN32_LEVEL_NONE; ++ break; ++ case GDK_WIN32_LEVEL_SHIFT: ++ if (keygroup[GDK_WIN32_LEVEL_NONE] != GDK_KEY_VoidSymbol) ++ shift_level = GDK_WIN32_LEVEL_NONE; ++ break; ++ case GDK_WIN32_LEVEL_SHIFT_ALTGR: ++ if (keygroup[GDK_WIN32_LEVEL_ALTGR] != GDK_KEY_VoidSymbol) ++ shift_level = GDK_WIN32_LEVEL_ALTGR; ++ else if (keygroup[GDK_WIN32_LEVEL_SHIFT] != GDK_KEY_VoidSymbol) ++ shift_level = GDK_WIN32_LEVEL_SHIFT; ++ else if (keygroup[GDK_WIN32_LEVEL_NONE] != GDK_KEY_VoidSymbol) ++ shift_level = GDK_WIN32_LEVEL_NONE; ++ break; ++ case GDK_WIN32_LEVEL_COUNT: ++ g_assert_not_reached (); ++ } + } + + /* See whether the group and shift level actually mattered + * to know what to put in consumed_modifiers + */ +- if (keyvals[group*2 + 1] == GDK_KEY_VoidSymbol || +- keyvals[group*2 + 0] == keyvals[group*2 + 1]) +- ignore_shift = TRUE; ++ if ((keygroup[GDK_WIN32_LEVEL_SHIFT] == GDK_KEY_VoidSymbol || ++ keygroup[GDK_WIN32_LEVEL_NONE] == keygroup[GDK_WIN32_LEVEL_SHIFT]) && ++ (keygroup[GDK_WIN32_LEVEL_SHIFT_ALTGR] == GDK_KEY_VoidSymbol || ++ keygroup[GDK_WIN32_LEVEL_ALTGR] == keygroup[GDK_WIN32_LEVEL_SHIFT_ALTGR])) ++ modifiers &= ~(GDK_SHIFT_MASK | GDK_LOCK_MASK); + +- if (keyvals[2 + shift_level] == GDK_KEY_VoidSymbol || +- keyvals[0 + shift_level] == keyvals[2 + shift_level]) +- ignore_group = TRUE; ++ if ((keygroup[GDK_WIN32_LEVEL_ALTGR] == GDK_KEY_VoidSymbol || ++ keygroup[GDK_WIN32_LEVEL_NONE] == keygroup[GDK_WIN32_LEVEL_ALTGR]) && ++ (keygroup[GDK_WIN32_LEVEL_SHIFT_ALTGR] == GDK_KEY_VoidSymbol || ++ keygroup[GDK_WIN32_LEVEL_SHIFT] == keygroup[GDK_WIN32_LEVEL_SHIFT_ALTGR])) ++ modifiers &= ~GDK_MOD2_MASK; + +- tmp_keyval = keyvals[group*2 + shift_level]; ++ tmp_keyval = keygroup[shift_level]; + + /* If a true CapsLock is toggled, and Shift is not down, + * and the shifted keysym is the uppercase of the unshifted, + * use it. + */ +- if (!(gdk_shift_modifiers & GDK_LOCK_MASK) && ++ if (!(options->shift_modifiers & GDK_LOCK_MASK) && + !(state & GDK_SHIFT_MASK) && +- (state & GDK_LOCK_MASK)) ++ (state & GDK_LOCK_MASK) && ++ (shift_level < GDK_WIN32_LEVEL_SHIFT_ALTGR)) + { + guint upper = gdk_keyval_to_upper (tmp_keyval); +- if (upper == keyvals[group*2 + 1]) ++ ++ if (upper == keygroup[shift_level + 1]) + tmp_keyval = upper; + } + +@@ -899,15 +1231,11 @@ gdk_keymap_translate_keyboard_state (GdkKeymap *keymap, + *level = shift_level; + + if (consumed_modifiers) +- { +- *consumed_modifiers = +- (ignore_group ? 0 : GDK_MOD2_MASK) | +- (ignore_shift ? 0 : (GDK_SHIFT_MASK|GDK_LOCK_MASK)); +- } +- ++ *consumed_modifiers = modifiers; ++ + #if 0 + GDK_NOTE (EVENTS, g_print ("... group=%d level=%d cmods=%#x keyval=%s\n", +- group, shift_level, tmp_modifiers, gdk_keyval_name (tmp_keyval))); ++ group, shift_level, modifiers, gdk_keyval_name (tmp_keyval))); + #endif + + return tmp_keyval != GDK_KEY_VoidSymbol; +@@ -928,11 +1256,6 @@ gdk_keymap_map_virtual_modifiers (GdkKeymap *keymap, + } + + static void +-gdk_win32_keymap_finalize (GObject *object) +-{ +-} +- +-static void + gdk_win32_keymap_class_init (GdkWin32KeymapClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); +diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c +index 46d2774..820b0fc 100644 +--- a/gdk/win32/gdkmain-win32.c ++++ b/gdk/win32/gdkmain-win32.c +@@ -90,6 +90,7 @@ _gdk_windowing_init (void) + _gdk_app_hmodule = GetModuleHandle (NULL); + _gdk_display_hdc = CreateDC ("DISPLAY", NULL, NULL, NULL); + _gdk_input_locale = GetKeyboardLayout (0); ++ _gdk_win32_keymap_set_active_layout (GDK_WIN32_KEYMAP (gdk_keymap_get_default ()), _gdk_input_locale); + _gdk_input_locale_is_ime = ImmIsIME (_gdk_input_locale); + GetLocaleInfo (MAKELCID (LOWORD (_gdk_input_locale), SORT_DEFAULT), + LOCALE_IDEFAULTANSICODEPAGE, +diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h +index 35116a5..ef4fa56 100644 +--- a/gdk/win32/gdkprivate-win32.h ++++ b/gdk/win32/gdkprivate-win32.h +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include "gdkinternals.h" + +@@ -407,8 +408,6 @@ extern gboolean _gdk_input_locale_is_ime; + extern UINT _gdk_input_codepage; + + extern guint _gdk_keymap_serial; +-extern gboolean _gdk_keyboard_has_altgr; +-extern guint _scancode_rshift; + + /* GdkAtoms: properties, targets and types */ + extern GdkAtom _gdk_selection; +@@ -500,7 +499,12 @@ void _gdk_win32_emit_configure_event (GdkWindow *window); + GdkWindow *_gdk_win32_find_window_for_mouse_event (GdkWindow* reported_window, + MSG* msg); + +-guint32 _gdk_win32_keymap_get_decimal_mark (void); ++guint32 _gdk_win32_keymap_get_decimal_mark (GdkWin32Keymap *keymap); ++gboolean _gdk_win32_keymap_has_altgr (GdkWin32Keymap *keymap); ++guint8 _gdk_win32_keymap_get_active_group (GdkWin32Keymap *keymap); ++guint8 _gdk_win32_keymap_get_rshift_scancode (GdkWin32Keymap *keymap); ++void _gdk_win32_keymap_set_active_layout (GdkWin32Keymap *keymap, ++ HKL hkl); + + /* Initialization */ + void _gdk_windowing_window_init (GdkScreen *screen); +-- +cgit v0.12 + diff --git a/mingw-w64-gtk2/0015-fix-dead-keys-part-3.patch b/mingw-w64-gtk2/0015-fix-dead-keys-part-3.patch new file mode 100644 index 0000000000..8caac0f8d6 --- /dev/null +++ b/mingw-w64-gtk2/0015-fix-dead-keys-part-3.patch @@ -0,0 +1,641 @@ +From 61de4e7b67ccff9297188717b2ab12f0adab32d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= + =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= +Date: Sat, 30 Jul 2016 20:35:51 +0000 +Subject: W32: Prefer the deadkey combinations that the OS uses + +Pick the W32 API for possible deadkey+ combinations +and prefer these to other sources of deadkey combos. +Specifically, if W32 API supports at least one combo for a particular +deadkey, only use that data and do not attempt to do other, unsupported +combinations, even if they make sense otherwise. +This is needed to, for example, correctly support US-International +keyboard layout, which produces a combined character for <' + a> +combo, but not for <' + s>, for example. + +This is achieved by stashing all the deadkeys that we find in +an array, then doing extra loop through all virtual key codes and +trying to combine them with each of these deadkeys. Any combinations +that produce a single character are cached for later use. + +In GTK Simple IM context, call a new GDK W32 function to do a lookup +on that cached combination table early on, among the "special cases" +(which are now partially obsolete). + +A limitation of this code is that combinations with more than +one deadkey are not supported, except for combinations that consist +entirely of 2 known deadkeys. The upshot is that lookups should +be relatively fast, as deadkey array stays small and the combination +tree stays shallow. + +Note that the use of ToUnicodeEx() seems suboptimal, as it should +be possible to just load a keyboard library (KBD*.DLL) manually +and obtain and use its key table directly. However, that is much more +complicated and would result in a significant rewrite of gdkkeys-win32. +The code from this commit, though hacky, is a direct addition to +existing code and should cover vast majority of the use-cases. + +https://bugzilla.gnome.org/show_bug.cgi?id=569581 +--- + gdk/gdk.symbols | 1 + + gdk/win32/gdkkeys-win32.c | 405 ++++++++++++++++++++++++++++++++++++++++++++-- + gdk/win32/gdkwin32keys.h | 24 +++ + gtk/gtkimcontextsimple.c | 32 ++++ + 4 files changed, 448 insertions(+), 14 deletions(-) + +diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols +index b2bd9eb..44b0354 100644 +--- a/gdk/gdk.symbols ++++ b/gdk/gdk.symbols +@@ -1286,6 +1286,7 @@ gdk_win32_selection_add_targets + #if IN_HEADER(__GDK_WIN32_H__) + #if IN_FILE(__GDK_KEYS_WIN32_C__) + gdk_win32_keymap_get_type G_GNUC_CONST ++gdk_win32_keymap_check_compose + #endif + #endif + #endif +diff --git a/gdk/win32/gdkkeys-win32.c b/gdk/win32/gdkkeys-win32.c +index edc26b2..b971774 100644 +--- a/gdk/win32/gdkkeys-win32.c ++++ b/gdk/win32/gdkkeys-win32.c +@@ -38,6 +38,87 @@ + #include "gdkkeys.h" + #include "gdkwin32keys.h" + ++enum _GdkWin32KeyLevelState ++{ ++ GDK_WIN32_LEVEL_NONE = 0, ++ GDK_WIN32_LEVEL_SHIFT, ++ GDK_WIN32_LEVEL_ALTGR, ++ GDK_WIN32_LEVEL_SHIFT_ALTGR, ++ GDK_WIN32_LEVEL_COUNT ++}; ++ ++typedef enum _GdkWin32KeyLevelState GdkWin32KeyLevelState; ++ ++struct _GdkWin32KeyNode ++{ ++ /* Non-spacing version of the dead key */ ++ guint undead_gdk_keycode; ++ ++ /* Virtual key code */ ++ guint8 vk; ++ ++ /* Level for which this virtual key code produces this gdk_keycode */ ++ GdkWin32KeyLevelState level; ++ ++ /* GDK (X11) code for this key */ ++ guint gdk_keycode; ++ ++ /* Array of GdkWin32KeyNode should be sorted by gdk_keycode, then by level */ ++ GArray *combinations; ++}; ++ ++typedef struct _GdkWin32KeyNode GdkWin32KeyNode; ++ ++/* ++Example: ++ GdkWin32KeyNode ++ { ++ undead_gdk_keycode = 0x0b4 GDK_KEY_acute (') ++ vk = 0xde VK_OEM_7 ++ level = GDK_WIN32_LEVEL_NONE ++ gdk_keycode = 0xfe51 GDK_KEY_dead_acute ++ combinations = ++ { ++ GdkWin32KeyNode ++ { ++ undead_gdk_keycode = 0x061 GDK_KEY_a (a) ++ level = GDK_WIN32_LEVEL_NONE ++ vk = 0x41 VK_A ++ gdk_keycode = 0xe1 GDK_KEY_aacute á ++ combinations = NULL ++ }, ++ GdkWin32KeyNode ++ { ++ unicode_char = 0x041 GDK_KEY_A (A) ++ level = GDK_WIN32_LEVEL_SHIFT ++ vk = 0x41 VK_A ++ gdk_keycode = 0x0c1 GDK_KEY_Aacute Á ++ combinations = NULL ++ }, ++ { ... } ++ } ++ } ++ ++Thus: ++ ++GDK_KEY_dead_acute + GDK_KEY_a ++= GDK_KEY_aacute ++ ++GDK_KEY_dead_acute + GDK_KEY_A ++= GDK_KEY_Aacute ++ ++GDK_KEY_dead_acute + GDK_KEY_s ++matches partially ++(GDK_KEY_dead_acute is a known dead key, but does not combine with GDK_KEY_s) ++and resolves into: ++GDK_KEY_acute + GDK_KEY_s ++ ++GDK_KEY_dead_somethingelse + GDK_KEY_anything ++does not match at all ++(W32 API did not provide any deadkey info for GDK_KEY_dead_somethingelse) ++and the caller will try other matching mechanisms for compose_buffer ++*/ ++ + struct _GdkWin32KeyGroupOptions + { + /* character that should be used as the decimal separator */ +@@ -53,6 +134,8 @@ struct _GdkWin32KeyGroupOptions + gboolean has_altgr; + + gboolean capslock_tested; ++ ++ GArray *dead_keys; + }; + + typedef struct _GdkWin32KeyGroupOptions GdkWin32KeyGroupOptions; +@@ -92,17 +175,6 @@ struct _GdkWin32Keymap + guint8 active_layout; + }; + +-enum _GdkWin32KeyLevelState +-{ +- GDK_WIN32_LEVEL_NONE = 0, +- GDK_WIN32_LEVEL_SHIFT, +- GDK_WIN32_LEVEL_ALTGR, +- GDK_WIN32_LEVEL_SHIFT_ALTGR, +- GDK_WIN32_LEVEL_COUNT +-}; +- +-typedef enum _GdkWin32KeyLevelState GdkWin32KeyLevelState; +- + G_DEFINE_TYPE (GdkWin32Keymap, gdk_win32_keymap, GDK_TYPE_KEYMAP) + + guint _gdk_keymap_serial = 0; +@@ -114,10 +186,23 @@ static GdkKeymap *default_keymap = NULL; + static void update_keymap (GdkKeymap *gdk_keymap); + + static void ++gdk_win32_key_group_options_clear (GdkWin32KeyGroupOptions *options) ++{ ++ g_clear_pointer (&options->dead_keys, g_array_unref); ++} ++ ++static void ++gdk_win32_key_node_clear (GdkWin32KeyNode *node) ++{ ++ g_clear_pointer (&node->combinations, g_array_unref); ++} ++ ++static void + gdk_win32_keymap_init (GdkWin32Keymap *keymap) + { + keymap->layout_handles = g_array_new (FALSE, FALSE, sizeof (HKL)); + keymap->options = g_array_new (FALSE, FALSE, sizeof (GdkWin32KeyGroupOptions)); ++ g_array_set_clear_func (keymap->options, (GDestroyNotify) gdk_win32_key_group_options_clear); + keymap->keysym_tab = NULL; + keymap->active_layout = 0; + update_keymap (GDK_KEYMAP (keymap)); +@@ -481,6 +566,26 @@ check_that_active_layout_is_in_sync (GdkWin32Keymap *keymap) + } + } + ++static gint ++sort_key_nodes_by_gdk_keyval (gconstpointer a, ++ gconstpointer b) ++{ ++ const GdkWin32KeyNode *one = a; ++ const GdkWin32KeyNode *two = b; ++ ++ if (one->gdk_keycode < two->gdk_keycode) ++ return -1; ++ else if (one->gdk_keycode > two->gdk_keycode) ++ return 1; ++ ++ if (one->level < two->level) ++ return -1; ++ else if (one->level > two->level) ++ return 1; ++ ++ return 0; ++} ++ + static void + update_keymap (GdkKeymap *gdk_keymap) + { +@@ -577,6 +682,8 @@ update_keymap (GdkKeymap *gdk_keymap) + options->scancode_rshift = 0; + options->has_altgr = FALSE; + options->capslock_tested = FALSE; ++ options->dead_keys = g_array_new (FALSE, FALSE, sizeof (GdkWin32KeyNode)); ++ g_array_set_clear_func (options->dead_keys, (GDestroyNotify) gdk_win32_key_node_clear); + + g_array_index (keymap->layout_handles, HKL, i) = hkls[i]; + +@@ -624,9 +731,10 @@ update_keymap (GdkKeymap *gdk_keymap) + if ((*ksymp == 0) || + ((vk == VK_DECIMAL) && (level == GDK_WIN32_LEVEL_NONE))) + { +- wchar_t wcs[10]; +- gint k; +- guint keysym; ++ wchar_t wcs[10]; ++ gint k; ++ guint keysym; ++ GdkWin32KeyNode dead_key; + + wcs[0] = wcs[1] = 0; + k = ToUnicodeEx (vk, scancode, key_state, +@@ -663,6 +771,13 @@ update_keymap (GdkKeymap *gdk_keymap) + + /* Use dead keysyms instead of "undead" ones */ + handle_dead (keysym, ksymp); ++ ++ dead_key.undead_gdk_keycode = keysym; ++ dead_key.vk = vk; ++ dead_key.level = level; ++ dead_key.gdk_keycode = *ksymp; ++ dead_key.combinations = NULL; ++ g_array_append_val (options->dead_keys, dead_key); + break; + case 0: + /* Seems to be necessary to "reset" the keyboard layout +@@ -738,12 +853,274 @@ update_keymap (GdkKeymap *gdk_keymap) + } + } + ++ scancode = 0x0; ++ ++ for (group = 0; group < hkls_len; group++) ++ { ++ options = &g_array_index (keymap->options, GdkWin32KeyGroupOptions, group); ++ ++ for (i = 0; i < options->dead_keys->len; i++) ++ { ++ wchar_t wcs[10]; ++ gint k; ++ GdkWin32KeyNode *dead_key; ++ GdkWin32KeyNode combo; ++ ++ dead_key = &g_array_index (options->dead_keys, GdkWin32KeyNode, i); ++ ++ for (vk = 0; vk < KEY_STATE_SIZE; vk++) ++ { ++ for (level = GDK_WIN32_LEVEL_NONE; level < GDK_WIN32_LEVEL_COUNT; level++) ++ { ++ /* Prime the ToUnicodeEx() internal state */ ++ wcs[0] = wcs[1] = 0; ++ set_level_vks (key_state, dead_key->level); ++ k = ToUnicodeEx (dead_key->vk, scancode, key_state, ++ wcs, G_N_ELEMENTS (wcs), ++ 0, hkls[group]); ++ switch (k) ++ { ++ case -1: ++ /* Okay */ ++ break; ++ default: ++ /* Expected a dead key, got something else */ ++ reset_after_dead (key_state, hkls[group]); ++ continue; ++ } ++ ++ /* Check how it combines with vk */ ++ wcs[0] = wcs[1] = 0; ++ set_level_vks (key_state, level); ++ k = ToUnicodeEx (vk, scancode, key_state, ++ wcs, G_N_ELEMENTS (wcs), ++ 0, hkls[group]); ++ ++ if (k == 0) ++ { ++ reset_after_dead (key_state, hkls[group]); ++ } ++ else if (k == -1) ++ { ++ /* Dead key chaining? TODO: support this (deeper tree?) */ ++ reset_after_dead (key_state, hkls[group]); ++ } ++ else if (k == 1) ++ { ++ combo.vk = vk; ++ combo.level = level; ++ combo.gdk_keycode = gdk_unicode_to_keyval (wcs[0]); ++ combo.undead_gdk_keycode = combo.gdk_keycode; ++ combo.combinations = NULL; ++ ++ if (dead_key->combinations == NULL) ++ { ++ dead_key->combinations = g_array_new (FALSE, FALSE, sizeof (GdkWin32KeyNode)); ++ g_array_set_clear_func (dead_key->combinations, (GDestroyNotify) gdk_win32_key_node_clear); ++ } ++ ++#if 0 ++ { ++ char *dead_key_undead_u8, *wcs_u8; ++ wchar_t t = gdk_keyval_to_unicode (dead_key->undead_gdk_keycode); ++ dead_key_undead_u8 = g_utf16_to_utf8 (&t, 1, NULL, NULL, NULL); ++ wcs_u8 = g_utf16_to_utf8 (wcs, 1, NULL, NULL, NULL); ++ g_fprintf (stdout, "%d %s%s0x%02x (%s) + %s%s0x%02x = 0x%04x (%s)\n", group, ++ (dead_key->level == GDK_WIN32_LEVEL_SHIFT || dead_key->level == GDK_WIN32_LEVEL_SHIFT_ALTGR) ? "SHIFT-" : " ", ++ (dead_key->level == GDK_WIN32_LEVEL_ALTGR || dead_key->level == GDK_WIN32_LEVEL_SHIFT_ALTGR) ? "ALTGR-" : " ", ++ dead_key->vk, ++ dead_key_undead_u8, ++ (combo.level == GDK_WIN32_LEVEL_SHIFT || combo.level == GDK_WIN32_LEVEL_SHIFT_ALTGR) ? "SHIFT-" : " ", ++ (combo.level == GDK_WIN32_LEVEL_ALTGR || combo.level == GDK_WIN32_LEVEL_SHIFT_ALTGR) ? "ALTGR-" : " ", ++ vk, ++ wcs[0], ++ wcs_u8); ++ g_free (dead_key_undead_u8); ++ g_free (wcs_u8); ++ } ++#endif ++ ++ g_array_append_val (dead_key->combinations, combo); ++ } ++ } ++ } ++ } ++ ++ g_array_sort (options->dead_keys, (GCompareFunc) sort_key_nodes_by_gdk_keyval); ++ } ++ + GDK_NOTE (EVENTS, print_keysym_tab (keymap)); + + check_that_active_layout_is_in_sync (keymap); + current_serial = _gdk_keymap_serial; + } + ++static gboolean ++find_deadkey_by_keyval (GArray *dead_keys, ++ guint16 keyval, ++ gsize *index) ++{ ++ gsize deadkey_i; ++ gsize deadkey_i_max; ++ ++ if (dead_keys->len == 0) ++ return FALSE; ++ ++ deadkey_i = 0; ++ deadkey_i_max = dead_keys->len - 1; ++ ++ while (deadkey_i != deadkey_i_max) ++ { ++ GdkWin32KeyNode *dead_key; ++ gsize middle; ++ ++ if (g_array_index (dead_keys, GdkWin32KeyNode, deadkey_i).gdk_keycode == keyval) ++ { ++ break; ++ } ++ else if (g_array_index (dead_keys, GdkWin32KeyNode, deadkey_i_max).gdk_keycode == keyval) ++ { ++ deadkey_i = deadkey_i_max; ++ break; ++ } ++ else if (deadkey_i + 1 == deadkey_i_max) ++ { ++ break; ++ } ++ ++ middle = deadkey_i + (deadkey_i_max - deadkey_i) / 2; ++ dead_key = &g_array_index (dead_keys, GdkWin32KeyNode, middle); ++ ++ if (dead_key->gdk_keycode < keyval) ++ deadkey_i = middle; ++ else if (dead_key->gdk_keycode > keyval) ++ deadkey_i_max = middle; ++ else ++ deadkey_i = deadkey_i_max = middle; ++ } ++ ++ if (g_array_index (dead_keys, GdkWin32KeyNode, deadkey_i).gdk_keycode == keyval) ++ { ++ *index = deadkey_i; ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++GdkWin32KeymapMatch ++gdk_win32_keymap_check_compose (GdkWin32Keymap *keymap, ++ guint *compose_buffer, ++ gsize compose_buffer_len, ++ guint16 *output, ++ gsize *output_len) ++{ ++ gint partial_match; ++ guint8 active_group; ++ gsize deadkey_i, node_i; ++ GdkWin32KeyNode *dead_key; ++ GdkWin32KeyGroupOptions *options; ++ GdkWin32KeymapMatch match; ++ gsize output_size; ++ ++ g_return_val_if_fail (output != NULL && output_len != NULL, GDK_WIN32_KEYMAP_MATCH_NONE); ++ ++ if (compose_buffer_len < 1) ++ return GDK_WIN32_KEYMAP_MATCH_NONE; ++ ++ output_size = *output_len; ++ ++ active_group = _gdk_win32_keymap_get_active_group (keymap); ++ options = &g_array_index (keymap->options, GdkWin32KeyGroupOptions, active_group); ++ ++ partial_match = -1; ++ match = GDK_WIN32_KEYMAP_MATCH_NONE; ++ ++ if (find_deadkey_by_keyval (options->dead_keys, compose_buffer[0], &deadkey_i)) ++ { ++ while (deadkey_i > 0 && ++ g_array_index (options->dead_keys, GdkWin32KeyNode, deadkey_i - 1).gdk_keycode == compose_buffer[0]) ++ deadkey_i--; ++ ++ /* Hardcoded 2-tier tree here (dead key + non dead key = character). ++ * TODO: support trees with arbitrary depth for dead key chaining. ++ */ ++ dead_key = &g_array_index (options->dead_keys, GdkWin32KeyNode, deadkey_i); ++ ++ /* "Partial match" means "matched the whole sequence except the last key" ++ * (right now the sequence only has 2 keys, so this turns into "matched ++ * at least the first key"). ++ * "last key" should be identified by having NULL further combinations. ++ * As a heuristic, convert the buffer contents into keyvals and use ++ * them as-is (normally there should be a separate unichar buffer for ++ * each combination, but we do not store these). ++ */ ++ partial_match = deadkey_i; ++ ++ if (compose_buffer_len < 2) ++ match = GDK_WIN32_KEYMAP_MATCH_INCOMPLETE; ++ ++ for (node_i = 0; ++ match != GDK_WIN32_KEYMAP_MATCH_INCOMPLETE && ++ node_i < dead_key->combinations->len; ++ node_i++) ++ { ++ GdkWin32KeyNode *node; ++ ++ node = &g_array_index (dead_key->combinations, GdkWin32KeyNode, node_i); ++ ++ if (keymap->keysym_tab[(node->vk * keymap->layout_handles->len + active_group) * GDK_WIN32_LEVEL_COUNT + node->level] == compose_buffer[1]) ++ { ++ match = GDK_WIN32_KEYMAP_MATCH_EXACT; ++ *output_len = 0; ++ ++ if (*output_len < output_size && node->gdk_keycode != 0) ++ output[(*output_len)++] = node->gdk_keycode; ++ ++ break; ++ } ++ } ++ } ++ ++ if (match == GDK_WIN32_KEYMAP_MATCH_EXACT || ++ match == GDK_WIN32_KEYMAP_MATCH_INCOMPLETE) ++ { ++ return match; ++ } ++ ++ if (partial_match >= 0) ++ { ++ if (compose_buffer_len == 2) ++ { ++ dead_key = &g_array_index (options->dead_keys, GdkWin32KeyNode, partial_match); ++ *output_len = 0; ++ ++ if (output_size >= 1) ++ output[(*output_len)++] = dead_key->undead_gdk_keycode; ++ ++ if (output_size >= 2) ++ { ++ gsize second_deadkey_i; ++ ++ /* Special case for "deadkey + deadkey = space-version-of-deadkey, space-version-of-deadkey" combinations. ++ * Normally the result is a sequence of 2 unichars, but we do not store this. ++ * For "deadkey + nondeadkey = space-version-of-deadkey, nondeadkey", we can use compose_buffer ++ * contents as-is, but space version of a dead key need to be looked up separately. ++ */ ++ if (find_deadkey_by_keyval (options->dead_keys, compose_buffer[1], &second_deadkey_i)) ++ output[(*output_len)++] = g_array_index (options->dead_keys, GdkWin32KeyNode, second_deadkey_i).undead_gdk_keycode; ++ else ++ output[(*output_len)++] = compose_buffer[1]; ++ } ++ } ++ ++ return GDK_WIN32_KEYMAP_MATCH_PARTIAL; ++ } ++ ++ return GDK_WIN32_KEYMAP_MATCH_NONE; ++} ++ + guint8 + _gdk_win32_keymap_get_rshift_scancode (GdkWin32Keymap *keymap) + { +diff --git a/gdk/win32/gdkwin32keys.h b/gdk/win32/gdkwin32keys.h +index c271d67..cbd1dfc 100644 +--- a/gdk/win32/gdkwin32keys.h ++++ b/gdk/win32/gdkwin32keys.h +@@ -26,6 +26,24 @@ + + G_BEGIN_DECLS + ++/** ++ * GdkWin32KeymapMatch: ++ * @GDK_WIN32_KEYMAP_MATCH_NONE: no matches found. Output is not valid. ++ * @GDK_WIN32_KEYMAP_MATCH_INCOMPLETE: the sequence matches so far, but is incomplete. Output is not valid. ++ * @GDK_WIN32_KEYMAP_MATCH_PARTIAL: the sequence matches up to the last key, ++ * which does not match. Output is valid. ++ * @GDK_WIN32_KEYMAP_MATCH_EXACT: the sequence matches exactly. Output is valid. ++ * ++ * An enumeration describing the result of a deadkey combination matching. ++ */ ++typedef enum ++{ ++ GDK_WIN32_KEYMAP_MATCH_NONE, ++ GDK_WIN32_KEYMAP_MATCH_INCOMPLETE, ++ GDK_WIN32_KEYMAP_MATCH_PARTIAL, ++ GDK_WIN32_KEYMAP_MATCH_EXACT ++} GdkWin32KeymapMatch; ++ + #ifdef GDK_COMPILATION + typedef struct _GdkWin32Keymap GdkWin32Keymap; + #else +@@ -42,6 +60,12 @@ typedef struct _GdkWin32KeymapClass GdkWin32KeymapClass; + + GType gdk_win32_keymap_get_type (void); + ++GdkWin32KeymapMatch gdk_win32_keymap_check_compose (GdkWin32Keymap *keymap, ++ guint *compose_buffer, ++ gsize compose_buffer_len, ++ guint16 *output, ++ gsize *output_len); ++ + G_END_DECLS + + #endif /* __GDK_WIN32_KEYMAP_H__ */ +diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c +index 1c40e9d..6d8b3bd 100644 +--- a/gtk/gtkimcontextsimple.c ++++ b/gtk/gtkimcontextsimple.c +@@ -18,6 +18,7 @@ + */ + + #include "config.h" ++ + #include + #include + +@@ -30,6 +31,10 @@ + #include "gtkintl.h" + #include "gtkalias.h" + ++#ifdef GDK_WINDOWING_WIN32 ++#include ++#endif ++ + typedef struct _GtkComposeTable GtkComposeTable; + typedef struct _GtkComposeTableCompact GtkComposeTableCompact; + +@@ -1058,6 +1063,33 @@ gtk_im_context_simple_filter_keypress (GtkIMContext *context, + } + else + { ++#ifdef GDK_WINDOWING_WIN32 ++ guint16 output[2]; ++ gsize output_size = 2; ++ ++ switch (gdk_win32_keymap_check_compose (GDK_WIN32_KEYMAP (gdk_keymap_get_default ()), ++ context_simple->compose_buffer, ++ n_compose, ++ output, &output_size)) ++ { ++ case GDK_WIN32_KEYMAP_MATCH_NONE: ++ break; ++ case GDK_WIN32_KEYMAP_MATCH_EXACT: ++ case GDK_WIN32_KEYMAP_MATCH_PARTIAL: ++ for (i = 0; i < output_size; i++) ++ { ++ guint32 output_char = gdk_keyval_to_unicode (output[i]); ++ gtk_im_context_simple_commit_char (GTK_IM_CONTEXT (context_simple), ++ output_char); ++ } ++ context_simple->compose_buffer[0] = 0; ++ return TRUE; ++ case GDK_WIN32_KEYMAP_MATCH_INCOMPLETE: ++ return TRUE; ++ } ++#endif ++ ++ + tmp_list = context_simple->tables; + while (tmp_list) + { +-- +cgit v0.12 + diff --git a/mingw-w64-gtk2/0016-handle-pause-key-correctly.patch b/mingw-w64-gtk2/0016-handle-pause-key-correctly.patch new file mode 100644 index 0000000000..790ecb0b3c --- /dev/null +++ b/mingw-w64-gtk2/0016-handle-pause-key-correctly.patch @@ -0,0 +1,36 @@ +From 962d3dffc1638e0952144c5236bf61b7eb20072c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= + =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= +Date: Wed, 27 Jul 2016 18:05:10 +0000 +Subject: GDK W32: Special handling for VK_PAUSE + +Similar to VK_DIVIDE, this key can't be mapped to a scancode by +MapVirtualKeyEx(). Googling suggests that this is a known bug. + +https://bugzilla.gnome.org/show_bug.cgi?id=769214 +--- + gdk/win32/gdkkeys-win32.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/gdk/win32/gdkkeys-win32.c b/gdk/win32/gdkkeys-win32.c +index b971774..12c6c07 100644 +--- a/gdk/win32/gdkkeys-win32.c ++++ b/gdk/win32/gdkkeys-win32.c +@@ -699,8 +699,13 @@ update_keymap (GdkKeymap *gdk_keymap) + scancode = MapVirtualKeyEx (vk, 0, hkls[group]); + keygroup = &keymap->keysym_tab[(vk * hkls_len + group) * GDK_WIN32_LEVEL_COUNT]; + ++ /* MapVirtualKeyEx() fails to produce a scancode for VK_DIVIDE and VK_PAUSE. ++ * Ignore that, handle_special() will figure out a Gdk keyval for these ++ * without needing a scancode. ++ */ + if (scancode == 0 && +- vk != VK_DIVIDE) ++ vk != VK_DIVIDE && ++ vk != VK_PAUSE) + { + for (level = GDK_WIN32_LEVEL_NONE; level < GDK_WIN32_LEVEL_COUNT; level++) + keygroup[level] = GDK_KEY_VoidSymbol; +-- +cgit v0.12 + diff --git a/mingw-w64-gtk2/PKGBUILD b/mingw-w64-gtk2/PKGBUILD index 209d4c766a..86ea2da392 100644 --- a/mingw-w64-gtk2/PKGBUILD +++ b/mingw-w64-gtk2/PKGBUILD @@ -4,8 +4,8 @@ _realname=gtk2 pkgbase=mingw-w64-${_realname} pkgname="${MINGW_PACKAGE_PREFIX}-${_realname}" -pkgver=2.24.28 -pkgrel=3 +pkgver=2.24.31 +pkgrel=1 pkgdesc="GTK+ is a multi-platform toolkit (v2) (mingw-w64)" arch=('any') url="http://www.gtk.org" @@ -32,31 +32,36 @@ options=(!libtool strip staticlibs) source=("https://download.gnome.org/sources/gtk+/${pkgver%.*}/gtk+-${pkgver}.tar.xz" 'gtkrc' 0001-fix-m4-location.mingw.patch - 0002-Fix-def-installation.all.patch 0003-Fix-notebook-tab-state-change.mingw.patch 0005-Fix-header-ref.all.patch 0006-Fix-unix-symbols-in-docs.mingw.patch 0009-give-cc-to-gir-scanner.mingw.patch 0010-put-gtk-dll-into-path.mingw.patch 0011-gir-for-gdkwin32.mingw.patch - 0012-embed-manifest.all.patch) + 0012-embed-manifest.all.patch + 0013-fix-dead-keys-part-1.patch + 0014-fix-dead-keys-part-2.patch + 0015-fix-dead-keys-part-3.patch + 0016-handle-pause-key-correctly.patch) -sha256sums=('b2c6441e98bc5232e5f9bba6965075dcf580a8726398f7374d39f90b88ed4656' +sha256sums=('68c1922732c7efc08df4656a5366dcc3afdc8791513400dac276009b40954658' 'b77a427df55a14182c10ad7e683b4d662df2846fcd38df2aa8918159d6be3ae2' '9641e7e7204df7b96448033cd45357ef4a9f60f4ba24dedab772034049dab04b' - '174fb8ba9fe56a233efc0fdc8a52bab65e0b1642e53e7f70a3fd1addfd00e507' 'a11eb8ca1ff7a96b1bda6202c259f85ca0c1b1a489ffa81745dffe329985a5f1' '90f5374c6b9b1cbdf59ca71ac3335475f4395af617e2a9bbca2dc7dfe00f6928' '07dac87d01d52bfe6c3f57098c0723dbda1bebb1c5b74b38e96e551bd631926c' '458840bc6bedeb7503114c89bf9f9f34766b39f9a6bfaec09af411a023c96a31' '75f3bd1098c39ccf881508f4c9d23278465bcfe15beaed4bed2af4b00efa00f3' '10569e2bc2afe6ab320dcb4b0e708ddd8235244ec0daff05ca518cb8463f2924' - '4bc70de68084585dcf2b5a7e4abe32a789360fc2be97a9c94ba3b52dac89ad93') + '4bc70de68084585dcf2b5a7e4abe32a789360fc2be97a9c94ba3b52dac89ad93' + '48d643e3ee8fa1098faa7dab82945f8d56358c164bb680df0f85656719b28dba' + '2787b4e9431570c3c5ab88e0ea9faf38d198900e1f2a4462bd10e6b352f019aa' + 'fe24b559c08cb4b2f4ff5c8f8fe06e45dc00dc36e4de032205bf15fd18febfda' + '85b084d0638ad47714f8d9af26d6799c4a02d84c4f52b65e49a64b6985ecbe70') prepare() { cd gtk+-$pkgver patch -p1 -i ${srcdir}/0001-fix-m4-location.mingw.patch - patch -p1 -i ${srcdir}/0002-Fix-def-installation.all.patch patch -p1 -i ${srcdir}/0003-Fix-notebook-tab-state-change.mingw.patch patch -p1 -i ${srcdir}/0005-Fix-header-ref.all.patch patch -p1 -i ${srcdir}/0006-Fix-unix-symbols-in-docs.mingw.patch @@ -64,6 +69,13 @@ prepare() { patch -p1 -i ${srcdir}/0010-put-gtk-dll-into-path.mingw.patch patch -p1 -i ${srcdir}/0011-gir-for-gdkwin32.mingw.patch #patch -p1 -i ${srcdir}/0012-embed-manifest.all.patch + # 0013-fix-dead-keys-part-1.patch adds this new file, so it has + # to be removed first for repeated package builds to work. + rm -f gdk/win32/gdkwin32keys.h + patch -p1 -i ${srcdir}/0013-fix-dead-keys-part-1.patch + patch -p1 -i ${srcdir}/0014-fix-dead-keys-part-2.patch + patch -p1 -i ${srcdir}/0015-fix-dead-keys-part-3.patch + patch -p1 -i ${srcdir}/0016-handle-pause-key-correctly.patch autoreconf -fi }