1 捕获键盘

(1) 在头文件中声明

  1. typedef struct HOTKEYINFORMATION {
  2. int identification; //标识
  3. unsigned long childevent; //事件子程序
  4. int normalkey; //普通键
  5. int functionkey; //功能键
  6. int otherkey; //其他键
  7. BYTE keystate; //键状态
  8. bool state; //状态
  9. bool directlytrigger;//直接触发
  10. }HKI;
  11. void MonitorHotkeyThreads();
  12. int MonitorTheHotkey(DWORD Event, int keycode, int functionstate = 0, int otherkey = 0, int period = 10, bool directlytrigger = false);

(2) 在cpp中定义

  1. vector<HKI> HotKeyInformation;
  2. void MonitorHotkeyThreads()
  3. {
  4. DWORD TempEvent;
  5. int tempidentification, tempvalue, BYTETemp;
  6. short cachstate[256];
  7. for (int i = 0; i < 255; ++i)
  8. {
  9. cachstate[i] = 251; //防检测
  10. cachstate[i] = GetAsyncKeyState(i);
  11. }
  12. for (vector<HKI>::iterator it = HotKeyInformation.begin(); it != HotKeyInformation.end(); ++it)
  13. {
  14. if (it->identification)
  15. {
  16. BYTETemp = (BYTE)it->normalkey;
  17. BYTETemp = cachstate[BYTETemp];
  18. if (BYTETemp == 0) //无状态
  19. {
  20. if (it->keystate == 1)
  21. {
  22. it->keystate = 2;
  23. }
  24. else
  25. {
  26. it->keystate = 0;
  27. continue; //如果啥键也没有按一直做状态判断循环
  28. }
  29. }
  30. if (BYTETemp < 0) //按下状态
  31. {
  32. if (it->keystate == 0)
  33. {
  34. it->keystate = 1;
  35. }
  36. if (it->normalkey < 0)
  37. {
  38. continue;
  39. }
  40. }
  41. /*监视热键_信息 [i].功能键 = 选择 (缓存键状态 [18] < 0, 1, 0) + 选择 (缓存键状态 [17] < 0, 2, 0) + 选择 (缓存键状态 [16] < 0, 4, 0) + 选择 (缓存键状态 [91] < 0, 8, 0))*/
  42. if (it->keystate > 0 && it->keystate != 88)
  43. {
  44. it->keystate = 88;
  45. tempvalue = (cachstate[18] < 0 ? 1 : 0) + (cachstate[17] < 0 ? 2 : 0) + (cachstate[16] < 0 ? 4 : 0) + (cachstate[91] < 0 ? 8 : 0);
  46. if (tempvalue == it->functionkey)
  47. {
  48. if (it->otherkey != 0)
  49. {
  50. BYTETemp = (BYTE)abs(it->otherkey);
  51. if (cachstate[BYTETemp] >= 0)
  52. {
  53. continue;
  54. }
  55. }
  56. TempEvent = it->childevent;
  57. tempidentification = it->identification;
  58. if (it->directlytrigger)
  59. {
  60. CallWindowProc((WNDPROC)TempEvent, (HWND)tempidentification, 0, 0, 0);
  61. }
  62. else
  63. {
  64. HANDLE handle = (HANDLE)_beginthreadex(nullptr, 0, (_beginthreadex_proc_type)TempEvent, nullptr, 0, nullptr);
  65. CloseHandle(handle);
  66. }
  67. }
  68. }
  69. }
  70. }
  71. }
  72. int MonitorTheHotkey(DWORD Event, int keycode, int functionstate /*= 0*/, int otherkey /*= 0*/, int period /*= 10*/, bool directlytrigger /*= false*/)
  73. {
  74. HKI TempHotKeyInformation;
  75. if ((BYTE)keycode <= 0)
  76. {
  77. return 0;
  78. }
  79. for (vector<HKI>::iterator it = HotKeyInformation.begin(); it != HotKeyInformation.end(); ++it)
  80. {
  81. if (it->normalkey == keycode && it->functionkey == functionstate && it->otherkey == otherkey)
  82. {
  83. it->childevent = Event;
  84. it->directlytrigger = directlytrigger;
  85. if (it->identification != 0)
  86. {
  87. return it->identification;
  88. }
  89. it->identification = (it - HotKeyInformation.begin()) + 1000001;
  90. return it->identification;
  91. }
  92. }
  93. TempHotKeyInformation.childevent = Event;
  94. TempHotKeyInformation.normalkey = keycode;
  95. TempHotKeyInformation.functionkey = functionstate;
  96. TempHotKeyInformation.otherkey = otherkey;
  97. TempHotKeyInformation.directlytrigger = directlytrigger;
  98. TempHotKeyInformation.identification = HotKeyInformation.size() + 1000001;
  99. HotKeyInformation.push_back(TempHotKeyInformation);//将临时的加入里面
  100. if (TempHotKeyInformation.identification == 1000001)
  101. {
  102. SetTimer(NULL, 661, period, (TIMERPROC)MonitorHotkeyThreads);
  103. }
  104. return TempHotKeyInformation.identification;
  105. }

