1. 程式人生 > 程式設計 >python3註冊全域性熱鍵的實現

python3註冊全域性熱鍵的實現

之前用python3做遊戲自動化指令碼,用過很多東西,然後最終有一套完整的方案。在這裡隨便闡述一下核心思路:

遊戲輔助的窗體設計方面:

不需要pyqt這種大型軟體,寫小工具用自帶的tkinter就行了。當然,並不是自己純手敲程式碼,是通過拖拽來實現的。怎麼,你還不知道tkinter可以介面拖拽生成程式碼就行VB一樣?

呵呵,PAGE瞭解一下。

遊戲輔助的應用釋出方面:

自然是用pyinstaller打包成32位版的exe釋出了,帶上程式圖示,版本資訊,都不是事兒

遊戲核心模擬方面:

當然不是通過手敲程式碼實現了,而是通過呼叫目前市場上強大的dll外掛了。比如com元件如大漠外掛、樂玩外掛。或者說,把易語言的一些模組編譯成windll來呼叫也行哦

輔助窗體熱鍵註冊方面:

這些需要用到底層的東西了,用win32的東西實現的,可以實現註冊全域性熱鍵。原理是單獨一個執行緒用於檢測熱鍵按下,然後熱鍵按下後單獨開闢執行緒執行需要的功能。鑑於原生的太難寫,我自己封裝了並且寫了一個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,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)  #這裡列印傳入給註冊函式的引數
              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) # 啟動監聽熱鍵按下執行緒
 
    try:
      msg = ctypes.wintypes.MSG()
      while True:
        if self.user32.GetMessageA(ctypes.byref(msg),None,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,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()

以下是舊的程式碼,用起來比較麻煩。

#!/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,enumerate
from time import sleep
h_ids = [i for i in range(2)] # 建立兩個熱鍵序列
h_keys = {i: False for i in h_ids} # 初始化所有熱鍵序列的標誌符為False
h_dict = {} # 初始化一個空的字典,記錄id與func
 
 
class Hotkey(Thread): # 建立一個Thread的擴充套件類
  user32 = ctypes.windll.user32 # 載入user32.dll
  # global h_ids,h_keys,h_dict
 
  def regiskey(self,vkey)
 
  def callback(self,func):
    h_dict[id] = func # 這個id對應這個func,沒有就是新增,有就是修改
 
    def inner():
      for key,value in h_dict.items():
        print(f'總的熱鍵池:{h_ids},當前熱鍵序號:{key},當前熱鍵功能:{value},當前熱鍵狀態:{h_keys[h_ids[key]]}')
      while True:
        for key,value in h_dict.items():
          if h_keys[h_ids[key]]:
            thread_it(value) # 另外開執行緒執行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並判斷是否成功,該熱鍵用於執行一次需要執行的內容。
      print(f"熱鍵註冊失敗! id{h_ids[0]}") # 返回一個錯誤資訊
    if not self.regiskey(None,h_ids[1],win32con.VK_F10):  # 註冊快捷鍵F10並判斷是否成功,該熱鍵用於結束程式,且最好這麼結束,否則影響下一次註冊熱鍵。
      print(f"熱鍵註冊失敗! id{h_ids[1]}")
 
    # 以下為檢測熱鍵是否被按下,並在最後釋放快捷鍵
    try:
      msg = ctypes.wintypes.MSG()
      while True:
        if self.user32.GetMessageA(ctypes.byref(msg),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=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啟用狀態為:{}".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啟用狀態為:{}".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"當前匯流排程數量:{count}")
  print('當前執行緒列表:',enumerate())
  print('熱鍵註冊初始化完畢,嘗試按組合鍵alt+F9 或者單鍵F10看效果')
  while True:
    pass
 
 
if __name__ == '__main__':
  run_ok()

這裡是沒弄介面的原始碼,所以我就把主執行緒死迴圈阻塞了。執行後按alt+F9會列印按下了開始鍵,按F10會列印按下了停止鍵。

如果你在tkinter裡面跑,直接把run_ok函式後面的while True:pass刪掉,然後在init函式裡面加入run_ok()就行了。這裡指的用PAGE設計的tkinter程式哈!

那麼窗體建立完畢就會自動阻塞主執行緒,其他監控熱鍵的執行緒隨主執行緒結束。啟動期間獨立執行互不干擾。

到此這篇關於python3註冊全域性熱鍵的實現的文章就介紹到這了,更多相關python3 註冊全域性熱鍵內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!