#16131

Let apps read and change named shortcuts with omarchy shortcut

Draftnchudleighwants to merge intofrom

Apps need a way to change global shortcuts without writing Hyprland config. This adds omarchy shortcut so an app can read and change a named shortcut, and Omarchy itself binds it and resolves conflicts. It replaces the approach in #14629.

omarchy shortcut get omarchy.dictation.hold            # F9 and ALT + Alt_R, one per line
omarchy shortcut set omarchy.dictation.hold F9 "SUPER + R"
omarchy shortcut set com.superwhisper.shortcut.hold Super_R \
  --description "Push to talk" --command "superwhisper start" --release "superwhisper stop"
omarchy shortcut reset omarchy.dictation.hold          # back to the default keys
omarchy shortcut list --json
  • Omarchy declares its own shortcuts with o.shortcut(id, spec) and their default keys. Dictation is the first: omarchy.dictation.toggle and omarchy.dictation.hold. Apps register their own under reverse-DNS ids, and can change the keys of omarchy.* shortcuts but not what they run.
  • A changed shortcut is stored as field=value lines in ~/.config/omarchy/shortcuts/<id>. Other programs write these files, so they are read as data and never loaded as Lua.
  • set applies the change right away with hyprctl eval "o.shortcuts.apply()", with no reload. get and list ask the running compositor what is bound, so they never show stale keys.
  • Conflicts: set refuses keys that a live binding or another named shortcut already uses. It exits 2 and names who holds them, as JSON with --json, so an app's shortcut recorder can offer to take them. --force takes the keys. A named shortcut that held them keeps the rest of its keys, and an Omarchy default comes back when the shortcut moves off its keys. That one case uses a reload, since only the config knows what the default was.
  • --release makes a hold shortcut such as push-to-talk, built on o.bind_hold. A modifier pressed on its own (Super_R, Alt_R) is matched with the modifier mask ignored, so apps don't need to know that Hyprland quirk.
  • Mouse buttons work as ordinary chords (SUPER + mouse:275). Double-press is left to #13576.

The full reference is in docs/shortcuts.md.

Validation

  • New test/shell.d/shortcuts-test.sh covers:
    • binding Omarchy and app shortcuts
    • chosen keys replacing defaults, and taking keys from a default
    • the reload when a shortcut releases a default's keys
    • valid snapshot JSON
    • every CLI path against a stand-in hyprctl: conflicts by keysym and keycode, --force, --none, reset, and the reload fallback for older configs
  • dictation-test.sh now checks the dictation shortcut names. Its stub previously crashed in Lua and still reported ok.
  • The dictation, hold-binding, binding-conflict, default-config and keybindings-menu tests pass, and so does ./test/cli.
  • Live check on Hyprland 0.56.2: an app shortcut on two chords bound as press/release pairs with eval, a second shortcut on the same keys was refused with its owner named, and reset unbound both.
  • Not yet tested by actually pressing the keys.

🤖 Generated with Claude Code

Activity

2

This pull request is a draft

Merging is unavailable until it is marked ready for review.