swift
keyboardwindows.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "keyboardwindows.h"
5 
6 using namespace swift::misc::input;
7 
8 namespace swift::input
9 {
10  static const auto &keyMapping()
11  {
12  static const QHash<int, KeyCode> hash {
13  { '0', Key_0 },
14  { '1', Key_1 },
15  { '2', Key_2 },
16  { '3', Key_3 },
17  { '4', Key_4 },
18  { '5', Key_5 },
19  { '6', Key_6 },
20  { '7', Key_7 },
21  { '8', Key_8 },
22  { '9', Key_9 },
23  { 'A', Key_A },
24  { 'B', Key_B },
25  { 'C', Key_C },
26  { 'D', Key_D },
27  { 'E', Key_E },
28  { 'F', Key_F },
29  { 'G', Key_G },
30  { 'H', Key_H },
31  { 'I', Key_I },
32  { 'J', Key_J },
33  { 'K', Key_K },
34  { 'L', Key_L },
35  { 'M', Key_M },
36  { 'N', Key_N },
37  { 'O', Key_O },
38  { 'P', Key_P },
39  { 'Q', Key_Q },
40  { 'R', Key_R },
41  { 'S', Key_S },
42  { 'T', Key_T },
43  { 'U', Key_U },
44  { 'V', Key_V },
45  { 'W', Key_W },
46  { 'X', Key_X },
47  { 'Y', Key_Y },
48  { 'Z', Key_Z },
49  { VK_LSHIFT, Key_ShiftLeft },
50  { VK_RSHIFT, Key_ShiftRight },
51  { VK_LCONTROL, Key_ControlLeft },
52  { VK_RCONTROL, Key_ControlRight },
53  { VK_LMENU, Key_AltLeft },
54  { VK_RMENU, Key_AltRight },
55  { VK_ADD, Key_Plus },
56  { VK_OEM_PLUS, Key_Plus },
57  { VK_SUBTRACT, Key_Minus },
58  { VK_OEM_MINUS, Key_Minus },
59  { VK_OEM_PERIOD, Key_Period },
60  { VK_DIVIDE, Key_Divide },
61  { VK_BACK, Key_Back },
62  { VK_TAB, Key_Tab },
63  { VK_ESCAPE, Key_Esc },
64  { VK_SPACE, Key_Space },
65  { VK_INSERT, Key_Insert },
66  { VK_DELETE, Key_Delete },
67  { VK_HOME, Key_Home },
68  { VK_END, Key_End },
69  { VK_PRIOR, Key_PageUp },
70  { VK_NEXT, Key_PageDown },
71  { VK_CAPITAL, Key_CapsLock },
72  { VK_RETURN, Key_Enter },
73  { VK_MULTIPLY, Key_Multiply },
74  { VK_SUBTRACT, Key_NumpadMinus },
75  { VK_ADD, Key_NumpadPlus },
76  { VK_DECIMAL, Key_NumpadDelete },
77  { VK_NUMPAD0, Key_Numpad0 },
78  { VK_NUMPAD1, Key_Numpad1 },
79  { VK_NUMPAD2, Key_Numpad2 },
80  { VK_NUMPAD3, Key_Numpad3 },
81  { VK_NUMPAD4, Key_Numpad4 },
82  { VK_NUMPAD5, Key_Numpad5 },
83  { VK_NUMPAD6, Key_Numpad6 },
84  { VK_NUMPAD7, Key_Numpad7 },
85  { VK_NUMPAD8, Key_Numpad8 },
86  { VK_NUMPAD9, Key_Numpad9 },
87  { VK_OEM_NEC_EQUAL, Key_NumpadEqual },
88  { VK_OEM_COMMA, Key_Comma },
89  { VK_OEM_1, Key_OEM1 },
90  { VK_OEM_2, Key_OEM2 },
91  { VK_OEM_3, Key_OEM3 },
92  { VK_OEM_4, Key_OEM4 },
93  { VK_OEM_5, Key_OEM5 },
94  { VK_OEM_6, Key_OEM6 },
95  { VK_OEM_7, Key_OEM7 },
96  { VK_OEM_8, Key_OEM8 },
97  { VK_OEM_102, Key_OEM102 },
98  { VK_F1, Key_Function1 },
99  { VK_F2, Key_Function2 },
100  { VK_F3, Key_Function3 },
101  { VK_F4, Key_Function4 },
102  { VK_F5, Key_Function5 },
103  { VK_F6, Key_Function6 },
104  { VK_F7, Key_Function7 },
105  { VK_F8, Key_Function8 },
106  { VK_F9, Key_Function9 },
107  { VK_F10, Key_Function10 },
108  { VK_F11, Key_Function11 },
109  { VK_F12, Key_Function12 },
110  { VK_F13, Key_Function13 },
111  { VK_F14, Key_Function14 },
112  { VK_F15, Key_Function15 },
113  { VK_F16, Key_Function16 },
114  { VK_F17, Key_Function17 },
115  { VK_F18, Key_Function18 },
116  { VK_F19, Key_Function19 },
117  { VK_F20, Key_Function20 },
118  { VK_F21, Key_Function21 },
119  { VK_F22, Key_Function22 },
120  { VK_F23, Key_Function23 },
121  { VK_F24, Key_Function24 },
122  };
123  return hash;
124  }
125 
126  static CKeyboardWindows *g_keyboardWindows = nullptr;
127 
128  CKeyboardWindows::CKeyboardWindows(QObject *parent) : IKeyboard(parent), m_keyboardHook(nullptr)
129  {
130  connect(&m_pollTimer, &QTimer::timeout, this, &CKeyboardWindows::pollKeyboardState);
131  }
132 
133  CKeyboardWindows::~CKeyboardWindows()
134  {
135  if (m_keyboardHook) { UnhookWindowsHookEx(m_keyboardHook); }
136  }
137 
138  bool CKeyboardWindows::init()
139  {
140  if (useWindowsHook) // cppcheck-suppress knownConditionTrueFalse
141  {
142  Q_ASSERT_X(g_keyboardWindows == nullptr, "CKeyboardWindows::init",
143  "Windows supports only one keyboard instance. Cannot initialize a second one!");
144  g_keyboardWindows = this;
145  HMODULE module;
146  GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
147  reinterpret_cast<LPCTSTR>(&CKeyboardWindows::keyboardProc), &module);
148  m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, CKeyboardWindows::keyboardProc, module, 0);
149  }
150  {
151  m_pollTimer.start(50);
152  }
153  return true;
154  }
155 
156  void CKeyboardWindows::processKeyEvent(DWORD vkcode, WPARAM event)
157  {
158  CHotkeyCombination oldCombination(m_keyCombination);
159  if ((event == WM_KEYDOWN) || (event == WM_SYSKEYDOWN))
160  {
161  auto key = keyMapping().value(static_cast<int>(vkcode));
162  if (key == Key_Unknown) { return; }
163  m_keyCombination.addKeyboardKey(CKeyboardKey(key));
164  }
165  else if ((event == WM_KEYUP) || (event == WM_SYSKEYUP))
166  {
167  auto key = keyMapping().value(static_cast<int>(vkcode));
168  if (key == Key_Unknown) { return; }
169  m_keyCombination.removeKeyboardKey(CKeyboardKey(key));
170  }
171 
172  if (oldCombination != m_keyCombination) { emit keyCombinationChanged(m_keyCombination); }
173  }
174 
175  void CKeyboardWindows::pollKeyboardState()
176  {
177  CHotkeyCombination oldCombination(m_keyCombination);
178  QList<int> vkeys = keyMapping().keys();
179  for (int vkey : vkeys)
180  {
181  if ((GetKeyState(vkey) & 0x8000) && !m_pressedKeys.contains(vkey))
182  {
183  // key down
184  auto key = keyMapping().value(vkey);
185  if (key == Key_Unknown) { return; }
186  m_pressedKeys.push_back(vkey);
187  m_keyCombination.addKeyboardKey(CKeyboardKey(key));
188  }
189  else if (!(GetKeyState(vkey) & 0x8000) && m_pressedKeys.contains(vkey))
190  {
191  // key up
192  auto key = keyMapping().value(vkey);
193  if (key == Key_Unknown) { return; }
194  m_pressedKeys.removeAll(vkey);
195  m_keyCombination.removeKeyboardKey(CKeyboardKey(key));
196  }
197  }
198 
199  if (oldCombination != m_keyCombination) { emit keyCombinationChanged(m_keyCombination); }
200  }
201 
202  LRESULT CALLBACK CKeyboardWindows::keyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
203  {
204  if (nCode == HC_ACTION)
205  {
206  KBDLLHOOKSTRUCT *keyboardEvent = reinterpret_cast<KBDLLHOOKSTRUCT *>(lParam);
207  DWORD vkCode = keyboardEvent->vkCode;
208  g_keyboardWindows->processKeyEvent(vkCode, wParam);
209  }
210  return CallNextHookEx(g_keyboardWindows->m_keyboardHook, nCode, wParam, lParam);
211  }
212 } // namespace swift::input
Value object representing hotkey sequence.
Value object representing a keyboard key.
Definition: keyboardkey.h:25
unsigned long DWORD
Fake Windows DWORD.