xref: /qemu/ui/win32-kbd-hook.c (revision 2df9f571)
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