← 返回首页
Code for How to Control your Keyboard in Python - Python Code
  The Python Code Menu

Code for How to Control your Keyboard in Python Tutorial


View on Github

keyboard_controller_2026.py

from __future__ import annotations import argparse import platform import sys import time from dataclasses import dataclass from typing import Callable @dataclass(frozen=True) class Action: """A keyboard action that can be previewed or executed.""" description: str callback: Callable[[object], None] def import_keyboard(): """Import keyboard lazily so --dry-run works in headless/test environments.""" try: import keyboard except ImportError as exc: raise SystemExit("Install the dependency first: pip install keyboard") from exc return keyboard def platform_hint() -> str: """Return a short note about common platform requirements.""" system = platform.system().lower() if system == "linux": return "Linux usually needs root privileges or access to /dev/input for global hooks." if system == "darwin": return "macOS support in the keyboard package is limited; pynput or PyAutoGUI is often a better fit." if system == "windows": return "Windows is the smoothest platform for the keyboard package." return "Global keyboard hooks depend on your operating system and permissions." def preview_or_run(action: Action, keyboard_module: object | None, execute: bool) -> None: """Print what would happen, or run the action when --execute is set.""" if not execute: print(f"DRY RUN: {action.description}") return if keyboard_module is None: raise RuntimeError("keyboard module is required when execute=True") print(f"RUNNING: {action.description}") action.callback(keyboard_module) def demo_typing(execute: bool) -> None: """Type text into the currently focused window.""" keyboard = import_keyboard() if execute else None actions = [ Action( "type 'Hello from Python!' with a small delay", lambda kb: kb.write("Hello from Python!", delay=0.03), ), Action("press Enter", lambda kb: kb.press_and_release("enter")), Action("send Ctrl+A", lambda kb: kb.send("ctrl+a")), ] for action in actions: preview_or_run(action, keyboard, execute) def demo_hotkeys(execute: bool) -> None: """Register a global hotkey and an abbreviation.""" keyboard = import_keyboard() if execute else None if not execute: print("DRY RUN: register Ctrl+Alt+H to print a message") print("DRY RUN: expand '@email' into 'name@example.com'") print("DRY RUN: wait until Esc is pressed") return keyboard.add_hotkey("ctrl+alt+h", lambda: print("Ctrl+Alt+H pressed")) keyboard.add_abbreviation("@email", "name@example.com") print("Hotkeys are active. Type @email + space in another app, or press Ctrl+Alt+H.") print("Press Esc to stop.") keyboard.wait("esc") keyboard.unhook_all() def demo_record(execute: bool) -> None: """Record keyboard events until Esc, then replay them after confirmation.""" keyboard = import_keyboard() if execute else None if not execute: print("DRY RUN: record keyboard events until Esc") print("DRY RUN: show typed strings") print("DRY RUN: ask before replaying events") return print("Recording now. Press Esc to stop.") events = keyboard.record("esc") typed = list(keyboard.get_typed_strings(events)) print("Typed strings:", typed) answer = input("Replay the recorded events? [y/N] ").strip().lower() if answer == "y": print("Replaying in 3 seconds. Focus the target window now.") time.sleep(3) keyboard.play(events) keyboard.unhook_all() def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Safe examples for controlling the keyboard in Python.") parser.add_argument( "demo", choices=("typing", "hotkeys", "record"), help="Which demo to run", ) parser.add_argument( "--execute", action="store_true", help="Actually send/listen to keyboard events. Without this flag, the script only prints what it would do.", ) args = parser.parse_args(argv) print(platform_hint()) if not args.execute: print("Running in dry-run mode. Add --execute on your own desktop to perform the actions.\n") if args.demo == "typing": demo_typing(args.execute) elif args.demo == "hotkeys": demo_hotkeys(args.execute) elif args.demo == "record": demo_record(args.execute) return 0 if __name__ == "__main__": raise SystemExit(main())