Skip to content

feat: bind key chords from the config file - #8

Open
clvrobj wants to merge 1 commit into
schacon:mainfrom
clvrobj:feat/config-key-chords
Open

clvrobj wants to merge 1 commit into
schacon:mainfrom
clvrobj:feat/config-key-chords

Conversation

@clvrobj

@clvrobj clvrobj commented Aug 15, 2026

Copy link
Copy Markdown

What

Adds an optional "chords" section to ~/.config/micromanager/config.json, binding a pad key to keys pressed in the focused agent's pane:

{ "chords": { "12": "enter" } }

Why

A text macro composes a prompt but deliberately leaves it unsubmitted — "you still read it and press enter", as the README puts it. That's the right default, but it means finishing a dictated line still requires the keyboard. A chord closes the loop: dictate into an agent pane, then tap the key to submit.

How

HerdrClient.sendKeys already existed and is already used by TuneController to drive the model menu (["up"], ["enter"], ["esc"]), so this is dispatch plumbing rather than new capability. Chord names are passed to pane.send_keys untouched, so the vocabulary is Herdr's — "enter", "esc", "ctrl+alt+u" — and an array is a sequence pressed in order.

A chord outranks a text macro on the same key. The reasoning: the KeyBindings.defaults entries are inherited rather than chosen, so an explicitly configured chord shouldn't have to unbind one first.

Scope is the flexible keys — macroKeyIDs + voiceKeyIDs (9, 10, 11, 12) — the same set that already accepts text macros, addressed the same way including "10+11". The key keeps its KV_OAI_AG* binding, so it stays lit and keeps reporting presses, and nothing touches the device keymap.

Limitations, stated up front

  • Chords reach Herdr panes only. They're injected into the pane's pty and never become system-wide key events, so a chord can't drive a system-wide app. Host-side CGEvent synthesis (as VoiceController does for right command) would be the route if that's ever wanted.
  • An unrecognised chord name fails at Herdr rather than at config-load time, surfacing through lastError in the panel.

Testing

  • 7 new unit tests in KeyBindingsTests: string form, array form, "" unbind, "10+11" expansion, chord-beats-text precedence, and malformed input falling back to defaults.
  • Full suite: 89 tests, 3 skipped, and one failure that is pre-existing and unrelated to this change — LiveDeviceTests.testDeviceKeymapHasTheStackKeyBound. It fails on my Creator Micro 2 because the joystick reports type: VENDOR with an empty sectors array, so isAgentKeymapApplied can never return true. Happy to open that separately if it's news; it also means apply() does a flash write on every connect for such a pad.
  • Verified end to end on hardware: key 12 lights and submits the focused agent's prompt.

🤖 Generated with Claude Code

A text macro composes a prompt but deliberately leaves it unsubmitted, so
finishing a dictated line still meant reaching for the keyboard. A `"chords"`
entry presses keys in the focused agent's pane instead of typing into it, which
is the other half of that gesture: `{"chords": {"12": "enter"}}` makes the
bottom-right key submit.

The names are Herdr's own, handed to `pane.send_keys` untouched, so a chord is
whatever that vocabulary allows — "enter", "esc", "ctrl+alt+u", or an array
pressed in order. A chord outranks a text macro on the same key: the text
defaults are inherited rather than chosen, so an explicit chord should not have
to unbind one first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant