33- 绑定全局热键

全局热键

程序处于后台也能触发热键即全局热键。pyside6似乎没有直接设置全局热键的方法,不过可以曲线救国利用pynput实现同样功能的全局热键。使用前需要先安装pynput模块

以下分别从键盘监控和全局热键两个角度尝试全局热键。

键盘显示器的一个常见用例是对全局热键做出反应。由于 监听器不维护任何状态,涉及多个键的热键必须 将此状态存储在某处。

Pynput为此提供了类。它 包含两种更新状态的方法pynput.keyboard.HotKeypynput.keyboard.GlobalHotKeys,旨在轻松互操作 带键盘监听器:可作为监听器直接传递 回调。

pynput.keyboard.Key: 键与值

Key = pynput.keyboard.Key
Key.f1 :功能键。定义了F1到F20。

Key.alt : 普通的Alt键
Key.alt_gr:AltGr键。
Key.alt_l:左边的Alt键
Key.alt_r :右边的Alt键
Key.backspace :回退键。
Key.caps_lock :CapsLock钥匙。
Key.cmd :通用命令按钮。在……上面Pc平台,这对应于超级键或Windows键,并且在麦克它对应于命令键。
Key.cmd_l :左边的命令按钮。在……上面Pc平台,这对应于超级键或Windows键,并且在麦克它对应于命令键。
Key.cmd_r :正确的命令按钮。在……上面Pc平台,这对应于超级键或Windows键,并且在麦克它对应于命令键。
Key.delete :删除钥匙。
Key.up :向上箭头键。
Key.down :向下箭头键。
Key.left :左箭头键。
Key.right :右箭头键。
Key.end :end键。
Key.enter :回车键。
Key.esc :ESC键。
Key.home :主页键。
Key.insert :插入键。对于某些平台来说,这可能是没有定义的。
Key.media_next :下一个轨道按钮。
Key.media_play_pause :这出戏/暂停切换。
Key.media_previous :前一个轨道按钮。
Key.media_volume_down :音量下降按钮。
Key.media_volume_mute :音量静音按钮。
Key.media_volume_up :音量上升按钮
Key.menu :菜单键。对于某些平台来说,这可能是没有定义的
Key.num_lock :NumLock钥匙。对于某些平台来说,这可能是没有定义的。
Key.page_down 下页键。
Key.page_up :上页键。
Key.pause :暂停/中断键。对于某些平台来说,这可能是没有定义的。
Key.print_screen :PrintScreen键。对于某些平台来说,这可能是没有定义的。
Key.scroll_lock :锁键。对于某些平台来说,这可能是没有定义的。
Key.shift :一个通用的移位键
Key.shift_l :左移键
Key.shift_r :右移键
Key.space :空格键。
Key.tab :Tab键。

监听键盘

主要有两种方法,类似于鼠标。一种是对Listener的封装,用于快捷键

pynput.keyboard.Listener
  • 当两个函数中任意一个返回False还有就是释放Exception或继承自Exception的异常时,就会结束进程。
  • 键盘事件监听器是一个线程,所有的回调函数都会在独立的线程中运行。 调用pynput.keyboard.Listener.stop,发起StopException异常,或者回调函数中返回False都会停止事件的监听。
  • 可以用listener.start()listener.stop()代替with语句。键盘侦听器有回调都将是 从线程调用。threading.Thread.
from pynput import keyboard



def keyboard_listener():
	"""键盘监听"""

	def on_press(key):
		"""
		:param key: 按下的按键。pynput.keyboard.Key
		:return: 按下按键时调用该方法
		"""
		print(f"{'-'* 20}type:{type(key)}--{key}按下{'-'* 20}")

	def on_release(key):
		"""
		:param key: 按下的按键。pynput.keyboard.Key
		:return: 松开按键时回调该方法
		"""
		print(f"{'-'* 20}type:{type(key)}--{key}释放{'-'* 20}")
		if not all([self.play_status,self.record_status]):
			return False

	# 注册系统全局热键监控键盘,监控按下F10
	with pynput.keyboard.Listener(on_press=on_press,on_release=on_release)as listener:
		listener.join()

官方示例:

from pynput import keyboard

def on_press(key):
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))

def on_release(key):
    print('{0} released'.format(
        key))
    if key == keyboard.Key.esc:
        # Stop listener
        return False

# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release)as listener:
    listener.join()

# ...or,in a non-blocking fashion:
listener = keyboard.Listener(
    on_press=on_press,
    on_release=on_release)
listener.start()

键盘侦听器是 a,所有回调都将是 从线程调用。threading.Thread

