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