qhotkey_win.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #include "qhotkey.h"
  2. #include "qhotkey_p.h"
  3. #include <QDebug>
  4. #include <QTimer>
  5. #include <qt_windows.h>
  6. #define HKEY_ID(nativeShortcut) \
  7. (((nativeShortcut.key ^ (nativeShortcut.modifier << 8)) & 0x0FFF) | 0x7000)
  8. #if !defined(MOD_NOREPEAT)
  9. #define MOD_NOREPEAT 0x4000
  10. #endif
  11. class QHotkeyPrivateWin : public QHotkeyPrivate
  12. {
  13. public:
  14. QHotkeyPrivateWin();
  15. // QAbstractNativeEventFilter interface
  16. bool nativeEventFilter(const QByteArray& eventType,
  17. void* message,
  18. long* result) Q_DECL_OVERRIDE;
  19. protected:
  20. void pollForHotkeyRelease();
  21. // QHotkeyPrivate interface
  22. quint32 nativeKeycode(Qt::Key keycode, bool& ok) Q_DECL_OVERRIDE;
  23. quint32 nativeModifiers(Qt::KeyboardModifiers modifiers,
  24. bool& ok) Q_DECL_OVERRIDE;
  25. bool registerShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
  26. bool unregisterShortcut(QHotkey::NativeShortcut shortcut) Q_DECL_OVERRIDE;
  27. private:
  28. static QString formatWinError(DWORD winError);
  29. QTimer pollTimer;
  30. QHotkey::NativeShortcut polledShortcut;
  31. };
  32. NATIVE_INSTANCE(QHotkeyPrivateWin)
  33. QHotkeyPrivateWin::QHotkeyPrivateWin()
  34. {
  35. pollTimer.setInterval(50);
  36. connect(&pollTimer,
  37. &QTimer::timeout,
  38. this,
  39. &QHotkeyPrivateWin::pollForHotkeyRelease);
  40. }
  41. bool QHotkeyPrivate::isPlatformSupported()
  42. {
  43. return true;
  44. }
  45. bool QHotkeyPrivateWin::nativeEventFilter(const QByteArray& eventType,
  46. void* message,
  47. long* result)
  48. {
  49. Q_UNUSED(eventType)
  50. Q_UNUSED(result)
  51. MSG* msg = static_cast<MSG*>(message);
  52. if (msg->message == WM_HOTKEY) {
  53. QHotkey::NativeShortcut shortcut = { HIWORD(msg->lParam),
  54. LOWORD(msg->lParam) };
  55. this->activateShortcut(shortcut);
  56. this->polledShortcut = shortcut;
  57. this->pollTimer.start();
  58. }
  59. return false;
  60. }
  61. void QHotkeyPrivateWin::pollForHotkeyRelease()
  62. {
  63. bool pressed =
  64. (GetAsyncKeyState(this->polledShortcut.key) & (1 << 15)) != 0;
  65. if (!pressed) {
  66. this->pollTimer.stop();
  67. this->releaseShortcut(this->polledShortcut);
  68. }
  69. }
  70. quint32 QHotkeyPrivateWin::nativeKeycode(Qt::Key keycode, bool& ok)
  71. {
  72. ok = true;
  73. if (keycode <= 0xFFFF) { // Try to obtain the key from it's "character"
  74. const SHORT vKey = VkKeyScanW(static_cast<WCHAR>(keycode));
  75. if (vKey > -1)
  76. return LOBYTE(vKey);
  77. }
  78. // find key from switch/case --> Only finds a very small subset of keys
  79. switch (keycode) {
  80. case Qt::Key_Escape:
  81. return VK_ESCAPE;
  82. case Qt::Key_Tab:
  83. case Qt::Key_Backtab:
  84. return VK_TAB;
  85. case Qt::Key_Backspace:
  86. return VK_BACK;
  87. case Qt::Key_Return:
  88. case Qt::Key_Enter:
  89. return VK_RETURN;
  90. case Qt::Key_Insert:
  91. return VK_INSERT;
  92. case Qt::Key_Delete:
  93. return VK_DELETE;
  94. case Qt::Key_Pause:
  95. return VK_PAUSE;
  96. case Qt::Key_Print:
  97. return VK_PRINT;
  98. case Qt::Key_Clear:
  99. return VK_CLEAR;
  100. case Qt::Key_Home:
  101. return VK_HOME;
  102. case Qt::Key_End:
  103. return VK_END;
  104. case Qt::Key_Left:
  105. return VK_LEFT;
  106. case Qt::Key_Up:
  107. return VK_UP;
  108. case Qt::Key_Right:
  109. return VK_RIGHT;
  110. case Qt::Key_Down:
  111. return VK_DOWN;
  112. case Qt::Key_PageUp:
  113. return VK_PRIOR;
  114. case Qt::Key_PageDown:
  115. return VK_NEXT;
  116. case Qt::Key_CapsLock:
  117. return VK_CAPITAL;
  118. case Qt::Key_NumLock:
  119. return VK_NUMLOCK;
  120. case Qt::Key_ScrollLock:
  121. return VK_SCROLL;
  122. case Qt::Key_F1:
  123. return VK_F1;
  124. case Qt::Key_F2:
  125. return VK_F2;
  126. case Qt::Key_F3:
  127. return VK_F3;
  128. case Qt::Key_F4:
  129. return VK_F4;
  130. case Qt::Key_F5:
  131. return VK_F5;
  132. case Qt::Key_F6:
  133. return VK_F6;
  134. case Qt::Key_F7:
  135. return VK_F7;
  136. case Qt::Key_F8:
  137. return VK_F8;
  138. case Qt::Key_F9:
  139. return VK_F9;
  140. case Qt::Key_F10:
  141. return VK_F10;
  142. case Qt::Key_F11:
  143. return VK_F11;
  144. case Qt::Key_F12:
  145. return VK_F12;
  146. case Qt::Key_F13:
  147. return VK_F13;
  148. case Qt::Key_F14:
  149. return VK_F14;
  150. case Qt::Key_F15:
  151. return VK_F15;
  152. case Qt::Key_F16:
  153. return VK_F16;
  154. case Qt::Key_F17:
  155. return VK_F17;
  156. case Qt::Key_F18:
  157. return VK_F18;
  158. case Qt::Key_F19:
  159. return VK_F19;
  160. case Qt::Key_F20:
  161. return VK_F20;
  162. case Qt::Key_F21:
  163. return VK_F21;
  164. case Qt::Key_F22:
  165. return VK_F22;
  166. case Qt::Key_F23:
  167. return VK_F23;
  168. case Qt::Key_F24:
  169. return VK_F24;
  170. case Qt::Key_Menu:
  171. return VK_APPS;
  172. case Qt::Key_Help:
  173. return VK_HELP;
  174. case Qt::Key_MediaNext:
  175. return VK_MEDIA_NEXT_TRACK;
  176. case Qt::Key_MediaPrevious:
  177. return VK_MEDIA_PREV_TRACK;
  178. case Qt::Key_MediaPlay:
  179. return VK_MEDIA_PLAY_PAUSE;
  180. case Qt::Key_MediaStop:
  181. return VK_MEDIA_STOP;
  182. case Qt::Key_VolumeDown:
  183. return VK_VOLUME_DOWN;
  184. case Qt::Key_VolumeUp:
  185. return VK_VOLUME_UP;
  186. case Qt::Key_VolumeMute:
  187. return VK_VOLUME_MUTE;
  188. case Qt::Key_Mode_switch:
  189. return VK_MODECHANGE;
  190. case Qt::Key_Select:
  191. return VK_SELECT;
  192. case Qt::Key_Printer:
  193. return VK_PRINT;
  194. case Qt::Key_Execute:
  195. return VK_EXECUTE;
  196. case Qt::Key_Sleep:
  197. return VK_SLEEP;
  198. case Qt::Key_Period:
  199. return VK_DECIMAL;
  200. case Qt::Key_Play:
  201. return VK_PLAY;
  202. case Qt::Key_Cancel:
  203. return VK_CANCEL;
  204. case Qt::Key_Forward:
  205. return VK_BROWSER_FORWARD;
  206. case Qt::Key_Refresh:
  207. return VK_BROWSER_REFRESH;
  208. case Qt::Key_Stop:
  209. return VK_BROWSER_STOP;
  210. case Qt::Key_Search:
  211. return VK_BROWSER_SEARCH;
  212. case Qt::Key_Favorites:
  213. return VK_BROWSER_FAVORITES;
  214. case Qt::Key_HomePage:
  215. return VK_BROWSER_HOME;
  216. case Qt::Key_LaunchMail:
  217. return VK_LAUNCH_MAIL;
  218. case Qt::Key_LaunchMedia:
  219. return VK_LAUNCH_MEDIA_SELECT;
  220. case Qt::Key_Launch0:
  221. return VK_LAUNCH_APP1;
  222. case Qt::Key_Launch1:
  223. return VK_LAUNCH_APP2;
  224. case Qt::Key_Massyo:
  225. return VK_OEM_FJ_MASSHOU;
  226. case Qt::Key_Touroku:
  227. return VK_OEM_FJ_TOUROKU;
  228. default:
  229. if (keycode <= 0xFFFF)
  230. return (byte)keycode;
  231. else {
  232. ok = false;
  233. return 0;
  234. }
  235. }
  236. }
  237. quint32 QHotkeyPrivateWin::nativeModifiers(Qt::KeyboardModifiers modifiers,
  238. bool& ok)
  239. {
  240. quint32 nMods = 0;
  241. if (modifiers & Qt::ShiftModifier)
  242. nMods |= MOD_SHIFT;
  243. if (modifiers & Qt::ControlModifier)
  244. nMods |= MOD_CONTROL;
  245. if (modifiers & Qt::AltModifier)
  246. nMods |= MOD_ALT;
  247. if (modifiers & Qt::MetaModifier)
  248. nMods |= MOD_WIN;
  249. ok = true;
  250. return nMods;
  251. }
  252. bool QHotkeyPrivateWin::registerShortcut(QHotkey::NativeShortcut shortcut)
  253. {
  254. BOOL ok = RegisterHotKey(
  255. NULL, HKEY_ID(shortcut), shortcut.modifier + MOD_NOREPEAT, shortcut.key);
  256. if (ok)
  257. return true;
  258. else {
  259. error = QHotkeyPrivateWin::formatWinError(::GetLastError());
  260. return false;
  261. }
  262. }
  263. bool QHotkeyPrivateWin::unregisterShortcut(QHotkey::NativeShortcut shortcut)
  264. {
  265. BOOL ok = UnregisterHotKey(NULL, HKEY_ID(shortcut));
  266. if (ok)
  267. return true;
  268. else {
  269. error = QHotkeyPrivateWin::formatWinError(::GetLastError());
  270. return false;
  271. }
  272. }
  273. QString QHotkeyPrivateWin::formatWinError(DWORD winError)
  274. {
  275. wchar_t* buffer = NULL;
  276. DWORD num = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  277. FORMAT_MESSAGE_FROM_SYSTEM,
  278. NULL,
  279. winError,
  280. 0,
  281. (LPWSTR)&buffer,
  282. 0,
  283. NULL);
  284. if (buffer) {
  285. QString res = QString::fromWCharArray(buffer, num);
  286. LocalFree(buffer);
  287. return res;
  288. } else
  289. return QString();
  290. }