core: add tri-state key (start / continue / interrupt) - #705
Merged
Conversation
rgoulter
commented
Aug 16, 2026
rgoulter
commented
Aug 16, 2026
There was a problem hiding this comment.
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.rswith a single armed session tracked in a per-familyContext, emittingVirtualKeyPress/VirtualKeyReleaseevents. - Extend Nickel authoring + codegen to support
K.tri_state.*constructors and emit the corresponding RustKey/Systemdata. - 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
force-pushed
the
feat/tri-state
branch
from
August 16, 2026 13:39
538b03d to
e5fe897
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New
key::tri_statefamily for a session that owns a modifier across later presses of the same key (Alt-Tab / swapper / ZMK tri-state).hold, taptap. First HID report is the chord (e.g. Alt+Tab), not a naked Tab.tapagain;holdstays down.holdin the same turn, so the host seesA, notAlt+A.The physical key is
NoOp; HID comes fromVirtualKeyPress/VirtualKeyRelease. At most one session is armed.Authoring
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_statecargo test --test rust-integration tri_statecargo test -p smart-keymap-full-system-std --test cucumber-keymap -- -n 'Alt'just check-quick