qemu/ui/win32-kbd-hook.c
<<
>>
Prefs
   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}
 103