从任何地方调用,从回调返回以停止侦听器。pynput.keyboard.Listener.stopStopExceptionFalse

传递给回调的参数是 a,对于 特殊键,a用于普通字母数字键,或 只是未知的钥匙。keypynput.keyboard.Keypynput.keyboard.KeyCodeNone

使用上面的非阻塞版本时,当前线程将继续 执行。这在与其他 GUI 框架集成时可能是必需的 包含主循环,但是当从脚本运行时,这将导致 程序立即终止。

如果回调处理程序引发异常,侦听器将被停止。因为 回调在专用线程中运行,异常不会自动 重新提出。

要收到有关回调错误的通知,请调用侦听器 实例:Thread.join

from pynput import keyboard

class MyException(Exception): pass

def on_press(key):
    if key == keyboard.Key.esc:
        raise MyException(key)

# Collect events until released
with keyboard.Listener(
        on_press=on_press)as listener:
    try:
        listener.join()
    except MyException as e:
        print('{0} was pressed'.format(e.args[0]))
pynput.keyboard.Events
import pynput

with pynput.keyboard.Events()as event:
    for i in event:  # 迭代用法。
        key_event = i
        break

    key_event = event.get()
    # get用法可以提供一个实数作为最长等待时间单位秒,超过这个时间没有事件,就会报错。错误类型是queue模块的Empty,而非TimeoutError。

if isinstance(key_event,pynput.keyboard.Events.Press):  # 判断事件情况:
    print('按下按键',end='')
elif isinstance(key_event,pynput.keyboard.Events.Release):
    print('松开按键',end='')

# 判断按键:这个事件的`key`属性 对应才是Listener方法获得的按键`'key'
try:
    print(key_event.key.name)
except AttributeError:  # 说明这个是普通按键。
    print(key_event.key.char)
else:  # 两种判断方式,第一种是我自创的,第二种是官网上的。
    if(key_event.key.name).startswith('ctrl'):  # 通过名称判断。
        print('发生了ctrl键事件。')
    elif key_event.key is pynput.keyboard.Key.esc:
        print('发生了esc键事件。')

若要读取单个事件,请使用以下代码:

from pynput import keyboard

# The event listener will be running in this block
with keyboard.Events()as events:
    # Block at most one second
    event = events.get(1.0)
    if event is None:
        print('You did not press a key within one second')
    else:
        print('Received event {}'.format(event))

若要循环访问键盘事件,请使用以下代码

from pynput import keyboard

# The event listener will be running in this block
with keyboard.Events()as events:
    for event in events:
        if event.key == keyboard.Key.esc:
            break
        else:
            print('Received event {}'.format(event))

全局热键监听

键盘显示器的一个常见用例是对全局热键做出反应。由于 监听器不维护任何状态,涉及多个键的热键必须 将此状态存储在某处。

Pynput为此提供了类。它 包含两种更新状态的方法pynput.keyboard.HotKeypynput.keyboard.GlobalHotKeys,旨在轻松互操作 带键盘监听器:可作为监听器直接传递 回调。

单个热键pynput.keyboard.HotKey
from pynput import keyboard


def on_activate():
    print('Global hotkey activated!')


def for_canonical(f):
    return lambda k: f(hot_Listener.canonical(k))


hotkey = keyboard.HotKey(keyboard.HotKey.parse('<ctrl>+<alt>+h'), on_activate)

with keyboard.Listener(on_press=for_canonical(hotkey.press),
                       on_release=for_canonical(hotkey.release)) as hot_Listener:
    hot_Listener.join()

这将创建一个热键,然后使用侦听器更新其状态。

一次 所有指定的键同时按下,将 调用on_activate

请注意,密钥是在传递之前 被传递给实例。这是为了删除任何修饰符状态 从关键事件,并使用多个物理对修饰符进行规范化 按钮。pynput.keyboard.Listener.canonicalHotKey

该方法是一个方便的功能 将快捷方式字符串转换为键集合。请参阅其文档 更多信息。pynput.keyboard.HotKey.parse

还有pynput.keyboard.HotKey可以实现热键功能但是并不建议使用

HotKey用于单个热键监控

from pynput import keyboard


def on_activate():
    print('Global hotkey activated!')


def for_canonical(f):
    return lambda k: f(hot_Listener.canonical(k))


hot_keys = keyboard.HotKey.parse('<ctrl>+<alt>+h')  # 把热键转化成其他形式用于监控
hotkey = keyboard.HotKey(hot_keys, on_activate)

# 当按下按键时hotkey.press更新按下的按键hotkey.release把释放按键从内置列表变量删除
with keyboard.Listener(on_press=for_canonical(hotkey.press),
                       on_release=for_canonical(hotkey.release)) as hot_Listener:
    hot_Listener.join()

