| /* | |
| * This work is licensed under the terms of the GNU GPL, version 2 or | |
| * (at your option) any later version. See the COPYING file in the | |
| * top-level directory. | |
| * | |
| * The win32 keyboard hooking code was imported from project spice-gtk. | |
| */ | |
| #include "qemu/osdep.h" | |
| #include "system/system.h" | |
| #include "ui/win32-kbd-hook.h" | |
| static Notifier win32_unhook_notifier; | |
| static HHOOK win32_keyboard_hook; | |
| static HWND win32_window; | |
| static DWORD win32_grab; | |
| static LRESULT CALLBACK keyboard_hook_cb(int code, WPARAM wparam, LPARAM lparam) | |
| { | |
| if (win32_window && code == HC_ACTION && win32_window == GetFocus()) { | |
| KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT *)lparam; | |
| if (wparam != WM_KEYUP) { | |
| DWORD dwmsg = (hooked->flags << 24) | | |
| ((hooked->scanCode & 0xff) << 16) | 1; | |
| switch (hooked->vkCode) { | |
| case VK_CAPITAL: | |
| /* fall through */ | |
| case VK_SCROLL: | |
| /* fall through */ | |
| case VK_NUMLOCK: | |
| /* fall through */ | |
| case VK_LSHIFT: | |
| /* fall through */ | |
| case VK_RSHIFT: | |
| /* fall through */ | |
| case VK_RCONTROL: | |
| /* fall through */ | |
| case VK_LMENU: | |
| /* fall through */ | |
| case VK_RMENU: | |
| break; | |
| case VK_LCONTROL: | |
| /* | |
| * When pressing AltGr, an extra VK_LCONTROL with a special | |
| * scancode with bit 9 set is sent. Let's ignore the extra | |
| * VK_LCONTROL, as that will make AltGr misbehave. | |
| */ | |
| if (hooked->scanCode & 0x200) { | |
| return 1; | |
| } | |
| break; | |
| default: | |
| if (win32_grab) { | |
| SendMessage(win32_window, wparam, hooked->vkCode, dwmsg); | |
| return 1; | |
| } | |
| break; | |
| } | |
| } else { | |
| switch (hooked->vkCode) { | |
| case VK_LCONTROL: | |
| if (hooked->scanCode & 0x200) { | |
| return 1; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| return CallNextHookEx(NULL, code, wparam, lparam); | |
| } | |
| static void keyboard_hook_unhook(Notifier *n, void *data) | |
| { | |
| UnhookWindowsHookEx(win32_keyboard_hook); | |
| win32_keyboard_hook = NULL; | |
| } | |
| void win32_kbd_set_window(void *hwnd) | |
| { | |
| if (hwnd && !win32_keyboard_hook) { | |
| /* note: the installing thread must have a message loop */ | |
| win32_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_cb, | |
| GetModuleHandle(NULL), 0); | |
| if (win32_keyboard_hook) { | |
| win32_unhook_notifier.notify = keyboard_hook_unhook; | |
| qemu_add_exit_notifier(&win32_unhook_notifier); | |
| } | |
| } | |
| win32_window = hwnd; | |
| } | |
| void win32_kbd_set_grab(bool grab) | |
| { | |
| win32_grab = grab; | |
| } |