kbd-global 0.1.0

Global hotkey runtime for kbd — threaded engine, device management, and backend selection for Linux
Documentation

kbd-global

crates.io docs.rs

Global hotkey runtime for kbd — threaded engine, device management, and backend selection for Linux.

When a key combination happens on a Linux keyboard, do something. Works on Wayland, X11, and TTY — it reads evdev directly, no display server integration needed.

[dependencies]
kbd = "0.1"
kbd-global = "0.1"

Quick start

use kbd::prelude::*;
use kbd_global::HotkeyManager;

let manager = HotkeyManager::new()?;

let _guard = manager.register(
    Hotkey::new(Key::C).modifier(Modifier::Ctrl).modifier(Modifier::Shift),
    || println!("Ctrl+Shift+C pressed!"),
)?;

std::thread::park();
# Ok::<(), kbd_global::Error>(())

Key types, actions, and layers come from kbd. kbd-global provides the runtime ([HotkeyManager], [BindingGuard], [Backend]).

Prerequisites

Your user must be in the input group to read /dev/input/event* devices:

sudo usermod -aG input $USER

Log out and back in for the group change to take effect.

Architecture

HotkeyManager is the public API. Internally it sends commands to a dedicated engine thread over an mpsc channel, with an eventfd wake mechanism to interrupt poll(). All mutable state lives in the engine — no locks, no shared mutation.

┌──────────────────┐    Command     ┌──────────────────┐
│  HotkeyManager   │ ─────────────► │  Engine thread   │
│  (command sender) │ ◄───────────── │  (event loop)    │
└──────────────────┘    Reply        └──────────────────┘
                                          │
                                     poll(devices + wake_fd)

Layers

Layers let you define context-dependent bindings. Define a layer, push it onto the stack, and its bindings take priority over global ones:

use kbd::prelude::*;
use kbd_global::HotkeyManager;

let manager = HotkeyManager::new()?;

let layer = Layer::new("vim-normal")
    .bind(Hotkey::new(Key::J), Action::from(|| println!("down")));

manager.define_layer(layer)?;
manager.push_layer("vim-normal")?;
// Key::J now fires "down" instead of any global binding
# Ok::<(), kbd_global::Error>(())

Feature flags

Feature Effect
grab Enables exclusive device capture via EVIOCGRAB with uinput forwarding for non-hotkey events
serde Adds Serialize/Deserialize to key and hotkey types (via kbd)

The grab feature requires udev rules for uinput access — see the docs for setup instructions.

License

kbd-global is licensed under the MIT license. See the LICENSE file for more information.