win32-kbd-hook.c (2986B)
1/* 2 * This work is licensed under the terms of the GNU GPL, version 2 or 3 * (at your option) any later version. See the COPYING file in the 4 * top-level directory. 5 * 6 * The win32 keyboard hooking code was imported from project spice-gtk. 7 */ 8 9#include "qemu/osdep.h" 10#include "sysemu/sysemu.h" 11#include "ui/win32-kbd-hook.h" 12 13static Notifier win32_unhook_notifier; 14static HHOOK win32_keyboard_hook; 15static HWND win32_window; 16static DWORD win32_grab; 17 18static LRESULT CALLBACK keyboard_hook_cb(int code, WPARAM wparam, LPARAM lparam) 19{ 20 if (win32_window && code == HC_ACTION && win32_window == GetFocus()) { 21 KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT *)lparam; 22 23 if (wparam != WM_KEYUP) { 24 DWORD dwmsg = (hooked->flags << 24) | 25 ((hooked->scanCode & 0xff) << 16) | 1; 26 27 switch (hooked->vkCode) { 28 case VK_CAPITAL: 29 /* fall through */ 30 case VK_SCROLL: 31 /* fall through */ 32 case VK_NUMLOCK: 33 /* fall through */ 34 case VK_LSHIFT: 35 /* fall through */ 36 case VK_RSHIFT: 37 /* fall through */ 38 case VK_RCONTROL: 39 /* fall through */ 40 case VK_LMENU: 41 /* fall through */ 42 case VK_RMENU: 43 break; 44 45 case VK_LCONTROL: 46 /* 47 * When pressing AltGr, an extra VK_LCONTROL with a special 48 * scancode with bit 9 set is sent. Let's ignore the extra 49 * VK_LCONTROL, as that will make AltGr misbehave. 50 */ 51 if (hooked->scanCode & 0x200) { 52 return 1; 53 } 54 break; 55 56 default: 57 if (win32_grab) { 58 SendMessage(win32_window, wparam, hooked->vkCode, dwmsg); 59 return 1; 60 } 61 break; 62 } 63 64 } else { 65 switch (hooked->vkCode) { 66 case VK_LCONTROL: 67 if (hooked->scanCode & 0x200) { 68 return 1; 69 } 70 break; 71 } 72 } 73 } 74 75 return CallNextHookEx(NULL, code, wparam, lparam); 76} 77 78static void keyboard_hook_unhook(Notifier *n, void *data) 79{ 80 UnhookWindowsHookEx(win32_keyboard_hook); 81 win32_keyboard_hook = NULL; 82} 83 84void win32_kbd_set_window(void *hwnd) 85{ 86 if (hwnd && !win32_keyboard_hook) { 87 /* note: the installing thread must have a message loop */ 88 win32_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_cb, 89 GetModuleHandle(NULL), 0); 90 if (win32_keyboard_hook) { 91 win32_unhook_notifier.notify = keyboard_hook_unhook; 92 qemu_add_exit_notifier(&win32_unhook_notifier); 93 } 94 } 95 96 win32_window = hwnd; 97} 98 99void win32_kbd_set_grab(bool grab) 100{ 101 win32_grab = grab; 102}