This adds a new Input tab to winecfg, moving the mouse grab settings there. Then this makes winex11 keyboard layout detection configurable as well, allowing the user to override the keyboard layout detection if for some reason it was incorrect.
This isn't solving anything yet, but I then intend to make keyboard scancode detection configurable as well, and optional.
As I described in https://www.winehq.org/pipermail/wine-devel/2020-October/175641.html, I believe that X11 keyboard keycode to scancode mapping is most of the time a fixed mapping, except in some rare cases.
Trying to detect it from the keyboard layout will never work reliably, especially nowadays where keyboard layouts are completely made up from Linux IME (for instance a GNOME language settings with up to four keyboard layouts translates to a single Xkb mapping using groups for each layout). The X11 keycode are remapped only in some more rarely used implementations, such as XVNC and we should try to detect it only in such cases.
Many Windows applications are depending on accurate scancodes, and making the mapping detection optional (and disabled by default) will solve all the issues we have in the most common case (https://bugs.winehq.org/show_bug.cgi?id=30984, https://bugs.winehq.org/show_bug.cgi?id=45605).
From: Rémi Bernon rbernon@codeweavers.com
--- MAINTAINERS | 1 + programs/winecfg/Makefile.in | 1 + programs/winecfg/input.c | 105 +++++++++++++++++++++++++++++++++++ programs/winecfg/main.c | 12 +++- programs/winecfg/resource.h | 6 +- programs/winecfg/winecfg.h | 4 ++ programs/winecfg/winecfg.rc | 36 +++++++----- programs/winecfg/x11drvdlg.c | 18 +----- 8 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 programs/winecfg/input.c
diff --git a/MAINTAINERS b/MAINTAINERS index 276471287da..fa155217267 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -179,6 +179,7 @@ F: dlls/user32/input.c F: dlls/win32u/input.c F: dlls/win32u/rawinput.c F: server/queue.c +F: programs/winecfg/input.c
Input methods M: Aric Stewart aric@codeweavers.com diff --git a/programs/winecfg/Makefile.in b/programs/winecfg/Makefile.in index 84be34eab10..0deab41954c 100644 --- a/programs/winecfg/Makefile.in +++ b/programs/winecfg/Makefile.in @@ -9,6 +9,7 @@ C_SRCS = \ audio.c \ drive.c \ driveui.c \ + input.c \ libraries.c \ main.c \ theme.c \ diff --git a/programs/winecfg/input.c b/programs/winecfg/input.c new file mode 100644 index 00000000000..115161b9040 --- /dev/null +++ b/programs/winecfg/input.c @@ -0,0 +1,105 @@ +/* + * Copyright 2023 Rémi Bernon for CodeWeavers + * + * 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.1 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include <stdarg.h> +#include <stddef.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "winecfg.h" +#include "resource.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winecfg); + +static BOOL updating_ui; + +static void init_dialog( HWND dialog ) +{ + WCHAR *buffer; + + convert_x11_desktop_key(); + + updating_ui = TRUE; + + buffer = get_reg_key( config_key, keypath( L"X11 Driver" ), L"GrabFullscreen", L"N" ); + if (IS_OPTION_TRUE( *buffer )) CheckDlgButton( dialog, IDC_FULLSCREEN_GRAB, BST_CHECKED ); + else CheckDlgButton( dialog, IDC_FULLSCREEN_GRAB, BST_UNCHECKED ); + free( buffer ); + + updating_ui = FALSE; +} + +static void on_fullscreen_grab_clicked( HWND dialog ) +{ + BOOL checked = IsDlgButtonChecked( dialog, IDC_FULLSCREEN_GRAB ) == BST_CHECKED; + if (checked) set_reg_key( config_key, keypath( L"X11 Driver" ), L"GrabFullscreen", L"Y" ); + else set_reg_key( config_key, keypath( L"X11 Driver" ), L"GrabFullscreen", L"N" ); +} + +INT_PTR CALLBACK InputDlgProc( HWND dialog, UINT message, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "dialog %p, message %#x, wparam %#Ix, lparam %#Ix\n", dialog, message, wparam, lparam ); + + switch (message) + { + case WM_SHOWWINDOW: + set_window_title( dialog ); + break; + + case WM_COMMAND: + switch (HIWORD(wparam)) + { + case BN_CLICKED: + if (updating_ui) break; + SendMessageW( GetParent( dialog ), PSM_CHANGED, 0, 0 ); + switch (LOWORD(wparam)) + { + case IDC_FULLSCREEN_GRAB: on_fullscreen_grab_clicked( dialog ); break; + } + break; + } + break; + + case WM_NOTIFY: + switch (((LPNMHDR)lparam)->code) + { + case PSN_KILLACTIVE: + SetWindowLongPtrW( dialog, DWLP_MSGRESULT, FALSE ); + break; + case PSN_APPLY: + apply(); + SetWindowLongPtrW( dialog, DWLP_MSGRESULT, PSNRET_NOERROR ); + break; + case PSN_SETACTIVE: + init_dialog( dialog ); + break; + case LVN_ITEMCHANGED: + break; + } + break; + case WM_INITDIALOG: + break; + } + + return FALSE; +} diff --git a/programs/winecfg/main.c b/programs/winecfg/main.c index 67df9146f3d..7ab5a71186a 100644 --- a/programs/winecfg/main.c +++ b/programs/winecfg/main.c @@ -58,7 +58,7 @@ PropSheetCallback (HWND hWnd, UINT uMsg, LPARAM lParam) return 0; }
-#define NUM_PROPERTY_PAGES 7 +#define NUM_PROPERTY_PAGES 8
static INT_PTR doPropertySheet (HINSTANCE hInstance, HWND hOwner) @@ -139,6 +139,16 @@ doPropertySheet (HINSTANCE hInstance, HWND hOwner) psp[pg].lParam = 0; pg++;
+ psp[pg].dwSize = sizeof (PROPSHEETPAGEW); + psp[pg].dwFlags = PSP_USETITLE; + psp[pg].hInstance = hInstance; + psp[pg].u.pszTemplate = MAKEINTRESOURCEW (IDD_INPUT_CONFIG); + psp[pg].u2.pszIcon = NULL; + psp[pg].pfnDlgProc = InputDlgProc; + psp[pg].pszTitle = load_string (IDS_TAB_INPUT); + psp[pg].lParam = 0; + pg++; + /* * Fill out the (General) PROPSHEETPAGE data structure * for the property sheet diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h index dd46bc71b40..716f87e0d6f 100644 --- a/programs/winecfg/resource.h +++ b/programs/winecfg/resource.h @@ -45,6 +45,7 @@ #define IDS_SHELL_FOLDER 16 #define IDS_LINKS_TO 17 #define IDS_WINECFG_TITLE_APP 18 /* App specific title */ +#define IDS_TAB_INPUT 19 #define IDI_WINECFG 100 #define IDI_LOGO 102 #define IDD_ABOUTCFG 107 @@ -54,6 +55,7 @@ #define IDD_DLLCFG 111 #define IDD_DRIVECFG 112 #define IDD_DESKTOP_INTEGRATION 115 +#define IDD_INPUT_CONFIG 116 #define IDC_WINVER 1012 #define IDC_DESKTOP_WIDTH 1023 #define IDC_DESKTOP_HEIGHT 1024 @@ -124,7 +126,6 @@ /* graphics */ #define IDC_ENABLE_MANAGED 1100 #define IDC_ENABLE_DECORATED 1101 -#define IDC_FULLSCREEN_GRAB 1102
#define IDC_RES_TRACKBAR 1107 #define IDC_RES_DPIEDIT 1108 @@ -218,3 +219,6 @@ #define IDC_ABT_TITLE_TEXT 8436 #define IDC_ABT_WEB_LINK 8437 #define IDC_ABT_LICENSE_TEXT 8438 + +/* input tab */ +#define IDC_FULLSCREEN_GRAB 1501 diff --git a/programs/winecfg/winecfg.h b/programs/winecfg/winecfg.h index f3f3ad2addf..0c7ed407803 100644 --- a/programs/winecfg/winecfg.h +++ b/programs/winecfg/winecfg.h @@ -74,6 +74,9 @@ WCHAR *keypath(const WCHAR *section); BOOL initialize(HINSTANCE hInstance); extern HKEY config_key;
+/* winex11 registry */ +void convert_x11_desktop_key(void); + /* hack for the property sheet control */ void set_window_title(HWND dialog);
@@ -86,6 +89,7 @@ INT_PTR CALLBACK LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM l INT_PTR CALLBACK AudioDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK ThemeDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK AboutDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK InputDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
/* Windows version management */ BOOL set_winver_from_string(const WCHAR *version); diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc index 8775b3b691b..19332ea0e64 100644 --- a/programs/winecfg/winecfg.rc +++ b/programs/winecfg/winecfg.rc @@ -39,6 +39,7 @@ BEGIN IDS_TAB_DESKTOP_INTEGRATION "Desktop Integration" IDS_TAB_AUDIO "Audio" IDS_TAB_ABOUT "About" + IDS_TAB_INPUT "Input" IDS_WINECFG_TITLE "Wine configuration" IDS_WINECFG_TITLE_APP "Wine configuration for %s" IDS_THEMEFILE "Theme files (*.msstyles; *.theme)" @@ -164,22 +165,21 @@ IDD_GRAPHCFG DIALOG 0, 0, 260, 220 STYLE WS_CHILD | WS_DISABLED FONT 8, "MS Shell Dlg" BEGIN - GROUPBOX "Window settings",IDC_STATIC,8,4,244,84 - CONTROL "Automatically capture the &mouse in full-screen windows",IDC_FULLSCREEN_GRAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,20,230,10 - CONTROL "Allow the window manager to &decorate the windows",IDC_ENABLE_DECORATED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,32,230,10 - CONTROL "Allow the &window manager to control the windows",IDC_ENABLE_MANAGED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,44,230,10 + GROUPBOX "Window settings",IDC_STATIC,8,4,244,72 + CONTROL "Allow the window manager to &decorate the windows",IDC_ENABLE_DECORATED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,20,230,10 + CONTROL "Allow the &window manager to control the windows",IDC_ENABLE_MANAGED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,32,230,10 CONTROL "&Emulate a virtual desktop",IDC_ENABLE_DESKTOP,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,15,56,230,10 - LTEXT "Desktop &size:",IDC_DESKTOP_SIZE,15,70,64,16,WS_DISABLED - LTEXT "#msgctxt#do not translate#X",IDC_DESKTOP_BY,129,70,8,8,WS_DISABLED - EDITTEXT IDC_DESKTOP_WIDTH,84,68,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED - EDITTEXT IDC_DESKTOP_HEIGHT,137,68,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + BS_AUTOCHECKBOX | WS_TABSTOP,15,44,230,10 + LTEXT "Desktop &size:",IDC_DESKTOP_SIZE,15,58,64,16,WS_DISABLED + LTEXT "#msgctxt#do not translate#X",IDC_DESKTOP_BY,129,58,8,8,WS_DISABLED + EDITTEXT IDC_DESKTOP_WIDTH,84,56,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED + EDITTEXT IDC_DESKTOP_HEIGHT,137,56,40,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
- GROUPBOX "Screen resolution",IDC_STATIC,8,95,244,84 - CONTROL "", IDC_RES_TRACKBAR, "msctls_trackbar32",WS_TABSTOP,12,105,171,15 - EDITTEXT IDC_RES_DPIEDIT,188,105,23,13,ES_NUMBER|WS_TABSTOP - LTEXT "#msgctxt#unit: dots/inch#dpi",IDC_STATIC,215,107,30,8 - LTEXT "This is a sample text using 10 point Tahoma",IDC_RES_FONT_PREVIEW,15,124,230,49 + GROUPBOX "Screen resolution",IDC_STATIC,8,83,244,84 + CONTROL "", IDC_RES_TRACKBAR, "msctls_trackbar32",WS_TABSTOP,12,93,171,15 + EDITTEXT IDC_RES_DPIEDIT,188,93,23,13,ES_NUMBER|WS_TABSTOP + LTEXT "#msgctxt#unit: dots/inch#dpi",IDC_STATIC,215,95,30,8 + LTEXT "This is a sample text using 10 point Tahoma",IDC_RES_FONT_PREVIEW,15,112,230,49 END
IDD_DLLCFG DIALOG 0, 0, 260, 220 @@ -310,6 +310,14 @@ BEGIN PUSHBUTTON "B&rowse...",IDC_BROWSE_SFPATH,195,195,50,13,WS_DISABLED END
+IDD_INPUT_CONFIG DIALOG 0, 0, 260, 220 +STYLE WS_CHILD | WS_DISABLED +FONT 8, "MS Shell Dlg" +BEGIN + GROUPBOX "Mouse settings",IDC_STATIC,8,4,244,64 + CONTROL "Automatically capture the &mouse in full-screen windows",IDC_FULLSCREEN_GRAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,20,230,10 +END + LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
/* @makedep: winecfg.ico */ diff --git a/programs/winecfg/x11drvdlg.c b/programs/winecfg/x11drvdlg.c index 215cd6534a2..cd7b7552a1e 100644 --- a/programs/winecfg/x11drvdlg.c +++ b/programs/winecfg/x11drvdlg.c @@ -47,7 +47,7 @@ static const UINT dpi_values[] = { 96, 120, 144, 168, 192, 216, 240, 288, 336, 3 static BOOL updating_ui;
/* convert the x11 desktop key to the new explorer config */ -static void convert_x11_desktop_key(void) +void convert_x11_desktop_key(void) { WCHAR *buf;
@@ -139,13 +139,6 @@ static void init_dialog(HWND dialog) SendDlgItemMessageW(dialog, IDC_DESKTOP_HEIGHT, EM_LIMITTEXT, RES_MAXLEN, 0); }
- buf = get_reg_key(config_key, keypath(L"X11 Driver"), L"GrabFullscreen", L"N"); - if (IS_OPTION_TRUE(*buf)) - CheckDlgButton(dialog, IDC_FULLSCREEN_GRAB, BST_CHECKED); - else - CheckDlgButton(dialog, IDC_FULLSCREEN_GRAB, BST_UNCHECKED); - free(buf); - buf = get_reg_key(config_key, keypath(L"X11 Driver"), L"Managed", L"Y"); if (IS_OPTION_TRUE(*buf)) CheckDlgButton(dialog, IDC_ENABLE_MANAGED, BST_CHECKED); @@ -220,14 +213,6 @@ static void on_enable_decorated_clicked(HWND dialog) { } }
-static void on_fullscreen_grab_clicked(HWND dialog) -{ - if (IsDlgButtonChecked(dialog, IDC_FULLSCREEN_GRAB) == BST_CHECKED) - set_reg_key(config_key, keypath(L"X11 Driver"), L"GrabFullscreen", L"Y"); - else - set_reg_key(config_key, keypath(L"X11 Driver"), L"GrabFullscreen", L"N"); -} - static INT read_logpixels_reg(void) { DWORD dwLogPixels; @@ -383,7 +368,6 @@ GraphDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) case IDC_ENABLE_DESKTOP: on_enable_desktop_clicked(hDlg); break; case IDC_ENABLE_MANAGED: on_enable_managed_clicked(hDlg); break; case IDC_ENABLE_DECORATED: on_enable_decorated_clicked(hDlg); break; - case IDC_FULLSCREEN_GRAB: on_fullscreen_grab_clicked(hDlg); break; } break; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/x11drv_main.c | 67 ++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-)
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 797e4f92d38..e04bdedd43a 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -356,11 +356,61 @@ HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len ) return NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 ) ? 0 : ret; }
+/* 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;
-HKEY open_hkcu_key( const char *name ) + 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 HKEY reg_open_hkcu_key( const char *name, BOOL create ) { WCHAR bufferW[256]; static HKEY hkcu; + DWORD disp; + HKEY key;
if (!hkcu) { @@ -385,7 +435,18 @@ HKEY open_hkcu_key( const char *name ) hkcu = reg_open_key( NULL, bufferW, len * sizeof(WCHAR) ); }
- return reg_open_key( hkcu, bufferW, asciiz_to_unicode( bufferW, name ) - sizeof(WCHAR) ); + if ((key = reg_open_key( hkcu, bufferW, asciiz_to_unicode( bufferW, name ) - sizeof(WCHAR) )) || !create) return key; + return reg_create_key( hkcu, bufferW, asciiz_to_unicode( bufferW, name ) - sizeof(WCHAR), 0, &disp ); +} + +HKEY open_hkcu_key( const char *name ) +{ + return reg_open_hkcu_key( name, FALSE ); +} + +static HKEY create_hkcu_key( const char *name ) +{ + return reg_open_hkcu_key( name, TRUE ); }
@@ -449,7 +510,7 @@ static void setup_options(void) DWORD len;
/* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */ - hkey = open_hkcu_key( "Software\Wine\X11 Driver" ); + hkey = create_hkcu_key( "Software\Wine\X11 Driver" );
/* open the app-specific key */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/keyboard.c | 21 +++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 4 ++++ dlls/winex11.drv/x11drv_main.c | 17 +++++++++++++++++ 3 files changed, 42 insertions(+)
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index f1ad4b01669..187979c4494 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1089,6 +1089,27 @@ static const WORD xfree86_vendor_key_vkey[256] = 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */ };
+WCHAR *x11drv_get_keyboard_layout_list( DWORD *length ) +{ + WCHAR *tmp, *layouts = calloc( 1, sizeof(WCHAR) ); + int i; + + for (i = 0, *length = 1; main_key_tab[i].comment; i++) + { + const char *name = main_key_tab[i].comment; + int len = strlen( name ) + 1; + + if (!(tmp = realloc( layouts, (*length + len) * sizeof(WCHAR) ))) return layouts; + layouts = tmp; + + asciiz_to_unicode( layouts + *length - 1, name ); + layouts[*length + len - 1] = 0; + (*length) += len; + } + + return layouts; +} + static inline KeySym keycode_to_keysym( Display *display, KeyCode keycode, int index ) { #ifdef HAVE_XKB diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 4997367ce9a..21fd16a5393 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -709,6 +709,10 @@ extern BOOL xinerama_get_fullscreen_monitors( const RECT *rect, long *indices ) extern void xinerama_init( unsigned int width, unsigned int height ) DECLSPEC_HIDDEN; extern void init_recursive_mutex( pthread_mutex_t *mutex ) DECLSPEC_HIDDEN;
+/* keyboard.c */ + +extern WCHAR *x11drv_get_keyboard_layout_list( DWORD *size ) DECLSPEC_HIDDEN; + #define DEPTH_COUNT 3 extern const unsigned int *depths DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index e04bdedd43a..66dbc3c8270 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -449,6 +449,19 @@ static HKEY create_hkcu_key( const char *name ) return reg_open_hkcu_key( name, TRUE ); }
+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_string_value( HKEY hkey, const char *name, const WCHAR *value, DWORD count ) +{ + WCHAR nameW[64]; + asciiz_to_unicode( nameW, name ); + set_reg_value( hkey, nameW, REG_MULTI_SZ, value, count ); +}
ULONG query_reg_value( HKEY hkey, const WCHAR *name, KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size ) { @@ -567,6 +580,10 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "GrabFullscreen", buffer, sizeof(buffer) )) grab_fullscreen = IS_OPTION_TRUE( buffer[0] );
+ p = x11drv_get_keyboard_layout_list( &len ); + if (p) set_reg_string_value( hkey, "KeyboardLayoutList", p, len * sizeof(WCHAR) ); + free( p ); + if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) )) default_visual.depth = wcstol( buffer, NULL, 0 );
From: Rémi Bernon rbernon@codeweavers.com
--- programs/winecfg/input.c | 48 ++++++++++++++++++++++++++++++++++++- programs/winecfg/resource.h | 3 +++ programs/winecfg/winecfg.rc | 9 +++++++ 3 files changed, 59 insertions(+), 1 deletion(-)
diff --git a/programs/winecfg/input.c b/programs/winecfg/input.c index 115161b9040..f2f035df80f 100644 --- a/programs/winecfg/input.c +++ b/programs/winecfg/input.c @@ -35,7 +35,9 @@ static BOOL updating_ui;
static void init_dialog( HWND dialog ) { - WCHAR *buffer; + WCHAR auto_detect_layout[256]; + WCHAR *buffer, *layout; + HWND layouts;
convert_x11_desktop_key();
@@ -46,6 +48,23 @@ static void init_dialog( HWND dialog ) else CheckDlgButton( dialog, IDC_FULLSCREEN_GRAB, BST_UNCHECKED ); free( buffer );
+ layouts = GetDlgItem( dialog, IDC_KEYBOARD_LAYOUT ); + LoadStringW( GetModuleHandleW( NULL ), IDS_INPUT_AUTO_DETECT_LAYOUT, auto_detect_layout, + ARRAY_SIZE(auto_detect_layout) ); + + SendMessageW( layouts, CB_RESETCONTENT, 0, 0 ); + SendMessageW( layouts, CB_ADDSTRING, 0, (LPARAM)auto_detect_layout ); + + buffer = get_reg_key( config_key, keypath( L"X11 Driver" ), L"KeyboardLayoutList", L"" ); + for (layout = buffer; *layout; layout += wcslen( layout ) + 1) + SendMessageW( layouts, CB_ADDSTRING, 0, (LPARAM)layout ); + free( buffer ); + + buffer = get_reg_key( config_key, keypath( L"X11 Driver" ), L"KeyboardLayout", L"" ); + if (!buffer || !buffer[0]) SendMessageW( layouts, CB_SETCURSEL, 0, 0 ); + else SendMessageW( layouts, CB_SELECTSTRING, -1, (LPARAM)buffer ); + free( buffer ); + updating_ui = FALSE; }
@@ -56,6 +75,24 @@ static void on_fullscreen_grab_clicked( HWND dialog ) else set_reg_key( config_key, keypath( L"X11 Driver" ), L"GrabFullscreen", L"N" ); }
+static void on_keyboard_layout_changed( HWND dialog ) +{ + int len, index; + WCHAR *buffer; + + if (!(index = SendMessageW( GetDlgItem( dialog, IDC_KEYBOARD_LAYOUT ), CB_GETCURSEL, 0, 0 ))) + set_reg_key( config_key, keypath( L"X11 Driver" ), L"KeyboardLayout", L"" ); + else + { + len = SendMessageW( GetDlgItem( dialog, IDC_KEYBOARD_LAYOUT ), CB_GETLBTEXTLEN, index, 0 ) + 1; + if (!(buffer = malloc( len * sizeof(WCHAR) ))) return; + + SendMessageW( GetDlgItem( dialog, IDC_KEYBOARD_LAYOUT ), CB_GETLBTEXT, index, (LPARAM)buffer ); + set_reg_key( config_key, keypath( L"X11 Driver" ), L"KeyboardLayout", buffer ); + free( buffer ); + } +} + INT_PTR CALLBACK InputDlgProc( HWND dialog, UINT message, WPARAM wparam, LPARAM lparam ) { TRACE( "dialog %p, message %#x, wparam %#Ix, lparam %#Ix\n", dialog, message, wparam, lparam ); @@ -77,6 +114,15 @@ INT_PTR CALLBACK InputDlgProc( HWND dialog, UINT message, WPARAM wparam, LPARAM case IDC_FULLSCREEN_GRAB: on_fullscreen_grab_clicked( dialog ); break; } break; + + case CBN_SELCHANGE: + if (updating_ui) break; + SendMessageW( GetParent( dialog ), PSM_CHANGED, 0, 0 ); + switch (LOWORD(wparam)) + { + case IDC_KEYBOARD_LAYOUT: on_keyboard_layout_changed( dialog ); break; + } + break; } break;
diff --git a/programs/winecfg/resource.h b/programs/winecfg/resource.h index 716f87e0d6f..276c5344bfd 100644 --- a/programs/winecfg/resource.h +++ b/programs/winecfg/resource.h @@ -222,3 +222,6 @@
/* input tab */ #define IDC_FULLSCREEN_GRAB 1501 +#define IDC_KEYBOARD_LAYOUT 1502 + +#define IDS_INPUT_AUTO_DETECT_LAYOUT 8501 diff --git a/programs/winecfg/winecfg.rc b/programs/winecfg/winecfg.rc index 19332ea0e64..d84bd783629 100644 --- a/programs/winecfg/winecfg.rc +++ b/programs/winecfg/winecfg.rc @@ -129,6 +129,11 @@ BEGIN IDC_SYSPARAMS_MENUBAR "Menu Bar" END
+STRINGTABLE +BEGIN + IDS_INPUT_AUTO_DETECT_LAYOUT "(Auto detect)" +END + IDD_ABOUTCFG DIALOGEX 0, 0, 260, 220 STYLE WS_CHILD FONT 8, "MS Shell Dlg" @@ -316,6 +321,10 @@ FONT 8, "MS Shell Dlg" BEGIN GROUPBOX "Mouse settings",IDC_STATIC,8,4,244,64 CONTROL "Automatically capture the &mouse in full-screen windows",IDC_FULLSCREEN_GRAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,20,230,10 + + GROUPBOX "Keyboard settings",IDC_STATIC,8,70,244,64 + LTEXT "&Layout:",IDC_STATIC,15,82,230,8 + COMBOBOX IDC_KEYBOARD_LAYOUT,110,80,135,60,CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_SORT | WS_VSCROLL | WS_TABSTOP END
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/keyboard.c | 33 +++++++++++++++++++++++++++------ dlls/winex11.drv/x11drv.h | 2 ++ dlls/winex11.drv/x11drv_main.c | 4 ++++ 3 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 187979c4494..26548c9256e 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -934,7 +934,6 @@ static const struct {
{0, NULL, NULL, NULL, NULL} /* sentinel */ }; -static unsigned kbd_layout=0; /* index into above table of layouts */
/* maybe more of these scancodes should be extended? */ /* extended must be set for ALT_R, CTRL_R, @@ -1089,6 +1088,26 @@ static const WORD xfree86_vendor_key_vkey[256] = 0, 0, 0, 0, 0, 0, 0, 0 /* 1008FFF8 */ };
+int x11drv_find_keyboard_layout( const WCHAR *layout ) +{ + int i, len; + char *tmp; + + len = lstrlenW( layout ); + if (!(tmp = malloc( len * 3 + 1 ))) return -1; + ntdll_wcstoumbs( layout, len + 1, tmp, len * 3 + 1, FALSE ); + + for (i = 0; main_key_tab[i].comment; i++) + { + const char *name = main_key_tab[i].comment; + if (!strcmp( name, tmp )) break; + } + free( tmp ); + + if (!main_key_tab[i].comment) return -1; + return i; +} + WCHAR *x11drv_get_keyboard_layout_list( DWORD *length ) { WCHAR *tmp, *layouts = calloc( 1, sizeof(WCHAR) ); @@ -1442,11 +1461,11 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) * whichever matches most closely. * kbd_section must be held. */ -static void +static int X11DRV_KEYBOARD_DetectLayout( Display *display ) { unsigned current, match, mismatch, seq, i, syms; - int score, keyc, key, pkey, ok; + int score, keyc, key, pkey, ok, kbd_layout = 0; KeySym keysym = 0; const char (*lkey)[MAIN_LEN][4]; unsigned max_seq = 0; @@ -1546,6 +1565,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) main_key_tab[kbd_layout].comment);
TRACE("detected layout is "%s"\n", main_key_tab[kbd_layout].comment); + return kbd_layout; }
static HKL get_locale_kbd_layout(void) @@ -1614,7 +1634,7 @@ void X11DRV_InitKeyboard( Display *display ) { 0x41, 0x5a }, /* VK_A - VK_Z */ { 0, 0 } }; - int vkey_range; + int vkey_range, kbd_layout;
pthread_mutex_lock( &kbd_mutex ); XDisplayKeycodes(display, &min_keycode, &max_keycode); @@ -1648,8 +1668,9 @@ void X11DRV_InitKeyboard( Display *display ) } XFreeModifiermap(mmp);
- /* Detect the keyboard layout */ - X11DRV_KEYBOARD_DetectLayout( display ); + /* use the configured layout from registry or auto detect it */ + kbd_layout = keyboard_layout; + if (kbd_layout == -1) kbd_layout = X11DRV_KEYBOARD_DetectLayout( display ); lkey = main_key_tab[kbd_layout].key; syms = (keysyms_per_keycode > 4) ? 4 : keysyms_per_keycode;
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 21fd16a5393..1166168f34d 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -443,6 +443,7 @@ extern BOOL use_system_cursors DECLSPEC_HIDDEN; extern BOOL show_systray DECLSPEC_HIDDEN; extern BOOL grab_pointer DECLSPEC_HIDDEN; extern BOOL grab_fullscreen DECLSPEC_HIDDEN; +extern int keyboard_layout DECLSPEC_HIDDEN; extern BOOL usexcomposite DECLSPEC_HIDDEN; extern BOOL managed_mode DECLSPEC_HIDDEN; extern BOOL decorated_mode DECLSPEC_HIDDEN; @@ -711,6 +712,7 @@ extern void init_recursive_mutex( pthread_mutex_t *mutex ) DECLSPEC_HIDDEN;
/* keyboard.c */
+extern int x11drv_find_keyboard_layout( const WCHAR *layout ) DECLSPEC_HIDDEN; extern WCHAR *x11drv_get_keyboard_layout_list( DWORD *size ) DECLSPEC_HIDDEN;
#define DEPTH_COUNT 3 diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 66dbc3c8270..dc2eb716d0b 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -79,6 +79,7 @@ BOOL use_system_cursors = TRUE; BOOL show_systray = TRUE; BOOL grab_pointer = TRUE; BOOL grab_fullscreen = FALSE; +int keyboard_layout = -1; BOOL managed_mode = TRUE; BOOL decorated_mode = TRUE; BOOL private_color_map = FALSE; @@ -580,6 +581,9 @@ static void setup_options(void) if (!get_config_key( hkey, appkey, "GrabFullscreen", buffer, sizeof(buffer) )) grab_fullscreen = IS_OPTION_TRUE( buffer[0] );
+ if (!get_config_key( hkey, appkey, "KeyboardLayout", buffer, sizeof(buffer) )) + keyboard_layout = x11drv_find_keyboard_layout( buffer ); + p = x11drv_get_keyboard_layout_list( &len ); if (p) set_reg_string_value( hkey, "KeyboardLayoutList", p, len * sizeof(WCHAR) ); free( p );
Fwiw this only exposes the winex11 keyboard layout to winecfg, I think this is pretty harmless. Is it something we don't want to do for some reason?
This merge request was closed by Rémi Bernon.