stochos (/'sto.xos/) — from Greek στόχος: aim, target, goal.
Keyboard-driven mouse control overlay for Wayland, X11, and macOS. OSS alternative to mouseless.
Displays a letter grid over your screen. Type a two-key combo to jump to a cell, refine with a sub-grid key, then act. Runs once per invocation (no daemon).
Wayland: Tested on Hyprland. Should work on any wlroots-based compositor with zwlr_layer_shell_v1 and zwlr_virtual_pointer_v1.
X11: Tested on i3. Should work on any X11 window manager with the XTest extension.
macOS: Single-display only. Requires Accessibility permission (see Setup → macOS below). Cold-start launches dismiss Control Center / WiFi-brightness widgets; other system menus and notification center are unaffected.
With curl:
curl -fsSL https://raw.githubusercontent.com/museslabs/stochos/main/install.sh | shWith cargo:
cargo install stochosFrom source:
git clone https://github.com/museslabs/stochos
cd stochos
cargo build --release # Linux: both backends
cargo build --release --no-default-features --features wayland # Wayland only
cargo build --release --no-default-features --features x11 # X11 only
cargo build --release --no-default-features # macOSBind it to a key in hyprland.conf:
bind = , SUPER_L, exec, stochos
Bind it to a key in ~/.config/i3/config:
bindsym Super_L exec stochos
Bind it to a key with your launcher of choice (Raycast, skhd, Aerospace, etc.). For example, in ~/.aerospace.toml:
alt-enter = 'exec-and-forget /usr/local/bin/stochos'On first launch, macOS will prompt for Accessibility permission. Open System Settings → Privacy & Security → Accessibility and enable the binary (or the terminal you launched from). stochos uses the permission to capture global keystrokes via CGEventTap and to synthesize mouse events via CGEventPost.
If CGEventTapCreate failed is printed instead, also enable the binary under Input Monitoring.
Released binaries are not codesigned with a Developer ID, so after every upgrade macOS treats the new binary as a different program and re-prompts for Accessibility (and Input Monitoring, if applicable). Re-enable it in System Settings each time. Install via the curl | sh command above — curl does not set the Gatekeeper quarantine attribute, so the binary runs without a "cannot be opened" prompt.
- Trigger the overlay
- Type two letters to select a grid cell (e.g.
athens) - Type one more letter to refine within the sub-grid
- Perform an action (see below)
| Key | Action |
|---|---|
| Space | Click |
| Enter | Double click |
m |
Triple click |
| Delete | Right click |
| Insert | Middle click (macOS is not supported) |
| Escape | Close overlay |
| Backspace | Undo last step |
| Arrow keys | Scroll (up/down/left/right) |
/ |
Start drag (select end point, then Space) |
` |
Toggle macro recording |
@ |
Replay macro by bind key |
| Tab | Search macros / quick-save position |
b |
Switch to bisect mode |
n |
Switch back to normal mode (from bisect) |
v |
Switch to free mode |
All keys are configurable (see Configuration below).
| Flag | Effect |
|---|---|
--bisect |
Start the overlay directly in bisect mode |
--free |
Start the overlay directly in free mode (cursor starts at current mouse position) |
--free-center |
Start the overlay directly in free mode with the cursor at the center of the screen |
--allow-multiple |
Skip the single-instance lock |
--print-default-config |
Print the default config (TOML) to stdout and exit. Diff against your config.toml to discover options added by newer versions |
An alternative grid mode that recursively subdivides. Instead of two-key combos and a sub-grid, each hint press zooms the grid into the cell you chose, re-rendering a fresh grid inside that region. Keep pressing hints to home in, then click.
- Enter bisect mode: press
bfrom normal mode, or launch with--bisect - Each hint key splits the current region into a smaller grid (2x2 by default)
- Space / Enter /
m/ Delete / Insert act (click / double-click / triple-click / right-click / middle-click) at the center of the current region and exit - Backspace pops back up one level
- Subdivision stops automatically once a cell would fall below
min_cell_sizepixels — the region is highlighted and you can act or back out - Press
nto switch back to normal mode
An alternative mode for direct keyboard-driven cursor movement. Instead of selecting a grid cell, you steer the cursor continuously with movement keys, then act.
- Enter free mode: press
vfrom normal or bisect mode, or launch with--free(starts at mouse position) or--free-center(starts at screen center) - Move the cursor with
h/j/k/l(left / down / up / right) - Press
=to increase speed and-to decrease it; the current speed is shown in the top-left corner - Space / Enter /
m/ Delete / Insert act (click / double-click / triple-click / right-click / middle-click) and exit - Backspace returns to the previous mode; Escape closes the overlay
- Key repeat is supported: hold a movement key to move continuously
Limitations: drag and text selection are not available in free mode. Use normal mode for those actions.
Key repeat cadence: On Wayland the overlay drives its own repeat (300 ms delay, 25 Hz). On macOS and X11 the OS provides repeats, so the initial delay and rate follow your system keyboard settings (System Settings → Keyboard on macOS, xset r rate on X11).
Record multi-step mouse sequences for replay.
Record: Press ` to start recording. Navigate and act normally (Space to click, Enter to double-click, m to triple-click, Tab to hover-only, / to drag). Press ` again to stop. You'll be prompted for an optional bind key and a name.
Replay: Press @ then the bind key. Or press Tab to search by name, then Enter to select.
Timing. Stochos captures the delay between each recorded action and replays at the same rhythm, so animations and page loads have time to settle. The first action has no wait (you weren't waiting for anything to start the macro). On replay, delays are scaled by macros.playback_speed in config.toml (default 1.0, 2.0 plays twice as fast, 0.0 or negative plays instantly with no waits). You can also hand-edit the per-action wait_ms values in macros.json for fine-grained tuning.
Macros are resolution-independent and stored at ~/.config/stochos/macros.json. Macros recorded before this version still load and replay (without inter-action delays).
Config file location: ~/.config/stochos/config.toml (respects XDG_CONFIG_HOME).
All fields are optional. Missing fields use defaults.
font_size = 2 # Glyph scale multiplier for the 8x8 bitmap font: 1=8px, 2=16px, 3=24px
sub_hint_font_size = 2 # Optional override for sub-grid hint glyphs; defaults to font_size when omitted
panel_font_size = 2 # Optional override for macro/search popup panels; defaults to sub_hint_font_size, then font_size
[grid]
hints = ["a", "s", "d", "f", "j", "k", "l", ";", "g", "h", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]
sub_hints = ["a", "s", "d", "f", "j", "k", "l", ";", "g", "h", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "z", "x", "c", "v", "b"]
sub_cols = 5
target_cell_size = 90 # Enable dynamic grid by setting this value
[bisect]
hints = ["a", "s", "d", "f"] # One per cell, row-major (length must be >= rows * cols)
rows = 2
cols = 2
min_cell_size = 16 # Stop subdividing once a cell would be smaller than this, in pixels
[macros]
playback_speed = 1.0 # 1.0 = recorded speed, 2.0 = twice as fast, 0.0 or negative = instant (no waits)
[keys]
normal = "n"
bisect = "b"
free_mode = "v"
click = "space"
double_click = "enter"
triple_click = "m"
close = "escape"
undo = "backspace"
right_click = "delete"
middle_click = "insert"
scroll_up = "up"
scroll_down = "down"
scroll_left = "left"
scroll_right = "right"
macro_menu = "tab"
macro_record = "`"
[colors]
# Grid colors - Maximum visibility in all conditions
cell_normal = "#00000050" # Semi-black overlay (works on light backgrounds)
text_dim = "#ffffff30" # Semi-white dim (slightly visible on dark)
sub_cell_normal = "#20202080" # Dark grey with good opacity
sub_bg = "#20202080" # Matches sub cell
text_first = "#00ff88ff" # Teal-green (good in sunlight)
text_second = "#ff8800ff" # Orange (high visibility)
cell_highlight = "#00000028" # Subtle dark tint (no color, just darkens slightly)
text_highlight = "#ffff00ff" # Pure yellow (maximum contrast)
cell_drag = "#ff00ddaa" # Hot pink (extremely visible)
panel_bg = "#121212f5" # Near-black (96% opaque) - creates strong contrast barrier
text_white = "#f5f5f5ff" # Off-white (comfortable for long reading)
text_grey = "#b8b8b8ff" # Light grey (maintains 4.5:1 contrast ratio)
selected_bg = "#2196f3ff" # Material Design Blue (works in light/dark)
rec_bg = "#f44336ff" # Material Design Red (urgent, visible everywhere)
border = "#00e676ff" # Material Green (fresh, visible)
border_dragging = "#e91e63ff" # Material Pink (strong attention grabber)
crosshair = "#ffaa00ff" # Amber crosshair in free mode
[free]
left = "h"
down = "j"
up = "k"
right = "l"
fast = "="
slow = "-"
base_speed = 25
fast_multiplier = 3.0
slow_multiplier = 3.0
min_speed = 1
max_speed = 500font_sizesets the glyph scale multiplier. Stochos uses an8x8bitmap font, so each step adds8px:1=8px,2=16px,3=24px, and so on. Default is2.- Increase
font_sizefor high-DPI displays such as3or4on 4K monitors. Valid range:1-10. sub_hint_font_sizesets the glyph scale multiplier for sub-grid hints. If omitted, it inheritsfont_size. It uses the same8pxsteps and1-10range, and still clamps down to fit inside each sub-cell.panel_font_sizesets the glyph scale multiplier for macro and search popup panels. If omitted, it inheritssub_hint_font_size, orfont_sizeif that is also unset. It uses the same8pxsteps and1-10range.
hintssets the characters for the main grid. Grid size islen(hints) x len(hints)(default 20x20 = 400 cells).sub_hintssets the characters for the sub-grid. Sub-grid size issub_cols x (len(sub_hints) / sub_cols)(default 5x5 = 25 cells).sub_colssets how many columns the sub-grid has.
hintssets the characters for each bisect cell, in row-major order. Must contain at leastrows * colsentries; extras are ignored.rowsandcolsset the grid shape used at every subdivision level (default 2x2).min_cell_sizeis the pixel floor at which subdivision stops. The glyph scale auto-shrinks to fit the cell, so lowering this lets you reach tiny regions.
left,down,up,rightset the movement keys (default:h,j,k,l).fast/slowincrease or decrease the step size byfast_multiplier/slow_multiplier(default:=and-).base_speedis the initial step size in pixels (default:25).fast_multiplier/slow_multiplierare the scale factors applied when pressing the speed keys (default:3.0).min_speed/max_speedclamp the step size in pixels (default:1and500).
playback_speedscales the per-action delays recorded into each macro.1.0plays at the recorded rhythm,2.0plays twice as fast,0.5plays at half speed. Setting it to0.0(or any negative value) disables waits entirely for instant playback. Default is1.0.
Any keyboard key can be bound to any action.
Character keys use the character itself: "a", ";", "/", "@", "!".
Special keys use snake_case names:
| Name | Key |
|---|---|
space |
Space |
enter |
Enter |
escape |
Escape |
backspace |
Backspace |
tab |
Tab |
delete |
Delete |
insert |
Insert |
home |
Home |
end |
End |
page_up |
Page Up |
page_down |
Page Down |
up down left right |
Arrow keys |
f1 through f12 |
Function keys |
caps_lock num_lock scroll_lock |
Lock keys |
print_screen pause context_menu |
System keys |
num_pad_0 through num_pad_9 |
Numpad digits |
num_pad_add num_pad_subtract num_pad_multiply num_pad_divide num_pad_decimal num_pad_enter |
Numpad operators |
Shifted characters work too: "@", "!", "~", "A" (uppercase), etc.
