keyhop 0.2.0

System-wide keyboard navigation overlay: drive your desktop without the mouse.
Documentation

keyhop

Drive your entire desktop from the keyboard. Press a leader chord, see hint labels on every clickable thing on screen, type the hint, done.

keyhop is a system-wide keyboard navigation layer that lets you control your whole computer without ever touching the mouse. Reaching for the mouse forces a constant context switch between thinking and pointing — your hands leave the home row, your eyes hunt for a cursor, and your flow breaks. keyhop keeps you on the keyboard so you stay fast, focused, and productive, using OS accessibility APIs (UI Automation on Windows) to target native UI elements semantically.

Status: v0.2.0 — Windows backend with visual configuration, customizable hotkeys/colors/alphabet, and Windows startup integration. Linux backend planned.

ci crates.io docs.rs license

Goals

  • Native performance and instant feel (sub-50ms hint overlay).
  • Semantic targeting via OS accessibility trees (UI Automation on Windows; AT-SPI on Linux when that backend lands).
  • Single, easy-to-install crate with platform backends gated behind cfg.

Crate layout

keyhop/
├─ src/
│  ├─ lib.rs               # public API: Action, Backend, Element, HintEngine
│  ├─ main.rs              # the `keyhop` binary
│  ├─ model.rs
│  ├─ action.rs
│  ├─ backend.rs
│  ├─ hint.rs
│  ├─ config.rs            # TOML config (%APPDATA%/keyhop/config.toml)
│  └─ windows/             # Windows backend (cfg(windows) only)
│     ├─ mod.rs            # WindowsBackend (UI Automation tree walk)
│     ├─ hotkey.rs         # global leader hotkeys + chord parser
│     ├─ overlay.rs        # transparent layered hint overlay + color parser
│     ├─ tray.rs           # system tray icon + context menu
│     ├─ settings_window.rs # visual Settings dialog (Win32)
│     ├─ startup.rs        # "launch at login" via HKCU Run key
│     ├─ notification.rs   # MessageBox-backed user notifications
│     └─ window_picker.rs  # Alt-Tab-style window picker
└─ examples/
   └─ enumerate_foreground.rs

One package, one publish: keyhop ships both the binary and a reusable library API. Linux / Wayland / macOS backends will land as additional cfg-gated modules under src/.

Install

From crates.io (recommended once published):

cargo install keyhop

From source:

git clone https://github.com/rsaz/keyhop
cd keyhop
cargo install --path .

Requires:

  • Rust stable with the x86_64-pc-windows-msvc toolchain
  • Visual Studio Build Tools with the "Desktop development with C++" workload

Run

keyhop                         # release install (no console, logs to file)
cargo run --release            # from source (no console, logs to file)
cargo run                      # debug build (shows console with live logs)
cargo run --example enumerate_foreground

The binary uses the Windows GUI subsystem in release builds, running silently in the background with no console window. Logs are written to %LOCALAPPDATA%\keyhop\keyhop.log and can be viewed via the tray menu's "View Log" option. Debug builds (cargo run without --release) still show a console window for development convenience.

Flags

Flag What it does
-h, --help Print usage and exit.
-V, --version Print version and exit.
--no-tray Run without the system tray icon (hotkeys-only mode).

Using it

After launching, keyhop registers two global hotkeys and a tray icon. The default chords below can be changed from Settings... in the tray menu — see Configuration.

Action Default keys What it does
Pick element Ctrl + Shift + Space Hints every interactable control inside the focused window. Type one to invoke it.
Pick window Ctrl + Alt + Space Hints every visible top-level window across all monitors. Type one to focus it.
Confirm type the hint label Commits the selection.
Backspace Backspace Drops the last typed character (inside an overlay).
Cancel Esc Dismisses the current overlay without doing anything.
Settings Tray menu → Settings... Open the visual configuration dialog.
Quit Tray menu → Quit Cleanly exits keyhop.

The tray icon's right-click menu mirrors the two leader chords, gives you a Settings... entry to customize keyhop visually, and (in release builds) a View Log shortcut so you can debug without leaving the keyboard.

Yellow badges = element picker (will invoke the control). Orange badges = window picker (will focus the window). Both show the hint letters on the home row by default — but as of v0.2.0 you can change the colors and the alphabet from Settings....

Configuration

