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 | 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};