python实现自己的全局热键的第2种方法

之前有过一版python实现的全局热键, 但是在实际运行中发现, 有时候不太灵敏, 明明按下了目标热键, 为什么没有反应呢? 通过定位发现, 有时候键盘勾子捕获不到ctrl down消息, 特别是一段时间不操作电脑后容易出现这种情况, 这时候ctrl键确实处于按下的状态(通过GetKeyState函数可以获取到当时的状态).
于是我又重新实现了一版热键功能, 如下代码:

class HotkeyMatch2:
    def __init__(self,hotkey:str):
        '''hotkey: 形如: 'ctrl+a';'''
        self.hotkey = hotkey
        self.keys = hotkey.split('+')   # 热键的列表
        self.target_key = 'VK_' + self.keys[-1].upper()  # 目标键, 形如'VK_A'
        # 确定目标ctrl键和alt键状态, True表示被按下
        self.target_ctrl = 'ctrl' in self.keys
        self.target_alt = 'alt' in self.keys
    def is_match(self,key:str,etype:str)->bool:
        '''
        key: 形如: VK_A
        etype: 形如: DOWN|UP
        返回值: True: 表示热键匹配, 否则表示不匹配
        '''
        if etype!='DOWN': return False  # 只接受down消息
        if key!=self.target_key: return False   # 判断是否是目标键
        if is_control_pressing()!=self.target_ctrl: return False  # 判断ctrl键是否按下
        if is_alt_pressing()!=self.target_alt: return False  # 判断alt键是否按下
        return True

def add_hotkey2(hotkey:str,callback:callable):
    '''
    增加一个热键
    hotkey: 形如: 'ctrl+a'
    callback: 回调函数: void f()
    '''
    hotkey_match = HotkeyMatch2(hotkey)
    def on_key(key:str,etype:str)->bool:
        result = hotkey_match.is_match(key,etype)
        ctx = msg.Context() # 订阅消息的回调函数的返回对象
        ctx.tag = result
        if result==True:    # 触发热键
            cmn.run_in_thread(callback)()   # 在新线程中运行回调函数
            ctx.discontinued = True
        return ctx
    msg.sub('23090501_KeyMsg',on_key)   # 订阅键盘消息

add_hotkey = add_hotkey2

初步测试, 应该是解决了问题.

posted @ 2023-09-10 10:19  顺其自然,道法自然  阅读(326)  评论(0编辑  收藏  举报