注册多个全局热键GlobalHotKeys

注册多个全局热键,请使用便利类:pynput.keyboard.GlobalHotKeys

多个热键监控需要手动执行GlobalHotKeys的stop停止

如下所有可以用上下文也可直接赋值进行热键监控。 需要注意start join 和stop使用时机

# -*- coding: UTF-8 -*-
# File date: Hi_2023/4/3 21:49
# File_name: 08- 注册多个全局热键-GlobalHotKeys.py


from pynput import keyboard


class keyboard_GlobalHotKeys1:

    def on_activate_h(self):
        print('<ctrl>+<alt>+h pressed')

    def on_activate_i(self):
        print('<ctrl>+<alt>+i pressed')

    def on_activate_x(self):
        print('<ctrl>+<alt>+x pressed')

    def stop(self):
        """"结束监控"""
        print('<esc>+<shift>+q pressed')
        self.h.stop()

    def listening_method(self):
        with keyboard.GlobalHotKeys({'<ctrl>+<alt>+h': self.on_activate_h,
                                     '<ctrl>+<alt>+i': self.on_activate_i,
                                     '<ctrl>+<alt>+x': self.on_activate_x,
                                     '<ctrl>+<alt>+q': self.stop}) as self.h:
            self.h.join()


class keyboard_GlobalHotKeys2:
    def on_activate_h(self):
        print('<ctrl>+<alt>+h pressed')

    def on_activate_i(self):
        print('<ctrl>+<alt>+i pressed')

    def on_activate_x(self):
        print('<ctrl>+<alt>+x pressed')

    def esc_shift(self):
        print('<esc>+<shift>+q pressed')
        self.listen.stop()

    def listening_method(self):
        self.listen = keyboard.GlobalHotKeys({'<ctrl>+<alt>+h': self.on_activate_h,
                                              '<ctrl>+<alt>+i': self.on_activate_i,
                                              '<ctrl>+<alt>+x': self.on_activate_x,
                                              '<ctrl>+<alt>+q': self.esc_shift})

        self.listen.start()
        self.listen.join()


if __name__ == '__main__':
    keyboard_GlobalHotKeys1().listening_method()  # 上下文写法
    keyboard_GlobalHotKeys2().listening_method()  # 手动stop和start

热键思路扩展

定义多个bool变量标识按键,按键列表标识按下顺序。按下则为Ture并在列表记录,反之释放为False,在列表移除。当三个都为Ture时触发热键回调函数

同时兼顾热键和热键按下顺序

使用打包程序时,得到匿名启动ImportError

当使用打包程序如PyInstaller打包应用,打开时报ImportError

错误的原因是打包程序尝试构建依赖项 检查语句使用importlib模块。Pynput*在运行时使用查找依赖于平台的后端模块。

要解决此问题,请参阅工具的文档以查找 如何显式添加模块。

要添加哪些模块取决于您的分发平台。后端模块是以下划线’_'开头的模块在pynput.keyboard and pynput.mouse包中的。此外,还需要pynput中具有相应名称的_util模块。

# 查看发现分别调用这两个,下面例子可能需要调整没试过
from pynput._util import backend,Events # keyboard的模块
from pynput._util import backend,Events # mouse的模块

需将此模块作为隐藏导入包含在PyInstaller程序中

python -m PyInstaller your_program.py -F
hidden-import=pynput.keyboard._xorg

您还将鼠标与pynput一起使用,那么模块pynput.mouse._xorg也会出现相同的错误:

python -m PyInstaller your_program.py  -F  
hidden-import=pynput.keyboard._xorg
hidden-import=pynput.mouse._xorg

警告!如果你是为Windows或Mac打包的,你可能会得到一个它找不到的不同模块。这就是Linux的功能。如果您希望您的程序是跨平台的,那么您必须将该程序打包例如,针对Windows并对其进行测试,以查看找不到哪个模块,并将其作为隐藏导入

如果希望程序在Linux和Windows上运行,请使用以下命令:

python -m PyInstaller your_program.py  onefile  
hidden-import=pynput.keyboard._xorg  
hidden-import=pynput.mouse._xorg  
hidden-import=pynput.keyboard._win32  
hidden-import=pynput.mouse._win32

如果您有很多隐藏的模块,那么您可以编辑.spec文件并将模块添加到hiddenimports列表中,如下所示在PyInstaller 4.1上:

hiddenimports=['pynput.keyboard._xorg','pynput.mouse._xorg'],
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

士别三日,当挖目相待

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值