1 捕获键盘
(1) 在头文件中声明
typedef struct HOTKEYINFORMATION {int identification; //标识unsigned long childevent; //事件子程序int normalkey; //普通键int functionkey; //功能键int otherkey; //其他键BYTE keystate; //键状态bool state; //状态bool directlytrigger;//直接触发}HKI;void MonitorHotkeyThreads();int MonitorTheHotkey(DWORD Event, int keycode, int functionstate = 0, int otherkey = 0, int period = 10, bool directlytrigger = false);
(2) 在cpp中定义
vector<HKI> HotKeyInformation;void MonitorHotkeyThreads(){DWORD TempEvent;int tempidentification, tempvalue, BYTETemp;short cachstate[256];for (int i = 0; i < 255; ++i){cachstate[i] = 251; //防检测cachstate[i] = GetAsyncKeyState(i);}for (vector<HKI>::iterator it = HotKeyInformation.begin(); it != HotKeyInformation.end(); ++it){if (it->identification){BYTETemp = (BYTE)it->normalkey;BYTETemp = cachstate[BYTETemp];if (BYTETemp == 0) //无状态{if (it->keystate == 1){it->keystate = 2;}else{it->keystate = 0;continue; //如果啥键也没有按一直做状态判断循环}}if (BYTETemp < 0) //按下状态{if (it->keystate == 0){it->keystate = 1;}if (it->normalkey < 0){continue;}}/*监视热键_信息 [i].功能键 = 选择 (缓存键状态 [18] < 0, 1, 0) + 选择 (缓存键状态 [17] < 0, 2, 0) + 选择 (缓存键状态 [16] < 0, 4, 0) + 选择 (缓存键状态 [91] < 0, 8, 0))*/if (it->keystate > 0 && it->keystate != 88){it->keystate = 88;tempvalue = (cachstate[18] < 0 ? 1 : 0) + (cachstate[17] < 0 ? 2 : 0) + (cachstate[16] < 0 ? 4 : 0) + (cachstate[91] < 0 ? 8 : 0);if (tempvalue == it->functionkey){if (it->otherkey != 0){BYTETemp = (BYTE)abs(it->otherkey);if (cachstate[BYTETemp] >= 0){continue;}}TempEvent = it->childevent;tempidentification = it->identification;if (it->directlytrigger){CallWindowProc((WNDPROC)TempEvent, (HWND)tempidentification, 0, 0, 0);}else{HANDLE handle = (HANDLE)_beginthreadex(nullptr, 0, (_beginthreadex_proc_type)TempEvent, nullptr, 0, nullptr);CloseHandle(handle);}}}}}}int MonitorTheHotkey(DWORD Event, int keycode, int functionstate /*= 0*/, int otherkey /*= 0*/, int period /*= 10*/, bool directlytrigger /*= false*/){HKI TempHotKeyInformation;if ((BYTE)keycode <= 0){return 0;}for (vector<HKI>::iterator it = HotKeyInformation.begin(); it != HotKeyInformation.end(); ++it){if (it->normalkey == keycode && it->functionkey == functionstate && it->otherkey == otherkey){it->childevent = Event;it->directlytrigger = directlytrigger;if (it->identification != 0){return it->identification;}it->identification = (it - HotKeyInformation.begin()) + 1000001;return it->identification;}}TempHotKeyInformation.childevent = Event;TempHotKeyInformation.normalkey = keycode;TempHotKeyInformation.functionkey = functionstate;TempHotKeyInformation.otherkey = otherkey;TempHotKeyInformation.directlytrigger = directlytrigger;TempHotKeyInformation.identification = HotKeyInformation.size() + 1000001;HotKeyInformation.push_back(TempHotKeyInformation);//将临时的加入里面if (TempHotKeyInformation.identification == 1000001){SetTimer(NULL, 661, period, (TIMERPROC)MonitorHotkeyThreads);}return TempHotKeyInformation.identification;}
(3) 在窗口构造函数中加入
MonitorTheHotkey((DWORD)HTK_RUN_Event, VK_HOME); // 捕获HOME热键
2 Qt注册全局热键
(注: 如果用的是静态编绎的Qt库, 则注册的热键无效)
1 添加user32.lib(用Vs时可跳过此步, 用Qt Creator需要在pro中加入)
2 注册全局热键
3 添加nativeEvent函数来接收系统消息
4 扩展, 更改热键
connect(ui.HTKE_RUN, &QKeySequenceEdit::keySequenceChanged, [=](const QKeySequence &keySequence) {QKeySequence Key_RUN = ui.HTKE_RUN->keySequence();qDebug() << Key_RUN;QString str = Key_RUN.toString();qDebug() << str;QStringList strLst = str.split('+');QString str_MOD, str_VK = NULL;if (strLst[0].compare("Ctrl") == 0){str_MOD = MOD_CONTROL;str_VK = strLst[1];}});
5 扩展,添加热键事件
bool KingHonor::nativeEvent(const QByteArray & eventType, void * message, long * result){if (eventType == "windows_generic_MSG"){MSG* pMsg = reinterpret_cast<MSG*>(message);if (pMsg->message == WM_HOTKEY){if (pMsg->wParam == HTK_RUN){qDebug() << "------------HTK_RUN 被按下-----------";HTK_RUN_Event();}else if (pMsg->wParam == HTK_STOP){qDebug() << "------------HTK_STOP 被按下------------";HTK_STOP_Event();}else if (pMsg->wParam == HTK_END){qDebug() << "------------HTK_END 被按下------------";HTK_END_Event();}}}return QWidget::nativeEvent(eventType, message, result);}
3 pyqt注册全局热键
import win32conimport ctypesimport ctypes.wintypesfrom threading import Thread,activeCount, enumeratefrom time import sleep,timeclass Hotkey(Thread):user32 = ctypes.windll.user32hkey_list = {}hkey_flags = {} #按下hkey_running = {} #启停_reg_list = {} #待注册热键信息def regiskey(self, hwnd=None, flagid=0, fnkey=win32con.MOD_ALT, vkey=win32con.VK_F9): # 注册热键,默认一个alt+F9return self.user32.RegisterHotKey(hwnd, flagid, fnkey, vkey)def get_reginfo(self):return self._reg_listdef get_id(self,func):self_id = Nonefor id in self.get_reginfo():if self.get_reginfo()[id]["func"] == func:self_id = idbreakif self_id:self.hkey_running[self_id] = Truereturn self_iddef get_running_state(self,self_id):if self.hkey_running.get(self_id):return self.hkey_running[self_id]else:return Falsedef reg(self,key,func,args=None):id = int(str(round(time()*10))[-6:])fnkey = key[0]vkey = key[1]info = {"fnkey":fnkey,"vkey":vkey,"func":func,"args":args}self._reg_list[id] = info# print(info) #这里待注册的信息sleep(0.1)return iddef fast_reg(self,id,key = (0,win32con.VK_HOME),func = lambda:print('热键注册开始')):if not self.regiskey(None, id, key[0], key[1]):print("热键注册失败")return Noneself.hkey_list[id] = funcself.hkey_flags[id] = Falsereturn iddef callback(self):def inner(self = self):for flag in self.hkey_flags:self.hkey_flags[flag] = Falsewhile True:for id, func in self.hkey_list.items():if self.hkey_flags[id]:args = self._reg_list[id]["args"]if args:# print(args) #这里打印传入给注册函数的参数thread_it(func,*args)else:thread_it(func)self.hkey_flags[id] = Falsereturn innerdef run(self):for id in self._reg_list:reg_info = self._reg_list[id]fnkey = reg_info["fnkey"]vkey = reg_info["vkey"]func = reg_info["func"]self.fast_reg(id,(fnkey, vkey), func)fn = self.callback()thread_it(fn) # 启动监听热键按下线程try:msg = ctypes.wintypes.MSG()while True:if self.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:if msg.message == win32con.WM_HOTKEY:if msg.wParam in self.hkey_list:self.hkey_flags[msg.wParam] = Trueself.user32.TranslateMessage(ctypes.byref(msg))self.user32.DispatchMessageA(ctypes.byref(msg))finally:for id in self.hkey_list:self.user32.UnregisterHotKey(None, id)def thread_it(func, *args):t = Thread(target=func, args=args)t.setDaemon(True)t.start()def jump(func,hotkey):self_id = hotkey.get_id(func)while hotkey.get_running_state(self_id):print(f"{self_id : } 你正在1秒1次的跳动")sleep(1)def stop_jump(start_id,hotkey):hotkey.hkey_running[start_id] = Falseprint(f"{start_id} 即将停止")sleep(1)print(f'当前线程列表:{activeCount()}', enumerate())def main():hotkey = Hotkey()start_id = hotkey.reg(key = (win32con.MOD_ALT,win32con.VK_HOME),func=jump,args=(jump,hotkey)) #alt home键 开始hotkey.reg(key = (0,win32con.VK_END),func=stop_jump,args=(start_id,hotkey)) #alt end键 结束hotkey.start() #启动热键主线程print(f"当前总线程数量:{activeCount()}")print('当前线程列表:', enumerate())print('热键注册初始化完毕,尝试按组合键alt+Home 或者单键END看效果')if __name__ == '__main__':main()
