python3注册全局热键的实现
之前用python3做游戏自动化脚本,用过很多东西,然后最终有一套完整的方案。在这里随便阐述一下核心思路:
游戏辅助的窗体设计方面:
不需要pyqt这种大型软件,写小工具用自带的tkinter就行了。当然,并不是自己纯手敲代码,是通过拖拽来实现的。怎么,你还不知道tkinter可以界面拖拽生成代码就行VB一样?
呵呵,PAGE了解一下。
游戏辅助的应用发布方面:
自然是用pyinstaller打包成32位版的exe发布了,带上程序图标,版本信息,都不是事儿
游戏核心模拟方面:
当然不是通过手敲代码实现了,而是通过调用目前市场上强大的dll插件了。比如com组件如大漠插件、乐玩插件。或者说,把易语言的一些模块编译成windll来调用也行哦
辅助窗体热键注册方面:
这些需要用到底层的东西了,用win32的东西实现的,可以实现注册全局热键。原理是单独一个线程用于检测热键按下,然后热键按下后单独开辟线程执行需要的功能。鉴于原生的太难写,我自己封装了并且写了一个demo。注册全局组合键和单独的热键都是没问题的。
前面三个方面仁者见仁了。后面这个我就贴个核心源码吧,免得以后找不到了。
下面贴一段新的代码:
#!/usr/bin/envpython3 #-*-coding:utf-8-*- #File:简单热键.py #Author:DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------ #Date:2020/3/4 importwin32con importctypes importctypes.wintypes fromthreadingimportThread,activeCount,enumerate fromtimeimportsleep,time classHotkey(Thread): user32=ctypes.windll.user32 hkey_list={} hkey_flags={}#按下 hkey_running={}#启停 _reg_list={}#待注册热键信息 defregiskey(self,hwnd=None,flagid=0,fnkey=win32con.MOD_ALT,vkey=win32con.VK_F9):#注册热键,默认一个alt+F9 returnself.user32.RegisterHotKey(hwnd,flagid,fnkey,vkey) defget_reginfo(self): returnself._reg_list defget_id(self,func): self_id=None foridinself.get_reginfo(): ifself.get_reginfo()[id]["func"]==func: self_id=id break ifself_id: self.hkey_running[self_id]=True returnself_id defget_running_state(self,self_id): ifself.hkey_running.get(self_id): returnself.hkey_running[self_id] else: returnFalse defreg(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) returnid deffast_reg(self,id,key=(0,win32con.VK_HOME),func=lambda:print('热键注册开始')): ifnotself.regiskey(None,id,key[0],key[1]): print("热键注册失败") returnNone self.hkey_list[id]=func self.hkey_flags[id]=False returnid defcallback(self): definner(self=self): forflaginself.hkey_flags: self.hkey_flags[flag]=False whileTrue: forid,funcinself.hkey_list.items(): ifself.hkey_flags[id]: args=self._reg_list[id]["args"] ifargs: #print(args)#这里打印传入给注册函数的参数 thread_it(func,*args) else: thread_it(func) self.hkey_flags[id]=False returninner defrun(self): foridinself._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() whileTrue: ifself.user32.GetMessageA(ctypes.byref(msg),None,0,0)!=0: ifmsg.message==win32con.WM_HOTKEY: ifmsg.wParaminself.hkey_list: self.hkey_flags[msg.wParam]=True self.user32.TranslateMessage(ctypes.byref(msg)) self.user32.DispatchMessageA(ctypes.byref(msg)) finally: foridinself.hkey_list: self.user32.UnregisterHotKey(None,id) defthread_it(func,*args): t=Thread(target=func,args=args) t.setDaemon(True) t.start() defjump(func,hotkey): self_id=hotkey.get_id(func) whilehotkey.get_running_state(self_id): print(f"{self_id:}你正在1秒1次的跳动") sleep(1) defstop_jump(start_id,hotkey): hotkey.hkey_running[start_id]=False print(f"{start_id}即将停止") sleep(1) print(f'当前线程列表:{activeCount()}',enumerate()) defmain(): hotkey=Hotkey() start_id=hotkey.reg(key=(win32con.MOD_ALT,win32con.VK_HOME),func=jump,args=(jump,hotkey))#althome键开始 hotkey.reg(key=(0,win32con.VK_END),func=stop_jump,args=(start_id,hotkey))#altend键结束 hotkey.start()#启动热键主线程 print(f"当前总线程数量:{activeCount()}") print('当前线程列表:',enumerate()) print('热键注册初始化完毕,尝试按组合键alt+Home或者单键END看效果') if__name__=='__main__': main()
以下是旧的代码,用起来比较麻烦。
#!/usr/bin/envpython3 #_*_coding:utf-8_*_ #File:demo.py #Author:DaShenHan&道长-----先苦后甜,任凭晚风拂柳颜------ #Date:2019/6/28 importwin32con importctypes importctypes.wintypes fromthreadingimportThread,Timer,activeCount,enumerate fromtimeimportsleep h_ids=[iforiinrange(2)]#创建两个热键序列 h_keys={i:Falseforiinh_ids}#初始化所有热键序列的标志符为False h_dict={}#初始化一个空的字典,记录id与func classHotkey(Thread):#创建一个Thread的扩展类 user32=ctypes.windll.user32#加载user32.dll #globalh_ids,h_keys,h_dict defregiskey(self,hwnd=None,flagid=0,fnkey=win32con.MOD_ALT,vkey=win32con.VK_F9):#注册热键,默认一个alt+F9 returnself.user32.RegisterHotKey(hwnd,flagid,fnkey,vkey) defcallback(self,id,func): h_dict[id]=func#这个id对应这个func,没有就是新增,有就是修改 definner(): forkey,valueinh_dict.items(): print(f'总的热键池:{h_ids},当前热键序号:{key},当前热键功能:{value},当前热键状态:{h_keys[h_ids[key]]}') whileTrue: forkey,valueinh_dict.items(): ifh_keys[h_ids[key]]: thread_it(value)#另外开线程执行value h_keys[h_ids[key]]=False returninner defrun(self): #print(self.user32) ifnotself.regiskey(None,h_ids[0],win32con.MOD_ALT,win32con.VK_F9):#注册快捷键alt+F9并判断是否成功,该热键用于执行一次需要执行的内容。 print(f"热键注册失败!id{h_ids[0]}")#返回一个错误信息 ifnotself.regiskey(None,h_ids[1],0,win32con.VK_F10):#注册快捷键F10并判断是否成功,该热键用于结束程序,且最好这么结束,否则影响下一次注册热键。 print(f"热键注册失败!id{h_ids[1]}") #以下为检测热键是否被按下,并在最后释放快捷键 try: msg=ctypes.wintypes.MSG() whileTrue: ifself.user32.GetMessageA(ctypes.byref(msg),None,0,0)!=0: ifmsg.message==win32con.WM_HOTKEY: ifmsg.wParaminh_ids: h_keys[msg.wParam]=True self.user32.TranslateMessage(ctypes.byref(msg)) self.user32.DispatchMessageA(ctypes.byref(msg)) finally: foriinh_ids: self.user32.UnregisterHotKey(None,i) #必须得释放热键,否则下次就会注册失败,所以当程序异常退出,没有释放热键, #那么下次很可能就没办法注册成功了,这时可以换一个热键测试 defthread_it(func,*args): t=Thread(target=func,args=args) t.setDaemon(True) t.start() defsettimeout(func,sec): definner(): func() Timer(sec,inner).start() thread_it(inner) defsetinterval(func,sec,tmrname,flag=True): globaltimer_dict timer_dict[tmrname]=flag print("已设置tqtimer启用状态为:{}".format(flag)) definner(): globaltimer_dict iftimer_dict[tmrname]: func() Timer(sec,inner).start() thread_it(inner) defclearinterval(timername): globaltimer_dict timer_dict[timername]=False flag=timer_dict[timername] print("已设置tqtimer启用状态为:{}".format(flag)) deftest_start(): print("按下了开始键...theprogrameisrunning") deftest_stop(): print("按下了停止键...theprogrameisstopped") defrun_ok(): hotkey=Hotkey() hotkey.start() fn=hotkey.callback(0,test_start) fn=hotkey.callback(1,test_stop) thread_it(fn) sleep(0.5) count=activeCount() print(f"当前总线程数量:{count}") print('当前线程列表:',enumerate()) print('热键注册初始化完毕,尝试按组合键alt+F9或者单键F10看效果') whileTrue: pass if__name__=='__main__': run_ok()
这里是没弄界面的源码,所以我就把主线程死循环阻塞了。运行后按alt+F9会打印按下了开始键,按F10会打印按下了停止键。
如果你在tkinter里面跑,直接把run_ok函数后面的whileTrue:pass删掉,然后在init函数里面加入run_ok()就行了。这里指的用PAGE设计的tkinter程序哈!
那么窗体创建完毕就会自动阻塞主线程,其他监控热键的线程随主线程结束。启动期间独立运行互不干扰。
到此这篇关于python3注册全局热键的实现的文章就介绍到这了,更多相关python3注册全局热键内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!