kbd-global 0.2.0

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

kbd-global

crates.io docs.rs

System-wide hotkeys on Linux for the kbd workspace.

kbd-global runs a background thread that reads from evdev input devices, feeds events through kbd's dispatcher, and fires your callbacks when bindings match. It handles device discovery, hotplug, and the event loop so you don't have to. Works on Wayland, X11, and TTY — no display server integration needed.

Requirements

kbd-global reads /dev/input/event* directly. Your user needs permission to access input devices:

sudo usermod -aG input $USER

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

Example

use kbd::hotkey::{Hotkey, Modifier};
use kbd::key::Key;
use kbd_global::manager::HotkeyManager;

let manager = HotkeyManager::new()?;

// Registration returns a guard — the binding lives until the guard is dropped
let _guard = manager.register(
    Hotkey::new(Key::C).modifier(Modifier::Ctrl).modifier(Modifier::Shift),
    || println!("Ctrl+Shift+C pressed"),
)?;

// Keep the main thread alive so the background listener keeps running
std::thread::park();

HotkeyManager is the main entry point. It spawns the engine thread on creation and communicates with it over a channel. Registration returns a BindingGuard — dropping it unregisters the binding. Dropping the manager (or calling shutdown()) stops the runtime.

Layers

Layers let you swap between different binding sets at runtime — think vim modes, or a "gaming" layer that disables desktop shortcuts:

use kbd::action::Action;
use kbd::key::Key;
use kbd::layer::Layer;
use kbd_global::manager::HotkeyManager;

let manager = HotkeyManager::new()?;

let layer = Layer::new("vim-normal")
    .bind(Key::J, || println!("down"))?
    .bind(Key::K, || println!("up"))?
    .bind(Key::I, Action::PushLayer("vim-insert".into()))?;

let insert = Layer::new("vim-insert")
    .bind("Escape".parse()?, Action::PopLayer)?;

manager.define_layer(layer)?;
manager.define_layer(insert)?;
manager.push_layer("vim-normal")?;

Layers stack — the most recently pushed layer is checked first. PopLayer removes the top layer, ToggleLayer adds or removes by name.

Grab mode

With the grab feature enabled, kbd-global can exclusively capture input devices so matched keys never reach other applications. Unmatched events are forwarded through a virtual uinput device.

use kbd_global::manager::HotkeyManager;

let manager = HotkeyManager::builder()
    .grab()
    .build()?;

Grab mode requires write access to /dev/uinput in addition to read access on /dev/input/.

Feature flags

Feature Effect
grab Exclusive device capture via EVIOCGRAB with uinput forwarding for unmatched events
serde Serde support for shared kbd key and hotkey types

Current status

  • Linux only
  • evdev is the only backend
  • Action::EmitHotkey and Action::EmitSequence are not yet implemented in the runtime

Related crates

License

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