即使 Python 脚本没有焦点,也要监听快捷方式(如 WIN+A)
Listen for a shortcut (like WIN+A) even if the Python script does not have the focus
我想要一个 Python 脚本 运行 不断地在后台运行,并在按下某个键盘快捷键时执行某些操作,例如 WIN+ A.
我已阅读 Key Listeners in python? 和使用 pynput
的解决方案,但它似乎可以工作并在 window/console 获得焦点时检测按键。
问题:如何检测Python中的快捷键,如WIN+A , 并在它发生时启动一个功能,即使焦点在其他地方(例如浏览器等)?
注意:我的 OS 是 Windows。此外,我更希望 Python 脚本仅“注册”侦听 WIN+A (这是否存在?),并且确实不要听所有的按键(否则它或多或少会是一个键盘记录器,我不想要!)。
这是我尝试过的:
import pyHook, pythoncom
def OnKeyboardEvent(event):
if event.Ascii == 8: # backspace
print('hello')
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages()
我想避免使用它有两个原因:首先,我发现听所有按键的声音非常干扰,其次,我在很多地方发现的这个关于 pyhook
的常见示例有一个错误:TypeError: KeyboardSwitch() missing 8 required positional arguments: 'msg', 'vk_ code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name'
。新版本 PyHook3 似乎也不适用于 Py36-64:pip install PyHook3
在 Windows.
上失败
事实上,我错了:pynput
确实能够全局检测按键,而不仅仅是当前活动的 window.
1) 使用 pynput
以下代码使用 WIN+W 和 calc
使用 [=38] 启动应用程序 notepad
=]WIN+C:
from pynput import keyboard
import subprocess
pressed = set()
COMBINATIONS = [
{
"keys": [
{keyboard.Key.cmd, keyboard.KeyCode(char="w")},
{keyboard.Key.cmd, keyboard.KeyCode(char="W")},
],
"command": "notepad",
},
{
"keys": [
{keyboard.Key.cmd, keyboard.KeyCode(char="c")},
{keyboard.Key.cmd, keyboard.KeyCode(char="C")},
],
"command": "calc",
},
]
def run(s):
subprocess.Popen(s)
def on_press(key):
pressed.add(key)
print(pressed)
for c in COMBINATIONS:
for keys in c["keys"]:
if keys.issubset(pressed):
run(c["command"])
def on_release(key):
if key in pressed:
pressed.remove(key)
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
2) 使用 ctypes
和 win32con
这受到@fpbhb 在评论中引用的 this post 的启发。它监听 WIN+F3 和 WIN+F4 .
import os, sys
import ctypes
from ctypes import wintypes
import win32con
def handle_win_f3():
os.startfile(os.environ["TEMP"])
def handle_win_f4():
ctypes.windll.user32.PostQuitMessage(0)
HOTKEYS = [
{"keys": (win32con.VK_F3, win32con.MOD_WIN), "command": handle_win_f3},
{"keys": (win32con.VK_F4, win32con.MOD_WIN), "command": handle_win_f4},
]
for i, h in enumerate(HOTKEYS):
vk, modifiers = h["keys"]
print("Registering id", i, "for key", vk)
if not ctypes.windll.user32.RegisterHotKey(None, i, modifiers, vk):
print("Unable to register id", i)
try:
msg = wintypes.MSG()
while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
HOTKEYS[msg.wParam]["command"]()
ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
finally:
for i, h in enumerate(HOTKEYS):
ctypes.windll.user32.UnregisterHotKey(None, i)
3) 使用 keyboard
参见 https://github.com/boppreh/keyboard。这很有趣,但对我来说,与其他解决方案相比,它有一些缺点:一些快速击键(在完成 CPU 密集处理时)没有被捕捉到。他们在使用解决方案 1) 或 2) 时被捕获。
似乎没有100%的Tkinter解决方案,见。
我想要一个 Python 脚本 运行 不断地在后台运行,并在按下某个键盘快捷键时执行某些操作,例如 WIN+ A.
我已阅读 Key Listeners in python? 和使用 pynput
的解决方案,但它似乎可以工作并在 window/console 获得焦点时检测按键。
问题:如何检测Python中的快捷键,如WIN+A , 并在它发生时启动一个功能,即使焦点在其他地方(例如浏览器等)?
注意:我的 OS 是 Windows。此外,我更希望 Python 脚本仅“注册”侦听 WIN+A (这是否存在?),并且确实不要听所有的按键(否则它或多或少会是一个键盘记录器,我不想要!)。
这是我尝试过的:
import pyHook, pythoncom
def OnKeyboardEvent(event):
if event.Ascii == 8: # backspace
print('hello')
return True
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages()
我想避免使用它有两个原因:首先,我发现听所有按键的声音非常干扰,其次,我在很多地方发现的这个关于 pyhook
的常见示例有一个错误:TypeError: KeyboardSwitch() missing 8 required positional arguments: 'msg', 'vk_ code', 'scan_code', 'ascii', 'flags', 'time', 'hwnd', and 'win_name'
。新版本 PyHook3 似乎也不适用于 Py36-64:pip install PyHook3
在 Windows.
事实上,我错了:pynput
确实能够全局检测按键,而不仅仅是当前活动的 window.
1) 使用 pynput
以下代码使用 WIN+W 和 calc
使用 [=38] 启动应用程序 notepad
=]WIN+C:
from pynput import keyboard
import subprocess
pressed = set()
COMBINATIONS = [
{
"keys": [
{keyboard.Key.cmd, keyboard.KeyCode(char="w")},
{keyboard.Key.cmd, keyboard.KeyCode(char="W")},
],
"command": "notepad",
},
{
"keys": [
{keyboard.Key.cmd, keyboard.KeyCode(char="c")},
{keyboard.Key.cmd, keyboard.KeyCode(char="C")},
],
"command": "calc",
},
]
def run(s):
subprocess.Popen(s)
def on_press(key):
pressed.add(key)
print(pressed)
for c in COMBINATIONS:
for keys in c["keys"]:
if keys.issubset(pressed):
run(c["command"])
def on_release(key):
if key in pressed:
pressed.remove(key)
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
2) 使用 ctypes
和 win32con
这受到@fpbhb 在评论中引用的 this post 的启发。它监听 WIN+F3 和 WIN+F4 .
import os, sys
import ctypes
from ctypes import wintypes
import win32con
def handle_win_f3():
os.startfile(os.environ["TEMP"])
def handle_win_f4():
ctypes.windll.user32.PostQuitMessage(0)
HOTKEYS = [
{"keys": (win32con.VK_F3, win32con.MOD_WIN), "command": handle_win_f3},
{"keys": (win32con.VK_F4, win32con.MOD_WIN), "command": handle_win_f4},
]
for i, h in enumerate(HOTKEYS):
vk, modifiers = h["keys"]
print("Registering id", i, "for key", vk)
if not ctypes.windll.user32.RegisterHotKey(None, i, modifiers, vk):
print("Unable to register id", i)
try:
msg = wintypes.MSG()
while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
HOTKEYS[msg.wParam]["command"]()
ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
finally:
for i, h in enumerate(HOTKEYS):
ctypes.windll.user32.UnregisterHotKey(None, i)
3) 使用 keyboard
参见 https://github.com/boppreh/keyboard。这很有趣,但对我来说,与其他解决方案相比,它有一些缺点:一些快速击键(在完成 CPU 密集处理时)没有被捕捉到。他们在使用解决方案 1) 或 2) 时被捕获。
似乎没有100%的Tkinter解决方案,见