[PATCH v2 0/5] MR10689: winex11: Keyboard layouts rework, part 1
Same as https://gitlab.winehq.org/wine/wine/-/merge_requests/10550 with misc tweaks. -- v2: winex11: Decode current keyboard layout from the Xkb group name. winex11: Look up keysyms for the currently selected Xkb group in X11DRV_KEYBOARD_DetectLayout(). winex11: Get Xkb group names. winex11: Factor out mapping keycodes to scancodes / keysyms into a separate function. winex11: Fix some X11DRV_InitKeyboard loop indentation. https://gitlab.winehq.org/wine/wine/-/merge_requests/10689
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/winex11.drv/keyboard.c | 71 ++++++++++++++++------------------ dlls/winex11.drv/x11drv.h | 2 +- dlls/winex11.drv/x11drv_main.c | 3 +- 3 files changed, 36 insertions(+), 40 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index e2281bef017..a432859ae69 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1435,16 +1435,8 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } -/********************************************************************** - * X11DRV_KEYBOARD_DetectLayout - * - * Called from X11DRV_InitKeyboard - * This routine walks through the defined keyboard layouts and selects - * whichever matches most closely. - * kbd_section must be held. - */ -static void -X11DRV_KEYBOARD_DetectLayout( Display *display ) +/* fuzzy layout detection through keysym / keycode matching, kbd_section must be held */ +static void detect_keyboard_layout( Display *display ) { unsigned current, match, mismatch, seq, i, syms; int score, keyc, key, pkey, ok; @@ -1547,10 +1539,8 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) } -/********************************************************************** - * X11DRV_InitKeyboard - */ -void X11DRV_InitKeyboard( Display *display ) +/* initialize or update keyboard layouts */ +static void init_keyboard_layouts( Display *display ) { XModifierKeymap *mmp; KeySym keysym; @@ -1582,37 +1572,34 @@ void X11DRV_InitKeyboard( Display *display ) int vkey_range; pthread_mutex_lock( &kbd_mutex ); - XDisplayKeycodes(display, &min_keycode, &max_keycode); + XDisplayKeycodes( display, &min_keycode, &max_keycode ); XFree( XGetKeyboardMapping( display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode ) ); - mmp = XGetModifierMapping(display); + mmp = XGetModifierMapping( display ); kcp = mmp->modifiermap; - for (i = 0; i < 8; i += 1) /* There are 8 modifier keys */ + for (int i = 0; i < 8; i += 1) /* There are 8 modifier keys */ { - int j; - - for (j = 0; j < mmp->max_keypermod; j += 1, kcp += 1) - if (*kcp) + for (int j = 0; j < mmp->max_keypermod; j += 1, kcp += 1) + { + for (int k = 0; *kcp && k < keysyms_per_keycode; k += 1) { - int k; - - for (k = 0; k < keysyms_per_keycode; k += 1) - if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Num_Lock) - { - NumLockMask = 1 << i; - TRACE_(key)("NumLockMask is %x\n", NumLockMask); - } - else if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Scroll_Lock) - { - ScrollLockMask = 1 << i; - TRACE_(key)("ScrollLockMask is %x\n", ScrollLockMask); - } + if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Num_Lock) + { + NumLockMask = 1 << i; + TRACE_(key)( "NumLockMask is %x\n", NumLockMask ); + } + else if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Scroll_Lock) + { + ScrollLockMask = 1 << i; + TRACE_(key)( "ScrollLockMask is %x\n", ScrollLockMask ); + } } + } } - XFreeModifiermap(mmp); + XFreeModifiermap( mmp ); /* Detect the keyboard layout */ - X11DRV_KEYBOARD_DetectLayout( display ); + detect_keyboard_layout( display ); lkey = main_key_tab[kbd_layout].key; syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode; @@ -1844,7 +1831,7 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) HWND hwnd; XRefreshKeyboardMapping(&event->xmapping); - X11DRV_InitKeyboard( event->xmapping.display ); + init_keyboard_layouts( event->xmapping.display ); hwnd = get_focus(); if (!hwnd) hwnd = get_active_window(); @@ -1854,6 +1841,16 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) } +/*********************************************************************** + * x11drv_init_keyboard + */ +void x11drv_init_keyboard( Display *display ) +{ + XkbUseExtension( display, NULL, NULL ); + init_keyboard_layouts( display ); +} + + /*********************************************************************** * VkKeyScanEx (X11DRV.@) * diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8b0c0a62f91..e69ac5a8ae0 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -753,7 +753,7 @@ extern void X11DRV_ActivateWindow( HWND hwnd, HWND previous ); extern void reapply_cursor_clipping(void); extern void ungrab_clipping_window(void); extern void move_resize_window( HWND hwnd, int dir, POINT pos ); -extern void X11DRV_InitKeyboard( Display *display ); +extern void x11drv_init_keyboard( Display *display ); extern BOOL X11DRV_ProcessEvents( DWORD mask ); typedef int (*x11drv_error_callback)( Display *display, XErrorEvent *event, void *arg ); diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 1bdcd282f2e..1c8002e263c 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -672,8 +672,7 @@ NTSTATUS __wine_unix_lib_init(void) #endif x11drv_xinput2_load(); - XkbUseExtension( gdi_display, NULL, NULL ); - X11DRV_InitKeyboard( gdi_display ); + x11drv_init_keyboard( gdi_display ); if (use_xim) use_xim = xim_init( input_style ); init_icm_profile(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10689
From: Matteo Bruni <mbruni@codeweavers.com> We'll entirely get rid of the new x11drv_init_layout() function after introducing the new implementation based on KBDTABLES. --- dlls/winex11.drv/keyboard.c | 74 ++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index a432859ae69..72ddf8c12cc 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1539,12 +1539,10 @@ static void detect_keyboard_layout( Display *display ) } -/* initialize or update keyboard layouts */ -static void init_keyboard_layouts( Display *display ) +/* initialize keyc2scan and keyc2vkey */ +static void init_keycode_mappings( Display *display ) { - XModifierKeymap *mmp; KeySym keysym; - KeyCode *kcp; XKeyEvent e2; WORD scan, vkey; int keyc, i, keyn, syms; @@ -1571,35 +1569,6 @@ static void init_keyboard_layouts( Display *display ) }; int vkey_range; - pthread_mutex_lock( &kbd_mutex ); - XDisplayKeycodes( display, &min_keycode, &max_keycode ); - XFree( XGetKeyboardMapping( display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode ) ); - - mmp = XGetModifierMapping( display ); - kcp = mmp->modifiermap; - for (int i = 0; i < 8; i += 1) /* There are 8 modifier keys */ - { - for (int j = 0; j < mmp->max_keypermod; j += 1, kcp += 1) - { - for (int k = 0; *kcp && k < keysyms_per_keycode; k += 1) - { - if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Num_Lock) - { - NumLockMask = 1 << i; - TRACE_(key)( "NumLockMask is %x\n", NumLockMask ); - } - else if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Scroll_Lock) - { - ScrollLockMask = 1 << i; - TRACE_(key)( "ScrollLockMask is %x\n", ScrollLockMask ); - } - } - } - } - XFreeModifiermap( mmp ); - - /* Detect the keyboard layout */ - detect_keyboard_layout( display ); lkey = main_key_tab[kbd_layout].key; syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode; @@ -1800,6 +1769,45 @@ static void init_keyboard_layouts( Display *display ) TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname); keyc2scan[keyc]=scan++; } +} + + +/* initialize or update keyboard layouts */ +void init_keyboard_layouts( Display *display ) +{ + XModifierKeymap *mmp; + KeyCode *kcp; + + pthread_mutex_lock( &kbd_mutex ); + XDisplayKeycodes( display, &min_keycode, &max_keycode ); + XFree( XGetKeyboardMapping( display, min_keycode, max_keycode + 1 - min_keycode, &keysyms_per_keycode ) ); + + mmp = XGetModifierMapping( display ); + kcp = mmp->modifiermap; + for (int i = 0; i < 8; i += 1) /* There are 8 modifier keys */ + { + for (int j = 0; j < mmp->max_keypermod; j += 1, kcp += 1) + { + for (int k = 0; *kcp && k < keysyms_per_keycode; k += 1) + { + if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Num_Lock) + { + NumLockMask = 1 << i; + TRACE_(key)( "NumLockMask is %x\n", NumLockMask ); + } + else if (XkbKeycodeToKeysym( display, *kcp, 0, k ) == XK_Scroll_Lock) + { + ScrollLockMask = 1 << i; + TRACE_(key)( "ScrollLockMask is %x\n", ScrollLockMask ); + } + } + } + } + XFreeModifiermap( mmp ); + + detect_keyboard_layout( display ); + + init_keycode_mappings( display ); pthread_mutex_unlock( &kbd_mutex ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10689
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/winex11.drv/keyboard.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 72ddf8c12cc..b08a0594c8e 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1775,7 +1775,11 @@ static void init_keycode_mappings( Display *display ) /* initialize or update keyboard layouts */ void init_keyboard_layouts( Display *display ) { + unsigned int xkb_group; + XkbStateRec xkb_state; XModifierKeymap *mmp; + XkbDescRec *xkb_desc; + Status status; KeyCode *kcp; pthread_mutex_lock( &kbd_mutex ); @@ -1805,6 +1809,29 @@ void init_keyboard_layouts( Display *display ) } XFreeModifiermap( mmp ); + status = XkbGetState( display, XkbUseCoreKbd, &xkb_state ); + xkb_group = status ? 0 : xkb_state.group; + TRACE( "current group %u (status %#x)\n", xkb_group, status ); + + if ((xkb_desc = XkbGetMap( display, XkbAllClientInfoMask, XkbUseCoreKbd ))) + { + char *names[4]; + int count; + + XkbGetNames( display, XkbGroupNamesMask, xkb_desc ); + for (count = 0; count < ARRAY_SIZE(xkb_desc->names->groups); count++) + if (!xkb_desc->names->groups[count]) break; + + if (!XGetAtomNames( display, xkb_desc->names->groups, count, names )) count = 0; + for (int i = 0; i < count; i++) + { + TRACE( "group %u name %s\n", i, debugstr_a(names[i]) ); + XFree( names[i] ); + } + + XkbFreeKeyboard( xkb_desc, 0, True ); + } + detect_keyboard_layout( display ); init_keycode_mappings( display ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10689
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/winex11.drv/keyboard.c | 42 +++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index b08a0594c8e..60e733630b6 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1388,15 +1388,6 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) pthread_mutex_lock( &kbd_mutex ); - /* If XKB extensions are used, the state mask for AltGr will use the group - index instead of the modifier mask. The group index is set in bits - 13-14 of the state field in the XKeyEvent structure. So if AltGr is - pressed, look if the group index is different than 0. From XKB - extension documentation, the group index for AltGr should be 2 - (event->state = 0x2000). It's probably better to not assume a - predefined group index and find it dynamically - - Ref: X Keyboard Extension: Library specification (section 14.1.1 and 17.1.1) */ /* Save also all possible modifier states. */ AltGrMask = event->state & (0x6000 | Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask); @@ -1436,15 +1427,28 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) } /* fuzzy layout detection through keysym / keycode matching, kbd_section must be held */ -static void detect_keyboard_layout( Display *display ) +static void detect_keyboard_layout( Display *display, XModifierKeymap *modmap, unsigned int xkb_group ) { unsigned current, match, mismatch, seq, i, syms; int score, keyc, key, pkey, ok; - KeySym keysym = 0; + KeySym keysym; const char (*lkey)[MAIN_LEN][4]; unsigned max_seq = 0; int max_score = INT_MIN, ismatch = 0; char ckey[256][4]; + unsigned int state, altgr_mod = 0, dummy, mod; + + TRACE( "display %p, mmp %p, xkb_group %u\n", display, modmap, xkb_group ); + + for (mod = 0; mod < 8 * modmap->max_keypermod; mod++) + { + int xmod = 1 << (mod / modmap->max_keypermod); + + if (!(keyc = modmap->modifiermap[mod])) continue; + XkbLookupKeySym( display, keyc, xkb_group * 0x2000, &dummy, &keysym ); + if (keysym == XK_ISO_Level3_Shift) altgr_mod = xmod; + } + TRACE( "AltGr is mapped to mod %#x\n", altgr_mod ); syms = keysyms_per_keycode; if (syms > 4) { @@ -1453,10 +1457,16 @@ static void detect_keyboard_layout( Display *display ) } memset( ckey, 0, sizeof(ckey) ); - for (keyc = min_keycode; keyc <= max_keycode; keyc++) { + for (keyc = min_keycode; keyc <= max_keycode; keyc++) + { /* get data for keycode from X server */ - for (i = 0; i < syms; i++) { - if (!(keysym = XkbKeycodeToKeysym( display, keyc, 0, i ))) continue; + for (i = 0; i < syms; i++) + { + /* With Xkb, the current group index is encoded in bits 13-14 of the state field. + * Ref: X Keyboard Extension: Library specification (section 18.1.1) + */ + state = xkb_group << 13 | (i & 1 ? ShiftMask : 0) | (i & 2 ? altgr_mod : 0); + if (!XkbLookupKeySym( display, keyc, state, &dummy, &keysym )) continue; /* Allow both one-byte and two-byte national keysyms */ if ((keysym < 0x8000) && (keysym != ' ')) { @@ -1807,7 +1817,6 @@ void init_keyboard_layouts( Display *display ) } } } - XFreeModifiermap( mmp ); status = XkbGetState( display, XkbUseCoreKbd, &xkb_state ); xkb_group = status ? 0 : xkb_state.group; @@ -1832,7 +1841,8 @@ void init_keyboard_layouts( Display *display ) XkbFreeKeyboard( xkb_desc, 0, True ); } - detect_keyboard_layout( display ); + detect_keyboard_layout( display, mmp, xkb_group ); + XFreeModifiermap( mmp ); init_keycode_mappings( display ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10689
From: Matteo Bruni <mbruni@codeweavers.com> For large parts lifted from Rémi's winewayland commit d64ea8e4a6c93ba77208cb680b91dc0c2830049d. --- configure.ac | 9 +- dlls/winex11.drv/Makefile.in | 4 +- dlls/winex11.drv/keyboard.c | 175 ++++++++++++++++++++++++++++++++++- 3 files changed, 183 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index f35ac4376d9..1ff84000e96 100644 --- a/configure.ac +++ b/configure.ac @@ -1433,6 +1433,13 @@ else X_LIBS="" fi +if test "x$have_x$with_wayland" != "xnono" +then + WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, + [AC_CHECK_HEADERS([xkbcommon/xkbregistry.h]) + AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])]) +fi + if test "x$with_wayland" != "xno" then WINE_PACKAGE_FLAGS(WAYLAND_CLIENT,[wayland-client],,,, @@ -1443,8 +1450,6 @@ then [WAYLAND_CLIENT_LIBS=""],[$WAYLAND_CLIENT_LIBS])])]) WINE_PACKAGE_FLAGS(XKBCOMMON,[xkbcommon],,,, [AC_CHECK_LIB(xkbcommon,xkb_context_new,[:],[XKBCOMMON_LIBS=""],[$XKBCOMMON_LIBS])]) - WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,, - [AC_CHECK_LIB(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])]) if test "x$with_opengl" != "xno" then WINE_PACKAGE_FLAGS(WAYLAND_EGL,[wayland-egl],,,, diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in index f9ddd05175b..31768e670da 100644 --- a/dlls/winex11.drv/Makefile.in +++ b/dlls/winex11.drv/Makefile.in @@ -1,7 +1,7 @@ MODULE = winex11.drv UNIXLIB = winex11.so -UNIX_CFLAGS = $(X_CFLAGS) -UNIX_LIBS = -lwin32u $(X_LIBS) $(PTHREAD_LIBS) -lm +UNIX_CFLAGS = $(X_CFLAGS) $(XKBREGISTRY_CFLAGS) +UNIX_LIBS = -lwin32u $(X_LIBS) $(XKBREGISTRY_LIBS) $(PTHREAD_LIBS) -lm VER_FILEDESCRIPTION_STR = "Wine X11 driver" diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 60e733630b6..c0bfa4bc1e2 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -36,6 +36,10 @@ #include <X11/Xutil.h> #include <X11/XKBlib.h> +#ifdef HAVE_XKBCOMMON_XKBREGISTRY_H +#include <xkbcommon/xkbregistry.h> +#endif + #include <ctype.h> #include <stdarg.h> #include <string.h> @@ -939,6 +943,9 @@ static const struct { {0, NULL, NULL, NULL, NULL} /* sentinel */ }; static unsigned kbd_layout=0; /* index into above table of layouts */ +#ifdef HAVE_XKBCOMMON_XKBREGISTRY_H +static struct rxkb_context *rxkb_context; +#endif /* maybe more of these scancodes should be extended? */ /* extended must be set for ALT_R, CTRL_R, @@ -1426,6 +1433,149 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } +static BOOL find_xkb_layout_variant( const char *name, const char **layout, const char **variant ) +{ +#ifdef HAVE_XKBCOMMON_XKBREGISTRY_H + struct rxkb_layout *iter; + + for (iter = rxkb_layout_first( rxkb_context ); iter; iter = rxkb_layout_next( iter )) + { + const char *desc = rxkb_layout_get_description( iter ); + + if (desc && !strcmp( name, desc )) + { + *layout = rxkb_layout_get_name( iter ); + *variant = rxkb_layout_get_variant( iter ); + return TRUE; + } + } +#endif + + return FALSE; +} + +static const struct layout_id_map_entry +{ + const char *name; + LANGID langid; +} layout_ids[] = +{ + { "af", MAKELANGID(LANG_DARI, SUBLANG_DEFAULT) }, + { "al", MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT) }, + { "am", MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT) }, + { "ara", MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT) }, + { "at", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN) }, + { "az", MAKELANGID(LANG_AZERBAIJANI, SUBLANG_DEFAULT) }, + { "au", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_AUS) }, + { "ba", MAKELANGID(LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC) }, + { "bd", MAKELANGID(LANG_BANGLA, SUBLANG_DEFAULT) }, + { "be", MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN) }, + { "bg", MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT) }, + { "br", MAKELANGID(LANG_PORTUGUESE, 2) }, + { "brai", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "bt", MAKELANGID(LANG_TIBETAN, 3) }, + { "bw", MAKELANGID(LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA) }, + { "by", MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT) }, + { "ca", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN) }, + { "cd", MAKELANGID(LANG_FRENCH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "ch", MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS) }, + { "cm", MAKELANGID(LANG_FRENCH, 11) }, + { "cn", MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT) }, + { "cz", MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT) }, + { "de", MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT) }, + { "dk", MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT) }, + { "dz", MAKELANGID(LANG_TAMAZIGHT, SUBLANG_TAMAZIGHT_ALGERIA_LATIN) }, + { "ee", MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT) }, + { "epo", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "es", MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT) }, + { "et", MAKELANGID(LANG_AMHARIC, SUBLANG_DEFAULT) }, + { "fi", MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT) }, + { "fo", MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT) }, + { "fr", MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT) }, + { "gb", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK) }, + { "ge", MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT) }, + { "gh", MAKELANGID(LANG_ENGLISH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "gn", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "gr", MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT) }, + { "hr", MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT) }, + { "hu", MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT) }, + { "id", MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT) }, + { "ie", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_EIRE) }, + { "il", MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT) }, + { "in", MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT) }, + { "iq", MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_IRAQ) }, + { "ir", MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT) }, + { "is", MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT) }, + { "it", MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT) }, + { "jp", MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT) }, + { "ke", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "kg", MAKELANGID(LANG_KYRGYZ, SUBLANG_DEFAULT) }, + { "kh", MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT) }, + { "kr", MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT) }, + { "kz", MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT) }, + { "la", MAKELANGID(LANG_LAO, SUBLANG_DEFAULT) }, + { "latam", MAKELANGID(LANG_SPANISH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "lk", MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT) }, + { "lt", MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT) }, + { "lv", MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT) }, + { "ma", MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_MOROCCO) }, + { "mao", MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT) }, + { "md", MAKELANGID(LANG_ROMANIAN, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "me", MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_MONTENEGRO_LATIN) }, + { "mk", MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT) }, + { "ml", MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT) }, + { "mm", MAKELANGID(0x55 /*LANG_BURMESE*/, SUBLANG_DEFAULT) }, + { "mn", MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT) }, + { "mt", MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT) }, + { "mv", MAKELANGID(LANG_DIVEHI, SUBLANG_DEFAULT) }, + { "my", MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT) }, + { "ng", MAKELANGID(LANG_ENGLISH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "nl", MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT) }, + { "no", MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT) }, + { "np", MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT) }, + { "ph", MAKELANGID(LANG_FILIPINO, SUBLANG_DEFAULT) }, + { "pk", MAKELANGID(LANG_URDU, SUBLANG_DEFAULT) }, + { "pl", MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT) }, + { "pt", MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT) }, + { "ro", MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT) }, + { "rs", MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_LATIN) }, + { "ru", MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT) }, + { "se", MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT) }, + { "si", MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT) }, + { "sk", MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT) }, + { "sn", MAKELANGID(LANG_WOLOF, SUBLANG_DEFAULT) }, + { "sy", MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT) }, + { "tg", MAKELANGID(LANG_FRENCH, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "th", MAKELANGID(LANG_THAI, SUBLANG_DEFAULT) }, + { "tj", MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT) }, + { "tm", MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT) }, + { "tr", MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT) }, + { "tw", MAKELANGID(LANG_CHINESE, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "tz", MAKELANGID(LANG_SWAHILI, SUBLANG_CUSTOM_UNSPECIFIED) }, + { "ua", MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT) }, + { "us", MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) }, + { "uz", MAKELANGID(LANG_UZBEK, 2) }, + { "vn", MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT) }, + { "za", MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA) }, +}; + +static int layout_id_map_cmp( const void *key, const void *element ) +{ + const struct layout_id_map_entry *entry = element; + return strcmp( key, entry->name ); +} + +static LANGID langid_from_xkb_layout( const char *layout ) +{ + struct layout_id_map_entry *entry; + + entry = bsearch( layout, layout_ids, ARRAY_SIZE(layout_ids), sizeof(*layout_ids), layout_id_map_cmp ); + if (entry) return entry->langid; + + FIXME( "Unknown layout %s\n", debugstr_a(layout) ); + return MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED); +}; + /* fuzzy layout detection through keysym / keycode matching, kbd_section must be held */ static void detect_keyboard_layout( Display *display, XModifierKeymap *modmap, unsigned int xkb_group ) { @@ -1789,6 +1939,7 @@ void init_keyboard_layouts( Display *display ) XkbStateRec xkb_state; XModifierKeymap *mmp; XkbDescRec *xkb_desc; + LANGID xkb_lang = 0; Status status; KeyCode *kcp; @@ -1834,7 +1985,15 @@ void init_keyboard_layouts( Display *display ) if (!XGetAtomNames( display, xkb_desc->names->groups, count, names )) count = 0; for (int i = 0; i < count; i++) { - TRACE( "group %u name %s\n", i, debugstr_a(names[i]) ); + const char *layout, *variant = NULL; + LANGID lang; + + if (!names[i] || !find_xkb_layout_variant( names[i], &layout, &variant )) layout = "us"; + lang = langid_from_xkb_layout( layout ); + if (i == xkb_group) xkb_lang = lang; + + TRACE( "Found group %u with name %s -> layout %s:%s, lang %04x\n", i, debugstr_a(names[i]), + debugstr_a(layout), debugstr_a(variant), lang ); XFree( names[i] ); } @@ -1844,6 +2003,10 @@ void init_keyboard_layouts( Display *display ) detect_keyboard_layout( display, mmp, xkb_group ); XFreeModifiermap( mmp ); + if (xkb_lang && xkb_lang != main_key_tab[kbd_layout].lcid) + WARN( "Xkb langid %04x differs from detected langid %04x\n", + xkb_lang, main_key_tab[kbd_layout].lcid ); + init_keycode_mappings( display ); pthread_mutex_unlock( &kbd_mutex ); @@ -1892,6 +2055,16 @@ BOOL X11DRV_MappingNotify( HWND dummy, XEvent *event ) void x11drv_init_keyboard( Display *display ) { XkbUseExtension( display, NULL, NULL ); + +#ifdef HAVE_XKBCOMMON_XKBREGISTRY_H + if (!(rxkb_context = rxkb_context_new( RXKB_CONTEXT_NO_FLAGS )) || + !rxkb_context_parse_default_ruleset( rxkb_context )) + { + ERR( "Failed to parse default Xkb ruleset\n" ); + return; + } +#endif + init_keyboard_layouts( display ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10689
participants (3)
-
Matteo Bruni -
Rémi Bernon -
Rémi Bernon (@rbernon)