From: Alexandros Frantzis <alexandros.frantzis(a)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 | 22 ++++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 85f4867fff7..2b391cbe9e7 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 ea5ff42d7fe..459a26998b0 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3565,7 +3565,7 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA * NtUserGetKeyboardLayout supports non-current threads. */ HKL layout = NtUserGetKeyboardLayout( 0 ); 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 ed099b3b989..80d9dedbd90 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" @@ -2171,6 +2172,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: vkey = VK_NUMPAD0; break; + case VK_END: vkey = VK_NUMPAD1; break; + case VK_DOWN: vkey = VK_NUMPAD2; break; + case VK_NEXT: vkey = VK_NUMPAD3; break; + case VK_LEFT: vkey = VK_NUMPAD4; break; + case VK_CLEAR: vkey = VK_NUMPAD5; break; + case VK_RIGHT: vkey = VK_NUMPAD6; break; + case VK_HOME: vkey = VK_NUMPAD7; break; + case VK_UP: vkey = VK_NUMPAD8; break; + case VK_PRIOR: vkey = VK_NUMPAD9; break; + case VK_DELETE: vkey = VK_DECIMAL; break; + default: break; + } + } + if ((foreground = get_foreground_thread( desktop, win ))) { struct rawinput_message raw_msg = {0}; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5601