j-input
Windows global input for Python, implemented in Rust.
One native thread owns the low-level mouse and keyboard hooks and a foreground-window event hook. Every hook callback runs a plain state machine and decides on the spot whether to swallow the event; it never calls into Python and never waits for the GIL. A busy Python main thread therefore cannot stall the system's mouse or keyboard. Only the few events the application cares about are queued for Python.
import inputhub
hub = inputhub.Hub() # one per process
hub.configure_gestures([(["ctrl"], "left"), (["win"], "right")], True)
hub.configure_side_buttons(True, ["x1"]) # swallow Back, report both side buttons
hub.bind_hotkey("clipboard", ["win"], 0x56) # take Win+V from the system
hub.watch_wheel("stitch", (0, 0, 1920, 1080)) # wheel events inside this rectangle only
hub.watch_keys("stitch", [0x10, 0xA0, 0xA1]) # Shift
hub.watch_foreground("clipboard") # every foreground change, including this process
event = hub.next_event() # blocks with the GIL released; next_event(100) waits at most 100 ms
# ("gesture", "start", id, x, y) / ("moved", id) / ("side", "x1") / ("hotkey", "clipboard") /
# ("wheel", watcher, x, y, delta, horizontal) / ("key", watcher, vk, pressed) /
# ("foreground", hwnd) / ("failure", message)
hub.take_position(gesture_id) # latest cursor position of a drag, consumed once per ("moved", id)
hub.close() # a pending next_event() returns None once queued events are drained
Gestures
A gesture binds one or two modifiers to a mouse button. It starts when the button is pressed while
exactly those modifiers are held, and finishes when the button is released. The press and release
are swallowed as a pair, so the window below never starts a drag. While a gesture is active, wheel
events and other clicks are swallowed; Escape or releasing one of its modifiers cancels it. Releasing
Win or Alt after a gesture sends a paired unassigned key first, so the Start menu or menu bar does not
open. accepts(id) tells whether a queued start or finish is still current after a cancel or a
reconfiguration.
A matching gesture takes precedence over a side-button hotkey on the same button.
Gestures accept injected mouse input and keyboard cancellation/release events, allowing remote-control software to drag, cancel with Esc, and release Win/Alt without opening menus. The configured modifier/button combination must still match exactly.
Hotkeys
A hotkey binds modifiers to a non-modifier key, and fires when that key is pressed while exactly those
modifiers are held. Unlike RegisterHotKey, it can take combinations the system already owns, such as
Win+V. The key's press, auto-repeats and release are swallowed together, and only the press is reported.
A key already held before the modifiers is left alone. Releasing Win or Alt afterwards is masked the same
way as after a gesture. Injected input is accepted so remote-control shortcuts also work. unbind_hotkey(name)
gives the combination back; a release still owed for a swallowed press is swallowed as well.
Hook lifetime
The low-level hooks are installed only while something needs them: enabled gestures or side buttons, a hotkey, a wheel or key watcher, or a swallowed press still waiting for its release. The out-of-context foreground-window hook is installed only while a foreground watcher exists. Foreground events are not filtered; the caller decides which windows count.
inputhub.Engine drives the same state machine without installing hooks, with held keys supplied by
the caller; it exists for tests and may be called from any thread.
The distribution is j-input; the module imports as inputhub. Without the default python
feature the crate is a plain Rust library.
Metadata
Release files for j-input 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| j_input-0.1.1-cp311-abi3-win_arm64.whl | CPython 3.11 | abi3 | Windows ARM64 | Details |
| j_input-0.1.1-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
Total release size: 418.6 kB
Release files / j_input-0.1.1-cp311-abi3-win_arm64.whl
| Download URL | j_input-0.1.1-cp311-abi3-win_arm64.whl |
|---|---|
| Size | 206.0 kB |
| Tags | CPython 3.11 Windows ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
bfafcbf3bdcfca805564233cae214624bd8c231a8f6b1259e3d262195293daf9
|
|
BLAKE2b-256 checksum How to use checksums |
0f8b59d5823b460e4cc2ca95919ee12f9814589c3c22261f8aac637b4b00c7e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / j_input-0.1.1-cp311-abi3-win_amd64.whl
| Download URL | j_input-0.1.1-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 212.6 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
9671ef6f7c05635608dded1eb626b98858de74c49b923cd9b6af82184d0f346f
|
|
BLAKE2b-256 checksum How to use checksums |
e81a5927dd4cee87cc81d6ac861775ce4f0ff2e85b6678a13f020eb1fc046b68
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|