# 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.
[](https://github.com/rsaz/keyhop/actions/workflows/ci.yml)
[](https://crates.io/crates/keyhop)
[](https://docs.rs/keyhop)
[](#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):
```powershell
cargo install keyhop
```
From source:
```powershell
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
```powershell
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
| `-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](#configuration).
| 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:
```toml
[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`](https://docs.rs/keyhop/latest/keyhop/trait.Backend.html), and the [`HintEngine`](https://docs.rs/keyhop/latest/keyhop/struct.HintEngine.html) is platform-agnostic.
```rust
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)
- [x] Single-crate scaffold publishable to crates.io
- [x] Foreground window UI Automation tree walk
- [x] Global leader hotkeys + modal input
- [x] Hint overlay (transparent layered window) with collision resolution
- [x] Invoke action dispatch
- [x] Window picker mode (Alt-Tab with hints, all monitors)
- [x] Multi-monitor coordinate handling
- [x] System tray icon + context menu
- [x] CLI flags (`--version`, `--help`, `--no-tray`)
- [x] Single-instance guard
- [x] GUI-subsystem release builds (hidden console, file logging)
### Shipped (v0.2.0)
- [x] Visual Settings dialog (no `.toml` editing required)
- [x] Configurable hotkeys via `%APPDATA%\keyhop\config.toml` with chord parser
- [x] Configurable hint alphabet
- [x] Configurable overlay colors (`#RRGGBB`)
- [x] Hotkey conflict detection with user notification
- [x] Windows startup integration via `HKCU\...\Run` (no admin)
- [x] Scroll action wired through UIA `UIScrollPattern`
- [x] 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](CHANGELOG.md) for release history.
## Contributing
Issues and PRs welcome. Please run before pushing:
```powershell
cargo fmt --all
cargo clippy --all-targets -- -D warnings
cargo test
```
## License
Dual-licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.