This MR improves the handling of numpad keys for drivers using KBDTABLES (only the Wayland driver at this point). It achieves this by: 1. Allowing drivers to send only the scancode in keyboard events, with win32u performing the scan->vkey mapping internally. A nice side effect of this change is that it fixes a few user32 input test TODOs. 2. Enhancing wineserver to read extended KBD vkey attributes and perform numpad key mapping depending on modifier state. 3. Providing default VK_NUMPAD* -> WCHAR mappings in win32u.
-- v7: winewayland.drv: Populate vkey to wchar entry for VK_DECIMAL. user32/tests: Add tests for SendInput with numpad scancodes. server: Send numpad virtual keys if NumLock is active. win32u: Store the full KBD vkey information in kbd_tables_init_vsc2vk. win32u: Allow drivers to send only the scan code for keyboard events.
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/win32u/input.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 04532e7d015..38350861c6b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -521,6 +521,7 @@ static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const if (vkey >= 'A' && vkey <= 'Z') return vkey - 'A' + 1; tables = &kbdus_tables; } + if (vkey >= VK_NUMPAD0 && vkey <= VK_NUMPAD9) tables = &kbdus_tables;
mod = caps_mod = kbd_tables_get_mod_num( tables, state, FALSE ); if (caps) caps_mod = kbd_tables_get_mod_num( tables, state, TRUE );
From: Alexandros Frantzis alexandros.frantzis@collabora.com
The implementation will map the scan code to a virtual key code internally. --- dlls/user32/tests/input.c | 31 ++++++++++++++++++------- dlls/win32u/message.c | 23 +++++++++++++++--- dlls/winewayland.drv/wayland_keyboard.c | 9 ++++--- 3 files changed, 47 insertions(+), 16 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index d84d543bed8..8fad3305f3e 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1063,16 +1063,26 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W struct send_input_keyboard_test rshift_scan[] = { {.scan = 0x36, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, - .todo_state = {[0] = TRUE, [VK_SHIFT] = TRUE, [VK_LSHIFT] = TRUE}, - .expect = {KEY_HOOK(WM_KEYDOWN, 0x36, VK_RSHIFT, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 0x36, VK_SHIFT, .todo_value = TRUE), {0}}}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x36, VK_RSHIFT), KEY_MSG(WM_KEYDOWN, 0x36, VK_SHIFT), {0}}}, {.scan = scan, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80, /*[vkey] = 0x80*/}, - .todo_state = {[0] = TRUE, [VK_SHIFT] = TRUE, [VK_LSHIFT] = TRUE, /*[vkey] = TRUE*/}, - .expect = {KEY_HOOK(WM_KEYDOWN, scan, vkey, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, scan, vkey, .todo_value = TRUE), WIN_MSG(WM_CHAR, wch_shift, MAKELONG(1, scan), .todo = TRUE), {0}}}, + .expect = {KEY_HOOK(WM_KEYDOWN, scan, vkey), KEY_MSG(WM_KEYDOWN, scan, vkey), WIN_MSG(WM_CHAR, wch_shift, MAKELONG(1, scan)), {0}}}, {.scan = scan, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, - .todo_state = {[VK_SHIFT] = TRUE, [VK_LSHIFT] = TRUE}, - .expect = {KEY_HOOK(WM_KEYUP, scan, vkey, .todo_value = TRUE), KEY_MSG(WM_KEYUP, scan, vkey, .todo_value = TRUE), {0}}}, + .expect = {KEY_HOOK(WM_KEYUP, scan, vkey), KEY_MSG(WM_KEYUP, scan, vkey), {0}}}, {.scan = 0x36, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, - .expect = {KEY_HOOK(WM_KEYUP, 0x36, VK_RSHIFT, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0x36, VK_SHIFT, .todo_value = TRUE), {0}}}, + .expect = {KEY_HOOK(WM_KEYUP, 0x36, VK_RSHIFT), KEY_MSG(WM_KEYUP, 0x36, VK_SHIFT), {0}}}, + {0}, + }; + + struct send_input_keyboard_test rctrl_scan[] = + { + {.scan = 0xe01d, .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 = 0xe01d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0x1d, VK_LCONTROL), KEY_MSG(WM_KEYUP, 0x1d, VK_CONTROL), {0}}}, + {.scan = 0x1d, .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 = 0x1d, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK_(WM_KEYUP, 0x1d, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0x11d, VK_CONTROL), {0}}}, {0}, };
@@ -1179,7 +1189,6 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W lmenu_lcontrol_vkey[2].expect_state[vkey] = 0x80; shift_vkey[1].expect_state[vkey] = 0x80; rshift_scan[1].expect_state[vkey] = 0x80; - rshift_scan[1].todo_state[vkey] = TRUE; unicode_vkey[0].expect_state[vkey] = 0x80;
/* test peeked messages */ @@ -1211,6 +1220,9 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W else check_send_input_keyboard_test( menu_ext_peeked, TRUE ); check_send_input_keyboard_test( lrshift_ext, TRUE ); check_send_input_keyboard_test( rshift_scan, TRUE ); + /* Skip on Korean layouts since they map the right control key to VK_HANJA */ + if (hkl == (HKL)0x04120412) skip( "skipping rctrl_scan test on Korean layout" ); + else check_send_input_keyboard_test( rctrl_scan, TRUE ); check_send_input_keyboard_test( unicode, TRUE ); check_send_input_keyboard_test( lmenu_unicode_peeked, TRUE ); check_send_input_keyboard_test( unicode_vkey, TRUE ); @@ -1251,6 +1263,9 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W else check_send_input_keyboard_test( menu_ext, FALSE ); check_send_input_keyboard_test( lrshift_ext, FALSE ); check_send_input_keyboard_test( rshift_scan, FALSE ); + /* Skip on Korean layouts since they map the right control key to VK_HANJA */ + if (hkl == (HKL)0x04120412) skip( "skipping rctrl_scan test on Korean layout" ); + else check_send_input_keyboard_test( rctrl_scan, FALSE ); check_send_input_keyboard_test( unicode, FALSE ); check_send_input_keyboard_test( lmenu_unicode, FALSE ); check_send_input_keyboard_test( unicode_vkey, FALSE ); diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 4a368ffb589..ddc9658f087 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3558,9 +3558,26 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)); break; case INPUT_KEYBOARD: - req->input.kbd.vkey = input->ki.wVk; - req->input.kbd.scan = input->ki.wScan; - req->input.kbd.flags = input->ki.dwFlags; + if (input->ki.dwFlags & KEYEVENTF_SCANCODE) + { + UINT scan = input->ki.wScan; + /* TODO: Use the keyboard layout of the target hwnd, once + * NtUserGetKeyboardLayout supports non-current threads. */ + HKL layout = NtUserGetKeyboardLayout( 0 ); + if (flags & SEND_HWMSG_INJECTED) + { + scan = scan & 0xff; + if (input->ki.dwFlags & KEYEVENTF_EXTENDEDKEY) scan |= 0xe000; + } + req->input.kbd.vkey = NtUserMapVirtualKeyEx( scan, MAPVK_VSC_TO_VK_EX, layout ); + req->input.kbd.scan = input->ki.wScan & 0xff; + } + else + { + req->input.kbd.vkey = input->ki.wVk; + req->input.kbd.scan = input->ki.wScan; + } + req->input.kbd.flags = input->ki.dwFlags & ~KEYEVENTF_SCANCODE; req->input.kbd.time = input->ki.time; req->input.kbd.info = input->ki.dwExtraInfo; affects_key_state = TRUE; diff --git a/dlls/winewayland.drv/wayland_keyboard.c b/dlls/winewayland.drv/wayland_keyboard.c index 04a1c0a9fc3..55b14b1dfd5 100644 --- a/dlls/winewayland.drv/wayland_keyboard.c +++ b/dlls/winewayland.drv/wayland_keyboard.c @@ -801,9 +801,8 @@ static void send_right_control(HWND hwnd, uint32_t state) { INPUT input = {0}; input.type = INPUT_KEYBOARD; - input.ki.wScan = key2scan(KEY_RIGHTCTRL); - input.ki.wVk = VK_RCONTROL; - input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY; + input.ki.wScan = 0xe000 | (key2scan(KEY_RIGHTCTRL) & 0xff); + input.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY; if (state == WL_KEYBOARD_KEY_STATE_RELEASED) input.ki.dwFlags |= KEYEVENTF_KEYUP; NtUserSendHardwareInput(hwnd, 0, &input, 0); } @@ -824,8 +823,8 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, if (key == KEY_RIGHTALT) send_right_control(hwnd, state);
input.type = INPUT_KEYBOARD; - input.ki.wScan = scan & 0xff; - input.ki.wVk = NtUserMapVirtualKeyEx(scan, MAPVK_VSC_TO_VK_EX, keyboard_hkl); + input.ki.wScan = (scan & 0x300) ? scan + 0xdf00 : scan; + input.ki.dwFlags = KEYEVENTF_SCANCODE; if (scan & ~0xff) input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
if (state == WL_KEYBOARD_KEY_STATE_RELEASED) input.ki.dwFlags |= KEYEVENTF_KEYUP;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/win32u/input.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 38350861c6b..333c0c1e4f7 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -410,27 +410,27 @@ LONG global_key_state_counter = 0; BOOL grab_pointer = TRUE; BOOL grab_fullscreen = FALSE;
-static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] ) +static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, USHORT vsc2vk[0x300] ) { const VSC_VK *entry; WORD vsc;
- memset( vsc2vk, 0, 0x300 ); + memset( vsc2vk, 0, 0x300 * sizeof(USHORT) );
for (vsc = 0; tables->pusVSCtoVK && vsc <= tables->bMaxVSCtoVK; ++vsc) { if (tables->pusVSCtoVK[vsc] == VK__none_) continue; - vsc2vk[vsc] = (BYTE)tables->pusVSCtoVK[vsc]; + vsc2vk[vsc] = tables->pusVSCtoVK[vsc]; } for (entry = tables->pVSCtoVK_E0; entry && entry->Vsc; entry++) { if (entry->Vk == VK__none_) continue; - vsc2vk[entry->Vsc + 0x100] = (BYTE)entry->Vk; + vsc2vk[entry->Vsc + 0x100] = entry->Vk; } for (entry = tables->pVSCtoVK_E1; entry && entry->Vsc; entry++) { if (entry->Vk == VK__none_) continue; - vsc2vk[entry->Vsc + 0x200] = (BYTE)entry->Vk; + vsc2vk[entry->Vsc + 0x200] = entry->Vk; } }
@@ -1033,7 +1033,8 @@ WORD WINAPI NtUserVkKeyScanEx( WCHAR chr, HKL layout ) */ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) { - BYTE vsc2vk[0x300], vk2char[0x100]; + USHORT vsc2vk[0x300]; + BYTE vk2char[0x100]; const KBDTABLES *kbd_tables; UINT ret = 0;
@@ -1066,7 +1067,7 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) }
kbd_tables_init_vsc2vk( kbd_tables, vsc2vk ); - for (ret = 0; ret < ARRAY_SIZE(vsc2vk); ++ret) if (vsc2vk[ret] == code) break; + for (ret = 0; ret < ARRAY_SIZE(vsc2vk); ++ret) if ((vsc2vk[ret] & 0xff) == code) break; if (ret >= ARRAY_SIZE(vsc2vk)) ret = 0;
if (type == MAPVK_VK_TO_VSC) @@ -1082,7 +1083,7 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout )
if (code & 0xe000) code -= 0xdf00; if (code >= ARRAY_SIZE(vsc2vk)) ret = 0; - else ret = vsc2vk[code]; + else ret = vsc2vk[code] & 0xff;
if (type == MAPVK_VSC_TO_VK) { @@ -1130,15 +1131,15 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size )
if (lparam & 0x2000000) { - BYTE vsc2vk[0x300]; + USHORT vsc2vk[0x300]; kbd_tables_init_vsc2vk( kbd_tables, vsc2vk ); - switch ((vkey = vsc2vk[code])) + switch ((vkey = vsc2vk[code] & 0xff)) { case VK_RSHIFT: case VK_RCONTROL: case VK_RMENU: for (code = 0; code < ARRAY_SIZE(vsc2vk); ++code) - if (vsc2vk[code] == (vkey - 1)) break; + if ((vsc2vk[code] & 0xff) == (vkey - 1)) break; break; } }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
If the hardware keyboard event has KBD virtual key information, use it to detect numpad key events and translate them to the appropriate virtual keys depending on NumLock (and Shift) state. --- dlls/win32u/input.c | 25 +++++++++++++++++++++++++ dlls/win32u/message.c | 2 +- dlls/win32u/win32u_private.h | 1 + server/queue.c | 27 +++++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 333c0c1e4f7..84bd26379f5 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -1112,6 +1112,31 @@ UINT WINAPI NtUserMapVirtualKeyEx( UINT code, UINT type, HKL layout ) return ret; }
+/*********************************************************************** + * map_scan_to_kbd_vkey + * + * Map a scancode to a virtual key with KBD information. + */ +USHORT map_scan_to_kbd_vkey( USHORT scan, HKL layout ) +{ + const KBDTABLES *kbd_tables; + USHORT vsc2vk[0x300]; + UINT vkey; + + if ((vkey = user_driver->pMapVirtualKeyEx( scan, MAPVK_VSC_TO_VK_EX, layout )) != -1) return vkey; + + if (!(kbd_tables = user_driver->pKbdLayerDescriptor( layout ))) kbd_tables = &kbdus_tables; + + kbd_tables_init_vsc2vk( kbd_tables, vsc2vk ); + if (scan & 0xe000) scan -= 0xdf00; + if (scan >= ARRAY_SIZE(vsc2vk)) vkey = 0; + else vkey = vsc2vk[scan]; + + if (kbd_tables != &kbdus_tables) user_driver->pReleaseKbdTables( kbd_tables ); + + return vkey; +} + /**************************************************************************** * NtUserGetKeyNameText (win32u.@) */ diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index ddc9658f087..531cb8d0649 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3569,7 +3569,7 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA scan = scan & 0xff; if (input->ki.dwFlags & KEYEVENTF_EXTENDEDKEY) scan |= 0xe000; } - req->input.kbd.vkey = NtUserMapVirtualKeyEx( scan, MAPVK_VSC_TO_VK_EX, layout ); + req->input.kbd.vkey = map_scan_to_kbd_vkey( scan, layout ); req->input.kbd.scan = input->ki.wScan & 0xff; } else diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 24e8b1b498d..94b9d00b4fb 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -108,6 +108,7 @@ extern void update_mouse_tracking_info( HWND hwnd ); extern BOOL get_clip_cursor( RECT *rect ); 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 );
/* menu.c */ extern HMENU create_menu( BOOL is_popup ); diff --git a/server/queue.c b/server/queue.c index cc10d0254eb..c4b9389695f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -36,6 +36,7 @@ #include "winternl.h" #include "ntuser.h" #include "hidusage.h" +#include "kbd.h"
#include "handle.h" #include "file.h" @@ -1763,7 +1764,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
if (input->type == INPUT_KEYBOARD) { - unsigned short vkey = input->kbd.vkey; + unsigned short vkey = input->kbd.vkey & 0xff; if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET; msg->lparam = (input->kbd.scan << 16) | vkey; } @@ -2102,6 +2103,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c struct message *msg; struct thread *foreground; unsigned char vkey = input->kbd.vkey; + hw_input_t hook_input = *input; unsigned int message_code, time; int wait;
@@ -2171,6 +2173,27 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; }
+ /* send numpad vkeys if NumLock is active */ + if ((input->kbd.vkey & KBDNUMPAD) && (desktop->keystate[VK_NUMLOCK] & 0x01) && + !(desktop->keystate[VK_SHIFT] & 0x80)) + { + switch (vkey) + { + case VK_INSERT: hook_input.kbd.vkey = vkey = VK_NUMPAD0; break; + case VK_END: hook_input.kbd.vkey = vkey = VK_NUMPAD1; break; + case VK_DOWN: hook_input.kbd.vkey = vkey = VK_NUMPAD2; break; + case VK_NEXT: hook_input.kbd.vkey = vkey = VK_NUMPAD3; break; + case VK_LEFT: hook_input.kbd.vkey = vkey = VK_NUMPAD4; break; + case VK_CLEAR: hook_input.kbd.vkey = vkey = VK_NUMPAD5; break; + case VK_RIGHT: hook_input.kbd.vkey = vkey = VK_NUMPAD6; break; + case VK_HOME: hook_input.kbd.vkey = vkey = VK_NUMPAD7; break; + case VK_UP: hook_input.kbd.vkey = vkey = VK_NUMPAD8; break; + case VK_PRIOR: hook_input.kbd.vkey = vkey = VK_NUMPAD9; break; + case VK_DELETE: hook_input.kbd.vkey = vkey = VK_DECIMAL; break; + default: break; + } + } + if ((foreground = get_foreground_thread( desktop, win ))) { struct rawinput_message raw_msg = {0}; @@ -2217,7 +2240,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg_data->flags |= (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8; }
- if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) + if (!(wait = send_hook_ll_message( desktop, msg, &hook_input, sender ))) queue_hardware_message( desktop, msg, 1 );
return wait;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 72 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 8fad3305f3e..f332aeddd08 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -615,15 +615,38 @@ static void check_keyboard_state_( int line, const BYTE expect_state[256], const } }
+static void clear_keyboard_state( void ) +{ + static BYTE empty_state[256] = {0}; + INPUT input = {.type = INPUT_KEYBOARD}; + BYTE lock_keys[] = {VK_NUMLOCK, VK_CAPITAL, VK_SCROLL}; + UINT i; + + for (i = 0; i < ARRAY_SIZE(lock_keys); ++i) + { + if (GetKeyState( lock_keys[i] ) & 0x0001) + { + input.ki.wVk = lock_keys[i]; + SendInput( 1, &input, sizeof(input) ); + input.ki.dwFlags = KEYEVENTF_KEYUP; + SendInput( 1, &input, sizeof(input) ); + wait_messages( 5, FALSE ); + memset( current_sequence, 0, sizeof(current_sequence) ); + current_sequence_len = 0; + } + } + + SetKeyboardState( empty_state ); +} + #define check_send_input_keyboard_test( a, b ) check_send_input_keyboard_test_( a, #a, b ) static void check_send_input_keyboard_test_( const struct send_input_keyboard_test *test, const char *context, BOOL peeked ) { - static BYTE empty_state[256] = {0}; INPUT input = {.type = INPUT_KEYBOARD}; UINT i;
winetest_push_context( "%s", context ); - SetKeyboardState( empty_state ); + clear_keyboard_state();
for (i = 0; test->vkey || test->scan; i++, test++) { @@ -641,7 +664,7 @@ static void check_send_input_keyboard_test_( const struct send_input_keyboard_te winetest_pop_context(); }
- SetKeyboardState( empty_state ); + clear_keyboard_state(); winetest_pop_context(); }
@@ -1146,6 +1169,45 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W {0}, };
+ struct send_input_keyboard_test numpad_scan[] = + { + {.scan = 0x4b, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_LEFT] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x4b, VK_LEFT), KEY_MSG(WM_KEYDOWN, 0x4b, VK_LEFT), {0}}}, + {.scan = 0x4b, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0x4b, VK_LEFT), KEY_MSG(WM_KEYUP, 0x4b, VK_LEFT), {0}}}, + {0}, + }; + + struct send_input_keyboard_test numpad_scan_numlock[] = + { + {.scan = 0x45, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_NUMLOCK] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0x45, VK_NUMLOCK), KEY_MSG(WM_KEYDOWN, 0x45, VK_NUMLOCK), {0}}}, + {.scan = 0x45, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_NUMLOCK] = 0x01}, + .expect = {KEY_HOOK(WM_KEYUP, 0x45, VK_NUMLOCK), KEY_MSG(WM_KEYUP, 0x45, VK_NUMLOCK), {0}}}, + { + .scan = 0x4b, .flags = KEYEVENTF_SCANCODE, + .expect_state = {[VK_NUMPAD4] = 0x80, [VK_NUMLOCK] = 0x01}, + .todo_state = {[VK_NUMPAD4] = TRUE, [VK_LEFT] = TRUE}, + .expect = + { + KEY_HOOK(WM_KEYDOWN, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + KEY_MSG(WM_KEYDOWN, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + WIN_MSG(WM_CHAR, '4', MAKELONG(1, 0x4b), .todo_value = TRUE), + {0} + } + }, + { + .scan = 0x4b, .flags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, .expect_state = {[VK_NUMLOCK] = 0x01}, + .expect = + { + KEY_HOOK(WM_KEYUP, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + KEY_MSG(WM_KEYUP, 0x4b, VK_NUMPAD4, .todo_value = TRUE), + {0} + } + }, + {0}, + }; + #undef WIN_MSG #undef KBD_HOOK #undef KEY_HOOK_ @@ -1226,6 +1288,8 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W check_send_input_keyboard_test( unicode, TRUE ); check_send_input_keyboard_test( lmenu_unicode_peeked, TRUE ); check_send_input_keyboard_test( unicode_vkey, TRUE ); + check_send_input_keyboard_test( numpad_scan, TRUE ); + check_send_input_keyboard_test( numpad_scan_numlock, TRUE ); winetest_pop_context();
wait_messages( 100, FALSE ); @@ -1269,6 +1333,8 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W check_send_input_keyboard_test( unicode, FALSE ); check_send_input_keyboard_test( lmenu_unicode, FALSE ); check_send_input_keyboard_test( unicode_vkey, FALSE ); + check_send_input_keyboard_test( numpad_scan, FALSE ); + check_send_input_keyboard_test( numpad_scan_numlock, FALSE ); winetest_pop_context();
ok_ret( 1, DestroyWindow( hwnd ) );
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/wayland_keyboard.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/dlls/winewayland.drv/wayland_keyboard.c b/dlls/winewayland.drv/wayland_keyboard.c index 55b14b1dfd5..bdef56e8f0c 100644 --- a/dlls/winewayland.drv/wayland_keyboard.c +++ b/dlls/winewayland.drv/wayland_keyboard.c @@ -358,7 +358,7 @@ static void add_xkb_layout(const char *xkb_layout, struct xkb_keymap *xkb_keymap
unsigned int mod, keyc, len, names_len, min_keycode, max_keycode; struct xkb_state *xkb_state = xkb_state_new(xkb_keymap); - xkb_mod_mask_t shift_mask, control_mask, altgr_mask, capslock_mask; + xkb_mod_mask_t shift_mask, control_mask, altgr_mask, capslock_mask, numlock_mask; VSC_LPWSTR *names_entry, *names_ext_entry; VSC_VK *vsc2vk_e0_entry, *vsc2vk_e1_entry; VK_TO_WCHARS8 *vk2wchars_entry; @@ -493,6 +493,7 @@ static void add_xkb_layout(const char *xkb_layout, struct xkb_keymap *xkb_keymap control_mask = 1 << xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL); capslock_mask = 1 << xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS); altgr_mask = 1 << xkb_keymap_mod_get_index(xkb_keymap, "Mod5"); + numlock_mask = 1 << xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_NUM);
for (keyc = min_keycode; keyc <= max_keycode; keyc++) { @@ -502,6 +503,19 @@ static void add_xkb_layout(const char *xkb_layout, struct xkb_keymap *xkb_keymap uint32_t caps_ret, shift_ret; unsigned int mod;
+ if ((vkey & KBDNUMPAD) && (vkey & 0xff) == VK_DELETE) + { + VK_TO_WCHARS8 num_vkey2wch = {.VirtualKey = VK_DECIMAL}; + + xkb_state_update_mask(xkb_state, 0, 0, numlock_mask, 0, 0, xkb_group); + if (!(num_vkey2wch.wch[0] = xkb_state_key_get_utf32(xkb_state, keyc))) + num_vkey2wch.wch[0] = WCH_NONE; + for (mod = 1; mod < 8; ++mod) num_vkey2wch.wch[mod] = WCH_NONE; + num_vkey2wch.Attributes = 0; + TRACE("vkey %#06x -> %s\n", num_vkey2wch.VirtualKey, debugstr_wn(num_vkey2wch.wch, 8)); + *vk2wchars_entry++ = num_vkey2wch; + } + for (mod = 0; mod < 8; ++mod) { xkb_mod_mask_t mod_mask = 0;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=145715
Your paranoid android.
=== w1064v1809 (32 bit report) ===
user32: input.c:4173: Test failed: layered 2: button_down_hwnd_todo 0 (missing): LL_HOOK_MOUSE msg 0, point (0,0), data 0, flags 0, time 0, extra 0 input.c:4173: Test failed: layered 2: button_down_hwnd_todo 1 (missing): MSG_TEST_WIN hwnd 00140272, WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032 input.c:4179: Test failed: layered 2: button_up_hwnd_todo 0: got LL_HOOK_MOUSE msg WM_LBUTTONDOWN, point (50,50), data 0, flags 0x1, time 6733765, extra 0 input.c:4179: Test failed: layered 2: button_up_hwnd_todo 1: got LL_HOOK_MOUSE msg WM_LBUTTONUP, point (50,50), data 0, flags 0x1, time 6733781, extra 0 input.c:4179: Test failed: layered 2: button_up_hwnd_todo 2 (spurious): got MSG_TEST_WIN hwnd 00140272, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032 input.c:4179: Test failed: layered 2: button_up_hwnd_todo 3 (spurious): got MSG_TEST_WIN hwnd 00140272, msg WM_LBUTTONUP, wparam 0, lparam 0x320032
=== w11pro64 (32 bit report) ===
user32: input.c:4193: Test failed: layered 2: button_down_hwnd_todo 0: got MSG_TEST_WIN hwnd 000E0278, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032 input.c:4193: Test failed: layered 2: button_down_hwnd_todo 1 (missing): MSG_TEST_WIN hwnd 000E0278, WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032
=== w11pro64_amd (64 bit report) ===
user32: input.c:4179: Test failed: layered 0: button_up_hwnd_todo 0: got MSG_TEST_WIN hwnd 0000000000050064, msg WM_LBUTTONUP, wparam 0, lparam 0x320032 input.c:4179: Test failed: layered 0: button_up_hwnd_todo 1 (missing): MSG_TEST_WIN hwnd 0000000000050064, WM_LBUTTONUP, wparam 0, lparam 0x320032
On Mon May 20 14:47:28 2024 +0000, Alexandros Frantzis wrote:
changed this line in [version 7 of the diff](/wine/wine/-/merge_requests/5601/diffs?diff_id=114433&start_sha=ed7f1c038b00d092eb1bcd676b66bce8e87b4f90#b4e51a57fda93554e5c008a209f92ef67bd4d777_1286_1286)
Done in v7.
v7: Compare against full HKL value to determine current layout.
Testbot for v7: https://testbot.winehq.org/JobDetails.pl?Key=145715
This merge request was approved by Rémi Bernon.