From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/input.c | 24 ++-- dlls/winex11.drv/keyboard.c | 226 +++++++++++++++++++++++++++++++++++- 2 files changed, 232 insertions(+), 18 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 8f3d5750c2f..8015b048527 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3337,7 +3337,6 @@ static void test_keyboard_layout_name(void) ActivateKeyboardLayout(layouts[i], 0);
tmplayout = GetKeyboardLayout(0); - todo_wine_if(tmplayout != layouts[i]) ok( tmplayout == layouts[i], "Failed to activate keyboard layout\n"); if (tmplayout != layouts[i]) { @@ -3352,21 +3351,25 @@ static void test_keyboard_layout_name(void) swprintf( tmpklid, KL_NAMELENGTH, L"%08X", layouts_preload[j] ); if (!wcscmp( tmpklid, klid )) break; } + todo_wine_if( layouts[i] != layout ) ok(j < len, "Could not find keyboard layout %s in preload list\n", wine_dbgstr_w(klid));
if (id & 0x80000000) { - todo_wine ok((id >> 28) == 0xf, "hkl high bits %#lx, expected 0xf\n", id >> 28); + todo_wine_if((UINT_PTR)layout >> 28 == 0xe) /* FIXME: winex11 currently fakes an IME on CJK locale */ + ok((id >> 28) == 0xf, "hkl high bits %#lx, expected 0xf\n", id >> 28);
value_size = sizeof(value); wcscpy(layout_path, L"System\CurrentControlSet\Control\Keyboard Layouts\"); wcscat(layout_path, klid); status = RegGetValueW(HKEY_LOCAL_MACHINE, layout_path, L"Layout Id", RRF_RT_REG_SZ, NULL, (void *)&value, &value_size); - todo_wine ok(!status, "RegGetValueW returned %lx\n", status); + todo_wine_if((UINT_PTR)layout >> 28 == 0xe) /* FIXME: winex11 currently fakes an IME on CJK locale */ + ok(!status, "RegGetValueW returned %lx\n", status); ok(value_size == 5 * sizeof(WCHAR), "RegGetValueW returned size %ld\n", value_size);
swprintf(tmpklid, KL_NAMELENGTH, L"%04X", (id >> 16) & 0x0fff); - todo_wine ok(!wcsicmp(value, tmpklid), "RegGetValueW returned %s, expected %s\n", debugstr_w(value), debugstr_w(tmpklid)); + todo_wine_if((UINT_PTR)layout >> 28 == 0xe) /* FIXME: winex11 currently fakes an IME on CJK locale */ + ok(!wcsicmp(value, tmpklid), "RegGetValueW returned %s, expected %s\n", debugstr_w(value), debugstr_w(tmpklid)); } else { @@ -3378,7 +3381,7 @@ static void test_keyboard_layout_name(void) tmplayout = LoadKeyboardLayoutW(klid, KLF_ACTIVATE);
/* The low word of HKL is the selected user lang and may be different as LoadKeyboardLayoutW also selects the default lang from the layout */ - ok(((UINT_PTR)tmplayout & ~0xffff) == ((UINT_PTR)layouts[i] & ~0xffff), "LoadKeyboardLayoutW returned %p, expected %p\n", tmplayout, layouts[i]); + ok(HIWORD(tmplayout) == HIWORD(layouts[i]), "LoadKeyboardLayoutW returned %p, expected %p\n", tmplayout, layouts[i]);
/* The layout name only depends on the keyboard layout: the high word of HKL. */ GetKeyboardLayoutNameW(tmpklid); @@ -3423,6 +3426,7 @@ static LRESULT CALLBACK test_ActivateKeyboardLayout_window_proc( HWND hwnd, UINT
ok( !got_setfocus, "got WM_SETFOCUS before WM_INPUTLANGCHANGE\n" ); ok( layout == expect_hkl, "got layout %p\n", layout ); + todo_wine_if( wparam == 0xfe ) ok( wparam == info.ciCharset || broken(wparam == 0 && (HIWORD(layout) & 0x8000)), "got wparam %#Ix\n", wparam ); ok( lparam == (LPARAM)expect_hkl, "got lparam %#Ix\n", lparam ); @@ -3475,11 +3479,10 @@ static void test_ActivateKeyboardLayout( char **argv ) got_setfocus = 0; ActivateKeyboardLayout( other_layout, 0 ); if (other_layout == layout) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); - else todo_wine ok( change_hkl == other_layout, "got change_hkl %p\n", change_hkl ); + else ok( change_hkl == other_layout, "got change_hkl %p\n", change_hkl ); change_hkl = expect_hkl = 0;
tmp_layout = GetKeyboardLayout( 0 ); - todo_wine_if(layout != other_layout) ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout );
/* changing the layout from another thread doesn't send the message */ @@ -3493,7 +3496,6 @@ static void test_ActivateKeyboardLayout( char **argv )
empty_message_queue(); tmp_layout = GetKeyboardLayout( 0 ); - todo_wine_if(layout != other_layout) ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout );
/* but the change only takes effect after focus changes */ @@ -3503,7 +3505,6 @@ static void test_ActivateKeyboardLayout( char **argv ) ok( !!hwnd2, "CreateWindow failed, error %lu\n", GetLastError() );
tmp_layout = GetKeyboardLayout( 0 ); - todo_wine_if(layout != other_layout) ok( tmp_layout == layout || broken(layout != other_layout && tmp_layout == other_layout) /* w7u */, "got tmp_layout %p\n", tmp_layout ); if (broken(layout != other_layout && tmp_layout == other_layout)) @@ -3519,7 +3520,6 @@ static void test_ActivateKeyboardLayout( char **argv ) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl );
tmp_layout = GetKeyboardLayout( 0 ); - todo_wine_if(layout != other_layout) ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout );
thread = CreateThread( NULL, 0, test_ActivateKeyboardLayout_thread_proc, layout, 0, 0 ); @@ -3528,7 +3528,6 @@ static void test_ActivateKeyboardLayout( char **argv ) CloseHandle( thread );
tmp_layout = GetKeyboardLayout( 0 ); - todo_wine_if(layout != other_layout) ok( tmp_layout == other_layout, "got tmp_layout %p\n", tmp_layout );
/* changing focus is enough for the layout change to take effect */ @@ -3547,11 +3546,10 @@ static void test_ActivateKeyboardLayout( char **argv ) }
if (other_layout == layout) ok( change_hkl == 0, "got change_hkl %p\n", change_hkl ); - else todo_wine ok( change_hkl == layout, "got change_hkl %p\n", change_hkl ); + else ok( change_hkl == layout, "got change_hkl %p\n", change_hkl ); change_hkl = expect_hkl = 0;
tmp_layout = GetKeyboardLayout( 0 ); - todo_wine_if(layout != other_layout) ok( tmp_layout == layout, "got tmp_layout %p\n", tmp_layout );
DestroyWindow( hwnd2 ); diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 9af558ee538..9de8be71a18 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -42,6 +42,8 @@
#define NONAMELESSUNION
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "x11drv.h"
#include "wingdi.h" @@ -68,6 +70,11 @@ struct layout
int xkb_group; char *xkb_layout; + + LANGID lang; + WORD index; + /* "Layout Id", used by NtUserGetKeyboardLayoutName / LoadKeyboardLayoutW */ + WORD layout_id; };
static const unsigned int ControlMask = 1 << 2; @@ -82,20 +89,202 @@ static struct list xkb_layouts = LIST_INIT( xkb_layouts );
static char KEYBOARD_MapDeadKeysym(KeySym keysym);
-static void create_layout_from_xkb( int xkb_group, const char *xkb_layout ) +static inline LANGID langid_from_xkb_layout( const char *layout, size_t layout_len ) { +#define MAKEINDEX(c0, c1) (MAKEWORD(c0, c1) - MAKEWORD('a', 'a')) + static const LANGID langids[] = + { + [MAKEINDEX('a','f')] = MAKELANGID(LANG_DARI, SUBLANG_DEFAULT), + [MAKEINDEX('a','l')] = MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT), + [MAKEINDEX('a','m')] = MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), + [MAKEINDEX('a','t')] = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_AUSTRIAN), + [MAKEINDEX('a','z')] = MAKELANGID(LANG_AZERBAIJANI, SUBLANG_DEFAULT), + [MAKEINDEX('b','a')] = MAKELANGID(LANG_BOSNIAN, SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC), + [MAKEINDEX('b','d')] = MAKELANGID(LANG_BANGLA, SUBLANG_DEFAULT), + [MAKEINDEX('b','e')] = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH_BELGIAN), + [MAKEINDEX('b','g')] = MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT), + [MAKEINDEX('b','r')] = MAKELANGID(LANG_PORTUGUESE, 2), + [MAKEINDEX('b','t')] = MAKELANGID(LANG_TIBETAN, 3), + [MAKEINDEX('b','w')] = MAKELANGID(LANG_TSWANA, SUBLANG_TSWANA_BOTSWANA), + [MAKEINDEX('b','y')] = MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT), + [MAKEINDEX('c','a')] = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_CAN), + [MAKEINDEX('c','d')] = MAKELANGID(LANG_FRENCH, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('c','h')] = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN_SWISS), + [MAKEINDEX('c','m')] = MAKELANGID(LANG_FRENCH, 11), + [MAKEINDEX('c','n')] = MAKELANGID(LANG_CHINESE, SUBLANG_DEFAULT), + [MAKEINDEX('c','z')] = MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), + [MAKEINDEX('d','e')] = MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), + [MAKEINDEX('d','k')] = MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT), + [MAKEINDEX('d','z')] = MAKELANGID(LANG_TAMAZIGHT, SUBLANG_TAMAZIGHT_ALGERIA_LATIN), + [MAKEINDEX('e','e')] = MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT), + [MAKEINDEX('e','s')] = MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), + [MAKEINDEX('e','t')] = MAKELANGID(LANG_AMHARIC, SUBLANG_DEFAULT), + [MAKEINDEX('f','i')] = MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT), + [MAKEINDEX('f','o')] = MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT), + [MAKEINDEX('f','r')] = MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), + [MAKEINDEX('g','b')] = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), + [MAKEINDEX('g','e')] = MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), + [MAKEINDEX('g','h')] = MAKELANGID(LANG_ENGLISH, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('g','n')] = MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), + [MAKEINDEX('g','r')] = MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), + [MAKEINDEX('h','r')] = MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), + [MAKEINDEX('h','u')] = MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT), + [MAKEINDEX('i','d')] = MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), + [MAKEINDEX('i','e')] = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_EIRE), + [MAKEINDEX('i','l')] = MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), + [MAKEINDEX('i','n')] = MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT), + [MAKEINDEX('i','r')] = MAKELANGID(LANG_PERSIAN, SUBLANG_DEFAULT), + [MAKEINDEX('i','s')] = MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), + [MAKEINDEX('i','t')] = MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT), + [MAKEINDEX('j','p')] = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), + [MAKEINDEX('j','v')] = MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), + [MAKEINDEX('k','e')] = MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), + [MAKEINDEX('k','g')] = MAKELANGID(LANG_KYRGYZ, SUBLANG_DEFAULT), + [MAKEINDEX('k','h')] = MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT), + [MAKEINDEX('k','z')] = MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT), + [MAKEINDEX('l','a')] = MAKELANGID(LANG_LAO, SUBLANG_DEFAULT), + [MAKEINDEX('l','k')] = MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT), + [MAKEINDEX('l','t')] = MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT), + [MAKEINDEX('l','v')] = MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT), + [MAKEINDEX('m','a')] = MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_MOROCCO), + [MAKEINDEX('m','d')] = MAKELANGID(LANG_ROMANIAN, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('m','e')] = MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_MONTENEGRO_LATIN), + [MAKEINDEX('m','k')] = MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), + [MAKEINDEX('m','l')] = MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT), + [MAKEINDEX('m','m')] = MAKELANGID(0x55 /*LANG_BURMESE*/, SUBLANG_DEFAULT), + [MAKEINDEX('m','n')] = MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT), + [MAKEINDEX('m','t')] = MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT), + [MAKEINDEX('m','v')] = MAKELANGID(LANG_DIVEHI, SUBLANG_DEFAULT), + [MAKEINDEX('m','y')] = MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), + [MAKEINDEX('n','g')] = MAKELANGID(LANG_ENGLISH, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('n','l')] = MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), + [MAKEINDEX('n','p')] = MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT), + [MAKEINDEX('p','h')] = MAKELANGID(LANG_FILIPINO, SUBLANG_DEFAULT), + [MAKEINDEX('p','k')] = MAKELANGID(LANG_URDU, SUBLANG_DEFAULT), + [MAKEINDEX('p','l')] = MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), + [MAKEINDEX('p','t')] = MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT), + [MAKEINDEX('r','o')] = MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), + [MAKEINDEX('r','s')] = MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_LATIN), + [MAKEINDEX('r','u')] = MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), + [MAKEINDEX('s','e')] = MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT), + [MAKEINDEX('s','i')] = MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT), + [MAKEINDEX('s','k')] = MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), + [MAKEINDEX('s','n')] = MAKELANGID(LANG_WOLOF, SUBLANG_DEFAULT), + [MAKEINDEX('s','y')] = MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), + [MAKEINDEX('t','g')] = MAKELANGID(LANG_FRENCH, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('t','h')] = MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), + [MAKEINDEX('t','j')] = MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT), + [MAKEINDEX('t','m')] = MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT), + [MAKEINDEX('t','r')] = MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), + [MAKEINDEX('t','w')] = MAKELANGID(LANG_CHINESE, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('t','z')] = MAKELANGID(LANG_SWAHILI, SUBLANG_CUSTOM_UNSPECIFIED), + [MAKEINDEX('u','a')] = MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT), + [MAKEINDEX('u','s')] = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + [MAKEINDEX('u','z')] = MAKELANGID(LANG_UZBEK, 2), + [MAKEINDEX('v','n')] = MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT), + [MAKEINDEX('z','a')] = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_SOUTH_AFRICA), + }; + LANGID langid; + + if (layout_len == 2 && (langid = langids[MAKEINDEX(layout[0], layout[1])])) return langid; + if (layout_len == 3 && !memcmp( layout, "ara", layout_len )) return MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT); + if (layout_len == 3 && !memcmp( layout, "epo", layout_len )) return MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT); + if (layout_len == 3 && !memcmp( layout, "mao", layout_len )) return MAKELANGID(LANG_MAORI, SUBLANG_DEFAULT); + if (layout_len == 4 && !memcmp( layout, "brai", layout_len )) return MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_DEFAULT); + if (layout_len == 5 && !memcmp( layout, "latam", layout_len )) return MAKELANGID(LANG_SPANISH, SUBLANG_CUSTOM_UNSPECIFIED); + return MAKELANGID(LANG_NEUTRAL, SUBLANG_CUSTOM_UNSPECIFIED); +#undef MAKEINDEX +}; + +/* wrapper for NtCreateKey that creates the key recursively if necessary */ +static HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len, + DWORD options, DWORD *disposition ) +{ + UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name }; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + HANDLE ret; + + attr.Length = sizeof(attr); + attr.RootDirectory = root; + attr.ObjectName = &nameW; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, options, disposition ); + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + { + static const WCHAR registry_rootW[] = { '\','R','e','g','i','s','t','r','y','\' }; + DWORD pos = 0, i = 0, len = name_len / sizeof(WCHAR); + + /* don't try to create registry root */ + if (!root && len > ARRAY_SIZE(registry_rootW) && + !memcmp( name, registry_rootW, sizeof(registry_rootW) )) + i += ARRAY_SIZE(registry_rootW); + + while (i < len && name[i] != '\') i++; + if (i == len) return 0; + for (;;) + { + unsigned int subkey_options = options; + if (i < len) subkey_options &= ~(REG_OPTION_CREATE_LINK | REG_OPTION_OPEN_LINK); + nameW.Buffer = (WCHAR *)name + pos; + nameW.Length = (i - pos) * sizeof(WCHAR); + status = NtCreateKey( &ret, MAXIMUM_ALLOWED, &attr, 0, NULL, subkey_options, disposition ); + + if (attr.RootDirectory != root) NtClose( attr.RootDirectory ); + if (!NT_SUCCESS(status)) return 0; + if (i == len) break; + attr.RootDirectory = ret; + while (i < len && name[i] == '\') i++; + pos = i; + while (i < len && name[i] != '\') i++; + } + } + return ret; +} + +static BOOL set_reg_value( HKEY hkey, const WCHAR *name, UINT type, const void *value, DWORD count ) +{ + unsigned int name_size = name ? lstrlenW( name ) * sizeof(WCHAR) : 0; + UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name }; + return !NtSetValueKey( hkey, &nameW, 0, type, value, count ); +} + +static void set_reg_ascii_value( HKEY hkey, const char *name, const char *value ) +{ + WCHAR nameW[64], valueW[128]; + asciiz_to_unicode( nameW, name ); + set_reg_value( hkey, nameW, REG_SZ, valueW, asciiz_to_unicode( valueW, value )); +} + +static void create_layout_from_xkb( int xkb_group, const char *xkb_layout, LANGID lang ) +{ + static WCHAR keyboard_layoutsW[] = + { + '\','R','e','g','i','s','t','r','y','\','M','a','c','h','i','n','e','\','S','y','s','t','e','m', + '\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\','C','o','n','t','r','o','l', + '\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s', + }; + static WORD next_layout_id = 1; + struct layout *layout; + WORD index = 0, len; + HKEY hkey, subkey;
- TRACE( "xkb_group %u, xkb_layout %s\n", xkb_group, xkb_layout ); + TRACE( "lang %04x, xkb_group %u, xkb_layout %s\n", lang, 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 ); + TRACE( "Found existing layout entry %p, hkl %04x%04x id %04x\n", + layout, layout->index, layout->lang, layout->layout_id ); layout->xkb_group = xkb_group; return; } + if (layout->lang == lang) index++; }
if (!(layout = calloc( 1, sizeof(*layout) + strlen( xkb_layout ) + 1 ))) @@ -108,7 +297,32 @@ 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; + layout->index = index; + if (index) layout->layout_id = next_layout_id++; + + if ((hkey = reg_create_key( NULL, keyboard_layoutsW, ARRAY_SIZE(keyboard_layoutsW), 0, NULL ))) + { + WCHAR bufferW[MAX_PATH]; + char buffer[MAX_PATH]; + + sprintf( buffer, "%04x%04x", layout->index, layout->lang ); + len = asciiz_to_unicode( bufferW, buffer ) - sizeof(WCHAR); + + if ((subkey = reg_create_key( hkey, bufferW, len, REG_OPTION_VOLATILE, NULL ))) + { + if (layout->layout_id) + { + sprintf( buffer, "%04x", layout->layout_id ); + set_reg_ascii_value( subkey, "Layout Id", buffer ); + } + NtClose( subkey ); + } + + NtClose( hkey ); + } + + TRACE( "Created layout entry %p, hkl %04x%04x id %04x\n", layout, layout->index, layout->lang, layout->layout_id ); }
/* Keyboard translation tables */ @@ -1605,6 +1819,7 @@ static void init_xkb_layouts( Display *display ) const char *next_layout = strchr( layout, ',' ), *next_variant = strchr( variant, ',' ); int layout_len, variant_len; char buffer[1024]; + LANGID lang;
if (!next_layout) next_layout = layout + strlen( layout ); if (!next_variant) next_variant = variant + strlen( variant ); @@ -1612,8 +1827,9 @@ static void init_xkb_layouts( Display *display ) layout_len = next_layout - layout; variant_len = next_variant - variant;
+ lang = langid_from_xkb_layout( layout, layout_len ); snprintf( buffer, ARRAY_SIZE(buffer), "%.*s:%.*s:%s", layout_len, layout, variant_len, variant, options ); - create_layout_from_xkb( i, buffer ); + create_layout_from_xkb( i, buffer, lang );
layout = *next_layout ? next_layout + 1 : layouts; variant = *next_layout ? (*next_variant ? next_variant + 1 : next_variant) : variants;