[PATCH v2 0/5] MR10779: winex11: Keyboard layouts rework, part 2
-- v2: winex11: Store Xkb keyboard layout LANGID. winex11: Keep a list of every known Xkb keyboard layout. winex11: Move Xkb layouts initialization to a separate function. win32u: Simplify layout name generation for base keyboard layouts. win32u: Tweak a couple of comments. https://gitlab.winehq.org/wine/wine/-/merge_requests/10779
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/win32u/input.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ab09c3b7d42..da203666549 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -872,7 +872,7 @@ DWORD WINAPI NtUserGetQueueStatus( UINT flags ) } /******************************************************************* - * NtUserGetThreadInfo (win32u.@) + * NtUserGetThreadState (win32u.@) */ ULONG_PTR WINAPI NtUserGetThreadState( USERTHREADSTATECLASS cls ) { @@ -977,9 +977,6 @@ static HKL get_locale_kbd_layout(void) /*********************************************************************** * NtUserGetKeyboardLayout (win32u.@) - * - * Device handle for keyboard layout defaulted to - * the language id. This is the way Windows default works. */ HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id ) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10779
From: Matteo Bruni <mbruni@codeweavers.com> Registry access is unnecessary, the layout name matches the high word of the HKL in those cases. --- dlls/win32u/input.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index da203666549..cf2e106e4dd 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1454,10 +1454,20 @@ BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name ) layout = NtUserGetKeyboardLayout( 0 ); id = HandleToUlong( layout ); - if (HIWORD( id ) == LOWORD( id )) id = LOWORD( id ); + TRACE_(keyboard)("hkl %08x\n", id); + if ((id & 0xf0000000) == 0xf0000000) id &= 0x0fffffff; + else id = HIWORD(id); snprintf( buffer, sizeof(buffer), "%08X", id ); asciiz_to_unicode( name, buffer ); + if ((HandleToUlong( layout ) & 0xf0000000) != 0xf0000000) + { + info->kbd_layout_id = id; + + TRACE_(keyboard)( "ret %s\n", debugstr_w( name ) ); + return TRUE; + } + if ((hkey = reg_open_key( NULL, keyboard_layouts_keyW, sizeof(keyboard_layouts_keyW) ))) { while (!NtEnumerateKey( hkey, i++, KeyNodeInformation, key, @@ -1469,8 +1479,6 @@ BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name ) if (query_reg_ascii_value( subkey, "Layout Id", value, sizeof(buffer) ) && value->Type == REG_SZ) id = 0xf000 | (wcstoul( (const WCHAR *)value->Data, NULL, 16 ) & 0xfff); - else - id = wcstoul( klid, NULL, 16 ); NtClose( subkey ); if (HIWORD( layout ) == id) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10779
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/winex11.drv/keyboard.c | 73 ++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 65de84678ec..1d75ae78046 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1446,9 +1446,10 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) return TRUE; } +#ifdef SONAME_LIBXKBREGISTRY + static BOOL find_xkb_layout_variant( const char *name, const char **layout, const char **variant ) { -#ifdef SONAME_LIBXKBREGISTRY struct rxkb_layout *iter; if (rxkb_context) @@ -1469,9 +1470,6 @@ static BOOL find_xkb_layout_variant( const char *name, const char **layout, cons } else WARN( "libxkbregistry not available, falling back to fuzzy layout detection\n" ); -#else - WARN( "libxkbregistry support not compiled in, falling back to fuzzy layout detection\n" ); -#endif return FALSE; } @@ -1597,6 +1595,42 @@ static LANGID langid_from_xkb_layout( const char *layout ) return MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED); }; +#endif + +static BOOL init_xkb_layouts( Display *display, XkbDescRec *xkb_desc, unsigned int xkb_group ) +{ +#ifdef SONAME_LIBXKBREGISTRY + unsigned int count; + char *names[4]; + + 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++) + { + const char *layout, *variant = NULL; + LANGID lang; + + if (!names[i]) continue; + if (find_xkb_layout_variant( names[i], &layout, &variant )) + { + lang = langid_from_xkb_layout( layout ); + + 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] ); + } + + return TRUE; +#else + WARN( "libxkbregistry support not compiled in, falling back to fuzzy layout detection\n" ); +#endif + return FALSE; +} + /* 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 ) { @@ -1960,7 +1994,6 @@ void init_keyboard_layouts( Display *display ) XkbStateRec xkb_state; XModifierKeymap *mmp; XkbDescRec *xkb_desc; - LANGID xkb_lang = 0; Status status; KeyCode *kcp; @@ -1996,41 +2029,13 @@ void init_keyboard_layouts( Display *display ) 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++) - { - const char *layout, *variant = NULL; - LANGID lang; - - if (!names[i]) continue; - if (find_xkb_layout_variant( names[i], &layout, &variant )) - { - 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] ); - } - + init_xkb_layouts( display, xkb_desc, xkb_group ); XkbFreeKeyboard( xkb_desc, 0, True ); } 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 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10779
From: Matteo Bruni <mbruni@codeweavers.com> Very much inspired by a patch by Rémi Bernon. Similarly for some of the following patches. --- dlls/winex11.drv/keyboard.c | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 1d75ae78046..e52a916b7f7 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -55,6 +55,7 @@ #include "kbd.h" #include "wine/server.h" #include "wine/debug.h" +#include "wine/list.h" /* log format (add 0-padding as appropriate): keycode %u as in output from xev @@ -65,6 +66,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(keyboard); WINE_DECLARE_DEBUG_CHANNEL(key); +struct layout +{ + struct list entry; + + int xkb_group; + char *xkb_layout; +}; + static const unsigned int ControlMask = 1 << 2; static int min_keycode, max_keycode, keysyms_per_keycode; @@ -73,9 +82,41 @@ static WORD keyc2vkey[256], keyc2scan[256]; static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */ static pthread_mutex_t kbd_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct list xkb_layouts = LIST_INIT( xkb_layouts ); static char KEYBOARD_MapDeadKeysym(KeySym keysym); +#ifdef SONAME_LIBXKBREGISTRY +static void create_layout_from_xkb( int xkb_group, const char *xkb_layout ) +{ + struct layout *layout; + + TRACE( "xkb_group %u, xkb_layout %s\n", xkb_group, xkb_layout ); + + LIST_FOR_EACH_ENTRY( layout, &xkb_layouts, struct layout, entry ) + { + if (!strcmp( layout->xkb_layout, xkb_layout )) + { + TRACE( "Found existing layout entry %p\n", layout ); + if (layout->xkb_group == -1) layout->xkb_group = xkb_group; + return; + } + } + + if (!(layout = calloc( 1, sizeof(*layout) + strlen( xkb_layout ) + 1 ))) + { + WARN( "Failed to allocate memory for Xkb layout entry\n" ); + return; + } + list_add_tail( &xkb_layouts, &layout->entry ); + + layout->xkb_group = xkb_group; + layout->xkb_layout = strcpy( (char *)(layout + 1), xkb_layout ); + + TRACE( "Created layout entry %p\n", layout ); +} +#endif + /* Keyboard translation tables */ #define MAIN_LEN 49 static const WORD main_key_scan_qwerty[MAIN_LEN] = @@ -1599,18 +1640,27 @@ static LANGID langid_from_xkb_layout( const char *layout ) static BOOL init_xkb_layouts( Display *display, XkbDescRec *xkb_desc, unsigned int xkb_group ) { + struct layout *entry; #ifdef SONAME_LIBXKBREGISTRY unsigned int count; char *names[4]; +#endif + /* Flag any previously created Xkb layout as invalid */ + LIST_FOR_EACH_ENTRY( entry, &xkb_layouts, struct layout, entry ) + entry->xkb_group = -1; + +#ifdef SONAME_LIBXKBREGISTRY 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; + TRACE("Found %u group names\n", count); for (int i = 0; i < count; i++) { const char *layout, *variant = NULL; + char buffer[1024]; LANGID lang; if (!names[i]) continue; @@ -1620,6 +1670,9 @@ static BOOL init_xkb_layouts( Display *display, XkbDescRec *xkb_desc, unsigned i 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 ); + + snprintf( buffer, ARRAY_SIZE(buffer), "%s:%s", layout, variant ); + create_layout_from_xkb( i, buffer ); } XFree( names[i] ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10779
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/winex11.drv/keyboard.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index e52a916b7f7..2c8ddf82114 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -72,6 +72,8 @@ struct layout int xkb_group; char *xkb_layout; + + LANGID lang; }; static const unsigned int ControlMask = 1 << 2; @@ -87,17 +89,17 @@ static struct list xkb_layouts = LIST_INIT( xkb_layouts ); static char KEYBOARD_MapDeadKeysym(KeySym keysym); #ifdef SONAME_LIBXKBREGISTRY -static void create_layout_from_xkb( int xkb_group, const char *xkb_layout ) +static void create_layout_from_xkb( int xkb_group, const char *xkb_layout, LANGID lang ) { struct layout *layout; - TRACE( "xkb_group %u, xkb_layout %s\n", xkb_group, xkb_layout ); + TRACE( "xkb_group %u, xkb_layout %s, lang %04x\n", xkb_group, xkb_layout, lang ); LIST_FOR_EACH_ENTRY( layout, &xkb_layouts, struct layout, entry ) { if (!strcmp( layout->xkb_layout, xkb_layout )) { - TRACE( "Found existing layout entry %p\n", layout ); + TRACE( "Found existing layout entry %p, lang %04x\n", layout, layout->lang ); if (layout->xkb_group == -1) layout->xkb_group = xkb_group; return; } @@ -113,7 +115,9 @@ static void create_layout_from_xkb( int xkb_group, const char *xkb_layout ) layout->xkb_group = xkb_group; layout->xkb_layout = strcpy( (char *)(layout + 1), xkb_layout ); - TRACE( "Created layout entry %p\n", layout ); + layout->lang = lang; + + TRACE( "Created layout entry %p, lang %04x\n", layout, layout->lang ); } #endif @@ -1672,7 +1676,7 @@ static BOOL init_xkb_layouts( Display *display, XkbDescRec *xkb_desc, unsigned i debugstr_a(layout), debugstr_a(variant), lang ); snprintf( buffer, ARRAY_SIZE(buffer), "%s:%s", layout, variant ); - create_layout_from_xkb( i, buffer ); + create_layout_from_xkb( i, buffer, lang ); } XFree( names[i] ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10779
I pushed my updated branch to [hl-kbl](https://gitlab.winehq.org/Mystral/wine/-/commits/hl-kbl?ref_type=heads), for reference. The commits up to https://gitlab.winehq.org/Mystral/wine/-/commit/4fa555a09c408d71a5b866c355cf... [winex11: Activate initial keyboard layout.] are probably the most relevant for this MR. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10779#note_138412
participants (2)
-
Matteo Bruni -
Matteo Bruni (@Mystral)