全局热键
程序处于后台也能触发热键即全局热键。pyside6似乎没有直接设置全局热键的方法,不过可以曲线救国利用pynput实现同样功能的全局热键。使用前需要先安装pynput
模块
以下分别从键盘监控和全局热键两个角度尝试全局热键。
键盘显示器的一个常见用例是对全局热键做出反应。由于 监听器不维护任何状态,涉及多个键的热键必须 将此状态存储在某处。
Pynput
为此提供了类。它 包含两种更新状态的方法pynput.keyboard.HotKey
和pynput.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.HotKey
和pynput.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'],