[PATCH] winex11.drv: Implement ActivateKeyboardLayout() using XKB extension.

Dmitry Timoshkov dmitry at baikal.ru
Fri Apr 10 02:10:08 CDT 2020


Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/winex11.drv/keyboard.c | 200 ++++++++++++++++++++++++++----------
 1 file changed, 146 insertions(+), 54 deletions(-)

diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 48da12c029..c8c6ef3478 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -867,73 +867,73 @@ static const char main_key_NL[MAIN_LEN][4] =
 static const struct {
     LCID lcid; /* input locale identifier, look for LOCALE_ILANGUAGE
                  in the appropriate dlls/kernel/nls/.nls file */
-    const char *comment;
+    const char *xkb_group_name;
     const char (*key)[MAIN_LEN][4];
     const WORD (*scan)[MAIN_LEN]; /* scan codes mapping */
     const WORD (*vkey)[MAIN_LEN]; /* virtual key codes mapping */
 } main_key_tab[]={
- {0x0409, "United States keyboard layout", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
- {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0809, "British keyboard layout", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0407, "German keyboard layout", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
- {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
- {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
- {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
- {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0409, "English (US)", &main_key_US, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0409, "English (US)", &main_key_US_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0409, "English (Dvorak)", &main_key_US_dvorak, &main_key_scan_dvorak, &main_key_vkey_dvorak},
+ {0x0409, "English (US, international with dead keys)", &main_key_US_intl, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0809, "English (UK)", &main_key_UK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0407, "German", &main_key_DE, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x0807, "German (Switzerland)", &main_key_SG, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x100c, "French (Switzerland)", &main_key_SF, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x041d, "Swedish", &main_key_SE, &main_key_scan_qwerty, &main_key_vkey_qwerty_v2},
+ {0x0425, "Estonian", &main_key_ET, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0414, "Norwegian", &main_key_NO, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0406, "Danish", &main_key_DA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x040c, "French keyboard layout", &main_key_FR, &main_key_scan_qwerty, &main_key_vkey_azerty},
- {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
- {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
- {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
+ {0x0c0c, "French (Canada, legacy)", &main_key_CF, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0c0c, "French (Canada)", &main_key_CA_fr, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0c0c, "English (Canada)", &main_key_CA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x080c, "Belgian", &main_key_BE, &main_key_scan_qwerty, &main_key_vkey_azerty},
+ {0x0816, "Portuguese", &main_key_PT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0416, "Portuguese (Brazil)", &main_key_PT_br, &main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
+ {0x0416, "Portuguese (Brazil, eliminate dead keys)", &main_key_PT_br_alt_gr,&main_key_scan_abnt_qwerty, &main_key_vkey_abnt_qwerty},
  {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0402, "Bulgarian", &main_key_BG_bds, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0402, "Bulgarian (traditional phonetic)", &main_key_BG_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0423, "Belarusian", &main_key_BY, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0419, "Russian", &main_key_RU, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0419, "Russian (legacy)", &main_key_RU_phantom, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
- {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
- {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
+ {0x0419, "Russian (phonetic)", &main_key_RU_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0422, "Ukrainian", &main_key_UA_std, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x040a, "Spanish", &main_key_ES, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0410, "Italian", &main_key_IT, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x040f, "Icelandic", &main_key_IS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x040e, "Hungarian", &main_key_HU, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x0415, "Polish", &main_key_PL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0424, "Slovenian", &main_key_SI, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x0c1a, "Serbian", &main_key_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
  {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_scan_qwerty, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */
- {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x041a, "Croatian", &main_key_HR, &main_key_scan_qwerty, &main_key_vkey_qwertz},
  {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
- {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
+ {0x0411, "Japanese", &main_key_JA_jp106, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
+ {0x0411, "Japanese (Macintosh)", &main_key_JA_macjp, &main_key_scan_qwerty_jp106, &main_key_vkey_qwerty_jp106},
  {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x041b, "Slovak", &main_key_SK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0405, "Czech", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
+ {0x0405, "Czech (qwerty)", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_scan_qwerty, &main_key_vkey_qwertz},
- {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x040a, "Spanish (Latin American)", &main_key_LA, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0427, "Lithuanian", &main_key_LT_B, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x041f, "Turkish", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x041f, "Turkish (F)", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x040d, "Hebrew", &main_key_IL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x040d, "Hebrew (phonetic)", &main_key_IL_phonetic, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_scan_qwerty, &main_key_vkey_qwerty},
  {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_scan_vnc, &main_key_vkey_vnc},
- {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x041e, "Thai (Kedmanee)  keyboard layout", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
- {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0408, "Greek", &main_key_EL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x041e, "Thai", &main_key_th, &main_key_scan_qwerty, &main_key_vkey_qwerty},
+ {0x0413, "Dutch", &main_key_NL, &main_key_scan_qwerty, &main_key_vkey_qwerty},
 
  {0, NULL, NULL, NULL, NULL} /* sentinel */
 };
@@ -1468,8 +1468,8 @@ X11DRV_KEYBOARD_DetectLayout( Display *display )
       }
   }
 
-  for (current = 0; main_key_tab[current].comment; current++) {
-    TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].comment);
+  for (current = 0; main_key_tab[current].xkb_group_name; current++) {
+    TRACE("Attempting to match against \"%s\"\n", main_key_tab[current].xkb_group_name);
     match = 0;
     mismatch = 0;
     score = 0;
@@ -1526,9 +1526,9 @@ X11DRV_KEYBOARD_DetectLayout( Display *display )
   /* we're done, report results if necessary */
   if (!ismatch)
     WARN("Using closest match (%s) for scan/virtual codes mapping.\n",
-        main_key_tab[kbd_layout].comment);
+        main_key_tab[kbd_layout].xkb_group_name);
 
-  TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].comment);
+  TRACE("detected layout is \"%s\"\n", main_key_tab[kbd_layout].xkb_group_name);
 }
 
 static HKL get_locale_kbd_layout(void)
@@ -1927,6 +1927,94 @@ BOOL CDECL X11DRV_UnloadKeyboardLayout(HKL hkl)
     return FALSE;
 }
 
+#ifdef HAVE_XKB
+static HKL XKB_activate_layout(HKL hkl, UINT flags)
+{
+    struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
+    Display *display = thread_init_display();
+    HKL old_hkl;
+    XkbDescRec *xkb_desc;
+    XkbStateRec xkb_state;
+    int hkl_idx[16], hkl_count, i, j, group_count;
+    BOOL activated;
+
+    TRACE("%p, %04x\n", hkl, flags);
+
+    old_hkl = thread_data->kbd_layout;
+    if (!old_hkl) old_hkl = get_locale_kbd_layout();
+
+    hkl_count = 0;
+    for (i = 0; main_key_tab[i].xkb_group_name; i++)
+    {
+        if (hkl == (HKL)main_key_tab[i].lcid || LOWORD(hkl) == LOWORD(main_key_tab[i].lcid))
+        {
+            if (hkl_count < ARRAY_SIZE(hkl_idx))
+                hkl_idx[hkl_count++] = i;
+        }
+    }
+
+    if (!hkl_count)
+    {
+        FIXME("can't find layout for %p\n", hkl);
+        return 0;
+    }
+
+    XkbGetState(display, XkbUseCoreKbd, &xkb_state);
+    TRACE("current group: %d\n", xkb_state.locked_group);
+
+    xkb_desc = XkbAllocKeyboard();
+    if (xkb_desc == NULL)
+        return old_hkl;
+
+    XkbGetControls(display, XkbAllControlsMask, xkb_desc);
+    XkbGetNames(display, XkbGroupNamesMask, xkb_desc);
+
+    /* count groups */
+    if (xkb_desc->ctrls != NULL)
+        group_count = xkb_desc->ctrls->num_groups;
+    else
+    {
+        group_count = 0;
+        while (group_count < XkbNumKbdGroups && xkb_desc->names->groups[group_count] != 0)
+            group_count++;
+    }
+
+    TRACE("group count: %d\n", group_count);
+
+    activated = FALSE;
+
+    /* get group names */
+    for (i = 0; i < group_count && !activated; i++)
+    {
+        if (xkb_desc->names->groups[i] != None)
+        {
+            char *group_name = XGetAtomName(display, xkb_desc->names->groups[i]);
+            if (group_name == NULL)
+                continue;
+
+            TRACE("%d: %s", i, group_name);
+
+            for (j = 0; j < hkl_count; j++)
+            {
+                if (!strcmp(group_name, main_key_tab[hkl_idx[j]].xkb_group_name))
+                {
+                    TRACE("activating %s\n", debugstr_a(group_name));
+                    XkbLockGroup(display, XkbUseCoreKbd, i);
+                    activated = TRUE;
+                    break;
+                }
+            }
+
+            XFree(group_name);
+        }
+    }
+
+    XkbFreeKeyboard(xkb_desc, 0, True);
+
+    thread_data->kbd_layout = hkl;
+    return old_hkl;
+}
+#endif
 
 /***********************************************************************
  *		ActivateKeyboardLayout (X11DRV.@)
@@ -1936,6 +2024,10 @@ HKL CDECL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
     HKL oldHkl = 0;
     struct x11drv_thread_data *thread_data = x11drv_init_thread_data();
 
+#ifdef HAVE_XKB
+    return XKB_activate_layout(hkl, flags);
+#endif
+
     FIXME("%p, %04x: semi-stub!\n", hkl, flags);
     if (flags & KLF_SETFORPROCESS)
     {
-- 
2.25.2




More information about the wine-devel mailing list