Skip to content

core: add tri-state key (start / continue / interrupt) - #705

Merged
rgoulter merged 4 commits into
masterfrom
feat/tri-state
Aug 16, 2026
Merged

core: add tri-state key (start / continue / interrupt)#705
rgoulter merged 4 commits into
masterfrom
feat/tri-state

Conversation

@rgoulter

Copy link
Copy Markdown
Owner

Summary

New key::tri_state family for a session that owns a modifier across later presses of the same key (Alt-Tab / swapper / ZMK tri-state).

  • Start (first press): virtual-hold hold, tap tap. First HID report is the chord (e.g. Alt+Tab), not a naked Tab.
  • Continue (re-press of the same key): tap tap again; hold stays down.
  • Interrupt (any other resolved key): release hold in the same turn, so the host sees A, not Alt+A.

The physical key is NoOp; HID comes from VirtualKeyPress / VirtualKeyRelease. At most one session is armed.

Authoring

K.tri_state.alt_tab
K.tri_state.cmd_tab
K.tri_state.ctrl_tab
K.tri_state.custom { hold = K.LeftCtrl, tap = K.Tab }

Not in this PR: timeout, layer-off end, reverse/continue allow-list (Shift+Tab), swallowing the interrupting key.

Test plan

  • cargo test -p smart-keymap-core --lib key::tri_state
  • cargo test --test rust-integration tri_state
  • cargo test -p smart-keymap-full-system-std --test cucumber-keymap -- -n 'Alt'
  • just check-quick
  • CI green

Comment thread features/keymap/key/tri_state.feature Outdated
Comment thread features/keymap/key/tri_state.feature Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new key::tri_state key family to smart-keymap-core (and the Nickel authoring/codegen pipeline) to support “swapper” behaviors like Alt-Tab / Cmd-Tab: first press starts a session (virtual-hold modifier + tap key), re-press continues (tap again), and any other resolved key interrupts (release the held modifier).

Changes:

  • Implement smart-keymap-core/src/key/tri_state.rs with a single armed session tracked in a per-family Context, emitting VirtualKeyPress/VirtualKeyRelease events.
  • Extend Nickel authoring + codegen to support K.tri_state.* constructors and emit the corresponding Rust Key/System data.
  • Add Rust integration tests and cucumber feature coverage wiring for the new family.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/rust/tri_state.rs New Rust integration tests covering start/continue/interrupt behavior and custom hold/tap.
tests/rust/keymap.rs Registers the new tri_state test module.
tests/rust/hid_keycodes.rs Adds HID constants needed by tri-state tests (Tab, LAlt, LGUI).
tests/cucumber/keymap.rs Adds tri-state key data to cucumber system construction (KeyVecs + System::new).
smart-keymap-full-system-std/tests/keymap_full_system.rs Adds tri-state system slot to full-system test keymap assemblies.
smart-keymap-core/src/key/tri_state.rs Core tri-state implementation: session management + virtual press/release injection.
smart-keymap-core/src/key.rs Exposes the new tri_state module in the core key family list.
ncl/smart_keys/tri_state/keymap-ncl-to-json.ncl Nickel → JSON mapping/validation for tri-state key specs ({ hold, tap }).
ncl/smart_keys/tri_state/keymap-codegen.ncl Codegen rules for tri-state key data + system construction.
ncl/smart_keys/tri_state/key-extensions.ncl Adds K.tri_state.{custom,alt_tab,cmd_tab,ctrl_tab} authoring helpers.
ncl/keys.ncl Enables the tri-state key extension in the global keys.ncl fold.
ncl/keymap-ncl-to-json.ncl Wires tri-state into the overall keymap NCL → JSON pipeline.
ncl/keymap-codegen.ncl Wires tri-state into the overall Rust codegen pipeline.
ncl/key-extensions.ncl Imports tri-state key extensions into the global extension set.
ncl/key_system/keymap-codegen.ncl Adds TriState to generated key_system module lists/checks.
ncl/key_system/families.ncl Defines the tri-state family in the generated aggregate system (data lengths, types, context expr).
features/keymap/key/tri_state.feature Adds cucumber feature/spec text for tri-state behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

A Context-owned session that virtual-holds one output and taps another.
First press starts, re-press of the same key continues, and any other
resolved key interrupts. The physical key is NoOp; HID is virtual
press/release so the first report is the hold+tap chord.
Wire the family through keys.ncl, codegen, and the full-profile
composite. Recipes: K.tri_state.alt_tab / cmd_tab / ctrl_tab, or
K.tri_state.custom { hold, tap }.
Cover first-press hold+tap chord, re-press continue, other-key
interrupt, and K.tri_state.custom.
Press is the hold+tap chord; release and re-press leave the hold down.
@rgoulter
rgoulter merged commit 47339f5 into master Aug 16, 2026
8 checks passed
@rgoulter
rgoulter deleted the feat/tri-state branch August 16, 2026 13:39
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.

2 participants