[PATCH v9 0/6] MR10963: winex11: Keyboard layouts rework, part 3
-- v9: user32/tests: Add more key map tests. user32/tests: Add more key names tests. user32/tests: Add a SendInput VK_PAUSE test. winex11: Support fixed X11 keycode to scancode conversion. win32u: Fixup PAUSE, NUMLOCK scancodes. winex11: Use scancode high bit to set KEYEVENTF_EXTENDEDKEY flag. https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
From: Rémi Bernon <rbernon@codeweavers.com> Apparently X11DRV_KeymapNotify() was checking the wrong bit. Fixes: 2bfe81e41f93ce75139e3a6a2d0b68eb2dcb8fa6 --- dlls/winex11.drv/keyboard.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 3d5d2c81f03..28d0f216907 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1339,7 +1339,7 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) if (!keys[vkey & 0xff].vkey) { keys[vkey & 0xff].vkey = vkey; - keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; + keys[vkey & 0xff].scan = keyc2scan[keycode]; } if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE; @@ -1374,7 +1374,7 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) { TRACE( "Sending KEYUP for a modifier %#.2x\n", vkey); flags = KEYEVENTF_KEYUP; - if (keys[vkey].vkey & 0x1000) flags |= KEYEVENTF_EXTENDEDKEY; + if (keys[vkey].scan & 0x100) flags |= KEYEVENTF_EXTENDEDKEY; X11DRV_send_keyboard_input( keymapnotify_hwnd, vkey, keys[vkey].scan, flags, NtGetTickCount() ); } @@ -1461,7 +1461,7 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) char buf[24]; char *Str = buf; KeySym keysym = 0; - WORD vkey = 0, bScan; + WORD vkey = 0, scan; DWORD dwFlags; int ascii_chars; XIC xic = X11DRV_get_ic( hwnd ); @@ -1528,10 +1528,10 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) vkey = EVENT_event_to_vkey(xic,event); /* X returns keycode 0 for composed characters */ if (!vkey && ascii_chars) vkey = VK_NONAME; - bScan = keyc2scan[event->keycode] & 0xFF; + scan = keyc2scan[event->keycode]; - TRACE_(key)("keycode %u converted to vkey 0x%X scan %02x\n", - event->keycode, vkey, bScan); + TRACE_(key)("keycode %u converted to vkey 0x%X scan %04x\n", + event->keycode, vkey, scan); pthread_mutex_unlock( &kbd_mutex ); @@ -1539,11 +1539,11 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) dwFlags = 0; if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP; - if ( vkey & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY; + if ( scan & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY; update_lock_state( hwnd, vkey, event->state, event_time ); - X11DRV_send_keyboard_input( hwnd, vkey & 0xff, bScan, dwFlags, event_time ); + X11DRV_send_keyboard_input( hwnd, vkey & 0xff, scan & 0xff, dwFlags, event_time ); return TRUE; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/win32u/input.c | 9 +++++++++ dlls/win32u/message.c | 2 +- dlls/win32u/win32u_private.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 733eb604fdc..adfbe306643 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1235,6 +1235,15 @@ USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ) return vkey; } +USHORT fixup_scancode( USHORT scan ) +{ + /* PAUSE, NUMLOCK are special */ + if (scan == 0x21d) scan = 0x45; + else if (scan == 0x45) scan = 0x145; + return scan; +} + + /**************************************************************************** * NtUserGetKeyNameText (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 1428ff586f4..521430ef78f 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3946,7 +3946,7 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA if (input->ki.dwFlags & KEYEVENTF_EXTENDEDKEY) scan |= 0xe000; } req->input.kbd.vkey = map_scan_to_kbd_vkey( scan, layout ); - req->input.kbd.scan = input->ki.wScan & 0xff; + req->input.kbd.scan = fixup_scancode( input->ki.wScan & 0xff ); } else { diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index be303ae4d13..a731fa8b18c 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -111,6 +111,7 @@ extern void update_current_mouse_window( HWND hwnd, INT hittest, POINT pos ); extern BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ); extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ); extern USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ); +extern USHORT fixup_scancode( USHORT scan ); /* menu.c */ extern UINT draw_nc_menu_bar( HDC hdc, RECT *rect, HWND hwnd ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
From: Rémi Bernon <rbernon@codeweavers.com> X11 keycodes are just Linux keycodes + 8 nowadays according to evdev or libinput drivers, and we can avoid inaccurate reconstruction in the most common case. This adds a dependency on linux/input.h or dev/evdev/input.h, on Linux and FreeBSD respectively. Add special handling for PAUSE, BREAK, NUMLOCK where necessary. --- configure.ac | 3 +- dlls/dinput/tests/device8.c | 2 +- dlls/winex11.drv/keyboard.c | 386 ++++++++++++++++++------------------ 3 files changed, 194 insertions(+), 197 deletions(-) diff --git a/configure.ac b/configure.ac index d597bad3750..b4bce551906 100644 --- a/configure.ac +++ b/configure.ac @@ -731,7 +731,8 @@ AC_CHECK_HEADERS(\ asm/termbits.h \ asm/types.h \ asm/user.h \ - bluetooth/bluetooth.h \ + bluetooth/bluetooth.h \ + dev/evdev/input.h \ elf.h \ gettext-po.h \ link.h \ diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c index 37ed9428561..e1a96558ad5 100644 --- a/dlls/dinput/tests/device8.c +++ b/dlls/dinput/tests/device8.c @@ -2486,7 +2486,7 @@ static void test_scan_codes( IDirectInputDevice8W *device, HANDLE event, HWND hw hr = IDirectInputDevice8_GetProperty( device, DIPROP_SCANCODE, &prop_dword.diph ); if (!map[j].found) - todo_wine ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_SCANCODE returned %#lx\n", hr ); + ok( hr == DIERR_NOTFOUND, "GetProperty DIPROP_SCANCODE returned %#lx\n", hr ); else if (version < 0x0800) ok( hr == DIERR_UNSUPPORTED, "GetProperty DIPROP_SCANCODE returned %#lx\n", hr ); else diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 28d0f216907..fcac0f63d55 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -57,6 +57,12 @@ #include "wine/debug.h" #include "wine/list.h" +#ifdef HAVE_LINUX_INPUT_H +#include <linux/input.h> +#elif defined HAVE_DEV_EVDEV_INPUT_H +#include <dev/evdev/input.h> +#endif + /* log format (add 0-padding as appropriate): keycode %u as in output from xev keysym %lx as in X11/keysymdef.h @@ -81,7 +87,107 @@ struct layout static const unsigned int ControlMask = 1 << 2; static int min_keycode, max_keycode, keysyms_per_keycode; -static WORD keyc2vkey[256], keyc2scan[256]; +static WORD keyc2vkey[256]; + +#ifndef KEY_KPDOT +#define KEY_KPDOT 83 +#endif + +static WORD keyc2scan( unsigned int keycode, unsigned int state ) +{ + unsigned int key = keycode - 8; + + /* base keys can be mapped directly */ + if (key <= KEY_KPDOT) return key; + +#ifdef KEY_SYSRQ + /* map keys found in KBDTABLES definitions (Txx Xxx Yxx macros) */ + switch (key) + { + case 84 /* ISO_Level3_Shift */: return 0x005a; /* T5A / VK_OEM_WSCTRL */ + case KEY_SYSRQ: return 0x0054; /* T54 / VK_SNAPSHOT */ + case KEY_102ND: return 0x0056; /* T56 / VK_OEM_102 */ + case KEY_F11: return 0x0057; /* T57 / VK_F11 */ + case KEY_F12: return 0x0058; /* T58 / VK_F12 */ + case KEY_LINEFEED: return 0x0059; /* T59 / VK_CLEAR */ + case KEY_EXIT: return 0x005b; /* T5B / VK_OEM_FINISH */ + case KEY_OPEN: return 0x005c; /* T5C / VK_OEM_JUMP */ + /* FIXME: map a KEY to T5D / VK_EREOF */ + /* FIXME: map a KEY to T5E / VK_OEM_BACKTAB */ + case KEY_COMPOSE: return 0x005f; /* T5F / VK_OEM_AUTO */ + case KEY_SCALE: return 0x0062; /* T62 / VK_ZOOM */ + case KEY_HELP: return 0x0063; /* T63 / VK_HELP */ + case KEY_F13: return 0x0064; /* T64 / VK_F13 */ + case KEY_F14: return 0x0065; /* T65 / VK_F14 */ + case KEY_F15: return 0x0066; /* T66 / VK_F15 */ + case KEY_F16: return 0x0067; /* T67 / VK_F16 */ + case KEY_F17: return 0x0068; /* T68 / VK_F17 */ + case KEY_F18: return 0x0069; /* T69 / VK_F18 */ + case KEY_F19: return 0x006a; /* T6A / VK_F19 */ + case KEY_F20: return 0x006b; /* T6B / VK_F20 */ + case KEY_F21: return 0x006c; /* T6C / VK_F21 */ + case KEY_F22: return 0x006d; /* T6D / VK_F22 */ + case KEY_F23: return 0x006e; /* T6E / VK_F23 */ + /* FIXME: map a KEY to T6F / VK_OEM_PA3 */ + case KEY_COMPUTER: return 0x0071; /* T71 / VK_OEM_RESET */ + /* FIXME: map a KEY to T73 / VK_ABNT_C1 */ + case KEY_F24: return 0x0076; /* T76 / VK_F24 */ + case KEY_KPPLUSMINUS: return 0x007b; /* T7B / VK_OEM_PA1 */ + /* FIXME: map a KEY to T7C / VK_TAB */ + /* FIXME: map a KEY to T7E / VK_ABNT_C2 */ + /* FIXME: map a KEY to T7F / VK_OEM_PA2 */ + case KEY_PREVIOUSSONG: return 0x0110; /* X10 / VK_MEDIA_PREV_TRACK */ + case KEY_NEXTSONG: return 0x0119; /* X19 / VK_MEDIA_NEXT_TRACK */ + case KEY_KPENTER: return 0x011c; /* X1C / VK_RETURN */ + case KEY_RIGHTCTRL: return 0x011d; /* X1D / VK_RCONTROL */ + case KEY_MUTE: return 0x0120; /* X20 / VK_VOLUME_MUTE */ + case KEY_PROG2: return 0x0121; /* X21 / VK_LAUNCH_APP2 */ + case KEY_PLAYPAUSE: return 0x0122; /* X22 / VK_MEDIA_PLAY_PAUSE */ + case KEY_STOPCD: return 0x0124; /* X24 / VK_MEDIA_STOP */ + case KEY_VOLUMEDOWN: return 0x012e; /* X2E / VK_VOLUME_DOWN */ + case KEY_VOLUMEUP: return 0x0130; /* X30 / VK_VOLUME_UP */ + case KEY_HOMEPAGE: return 0x0132; /* X32 / VK_BROWSER_HOME */ + case KEY_KPSLASH: return 0x0135; /* X35 / VK_DIVIDE */ + case KEY_PRINT: return 0x0137; /* X37 / VK_SNAPSHOT */ + case KEY_RIGHTALT: return 0x0138; /* X38 / VK_RMENU */ + case KEY_CANCEL: return 0x0146; /* X46 / VK_CANCEL */ + case KEY_HOME: return 0x0147; /* X47 / VK_HOME */ + case KEY_UP: return 0x0148; /* X48 / VK_UP */ + case KEY_PAGEUP: return 0x0149; /* X49 / VK_PRIOR */ + case KEY_LEFT: return 0x014b; /* X4B / VK_LEFT */ + case KEY_RIGHT: return 0x014d; /* X4D / VK_RIGHT */ + case KEY_END: return 0x014f; /* X4F / VK_END */ + case KEY_DOWN: return 0x0150; /* X50 / VK_DOWN */ + case KEY_PAGEDOWN: return 0x0151; /* X51 / VK_NEXT */ + case KEY_INSERT: return 0x0152; /* X52 / VK_INSERT */ + case KEY_DELETE: return 0x0153; /* X53 / VK_DELETE */ + case KEY_LEFTMETA: return 0x015b; /* X5B / VK_LWIN */ + case KEY_RIGHTMETA: return 0x015c; /* X5C / VK_RWIN */ + case KEY_MENU: return 0x015d; /* X5D / VK_APPS */ + case KEY_POWER: return 0x015e; /* X5E / VK_POWER */ + case KEY_SLEEP: return 0x015f; /* X5F / VK_SLEEP */ + case KEY_FIND: return 0x0165; /* X65 / VK_BROWSER_SEARCH */ + case KEY_BOOKMARKS: return 0x0166; /* X66 / VK_BROWSER_FAVORITES */ + case KEY_REFRESH: return 0x0167; /* X67 / VK_BROWSER_REFRESH */ + case KEY_STOP: return 0x0168; /* X68 / VK_BROWSER_STOP */ + case KEY_FORWARD: return 0x0169; /* X69 / VK_BROWSER_FORWARD */ + case KEY_BACK: return 0x016a; /* X6A / VK_BROWSER_BACK */ + case KEY_PROG1: return 0x016b; /* X6B / VK_LAUNCH_APP1 */ + case KEY_MAIL: return 0x016c; /* X6C / VK_LAUNCH_MAIL */ + case KEY_MEDIA: return 0x016d; /* X6D / VK_LAUNCH_MEDIA_SELECT */ + case KEY_PAUSE: + if (state & ControlMask) + return 0x0146; /* X46 / VK_CANCEL */ + else + return 0x021d; /* Y1D / VK_PAUSE */ + } +#else + FIXME("evdev keycodes not available, scancode mapping is going to be broken\n"); +#endif + + /* otherwise just make up some extended scancode */ + return 0x200 | (key & 0x7f); +} static int NumLockMask, ScrollLockMask, AltGrMask; /* mask in the XKeyEvent state */ @@ -179,46 +285,6 @@ static void create_layout_from_xkb( int xkb_group, const char *xkb_layout, LANGI /* Keyboard translation tables */ #define MAIN_LEN 49 -static const WORD main_key_scan_qwerty[MAIN_LEN] = -{ -/* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */ - /* ` 1 2 3 4 5 6 7 8 9 0 - = */ - 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, - /* q w e r t y u i o p [ ] */ - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B, - /* a s d f g h j k l ; ' \ */ - 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B, - /* z x c v b n m , . / */ - 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35, - 0x56 /* the 102nd key (actually to the right of l-shift) */ -}; - -static const WORD main_key_scan_abnt_qwerty[MAIN_LEN] = -{ - /* ` 1 2 3 4 5 6 7 8 9 0 - = */ - 0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, - /* q w e r t y u i o p [ ] */ - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B, - /* a s d f g h j k l ; ' \ */ - 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B, - /* \ z x c v b n m , . / */ - 0x5e,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35, - 0x56, /* the 102nd key (actually to the right of l-shift) */ -}; - -static const WORD main_key_scan_qwerty_jp106[MAIN_LEN] = -{ - /* 1 2 3 4 5 6 7 8 9 0 - ^ \ (Yen) */ - 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x7D, - /* q w e r t y u i o p @ [ */ - 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B, - /* a s d f g h j k l ; : ] */ - 0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B, - /* z x c v b n m , . / \ (Underscore) */ - 0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x73 -}; - - static const WORD main_key_vkey_qwerty[MAIN_LEN] = { /* NOTE: this layout must concur with the scan codes layout above */ @@ -936,13 +1002,6 @@ static const char main_key_th[MAIN_LEN][4] = }; /*** VNC keyboard layout */ -static const WORD main_key_scan_vnc[MAIN_LEN] = -{ - 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x1A,0x1B,0x27,0x28,0x29,0x33,0x34,0x35,0x2B, - 0x1E,0x30,0x2E,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18,0x19,0x10,0x13,0x1F,0x14,0x16,0x2F,0x11,0x2D,0x15,0x2C, - 0x56 -}; - static const WORD main_key_vkey_vnc[MAIN_LEN] = { '1','2','3','4','5','6','7','8','9','0',VK_OEM_MINUS,VK_OEM_PLUS,VK_OEM_4,VK_OEM_6,VK_OEM_1,VK_OEM_7,VK_OEM_3,VK_OEM_COMMA,VK_OEM_PERIOD,VK_OEM_2,VK_OEM_5, @@ -974,76 +1033,74 @@ static const struct { in the appropriate dlls/kernel/nls/.nls file */ const char *comment; 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}, - /* Dvorak users tend to run QWERTY keyboards and rely on Windows/X11/Wayland to translate to the correct keysyms */ - {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_scan_qwerty, &main_key_vkey_dvorak}, - {0x0409, "United States keyboard layout (programmer dvorak)", &main_key_US_programmer_dvorak, &main_key_scan_qwerty, &main_key_vkey_dvorak}, - {0x0409, "United States keyboard layout (dvorak with phantom key)", &main_key_US_dvorak_phantom, &main_key_scan_qwerty, &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}, - {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}, - {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}, - {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 */ - {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 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 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 and Czech keyboard layout without dead keys", &main_key_SK_prog, &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}, - {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, "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}, - - {0, NULL, NULL, NULL, NULL} /* sentinel */ + {0x0409, "United States keyboard layout", &main_key_US, &main_key_vkey_qwerty}, + {0x0409, "United States keyboard layout (phantom key version)", &main_key_US_phantom, &main_key_vkey_qwerty}, + {0x0409, "United States keyboard layout (dvorak)", &main_key_US_dvorak, &main_key_vkey_dvorak}, + {0x0409, "United States keyboard layout (programmer dvorak)", &main_key_US_programmer_dvorak, &main_key_vkey_dvorak}, + {0x0409, "United States keyboard layout (dvorak with phantom key)", &main_key_US_dvorak_phantom, &main_key_vkey_dvorak}, + {0x0409, "United States International keyboard layout", &main_key_US_intl, &main_key_vkey_qwerty}, + {0x0809, "British keyboard layout", &main_key_UK, &main_key_vkey_qwerty}, + {0x0407, "German keyboard layout", &main_key_DE, &main_key_vkey_qwertz}, + {0x0807, "Swiss German keyboard layout", &main_key_SG, &main_key_vkey_qwertz}, + {0x100c, "Swiss French keyboard layout", &main_key_SF, &main_key_vkey_qwertz}, + {0x041d, "Swedish keyboard layout", &main_key_SE, &main_key_vkey_qwerty_v2}, + {0x0425, "Estonian keyboard layout", &main_key_ET, &main_key_vkey_qwerty}, + {0x0414, "Norwegian keyboard layout", &main_key_NO, &main_key_vkey_qwerty}, + {0x0406, "Danish keyboard layout", &main_key_DA, &main_key_vkey_qwerty}, + {0x040c, "French keyboard layout", &main_key_FR, &main_key_vkey_azerty}, + {0x0c0c, "Canadian French keyboard layout", &main_key_CF, &main_key_vkey_qwerty}, + {0x0c0c, "Canadian French keyboard layout (CA_fr)", &main_key_CA_fr, &main_key_vkey_qwerty}, + {0x0c0c, "Canadian keyboard layout", &main_key_CA, &main_key_vkey_qwerty}, + {0x080c, "Belgian keyboard layout", &main_key_BE, &main_key_vkey_azerty}, + {0x0816, "Portuguese keyboard layout", &main_key_PT, &main_key_vkey_qwerty}, + {0x0416, "Brazilian ABNT-2 keyboard layout", &main_key_PT_br, &main_key_vkey_abnt_qwerty}, + {0x0416, "Brazilian ABNT-2 keyboard layout ALT GR", &main_key_PT_br_alt_gr,&main_key_vkey_abnt_qwerty}, + {0x040b, "Finnish keyboard layout", &main_key_FI, &main_key_vkey_qwerty}, + {0x0402, "Bulgarian bds keyboard layout", &main_key_BG_bds, &main_key_vkey_qwerty}, + {0x0402, "Bulgarian phonetic keyboard layout", &main_key_BG_phonetic, &main_key_vkey_qwerty}, + {0x0423, "Belarusian keyboard layout", &main_key_BY, &main_key_vkey_qwerty}, + {0x0419, "Russian keyboard layout", &main_key_RU, &main_key_vkey_qwerty}, + {0x0419, "Russian keyboard layout (phantom key version)", &main_key_RU_phantom, &main_key_vkey_qwerty}, + {0x0419, "Russian keyboard layout KOI8-R", &main_key_RU_koi8r, &main_key_vkey_qwerty}, + {0x0419, "Russian keyboard layout cp1251", &main_key_RU_cp1251, &main_key_vkey_qwerty}, + {0x0419, "Russian phonetic keyboard layout", &main_key_RU_phonetic, &main_key_vkey_qwerty}, + {0x0422, "Ukrainian keyboard layout KOI8-U", &main_key_UA, &main_key_vkey_qwerty}, + {0x0422, "Ukrainian keyboard layout (standard)", &main_key_UA_std, &main_key_vkey_qwerty}, + {0x0419, "Russian keyboard layout (standard)", &main_key_RU_std, &main_key_vkey_qwerty}, + {0x040a, "Spanish keyboard layout", &main_key_ES, &main_key_vkey_qwerty}, + {0x0410, "Italian keyboard layout", &main_key_IT, &main_key_vkey_qwerty}, + {0x040f, "Icelandic keyboard layout", &main_key_IS, &main_key_vkey_qwerty}, + {0x040e, "Hungarian keyboard layout", &main_key_HU, &main_key_vkey_qwertz}, + {0x0415, "Polish (programmer's) keyboard layout", &main_key_PL, &main_key_vkey_qwerty}, + {0x0424, "Slovenian keyboard layout", &main_key_SI, &main_key_vkey_qwertz}, + {0x0c1a, "Serbian keyboard layout sr", &main_key_SR, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */ + {0x0c1a, "Serbian keyboard layout us,sr", &main_key_US_SR, &main_key_vkey_qwerty}, /* LANG_SERBIAN,SUBLANG_SERBIAN_CYRILLIC */ + {0x041a, "Croatian keyboard layout", &main_key_HR, &main_key_vkey_qwertz}, + {0x041a, "Croatian keyboard layout (specific)", &main_key_HR_jelly, &main_key_vkey_qwerty}, + {0x0411, "Japanese 106 keyboard layout", &main_key_JA_jp106, &main_key_vkey_qwerty_jp106}, + {0x0411, "Japanese Mac keyboard layout", &main_key_JA_macjp, &main_key_vkey_qwerty_jp106}, + {0x0411, "Japanese pc98x1 keyboard layout", &main_key_JA_pc98x1, &main_key_vkey_qwerty}, + {0x041b, "Slovak keyboard layout", &main_key_SK, &main_key_vkey_qwerty}, + {0x041b, "Slovak and Czech keyboard layout without dead keys", &main_key_SK_prog, &main_key_vkey_qwerty}, + {0x0405, "Czech keyboard layout", &main_key_CS, &main_key_vkey_qwerty}, + {0x0405, "Czech keyboard layout cz", &main_key_CZ, &main_key_vkey_qwertz}, + {0x0405, "Czech keyboard layout cz_qwerty", &main_key_CZ_qwerty, &main_key_vkey_qwerty}, + {0x040a, "Latin American keyboard layout", &main_key_LA, &main_key_vkey_qwerty}, + {0x0427, "Lithuanian (Baltic) keyboard layout", &main_key_LT_B, &main_key_vkey_qwerty}, + {0x041f, "Turkish keyboard layout", &main_key_TK, &main_key_vkey_qwerty}, + {0x041f, "Turkish keyboard layout tr", &main_key_TR, &main_key_vkey_qwerty}, + {0x041f, "Turkish keyboard layout trf", &main_key_TR_F, &main_key_vkey_qwerty}, + {0x040d, "Israelian keyboard layout", &main_key_IL, &main_key_vkey_qwerty}, + {0x040d, "Israelian phonetic keyboard layout", &main_key_IL_phonetic, &main_key_vkey_qwerty}, + {0x040d, "Israelian Saharon keyboard layout", &main_key_IL_saharon, &main_key_vkey_qwerty}, + {0x0409, "VNC keyboard layout", &main_key_vnc, &main_key_vkey_vnc}, + {0x0408, "Greek keyboard layout", &main_key_EL, &main_key_vkey_qwerty}, + {0x041e, "Thai (Kedmanee) keyboard layout", &main_key_th, &main_key_vkey_qwerty}, + {0x0413, "Dutch keyboard layout", &main_key_NL, &main_key_vkey_qwerty}, + + {0, NULL, NULL, NULL} /* sentinel */ }; static unsigned kbd_layout=0; /* index into above table of layouts */ #ifdef SONAME_LIBXKBREGISTRY @@ -1127,53 +1184,6 @@ static const WORD nonchar_key_vkey[256] = 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */ }; -static const WORD nonchar_key_scan[256] = -{ - /* unused */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */ - /* special keys */ - 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */ - 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */ - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */ - /* Japanese special keys */ - 0x00, 0x29, 0x7B, 0x79, 0x70, 0x00, 0x00, 0x70, /* FF20 */ - 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */ - /* Korean special keys (FF31-) */ - 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */ - /* unused */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */ - /* cursor keys */ - 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */ - /* misc keys */ - /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x15D, /* FF60 */ - /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */ - /* keypad keys */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x145, /* FF78 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */ - 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */ - 0x00, 0x00, 0x37, 0x4E, 0x53, 0x4A, 0x53, 0x135, /* FFA8 */ - 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */ - 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */ - /* function keys */ - 0x3B, 0x3C, - 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */ - 0x57, 0x58, 0x5B, 0x5C, 0x5D, 0x00, 0x00, 0x00, /* FFC8 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */ - /* modifier keys */ - 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */ - 0x138, 0x38, 0x138, 0x15b, 0x15c, 0x00, 0x00, 0x00, /* FFE8 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */ -}; - static const WORD xfree86_vendor_key_vkey[256] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 1008FF00 */ @@ -1339,7 +1349,7 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) if (!keys[vkey & 0xff].vkey) { keys[vkey & 0xff].vkey = vkey; - keys[vkey & 0xff].scan = keyc2scan[keycode]; + keys[vkey & 0xff].scan = keyc2scan( keycode, 0 ); } if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE; @@ -1525,10 +1535,10 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) if (buf != Str) free( Str ); + scan = keyc2scan( event->keycode, event->state ); vkey = EVENT_event_to_vkey(xic,event); /* X returns keycode 0 for composed characters */ if (!vkey && ascii_chars) vkey = VK_NONAME; - scan = keyc2scan[event->keycode]; TRACE_(key)("keycode %u converted to vkey 0x%X scan %04x\n", event->keycode, vkey, scan); @@ -1838,12 +1848,12 @@ static unsigned int detect_keyboard_layout( Display *display, XModifierKeymap *m } -/* initialize keyc2scan and keyc2vkey */ +/* initialize keyc2vkey */ static void init_keycode_mappings( Display *display ) { KeySym keysym; XKeyEvent e2; - WORD scan, vkey; + WORD vkey; int keyc, i, keyn, syms; char ckey[4]={0,0,0,0}; const char (*lkey)[MAIN_LEN][4]; @@ -1888,23 +1898,18 @@ static void init_keycode_mappings( Display *display ) keysym = 0; e2.keycode = (KeyCode)keyc; have_chars = XLookupString(&e2, buf, sizeof(buf), &keysym, NULL); - vkey = 0; scan = 0; + vkey = 0; if (keysym) /* otherwise, keycode not used */ { if ((keysym >> 8) == 0xFF) /* non-character key */ { vkey = nonchar_key_vkey[keysym & 0xff]; - scan = nonchar_key_scan[keysym & 0xff]; - /* set extended bit when necessary */ - if (scan & 0x100) vkey |= 0x100; } else if ((keysym >> 8) == 0x1008FF) { /* XFree86 vendor keys */ vkey = xfree86_vendor_key_vkey[keysym & 0xff]; /* All vendor keys are extended with a scan code of 0 per testing on WinXP */ - scan = 0x100; vkey |= 0x100; } else if (keysym == 0x20) { /* Spacebar */ vkey = VK_SPACE; - scan = 0x39; } else if (have_chars) { /* we seem to need to search the layout-dependent scancodes */ int maxlen=0,maxval=-1,ok; @@ -1936,16 +1941,13 @@ static void init_keycode_mappings( Display *display ) } if (maxval>=0) { /* got it */ - const WORD (*lscan)[MAIN_LEN] = main_key_tab[kbd_layout].scan; const WORD (*lvkey)[MAIN_LEN] = main_key_tab[kbd_layout].vkey; - scan = (*lscan)[maxval]; vkey = (*lvkey)[maxval]; } } } TRACE("keycode %u => vkey %04X\n", e2.keycode, vkey); keyc2vkey[e2.keycode] = vkey; - keyc2scan[e2.keycode] = scan; if ((vkey & 0xff) && vkey_used[(vkey & 0xff)]) WARN("vkey %04X is being used by more than one keycode\n", vkey); vkey_used[(vkey & 0xff)] = 1; @@ -2054,20 +2056,6 @@ static void init_keycode_mappings( Display *display ) vkey_used[vkey] = 1; } /* for */ #undef VKEY_IF_NOT_USED - - /* If some keys still lack scancodes, assign some arbitrary ones to them now */ - for (scan = 0x60, keyc = min_keycode; keyc <= max_keycode; keyc++) - if (keyc2vkey[keyc]&&!keyc2scan[keyc]) { - const char *ksname; - keysym = XkbKeycodeToKeysym( display, keyc, 0, 0 ); - ksname = XKeysymToString(keysym); - if (!ksname) ksname = "NoSymbol"; - - /* should make sure the scancode is unassigned here, but >=0x60 currently always is */ - - TRACE_(key)("assigning scancode %02x to unidentified keycode %u (%s)\n",scan,keyc,ksname); - keyc2scan[keyc]=scan++; - } } static void find_xkb_layout_variant( Display *display, XModifierKeymap *mmp, int group, const char *name, @@ -2388,7 +2376,7 @@ UINT X11DRV_MapVirtualKeyEx( UINT wCode, UINT wMapType, HKL hkl ) { if ((keyc2vkey[keyc] & 0xFF) == wCode) { - ret = keyc2scan[keyc] & 0xFF; + ret = keyc2scan( keyc, 0 ) & 0xFF; break; } } @@ -2404,7 +2392,7 @@ UINT X11DRV_MapVirtualKeyEx( UINT wCode, UINT wMapType, HKL hkl ) /* let's do scan -> keycode -> vkey */ for (keyc = min_keycode; keyc <= max_keycode; keyc++) - if ((keyc2scan[keyc] & 0xFF) == (wCode & 0xFF)) + if ((keyc2scan( keyc, 0 ) & 0xFF) == (wCode & 0xFF)) { ret = keyc2vkey[keyc] & 0xFF; /* Only stop if it's not a numpad vkey; otherwise keep @@ -2575,9 +2563,17 @@ INT X11DRV_GetKeyNameText( LONG lParam, LPWSTR lpBuffer, INT nSize ) pthread_mutex_lock( &kbd_mutex ); - for (keyi=min_keycode; keyi<=max_keycode; keyi++) - if ((keyc2scan[keyi]) == scanCode) - break; + /* PAUSE, NUMLOCK are special */ + if (scanCode == 0x45) + keyi = KEY_PAUSE + 8; + else if (scanCode == 0x145) + keyi = KEY_NUMLOCK + 8; + else + { + for (keyi=min_keycode; keyi<=max_keycode; keyi++) + if (keyc2scan( keyi, 0 ) == scanCode) + break; + } if (keyi <= max_keycode) { INT rc; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/user32/tests/input.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 6ad01e82978..9c9b83e1578 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1313,6 +1313,27 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W {0}, }; + struct send_input_keyboard_test pause_scan[] = + { + {.scan = 0x21d, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0x21d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_CONTROL] = 0x01, [VK_LCONTROL] = 0x01}, + .expect = {KEY_HOOK(WM_KEYUP, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYUP, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0xe11d, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0xe11d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_CONTROL] = 0x01, [VK_LCONTROL] = 0x01}, + .expect = {KEY_HOOK(WM_KEYUP, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYUP, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0xe11d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_CONTROL] = 0x80, [VK_RCONTROL] = 0x80}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 0x1d, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 0x11d, VK_CONTROL), {0}}}, + {.scan = 0xe11d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, .expect_state = {[VK_CONTROL] = 0x01, [VK_RCONTROL] = 0x01}, + .expect = {KEY_HOOK_(WM_KEYUP, 0x1d, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0x11d, VK_CONTROL), {0}}}, + {.vkey = VK_PAUSE, .expect_state = {[VK_PAUSE] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x7, VK_PAUSE), KEY_MSG(WM_KEYDOWN, 0x7, VK_PAUSE), {0}}}, + {.vkey = VK_PAUSE, .flags = KEYEVENTF_KEYUP, .expect_state = {[VK_PAUSE] = 0x01}, + .expect = {KEY_HOOK(WM_KEYUP, 0x8, VK_PAUSE), KEY_MSG(WM_KEYUP, 0x8, VK_PAUSE), {0}}}, + {0}, + }; + #undef WIN_MSG #undef KBD_HOOK #undef KEY_HOOK_ @@ -1397,6 +1418,7 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W check_send_input_keyboard_test( unicode_vkey_packet, TRUE ); check_send_input_keyboard_test( numpad_scan, TRUE ); check_send_input_keyboard_test( numpad_scan_numlock, TRUE ); + check_send_input_keyboard_test( pause_scan, TRUE ); winetest_pop_context(); wait_messages( 100, FALSE ); @@ -1444,6 +1466,7 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W check_send_input_keyboard_test( unicode_vkey_packet, FALSE ); check_send_input_keyboard_test( numpad_scan, FALSE ); check_send_input_keyboard_test( numpad_scan_numlock, FALSE ); + check_send_input_keyboard_test( pause_scan, FALSE ); winetest_pop_context(); ok_ret( 1, DestroyWindow( hwnd ) ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/user32/tests/input.c | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 9c9b83e1578..93d8061a166 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1479,6 +1479,36 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W static void test_keynames(void) { + static const struct + { + LONG lparam; + const char *expected_name; + BOOL todo; + BOOL todo_value; + } tests[] = + { + {0x00370000, "Num *", .todo_value = TRUE}, + {0x01370000, "Prnt Scrn", .todo_value = TRUE}, + {0x02370000, "Num *", .todo_value = TRUE}, + {0xe0370000, "Num *", .todo_value = TRUE}, + {0xe1370000, "Prnt Scrn", .todo_value = TRUE}, + {0x00450000, "Pause"}, + {0x01450000, "Num Lock", .todo_value = TRUE}, + {0x02450000, "Pause"}, + {0xe0450000, "Pause"}, + {0xe1450000, "Num Lock", .todo_value = TRUE}, + {0x00460000, "Scroll Lock", .todo_value = TRUE}, + {0x01460000, "Break", .todo_value = TRUE}, + {0xe0460000, "Scroll Lock", .todo_value = TRUE}, + {0xe1460000, "Break", .todo_value = TRUE}, + {0x01480000, "Up"}, + {0x001d0000, "Ctrl", .todo_value = TRUE}, + {0x011d0000, "Right Ctrl", .todo_value = TRUE}, + {0x021d0000, "Ctrl", .todo_value = TRUE}, + {0xe01d0000, "Ctrl", .todo_value = TRUE}, + {0xe11d0000, "Right Ctrl", .todo_value = TRUE}, + }; + BOOL us_kbd = (GetKeyboardLayout(0) == (HKL)(ULONG_PTR)0x04090409); int i, len; char buff[256]; @@ -1488,6 +1518,16 @@ static void test_keynames(void) len = GetKeyNameTextA(i << 16, buff, sizeof(buff)); ok(len || !buff[0], "%d: Buffer is not zeroed\n", i); } + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + winetest_push_context("scancode %.4x", (unsigned int)tests[i].lparam >> 16); + len = GetKeyNameTextA(tests[i].lparam, buff, sizeof(buff)); + todo_wine_if(tests[i].todo) ok(len, "No key name\n"); + if (us_kbd) todo_wine_if(tests[i].todo_value) + ok(!strcmp(buff, tests[i].expected_name), "Unexpected key name %s\n", debugstr_a(buff)); + trace("name %s\n", debugstr_a(buff)); + winetest_pop_context(); + } } static BOOL accept_keyboard_messages_raw( UINT msg ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
From: Matteo Bruni <mbruni@codeweavers.com> --- dlls/user32/tests/input.c | 64 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 93d8061a166..09d5fd90559 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3259,10 +3259,65 @@ static void test_DefRawInputProc(void) ok(GetLastError() == 0xdeadbeef, "got %ld\n", GetLastError()); } +static const char *debug_map_type(UINT map_type) +{ +#define MAP_TO_STR(x) case x: return #x + switch (map_type) + { + MAP_TO_STR(MAPVK_VK_TO_VSC); + MAP_TO_STR(MAPVK_VSC_TO_VK); + MAP_TO_STR(MAPVK_VK_TO_CHAR); + MAP_TO_STR(MAPVK_VSC_TO_VK_EX); + MAP_TO_STR(MAPVK_VK_TO_VSC_EX); + default: + return "<unknown>"; + } +#undef MAP_TO_STR +} + static void test_key_map(void) { + static const struct + { + UINT input; + UINT map_type; + UINT expected; + BOOL todo; + } tests[] = + { + {0x136, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0xe036, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0xe136, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0x37, MAPVK_VSC_TO_VK_EX, VK_MULTIPLY, TRUE}, + {0x137, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0x237, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0xe037, MAPVK_VSC_TO_VK_EX, VK_SNAPSHOT}, + {0xe137, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0x45, MAPVK_VSC_TO_VK_EX, VK_NUMLOCK}, + {0x145, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0xe045, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0xe145, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0x1d, MAPVK_VSC_TO_VK_EX, VK_LCONTROL}, + {0x011d, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0x021d, MAPVK_VSC_TO_VK_EX, 0, TRUE}, + {0xe01d, MAPVK_VSC_TO_VK_EX, VK_RCONTROL, TRUE}, + {0xe11d, MAPVK_VSC_TO_VK_EX, VK_PAUSE, TRUE}, + {0x46, MAPVK_VSC_TO_VK_EX, VK_SCROLL}, + {0xe046, MAPVK_VSC_TO_VK_EX, VK_CANCEL, TRUE}, + + {VK_RSHIFT, MAPVK_VK_TO_VSC_EX, 0x36}, + {VK_MULTIPLY, MAPVK_VK_TO_VSC_EX, 0x37}, + {VK_NUMLOCK, MAPVK_VK_TO_VSC_EX, 0x45}, + {VK_UP, MAPVK_VK_TO_VSC_EX, 0x48}, + {VK_LCONTROL, MAPVK_VK_TO_VSC_EX, 0x1d}, + {VK_RCONTROL, MAPVK_VK_TO_VSC_EX, 0xe01d}, + {VK_PAUSE, MAPVK_VK_TO_VSC_EX, 0xe11d, TRUE}, + {VK_SCROLL, MAPVK_VK_TO_VSC_EX, 0x46}, + {VK_CANCEL, MAPVK_VK_TO_VSC_EX, 0xe046, TRUE}, + {VK_SNAPSHOT, MAPVK_VK_TO_VSC_EX, 0x54}, + }; HKL kl = GetKeyboardLayout(0); - UINT kL, kR, s, sL; + UINT kL, kR, s, sL, r; int i; static const UINT numpad_collisions[][2] = { { VK_NUMPAD0, VK_INSERT }, @@ -3319,6 +3374,13 @@ static void test_key_map(void) ok(s >> 8 == 0xE0 || broken(s == 0), "Scan code prefix for VK_RMENU should be 0xE0 when MAPVK_VK_TO_VSC_EX is set, was %#1x\n", s >> 8); s = MapVirtualKeyExA(VK_RSHIFT, MAPVK_VK_TO_VSC_EX, kl); ok(s >> 8 == 0x00 || broken(s == 0), "The scan code shouldn't have a prefix, got %#1x\n", s >> 8); + + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + r = MapVirtualKeyExA(tests[i].input, tests[i].map_type, kl); + todo_wine_if(tests[i].todo) ok(r == tests[i].expected, "Unexpected %s %x -> %x\n", + debug_map_type(tests[i].map_type), tests[i].input, r); + } } #define shift 1 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10963
On Wed Jun 10 20:29:04 2026 +0000, Matteo Bruni wrote:
changed this line in [version 9 of the diff](/wine/wine/-/merge_requests/10963/diffs?diff_id=274152&start_sha=c751a8ac2af27f1e22ec95a80038126312b31b93#ff16e096ba3fdb3e28a6cc2560a364b95deee87a_1539_1550) This is a bit tricky... In kbdus.dll the `tables->pKeyNames` entry for vsc 0x45 is "Pause", the one in `pKeyNamesExt` (so for 0x145) is "Num Lock" (i.e. they're already swapped in there). We don't have to replicate this in our driver-generated `KBDTABLES`, I guess, but adding some difference that will get in the way if we ever want to support custom keyboard layouts seems not ideal. [*]
Similarly, `VK_PAUSE` should map to scancode 0xe11d, which means that the KEY_PAUSE -> 0x021d mapping in the new setup probably needs to stay (or, if we e.g. go for KEY_PAUSE -> 0x45, we'll need to override the scancode for `MapVirtualKeyEx()` and such - exchanging one set of places needing special casing with a different one). Another thing is that `keyc2scan()` is often used when there is no reasonable state to pass in. That's currently happening in `X11DRV_MapVirtualKeyEx()`, `X11DRV_GetKeyNameText()`, which will go away soon but those uses will be replaced by equivalent ones to fill a number of tables in the `KBDTABLES` struct. No real problem, but it doesn't look super nice. FWIW, this is only useful for Pause vs Break (both scancode and VK) and potentially PrtSc vs ALT + PrtSc (scancode only).
And probably then while we're fixing exotic scancodes, maybe worth adding the extra cases for PrtSc / SysRq while at it. According to https://kbdlayout.info/kbdus/scancodes, I expect it to be something like: `scan == 0x12a && mod & (Ctrl | Shift) => 0x137` and `scan == 0x12a && mod & (Alt) => 0x54`.
That's basically right. There's an additional weirdness in that there is no WM_[SYS]KEYDOWN message for any PrtSc keypress, just the WM_[SYS]KEYUP. I know I read about it somewhere but I can't find it again... Anyway, that's a bit of a hassle for the tests so I'm going to take care of that later on. [*]: I agree that it would be nice to handle this for both winex11 and winewayland from common code. I don't know where the common code would live and how to structure it, though :/ -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10963#note_142719
participants (3)
-
Matteo Bruni -
Matteo Bruni (@Mystral) -
Rémi Bernon