keyhop is configured through a small visual dialog reachable from the tray icon (Settings...), so you never have to touch a config file unless you want to. The dialog lets you change:

  • Hotkeys — both leader chords. Type any combination of Ctrl, Shift, Alt, Win/Super modifiers plus a key (A-Z, 0-9, F1-F24, Space, arrow keys, punctuation, etc.). Example: Ctrl+Alt+K.
  • Hint alphabet — the characters used to build hint labels. Default asdfghjkl (the home row).
  • Overlay colors — element badge background and window badge background, as #RRGGBB hex.
  • Launch at Windows startup — toggles a per-user entry in HKCU\Software\Microsoft\Windows\CurrentVersion\Run (no admin rights required).

Save validates everything (invalid hotkey strings or hex colors are rejected up-front), writes %APPDATA%\keyhop\config.toml, and shows a confirmation. Reset to Defaults deletes the config file. Hotkey, alphabet, and color changes apply on the next launch; the startup toggle takes effect immediately.

If a configured hotkey is already in use by another app at startup, keyhop reports the conflict via a notification dialog and continues running with the surviving chord (e.g. if pick-window conflicts but pick-element doesn't, the latter still works). Open Settings... to choose a different combination.

config.toml format (for power users)

The Settings dialog is the recommended path, but %APPDATA%\keyhop\config.toml is plain TOML if you prefer to script it:

[hotkeys]

pick_element = "Ctrl+Shift+Space"

pick_window  = "Ctrl+Alt+Space"



[hints]

alphabet = "asdfghjkl"



[colors.element]

badge_bg = "#FFE500"   # leave empty to keep the default

badge_fg = ""

border   = ""



[colors.window]

badge_bg = "#33AAFF"

badge_fg = ""

border   = ""



[startup]

launch_at_startup = false

Missing keys, missing sections, and an entirely missing file all fall back to the v0.1.0 defaults. Malformed TOML is logged and ignored — keyhop will start with defaults rather than refuse to run.

Library use

Beyond the binary, keyhop exposes a small library API. The Windows backend implements Backend, and the HintEngine is platform-agnostic.

use keyhop::{Backend, HintEngine};

#[cfg(windows)]
fn enumerate() -> anyhow::Result<()> {
    let mut backend = keyhop::windows::WindowsBackend::new()?;
    let elements = backend.enumerate_foreground()?;
    let hints = HintEngine::default().generate(elements.len());
    for (el, hint) in elements.iter().zip(hints.iter()) {
        println!("{hint}: {:?} {:?}", el.role, el.name);
    }
    Ok(())
}

The library surface is experimental while we're pre-1.0 — minor releases may break it. Pin a specific version if you embed it.

Roadmap

Shipped (v0.1.0)

  • Single-crate scaffold publishable to crates.io
  • Foreground window UI Automation tree walk
  • Global leader hotkeys + modal input
  • Hint overlay (transparent layered window) with collision resolution
  • Invoke action dispatch
  • Window picker mode (Alt-Tab with hints, all monitors)
  • Multi-monitor coordinate handling
  • System tray icon + context menu
  • CLI flags (--version, --help, --no-tray)
  • Single-instance guard
  • GUI-subsystem release builds (hidden console, file logging)

Shipped (v0.2.0)

  • Visual Settings dialog (no .toml editing required)
  • Configurable hotkeys via %APPDATA%\keyhop\config.toml with chord parser
  • Configurable hint alphabet
  • Configurable overlay colors (#RRGGBB)
  • Hotkey conflict detection with user notification
  • Windows startup integration via HKCU\...\Run (no admin)
  • Scroll action wired through UIA UIScrollPattern
  • User-facing notifications (no elements found, hotkey conflict, action failed)

Next up (v0.3.0)

  • Polished tray icon (multi-resolution .ico instead of the procedural badge)
  • Hot-reload config without restarting (re-register hotkeys at runtime)
  • Per-color overrides exposed in the Settings dialog (today only badge backgrounds are editable)

Future

  • Click-through overlay so non-target apps still see the mouse
  • MSI installer and a Winget manifest
  • Linux backend (X11 first, then Wayland) via AT-SPI
  • macOS backend via the Accessibility API

See CHANGELOG.md for release history.

Contributing

Issues and PRs welcome. Please run before pushing:

cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo test

License

Dual-licensed under either of:

at your option.