]>
Commit | Line | Data |
---|---|---|
2df9f571 VR |
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 | ||
13 | static Notifier win32_unhook_notifier; | |
14 | static HHOOK win32_keyboard_hook; | |
15 | static HWND win32_window; | |
16 | static DWORD win32_grab; | |
17 | ||
18 | static 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 | ||
78 | static void keyboard_hook_unhook(Notifier *n, void *data) | |
79 | { | |
80 | UnhookWindowsHookEx(win32_keyboard_hook); | |
81 | win32_keyboard_hook = NULL; | |
82 | } | |
83 | ||
84 | void 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 | ||
99 | void win32_kbd_set_grab(bool grab) | |
100 | { | |
101 | win32_grab = grab; | |
102 | } |