(3) 在窗口构造函数中加入
MonitorTheHotkey((DWORD)HTK_RUN_Event, VK_HOME); // 捕获HOME热键

2 Qt注册全局热键

(注: 如果用的是静态编绎的Qt库, 则注册的热键无效)
1 添加user32.lib(用Vs时可跳过此步, 用Qt Creator需要在pro中加入)
image.png

2 注册全局热键
image.png

3 添加nativeEvent函数来接收系统消息
image.png

4 扩展, 更改热键

  1. connect(ui.HTKE_RUN, &QKeySequenceEdit::keySequenceChanged, [=](const QKeySequence &keySequence) {
  2. QKeySequence Key_RUN = ui.HTKE_RUN->keySequence();
  3. qDebug() << Key_RUN;
  4. QString str = Key_RUN.toString();
  5. qDebug() << str;
  6. QStringList strLst = str.split('+');
  7. QString str_MOD, str_VK = NULL;
  8. if (strLst[0].compare("Ctrl") == 0)
  9. {
  10. str_MOD = MOD_CONTROL;
  11. str_VK = strLst[1];
  12. }
  13. });

5 扩展,添加热键事件

  1. bool KingHonor::nativeEvent(const QByteArray & eventType, void * message, long * result)
  2. {
  3. if (eventType == "windows_generic_MSG")
  4. {
  5. MSG* pMsg = reinterpret_cast<MSG*>(message);
  6. if (pMsg->message == WM_HOTKEY)
  7. {
  8. if (pMsg->wParam == HTK_RUN)
  9. {
  10. qDebug() << "------------HTK_RUN 被按下-----------";
  11. HTK_RUN_Event();
  12. }
  13. else if (pMsg->wParam == HTK_STOP)
  14. {
  15. qDebug() << "------------HTK_STOP 被按下------------";
  16. HTK_STOP_Event();
  17. }
  18. else if (pMsg->wParam == HTK_END)
  19. {
  20. qDebug() << "------------HTK_END 被按下------------";
  21. HTK_END_Event();
  22. }
  23. }
  24. }
  25. return QWidget::nativeEvent(eventType, message, result);
  26. }

