feat: shortcuts made with Karabiner-Elements, including a Hyper key, work in Miri and can be recorded in Settings#302

opened5d agobySSamanyu Das

Problem

Many people use Karabiner-Elements to remap keys, often to turn Caps Lock into a Hyper key that holds Control, Option, Shift, and Command at once. Nobody has checked whether Miri's shortcuts work when Karabiner-Elements sends them, or whether you can record a Hyper key chord in Settings.

What the code shows on main at 6f398e2b, engine ee89647, without a live test:

  • Karabiner-Elements sends keys through a virtual keyboard driver, so macOS should deliver them like keys from a physical keyboard. The engine's keyboard listener (src/platform/input.rs:352) reads those events, so remapped shortcuts should already match.
  • The configuration accepts a chord with all four modifiers, such as ctrl+alt+shift+cmd-h, but rejects the word hyper as a modifier name (Tests/MiriCoreTests/BindingsTests.swift:517).
  • The Settings shortcut recorder reads all four modifiers (Sources/Miri/ShortcutRecorder.swift:133), and nothing found rejects a chord with four of them.
  • decisions/keybinding reference.md:221 says that recording Hyper key combinations made with tools such as Karabiner-Elements is deferred to v2. decisions/release-scope.md:247, decisions/v2-roadmap.md:37, decisions/design-tree-status.md:176, and docs/specs/miri-v1.md:406 and :642 say the same. Sam made this a v1 blocker on 5 November 2026, so those documents must change with it.

Proposed behavior

  • Shortcuts that Karabiner-Elements sends or remaps act exactly like the same keys pressed on a keyboard.
  • The Settings shortcut recorder records a Hyper key chord, shows it as ⌃⌥⇧⌘ and the key, and saves it so that the engine runs it.
  • If a Hyper key chord conflicts with a macOS shortcut or another Miri action, the recorder warns, as it does for any other chord.
  • docs/limitations.md and decisions/keybinding reference.md say what works with Karabiner-Elements and what does not.

Requested by

Sam, 5 November 2026

Release

v1

Acceptance criteria

  • Manual check on Miri Developer with Karabiner-Elements running and a rule that maps Caps Lock to Control, Option, Shift, and Command: the binding ctrl+alt+shift+cmd-h in the configuration file moves focus one column left when you press Caps Lock and H.
  • Manual check: with that rule on, the Settings shortcut recorder records Caps Lock and H as ⌃⌥⇧⌘H, and the recorded shortcut then moves focus.
  • Manual check: a Karabiner-Elements rule that sends ⌃⌥← from another key moves focus the same way as pressing ⌃⌥← on the keyboard.
  • Manual check: with Karabiner-Elements running and no rules, Miri's default shortcuts still work.
  • A test in Tests/MiriCoreTests checks that a chord with all four modifiers parses, saves, and reads back unchanged. make swift-test passes.
  • decisions/keybinding reference.md, decisions/release-scope.md, decisions/v2-roadmap.md, decisions/design-tree-status.md, and docs/specs/miri-v1.md put Hyper key recording in v1, and make lint passes.
  • make check passes.

Alternatives considered

  • Accept the word hyper as a modifier name in the configuration file, meaning all four modifiers. This is shorter to write, but adds a second spelling for the same chord.
  • Keep the v2 deferral and document only what already works with Karabiner-Elements. Sam chose v1 instead.

Note

🤖 Claude Opus 5.5 responding on behalf of Sam (samanyudas)

Triage result: I found no defect in the engine, the recorder, or the configuration that would stop a Hyper key or a Karabiner-Elements rule from working. Acceptance criteria 1 and 2 cannot pass as written, because ⌃⌥⇧⌘H is already a default shortcut. I added needs-info until the criteria name a free chord.

The gap in the criteria

  • ctrl+alt+cmd+shift-h is a default chord for Move column to first position or monitor left (window_moveedge_west, Sources/MiriCore/Bindings.swift:156 on main at ffefedfa). Sam's live config.toml holds it too.
  • Criterion 2: the recorder rejects a chord that another action holds (Sources/MiriCore/Shortcuts.swift:102). Recording Caps Lock and H for Focus column left would show "⌃⌥⇧⌘H is already used by Move column to first position or monitor left." and save nothing. This is inferred from the code. I did not run it.
  • Criterion 1: if the file binds the chord to both actions, the engine runs the first match from a HashMap (vendor/paneru/src/config.rs:436, map at :1209). Which action wins can change at each engine start, so focus might or might not move. This is also inferred from the code.

Proposed rewording, for Sam to accept or change:

  1. With the Hyper rule on, Caps Lock and H runs its default, Move column to first position or monitor left. This needs no config edit.
  2. With the Hyper rule on, the recorder records Caps Lock and U for Focus column left as ⌃⌥⇧⌘U, and Caps Lock and U then moves focus one column left. No binding in config.toml uses the U key today.
  3. With the Hyper rule on, recording Caps Lock and H for Focus column left shows the "already used" warning. This checks the conflict bullet under Proposed behavior.

Criteria 3 to 7 can be checked as written.

Why I expect the rest to work

  • The engine builds modifiers from the left and right device bits, then falls back to the generic flags (vendor/paneru/src/platform/input.rs:827 and :856). The Caps Lock flag is in no group, so the engine ignores it.
  • Miri's defaults already use all four modifiers on twelve chords: the arrows, H, J, K, L, W, A, S, and D for edge and display moves.
  • The recorder's tap sits at the head of the HID event tap and reads all four modifiers (Sources/Miri/ShortcutRecorder.swift:68 and :133). It needs only one of Control, Option, or Command, and it saves the chord as ctrl+alt+cmd+shift-<key>.
  • Karabiner-Elements 16.3.0 on this Mac has grabbed the Apple Internal Keyboard since 5 November at 23:40, according to its core_service.log. That keyboard is the only physical keyboard attached. So every Miri shortcut typed on this Mac since then reached macOS through Karabiner's virtual keyboard. The record does not show which Miri shortcuts Sam pressed in that time.

What only Sam can check

An agent cannot test the Karabiner path. Karabiner-Elements reads the physical keyboard through IOKit, and a synthetic CGEvent never passes through it. This comes from Karabiner's design, and I did not test it here.

Karabiner-Elements on this Mac now has two extra profiles, "Miri 302 Hyper test" and "Miri 302 no rules". The Default profile is unchanged and still selected. The Hyper test profile maps Caps Lock to ⌃⌥⇧⌘ and Right Option to ⌃⌥←.

Open guess

macOS reserves some Hyper chords, such as ⌃⌥⇧⌘. for sysdiagnose. Miri's conflict table holds only symbolic hot keys, so the recorder might not warn about those. I have not checked this. docs/limitations.md can name it once someone confirms it.