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;