3 pyqt注册全局热键

  1. import win32con
  2. import ctypes
  3. import ctypes.wintypes
  4. from threading import Thread,activeCount, enumerate
  5. from time import sleep,time
  6. class Hotkey(Thread):
  7. user32 = ctypes.windll.user32
  8. hkey_list = {}
  9. hkey_flags = {} #按下
  10. hkey_running = {} #启停
  11. _reg_list = {} #待注册热键信息
  12. def regiskey(self, hwnd=None, flagid=0, fnkey=win32con.MOD_ALT, vkey=win32con.VK_F9): # 注册热键,默认一个alt+F9
  13. return self.user32.RegisterHotKey(hwnd, flagid, fnkey, vkey)
  14. def get_reginfo(self):
  15. return self._reg_list
  16. def get_id(self,func):
  17. self_id = None
  18. for id in self.get_reginfo():
  19. if self.get_reginfo()[id]["func"] == func:
  20. self_id = id
  21. break
  22. if self_id:
  23. self.hkey_running[self_id] = True
  24. return self_id
  25. def get_running_state(self,self_id):
  26. if self.hkey_running.get(self_id):
  27. return self.hkey_running[self_id]
  28. else:
  29. return False
  30. def reg(self,key,func,args=None):
  31. id = int(str(round(time()*10))[-6:])
  32. fnkey = key[0]
  33. vkey = key[1]
  34. info = {
  35. "fnkey":fnkey,
  36. "vkey":vkey,
  37. "func":func,
  38. "args":args
  39. }
  40. self._reg_list[id] = info
  41. # print(info) #这里待注册的信息
  42. sleep(0.1)
  43. return id
  44. def fast_reg(self,id,key = (0,win32con.VK_HOME),func = lambda:print('热键注册开始')):
  45. if not self.regiskey(None, id, key[0], key[1]):
  46. print("热键注册失败")
  47. return None
  48. self.hkey_list[id] = func
  49. self.hkey_flags[id] = False
  50. return id
  51. def callback(self):
  52. def inner(self = self):
  53. for flag in self.hkey_flags:
  54. self.hkey_flags[flag] = False
  55. while True:
  56. for id, func in self.hkey_list.items():
  57. if self.hkey_flags[id]:
  58. args = self._reg_list[id]["args"]
  59. if args:
  60. # print(args) #这里打印传入给注册函数的参数
  61. thread_it(func,*args)
  62. else:
  63. thread_it(func)
  64. self.hkey_flags[id] = False
  65. return inner
  66. def run(self):
  67. for id in self._reg_list:
  68. reg_info = self._reg_list[id]
  69. fnkey = reg_info["fnkey"]
  70. vkey = reg_info["vkey"]
  71. func = reg_info["func"]
  72. self.fast_reg(id,(fnkey, vkey), func)
  73. fn = self.callback()
  74. thread_it(fn) # 启动监听热键按下线程
  75. try:
  76. msg = ctypes.wintypes.MSG()
  77. while True:
  78. if self.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
  79. if msg.message == win32con.WM_HOTKEY:
  80. if msg.wParam in self.hkey_list:
  81. self.hkey_flags[msg.wParam] = True
  82. self.user32.TranslateMessage(ctypes.byref(msg))
  83. self.user32.DispatchMessageA(ctypes.byref(msg))
  84. finally:
  85. for id in self.hkey_list:
  86. self.user32.UnregisterHotKey(None, id)
  87. def thread_it(func, *args):
  88. t = Thread(target=func, args=args)
  89. t.setDaemon(True)
  90. t.start()
  91. def jump(func,hotkey):
  92. self_id = hotkey.get_id(func)
  93. while hotkey.get_running_state(self_id):
  94. print(f"{self_id : } 你正在1秒1次的跳动")
  95. sleep(1)
  96. def stop_jump(start_id,hotkey):
  97. hotkey.hkey_running[start_id] = False
  98. print(f"{start_id} 即将停止")
  99. sleep(1)
  100. print(f'当前线程列表:{activeCount()}', enumerate())
  101. def main():
  102. hotkey = Hotkey()
  103. start_id = hotkey.reg(key = (win32con.MOD_ALT,win32con.VK_HOME),func=jump,args=(jump,hotkey)) #alt home键 开始
  104. hotkey.reg(key = (0,win32con.VK_END),func=stop_jump,args=(start_id,hotkey)) #alt end键 结束
  105. hotkey.start() #启动热键主线程
  106. print(f"当前总线程数量:{activeCount()}")
  107. print('当前线程列表:', enumerate())
  108. print('热键注册初始化完毕,尝试按组合键alt+Home 或者单键END看效果')
  109. if __name__ == '__main__':
  110. main()