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, 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)   #这里打印传入给注册函数的参数
                            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) != 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键 结束
    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, activeCount, 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, 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},当前热键状态:{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],0,win32con.VK_F10):   # 注册快捷键F10并判断是否成功,该热键用于结束程序,且最好这么结束,否则影响下一次注册热键。
            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启用状态为:{}".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程序哈!

那么窗体创建完毕就会自动阻塞主线程,其他监控热键的线程随主线程结束。启动期间独立运行互不干扰。

 

 

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值