pynput
A Python library for controlling and monitoring mouse and keyboard input across Windows, macOS, and Linux.
Repository Health
Technical Analysis
pynput gives Python programs a single, platform-independent API for two things that normally require separate OS-specific code paths: sending synthetic mouse and keyboard events, and listening for real ones as they happen. Instead of writing directly against Win32, Xlib/evdev, or the macOS Quartz/ApplicationServices frameworks, developers import pynput.mouse and pynput.keyboard and get Controller classes for driving input and Listener classes for observing it, with the platform-specific implementation selected automatically at import time.
The library is commonly used to build desktop automation scripts, global hotkey handlers, input-based testing harnesses, and accessibility tools, anywhere a program needs to move the cursor, simulate keystrokes, or react to physical input without stealing focus from the user’s active window. Its API mirrors natural input semantics closely — keys have symbolic names and virtual key codes, mouse buttons are an enum, and listeners run in their own thread so they don’t block the caller.
What You Get
- A
mouse.Controllerfor moving the pointer, clicking, and scrolling programmatically - A
mouse.Listenerthat runs on a background thread and reports move/click/scroll events - A
keyboard.Controllerfor pressing, releasing, and typing arbitrary text or key sequences - A
keyboard.Listenerfor capturing key press/release events, including global hotkeys - A
keyboard.GlobalHotKeyshelper for registering and dispatching hotkey combinations declaratively - Automatic backend selection per platform, with an override via
PYNPUT_BACKENDenvironment variables for testing
Common Use Cases
- Desktop automation scripts that move the mouse and type text to drive existing GUI applications
- Global hotkey daemons that trigger application actions regardless of which window has focus
- Recording and replaying input sequences for macro tools or QA/UI test harnesses
- Accessibility utilities that remap or augment keyboard and mouse behavior for users with motor impairments
Under The Hood
Architecture
pynput separates concerns into a thin base module (mouse/_base.py, keyboard/_base.py) defining the public Controller/Listener/Key/Button classes as documentation-bearing stubs, then a backend() resolver in pynput/_util/__init__.py that inspects PYNPUT_BACKEND environment variables (or the detected platform) to pick one of the _win32, _xorg, _darwin, _uinput, or _dummy modules and rebind Controller/Listener to the platform implementation at import time in keyboard/__init__.py/mouse/__init__.py. This is a clean strategy/bridge pattern: application code always talks to the same interface, and swapping in the dummy backend for tests needs only an environment variable. Because every platform module independently subclasses the same base classes and implements the same private hook methods the base classes call, changing that shared contract would ripple through all platform implementations at once.
Tech Stack
pynput is pure Python, supporting both Python 2.7 and 3.x through the six compatibility shim, its only mandatory runtime dependency. Platform-specific extras are declared through environment-marker extras in setup.py: PyObjC framework bindings for ApplicationServices and Quartz on macOS, evdev/python-xlib on Linux, and direct Win32 API calls on Windows with no extra dependency required. Documentation is built with Sphinx from reStructuredText files under docs/, and releases are published to PyPI via twine. There is no web framework, database layer, or bundler involved — it is a low-level systems-integration library, not an application.
Code Quality
The tests/ directory holds five modules covering keyboard controller behavior, keyboard hotkeys, keyboard and mouse listener behavior, built on a shared EventTest base class that exercises a dummy/synthetic backend so tests run headlessly rather than driving the real OS input system. A pylintrc enforces style, and a tester shell script supports manual interactive checks, but no GitHub Actions workflow exists under .github/ (only an issue template), so automated CI enforcement is limited or absent. Error handling favors explicit exceptions with platform-specific resolution hints over silent failures, though the codebase still carries Python 2/3 dual-support branching and has no type annotations or stub files.
What Makes It Unique pynput’s contribution is narrow but genuinely useful: one identical API for mouse/keyboard control and monitoring across three very different OS input models — Win32 message hooks, X11/evdev event streams, and macOS Quartz event taps — including details like dead-key/combining-character composition and modifier-key normalization that single-platform scripts commonly get wrong. The Controller/Listener split itself is a standard pattern rather than a novel abstraction, so the value is consistent cross-platform correctness rather than a new programming model.