python3注冊全局熱鍵的實現(xiàn)
之前用python3做游戲自動化腳本,用過很多東西,然后最終有一套完整的方案。在這里隨便闡述一下核心思路:
游戲輔助的窗體設計方面:
不需要pyqt這種大型軟件,寫小工具用自帶的tkinter就行了。當然,并不是自己純手敲代碼,是通過拖拽來實現(xiàn)的。怎么,你還不知道tkinter可以界面拖拽生成代碼就行VB一樣?
呵呵,PAGE了解一下。
游戲輔助的應用發(fā)布方面:
自然是用pyinstaller打包成32位版的exe發(fā)布了,帶上程序圖標,版本信息,都不是事兒
游戲核心模擬方面:
當然不是通過手敲代碼實現(xiàn)了,而是通過調(diào)用目前市場上強大的dll插件了。比如com組件如大漠插件、樂玩插件。或者說,把易語言的一些模塊編譯成windll來調(diào)用也行哦
輔助窗體熱鍵注冊方面:
這些需要用到底層的東西了,用win32的東西實現(xiàn)的,可以實現(xiàn)注冊全局熱鍵。原理是單獨一個線程用于檢測熱鍵按下,然后熱鍵按下后單獨開辟線程執(zhí)行需要的功能。鑒于原生的太難寫,我自己封裝了并且寫了一個demo。注冊全局組合鍵和單獨的熱鍵都是沒問題的。
前面三個方面仁者見仁了。后面這個我就貼個核心源碼吧,免得以后找不到了。
下面貼一段新的代碼:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File : 簡單熱鍵.py
# Author: DaShenHan&道長-----先苦后甜,任憑晚風拂柳顏------
# Date : 2020/3/4
import win32con
import ctypes
import ctypes.wintypes
from threading import Thread,activeCount, enumerate
from time import sleep,time
class Hotkey(Thread):
user32 = ctypes.windll.user32
hkey_list = {}
hkey_flags = {} #按下
hkey_running = {} #啟停
_reg_list = {} #待注冊熱鍵信息
def regiskey(self, hwnd=None, flagid=0, fnkey=win32con.MOD_ALT, vkey=win32con.VK_F9): # 注冊熱鍵,默認一個alt+F9
return self.user32.RegisterHotKey(hwnd, flagid, fnkey, vkey)
def get_reginfo(self):
return self._reg_list
def get_id(self,func):
self_id = None
for id in self.get_reginfo():
if self.get_reginfo()[id]["func"] == func:
self_id = id
break
if self_id:
self.hkey_running[self_id] = True
return self_id
def get_running_state(self,self_id):
if self.hkey_running.get(self_id):
return self.hkey_running[self_id]
else:
return False
def 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 id
def fast_reg(self,id,key = (0,win32con.VK_HOME),func = lambda:print('熱鍵注冊開始')):
if not self.regiskey(None, id, key[0], key[1]):
print("熱鍵注冊失敗")
return None
self.hkey_list[id] = func
self.hkey_flags[id] = False
return id
def callback(self):
def inner(self = self):
for flag in self.hkey_flags:
self.hkey_flags[flag] = False
while True:
for id, func in self.hkey_list.items():
if self.hkey_flags[id]:
args = self._reg_list[id]["args"]
if args:
# print(args) #這里打印傳入給注冊函數(shù)的參數(shù)
thread_it(func,*args)
else:
thread_it(func)
self.hkey_flags[id] = False
return inner
def 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) # 啟動監(jiān)聽熱鍵按下線程
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] = True
self.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] = False
print(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鍵 結(jié)束
hotkey.start() #啟動熱鍵主線程
print(f"當前總線程數(shù)量:{activeCount()}")
print('當前線程列表:', enumerate())
print('熱鍵注冊初始化完畢,嘗試按組合鍵alt+Home 或者單鍵END看效果')
if __name__ == '__main__':
main()
以下是舊的代碼,用起來比較麻煩。
#!/usr/bin/env python3
# _*_ coding: utf-8 _*_
# File : demo.py
# Author: DaShenHan&道長-----先苦后甜,任憑晚風拂柳顏------
# Date : 2019/6/28
import win32con
import ctypes
import ctypes.wintypes
from threading import Thread, Timer, activeCount, enumerate
from time import sleep
h_ids = [i for i in range(2)] # 創(chuàng)建兩個熱鍵序列
h_keys = {i: False for i in h_ids} # 初始化所有熱鍵序列的標志符為False
h_dict = {} # 初始化一個空的字典,記錄id與func
class Hotkey(Thread): # 創(chuàng)建一個Thread的擴展類
user32 = ctypes.windll.user32 # 加載user32.dll
# global h_ids, h_keys,h_dict
def regiskey(self, hwnd=None, flagid=0, fnkey=win32con.MOD_ALT, vkey=win32con.VK_F9): # 注冊熱鍵,默認一個alt+F9
return self.user32.RegisterHotKey(hwnd, flagid, fnkey, vkey)
def callback(self, id, func):
h_dict[id] = func # 這個id對應這個func,沒有就是新增,有就是修改
def inner():
for key, value in h_dict.items():
print(f'總的熱鍵池:{h_ids},當前熱鍵序號:{key}, 當前熱鍵功能:{value},當前熱鍵狀態(tài):{h_keys[h_ids[key]]}')
while True:
for key, value in h_dict.items():
if h_keys[h_ids[key]]:
thread_it(value) # 另外開線程執(zhí)行value
h_keys[h_ids[key]] = False
return inner
def run(self):
# print(self.user32)
if not self.regiskey(None,h_ids[0],win32con.MOD_ALT,win32con.VK_F9): # 注冊快捷鍵alt+F9并判斷是否成功,該熱鍵用于執(zhí)行一次需要執(zhí)行的內(nèi)容。
print(f"熱鍵注冊失?。?id{h_ids[0]}") # 返回一個錯誤信息
if not self.regiskey(None,h_ids[1],0,win32con.VK_F10): # 注冊快捷鍵F10并判斷是否成功,該熱鍵用于結(jié)束程序,且最好這么結(jié)束,否則影響下一次注冊熱鍵。
print(f"熱鍵注冊失??! id{h_ids[1]}")
# 以下為檢測熱鍵是否被按下,并在最后釋放快捷鍵
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 h_ids:
h_keys[msg.wParam] = True
self.user32.TranslateMessage(ctypes.byref(msg))
self.user32.DispatchMessageA(ctypes.byref(msg))
finally:
for i in h_ids:
self.user32.UnregisterHotKey(None, i)
# 必須得釋放熱鍵,否則下次就會注冊失敗,所以當程序異常退出,沒有釋放熱鍵,
# 那么下次很可能就沒辦法注冊成功了,這時可以換一個熱鍵測試
def thread_it(func, *args):
t = Thread(target=func, args=args)
t.setDaemon(True)
t.start()
def settimeout(func, sec):
def inner():
func()
Timer(sec, inner).start()
thread_it(inner)
def setinterval(func, sec, tmrname, flag=True):
global timer_dict
timer_dict[tmrname] = flag
print("已設置tqtimer啟用狀態(tài)為:{}".format(flag))
def inner():
global timer_dict
if timer_dict[tmrname]:
func()
Timer(sec, inner).start()
thread_it(inner)
def clearinterval(timername):
global timer_dict
timer_dict[timername] = False
flag = timer_dict[timername]
print("已設置tqtimer啟用狀態(tài)為:{}".format(flag))
def test_start():
print("按下了開始鍵...the programe is running")
def test_stop():
print("按下了停止鍵...the programe is stopped")
def run_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"當前總線程數(shù)量:{count}")
print('當前線程列表:', enumerate())
print('熱鍵注冊初始化完畢,嘗試按組合鍵alt+F9 或者單鍵F10看效果')
while True:
pass
if __name__ == '__main__':
run_ok()
這里是沒弄界面的源碼,所以我就把主線程死循環(huán)阻塞了。運行后按alt+F9會打印按下了開始鍵,按F10會打印按下了停止鍵。
如果你在tkinter里面跑,直接把run_ok函數(shù)后面的while True:pass刪掉,然后在init函數(shù)里面加入run_ok()就行了。這里指的用PAGE設計的tkinter程序哈!
那么窗體創(chuàng)建完畢就會自動阻塞主線程,其他監(jiān)控熱鍵的線程隨主線程結(jié)束。啟動期間獨立運行互不干擾。
到此這篇關于python3注冊全局熱鍵的實現(xiàn)的文章就介紹到這了,更多相關python3 注冊全局熱鍵內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python實現(xiàn)將一個大文件按段落分隔為多個小文件的簡單操作方法
這篇文章主要介紹了Python實現(xiàn)將一個大文件按段落分隔為多個小文件的簡單操作方法,涉及Python針對文件的讀取、遍歷、轉(zhuǎn)換、寫入等相關操作技巧,需要的朋友可以參考下2017-04-04
Pytorch BCELoss和BCEWithLogitsLoss的使用

