2
0

win32-kbd-hook.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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. #include "qemu/osdep.h"
  9. #include "sysemu/sysemu.h"
  10. #include "ui/win32-kbd-hook.h"
  11. static Notifier win32_unhook_notifier;
  12. static HHOOK win32_keyboard_hook;
  13. static HWND win32_window;
  14. static DWORD win32_grab;
  15. static LRESULT CALLBACK keyboard_hook_cb(int code, WPARAM wparam, LPARAM lparam)
  16. {
  17. if (win32_window && code == HC_ACTION && win32_window == GetFocus()) {
  18. KBDLLHOOKSTRUCT *hooked = (KBDLLHOOKSTRUCT *)lparam;
  19. if (wparam != WM_KEYUP) {
  20. DWORD dwmsg = (hooked->flags << 24) |
  21. ((hooked->scanCode & 0xff) << 16) | 1;
  22. switch (hooked->vkCode) {
  23. case VK_CAPITAL:
  24. /* fall through */
  25. case VK_SCROLL:
  26. /* fall through */
  27. case VK_NUMLOCK:
  28. /* fall through */
  29. case VK_LSHIFT:
  30. /* fall through */
  31. case VK_RSHIFT:
  32. /* fall through */
  33. case VK_RCONTROL:
  34. /* fall through */
  35. case VK_LMENU:
  36. /* fall through */
  37. case VK_RMENU:
  38. break;
  39. case VK_LCONTROL:
  40. /*
  41. * When pressing AltGr, an extra VK_LCONTROL with a special
  42. * scancode with bit 9 set is sent. Let's ignore the extra
  43. * VK_LCONTROL, as that will make AltGr misbehave.
  44. */
  45. if (hooked->scanCode & 0x200) {
  46. return 1;
  47. }
  48. break;
  49. default:
  50. if (win32_grab) {
  51. SendMessage(win32_window, wparam, hooked->vkCode, dwmsg);
  52. return 1;
  53. }
  54. break;
  55. }
  56. } else {
  57. switch (hooked->vkCode) {
  58. case VK_LCONTROL:
  59. if (hooked->scanCode & 0x200) {
  60. return 1;
  61. }
  62. break;
  63. }
  64. }
  65. }
  66. return CallNextHookEx(NULL, code, wparam, lparam);
  67. }
  68. static void keyboard_hook_unhook(Notifier *n, void *data)
  69. {
  70. UnhookWindowsHookEx(win32_keyboard_hook);
  71. win32_keyboard_hook = NULL;
  72. }
  73. void win32_kbd_set_window(void *hwnd)
  74. {
  75. if (hwnd && !win32_keyboard_hook) {
  76. /* note: the installing thread must have a message loop */
  77. win32_keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_hook_cb,
  78. GetModuleHandle(NULL), 0);
  79. if (win32_keyboard_hook) {
  80. win32_unhook_notifier.notify = keyboard_hook_unhook;
  81. qemu_add_exit_notifier(&win32_unhook_notifier);
  82. }
  83. }
  84. win32_window = hwnd;
  85. }
  86. void win32_kbd_set_grab(bool grab)
  87. {
  88. win32_grab = grab;
  89. }