本文目录导读:

我来介绍几种实现全局热键的Python方法,并提供完整的案例。
使用 keyboard 库(最简单)
import keyboard
import time
class GlobalHotkey:
def __init__(self):
self.is_running = False
def on_ctrl_shift_a(self):
print("按下: Ctrl+Shift+A - 执行操作A")
def on_ctrl_shift_b(self):
print("按下: Ctrl+Shift+B - 执行操作B")
def on_esc(self):
print("按下: ESC - 退出程序")
self.is_running = False
return False # 停止监听
def start(self):
# 注册热键
keyboard.add_hotkey('ctrl+shift+a', self.on_ctrl_shift_a)
keyboard.add_hotkey('ctrl+shift+b', self.on_ctrl_shift_b)
keyboard.add_hotkey('esc', self.on_esc)
print("全局热键启动成功!")
print("Ctrl+Shift+A: 执行操作A")
print("Ctrl+Shift+B: 执行操作B")
print("ESC: 退出程序")
print("按下 Ctrl+C 也可以退出...")
self.is_running = True
try:
keyboard.wait() # 等待按键
except KeyboardInterrupt:
pass
finally:
keyboard.unhook_all()
# 使用示例
if __name__ == "__main__":
hotkey = GlobalHotkey()
hotkey.start()
使用 pynput 库(更专业)
from pynput import keyboard
from pynput.keyboard import Key, Controller
import threading
import time
class PynputHotkey:
def __init__(self):
self.current_keys = set()
self.hotkeys = {
frozenset({Key.ctrl, Key.shift, keyboard.KeyCode.from_char('a')}): self.action_a,
frozenset({Key.ctrl, Key.shift, keyboard.KeyCode.from_char('b')}): self.action_b,
frozenset({Key.ctrl, Key.alt, keyboard.KeyCode.from_char('c')}): self.action_c,
}
self.key_controller = Controller()
def action_a(self):
print("执行操作A: 复制选中内容")
# 模拟Ctrl+C
with self.key_controller.pressed(Key.ctrl):
self.key_controller.press('c')
self.key_controller.release('c')
def action_b(self):
print("执行操作B: 粘贴内容")
# 模拟Ctrl+V
with self.key_controller.pressed(Key.ctrl):
self.key_controller.press('v')
self.key_controller.release('v')
def action_c(self):
print("执行操作C: 显示通知")
# 这里可以执行任何操作
self.show_notification()
def show_notification(self):
try:
from plyer import notification
notification.notify(
title="全局热键",
message="执行操作C成功!",
timeout=3
)
except ImportError:
print("提示: 如需显示系统通知,请安装plyer库")
def on_press(self, key):
try:
self.current_keys.add(key)
# 检查是否匹配任何热键组合
for hotkey_set in self.hotkeys:
if hotkey_set.issubset(self.current_keys):
self.hotkeys[hotkey_set]()
self.current_keys.clear() # 防止重复触发
break
except Exception as e:
print(f"按键处理错误: {e}")
def on_release(self, key):
try:
if key in self.current_keys:
self.current_keys.remove(key)
# 退出条件
if key == Key.esc:
print("ESC按下,退出程序...")
return False
except Exception as e:
print(f"释放按键错误: {e}")
def start(self):
print("全局热键启动成功!")
print("Ctrl+Shift+A: 复制")
print("Ctrl+Shift+B: 粘贴")
print("Ctrl+Alt+C: 显示通知")
print("ESC: 退出程序")
# 启动监听器
with keyboard.Listener(
on_press=self.on_press,
on_release=self.on_release
) as listener:
listener.join()
# 使用示例
if __name__ == "__main__":
hotkey = PynputHotkey()
hotkey.start()
使用 ctypes(Windows原生API)
import ctypes
from ctypes import wintypes
import threading
import sys
class WindowsGlobalHotkey:
# Windows API 常量
WM_HOTKEY = 0x0312
MOD_ALT = 0x0001
MOD_CONTROL = 0x0002
MOD_SHIFT = 0x0004
MOD_WIN = 0x0008
def __init__(self):
self.hotkeys = {}
self.running = True
# 加载user32.dll
self.user32 = ctypes.windll.user32
# 获取消息函数
self.GetMessage = self.user32.GetMessageW
self.GetMessage.argtypes = [
ctypes.POINTER(ctypes.wintypes.MSG),
wintypes.HWND,
wintypes.UINT,
wintypes.UINT
]
self.GetMessage.restype = ctypes.wintypes.BOOL
def register_hotkey(self, hotkey_id, modifiers, vk_code, callback):
"""
注册全局热键
:param hotkey_id: 热键ID
:param modifiers: 修饰键组合 (MOD_ALT, MOD_CONTROL, MOD_SHIFT, MOD_WIN)
:param vk_code: 虚拟键码
:param callback: 回调函数
"""
result = self.user32.RegisterHotKey(
None, # hWnd
hotkey_id, # id
modifiers, # fsModifiers
vk_code # vk
)
if result:
self.hotkeys[hotkey_id] = callback
print(f"热键 {hotkey_id} 注册成功")
else:
print(f"热键 {hotkey_id} 注册失败")
def unregister_all(self):
"""注销所有热键"""
for hotkey_id in self.hotkeys:
self.user32.UnregisterHotKey(None, hotkey_id)
self.hotkeys.clear()
def start(self):
"""开始监听热键"""
print("Windows全局热键启动成功!")
# 创建消息结构体
msg = ctypes.wintypes.MSG()
while self.running:
# 获取消息
ret = self.GetMessage(
ctypes.byref(msg),
None,
0,
0
)
if ret == 0: # WM_QUIT
break
elif ret == -1: # 错误
print("消息获取错误")
break
# 处理热键消息
if msg.message == self.WM_HOTKEY:
hotkey_id = msg.wParam
if hotkey_id in self.hotkeys:
try:
self.hotkeys[hotkey_id]()
except Exception as e:
print(f"热键执行错误: {e}")
def stop(self):
"""停止监听"""
self.running = False
# 发送退出消息
self.user32.PostQuitMessage(0)
self.unregister_all()
# 热键操作类
class HotkeyActions:
@staticmethod
def action_1():
print("执行操作1: Ctrl+Shift+A")
@staticmethod
def action_2():
print("执行操作2: Ctrl+Shift+B")
@staticmethod
def action_3():
print("执行操作3: Ctrl+Alt+D")
@staticmethod
def exit_action():
print("退出程序")
sys.exit(0)
# 使用示例
if __name__ == "__main__":
# Windows虚拟键码
VK_A = 0x41
VK_B = 0x42
VK_D = 0x44
VK_ESCAPE = 0x1B
hotkey = WindowsGlobalHotkey()
# 注册热键
actions = HotkeyActions()
# Ctrl+Shift+A
hotkey.register_hotkey(
1,
WindowsGlobalHotkey.MOD_CONTROL | WindowsGlobalHotkey.MOD_SHIFT,
VK_A,
actions.action_1
)
# Ctrl+Shift+B
hotkey.register_hotkey(
2,
WindowsGlobalHotkey.MOD_CONTROL | WindowsGlobalHotkey.MOD_SHIFT,
VK_B,
actions.action_2
)
# Ctrl+Alt+D
hotkey.register_hotkey(
3,
WindowsGlobalHotkey.MOD_CONTROL | WindowsGlobalHotkey.MOD_ALT,
VK_D,
actions.action_3
)
# ESC退出
hotkey.register_hotkey(
4,
0,
VK_ESCAPE,
actions.exit_action
)
try:
hotkey.start()
except KeyboardInterrupt:
hotkey.stop()
使用万能的热键管理器
import sys
import threading
from typing import Dict, Callable, Set
from dataclasses import dataclass
from enum import Enum
class KeyModifier(Enum):
NONE = 0
CTRL = 1
SHIFT = 2
ALT = 3
WIN = 4
@dataclass
class HotkeyConfig:
"""热键配置"""
keys: tuple # 按键组合
modifiers: tuple # 修饰键
callback: Callable
description: str = ""
class SmartHotkeyManager:
"""智能热键管理器"""
def __init__(self):
self.hotkeys: Dict[str, HotkeyConfig] = {}
self.use_library = self._detect_best_library()
def _detect_best_library(self) -> str:
"""检测最佳可用的库"""
try:
import keyboard
return 'keyboard'
except ImportError:
try:
import pynput
return 'pynput'
except ImportError:
return 'fallback'
def add_hotkey(self, name: str, keys: tuple, modifiers: tuple,
callback: Callable, description: str = ""):
"""添加热键"""
config = HotkeyConfig(
keys=keys,
modifiers=modifiers,
callback=callback,
description=description
)
self.hotkeys[name] = config
def remove_hotkey(self, name: str):
"""移除热键"""
if name in self.hotkeys:
del self.hotkeys[name]
def _format_hotkey(self, config: HotkeyConfig) -> str:
"""格式化热键显示"""
parts = []
for mod in config.modifiers:
if mod == KeyModifier.CTRL:
parts.append('Ctrl')
elif mod == KeyModifier.SHIFT:
parts.append('Shift')
elif mod == KeyModifier.ALT:
parts.append('Alt')
elif mod == KeyModifier.WIN:
parts.append('Win')
for key in config.keys:
parts.append(key.upper() if len(key) == 1 else key)
return '+'.join(parts)
def show_help(self):
"""显示帮助信息"""
print("\n=== 全局热键帮助 ===")
print(f"使用库: {self.use_library}")
print("-" * 40)
for name, config in self.hotkeys.items():
hotkey_str = self._format_hotkey(config)
desc = config.description or name
print(f"{hotkey_str:20s} - {desc}")
print("=" * 40)
def start(self):
"""启动热键监听"""
if self.use_library == 'keyboard':
self._start_with_keyboard()
elif self.use_library == 'pynput':
self._start_with_pynput()
else:
print("警告: 未检测到keyboard或pynput库")
print("请安装: pip install keyboard 或 pip install pynput")
def _start_with_keyboard(self):
"""使用keyboard库启动"""
import keyboard
for name, config in self.hotkeys.items():
hotkey_str = self._format_hotkey(config).lower()
keyboard.add_hotkey(hotkey_str, config.callback)
self.show_help()
print("按 ESC 退出程序")
try:
keyboard.wait('esc')
except KeyboardInterrupt:
pass
finally:
keyboard.unhook_all()
def _start_with_pynput(self):
"""使用pynput库启动"""
from pynput import keyboard
class PynputHandler:
def __init__(self, hotkeys):
self.hotkeys = hotkeys
self.current_keys = set()
def format_pynput_hotkey(self, config: HotkeyConfig) -> set:
result = set()
for mod in config.modifiers:
if mod == KeyModifier.CTRL:
result.add(keyboard.Key.ctrl)
elif mod == KeyModifier.SHIFT:
result.add(keyboard.Key.shift)
elif mod == KeyModifier.ALT:
result.add(keyboard.Key.alt)
elif mod == KeyModifier.WIN:
result.add(keyboard.Key.cmd)
for key in config.keys:
if len(key) == 1:
result.add(keyboard.KeyCode.from_char(key))
else:
result.add(getattr(keyboard.Key, key.lower(), None))
return result
def on_press(self, key):
try:
self.current_keys.add(key)
for config in self.hotkeys.values():
hotkey_set = self.format_pynput_hotkey(config)
if hotkey_set.issubset(self.current_keys):
config.callback()
self.current_keys.clear()
break
except Exception as e:
print(f"错误: {e}")
def on_release(self, key):
try:
self.current_keys.discard(key)
if key == keyboard.Key.esc:
return False
except:
pass
handler = PynputHandler(self.hotkeys)
self.show_help()
with keyboard.Listener(
on_press=handler.on_press,
on_release=handler.on_release
) as listener:
listener.join()
# 使用示例
if __name__ == "__main__":
def action_copy():
print("复制操作!")
def action_paste():
print("粘贴操作!")
def action_custom():
print("自定义操作!")
# 创建热键管理器
manager = SmartHotkeyManager()
# 注册热键
manager.add_hotkey(
"copy",
keys=('c',),
modifiers=(KeyModifier.CTRL,),
callback=action_copy,
description="复制"
)
manager.add_hotkey(
"paste",
keys=('v',),
modifiers=(KeyModifier.CTRL,),
callback=action_paste,
description="粘贴"
)
manager.add_hotkey(
"custom",
keys=('f1',),
modifiers=(KeyModifier.CTRL, KeyModifier.SHIFT),
callback=action_custom,
description="自定义操作"
)
# 启动
manager.start()
安装依赖
# 方法一 (推荐): keyboard pip install keyboard # 方法二: pynput pip install pynput # 可选: 系统通知 pip install plyer
使用建议
- 简单使用: 使用
keyboard库,代码最简单 - 跨平台: 使用
pynput库,支持Windows/Linux/Mac - Windows专用: 使用Windows API,性能最好
- 通用方案: 使用智能管理器,自动选择最佳库
选择哪种方法取决于你的具体需求和应用场景。