windows下python的keyboard库在锁屏之后再次登陆快捷键(热键)失效问题

发布时间 2023-09-21 00:52:37作者: pmh905001

背景:

python的keyboard是一个强大的键盘事件处理工具包,可以找到很多介绍如何使用的文章。而我用它注册快捷键(热键,hot keys)完成一些功能,但是时不时的发现注册的热键是不起作用,没有找到重现步骤。 为此,我不得不在菜单项中增加了一个重启功能,当用户发现快捷键不起作用,重启该进程临时解决一下。

作为一个有追求的工程师,怎么能忍受这种不稳定性问题?跟踪一下keyboard源码。

调查

先查看正常情况下快捷键是如何触发的:

 218行如下代码

    def pre_process_event(self, event):
        for key_hook in self.nonblocking_keys[event.scan_code]:
            key_hook(event)

        with _pressed_events_lock:
            hotkey = tuple(sorted(_pressed_events))
        for callback in self.nonblocking_hotkeys[hotkey]:
            callback(event)

        return event.scan_code or (event.name and event.name != 'unknown')

代码解释:

它的作用是对键盘事件进行预处理。

首先,它会遍历self.nonblocking_keys[event.scan_code]中的所有按键钩子(key hook),并将当前事件传递给这些钩子进行处理。

接着,它会获取当前已按下的按键事件列表(存储在_pressed_events变量中),并对其进行排序,生成一个元组hotkey。

然后,它会遍历self.nonblocking_hotkeys[hotkey]中的所有回调函数(callback),并将当前事件传递给这些回调函数进行处理。

最后,它会返回当前事件的扫描码(scan code)或者事件名称(如果事件名称不为'unknown')。
  • _pressed_events这个全局变量存储的用户当前按下哪些个快捷键,比如按下了alt键则会形成(56,)这个元组,最终根据这个元组在nonblocking_hotkeys找到注册的热键回调函数。
  • 当用户释放alt快捷键的时候,则会清理_pressed_events里面保存的快捷键信息。

分析:

  • 正常逻辑搞清楚后,剩下就等待快捷键不起作用的情况下,找到他们的差别在哪里。
  • 很快便发现 hotkey 这个变量与预期的(56,)是不一样的,怎么变成了(29,56)?在这种情况下 self.nonblocking_hotkeys[hotkey]根本找不到对应的回调函数而导致热键功能失效。
  • 29对应的scan code为左windows键(田字格那个快捷键)。什么时候会使用这个快捷键呢?我想起来我平时都是使用锁屏快捷键(windows+l)。
  • 锁频的时候,windows的scan code一直保存在_pressed_events没有被清理掉,所以当按下了alt键的时候,系统会认为用户按下了windows+alt快捷键,而我们根本没有注册过这个快捷键回调函数,所以造成了之前注册的alt快捷键失效

总结:

锁屏时候未成功清理windows键信息,导致的注册的快捷键失效问题。