keymap: extract pending session module and unify replay dispatch - #584
Conversation
faea525 to
8d258e3
Compare
There was a problem hiding this comment.
Pull request overview
This PR continues the Keymap pending-key refactor by extracting pending-session state into a dedicated pending module and routing both “resolve replay” and “nested pending replay” through a single dispatcher, reducing duplicated replay logic in keymap.rs.
Changes:
- Extract pending-session types and helpers into
src/keymap/pending.rs(PendingState,PendingKeySession,pending_resolution_events+ tests). - Unify replay routing via
ReplayPolicy+dispatch_replayed_events, used by both resolve and nested-pending replay paths. - Simplify pending update loop matching via
pressed_key_result_outcome/PendingPressedKeyOutcome.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/keymap/pending.rs | New module containing pending-session state, replay dispatch, and the pending-resolution filter (with unit tests). |
| src/keymap.rs | Integrates PendingKeySession and replaces duplicated replay logic with dispatch_replayed_events for both replay paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// This is not a configuration setting — it names the *situation* that triggered | ||
| /// replay, and selects the corresponding dispatch behaviour. |
There was a problem hiding this comment.
Eh.
Previous iteration of PR was under-explained. This is over-explained. :|
a12c794 to
4b9892e
Compare
| // Pending key transitioned to another pending state: replay session log. | ||
| dispatch_replayed_events( | ||
| ReplayCase::OnNestedPending, |
There was a problem hiding this comment.
So, this is called once with OnNestedPending...
| dispatch_replayed_events( | ||
| ReplayCase::OnResolve { keymap_index }, |
There was a problem hiding this comment.
...And this is called once with OnResolve...
|
Hmm. Reading through this. I might have to come back to this later. It might be clearer if many cases had unit tests to illustrate the mechanism (or at least encode what happens now). -- This seems (imo) the best next task to get an LLM to help with. -- It's apparent there are several subtle cases, but these are only caught later in the Rust integration test suite. I do like the LLM describing the two current queues in terms of 'input queue is delay lane' (so e.g. chorded keys can accurately resolve), and 'session log' for replay-on-resolve. -- That was covered in #581. I think previous PRs #571 and #575 (and to an extend the CRUCIAL bugfix #578!) already give me more confidence in the pending key resolution.
This PR? It's 'just' shifting code around. Which is nice in terms of being a small change. -- But, although the
Yeah. Having an enum only used to call a function with disjointed body is just a silly LLMism. I think moving the code stuff to "pending key resolution" module is nice. I think having Snippets from LLM's analysis (LLM makes a good point as to what would be worth trying to separate out, but it's not clear if it'll work): Problem summary
While a key is pending, input can accumulate in:
On resolve, replayed events must run before whatever was already sitting in the global Three jobs tangled in
|
| Job | What it means |
|---|---|
| Filter | For the resolving key: keep only the last event targeting that keymap_index; replay all other events in order. |
| Route | key::Event::Input → input queue; other key::Event → event_scheduler with staggered tick delays (so press/release can affect HID report one tick apart). |
| Priority | Replay batch must run before whatever was already in the global input_queue. |
take_all / append_all existed only for priority (fixed in #575). The partition + .last() logic is a separate policy concern (extracted as pending_resolution_events in #575).
. . .
LLM reckons:
Delay only on replay (optional)
Apply tick spacing when flushing on resolve, not when ingesting during pending. Combines with pending-local ingest pacing for a single logical buffer.
...
What's still gnarly
handle_input → input_queue (pacing) → process_input → queued_events (log)
↓
update_pending_state
↓
resolve → filter log → prepend / scheduler → handle_event ↺
Three concerns still share plumbing:
- Pacing —
input_queuespaces inputs one-per-tick - Logging —
queued_eventsrecords the pending session - Replay — filter, route, cascade via
handle_pending_events
#578 fixed a specific handle_event/process_input hazard; the overall flow is still dense.
Subtle point: events still in the input_queue delay line at resolve time are intentionally not in queued_events — they process post-resolve in normal mode.
PendingState owns ingest_delay; global input_queue only for non-pending traffic. Gate on rust-integration tap-hold/chorded tests.
| NestedPending(PKS), | ||
| } | ||
|
|
||
| pub(crate) fn pressed_key_result_outcome<R, PKS, KS>( |
There was a problem hiding this comment.
Similarly in terms of LLM-isms, this enum provides very little value.
This codebase is full of abstractions that are 'cute'. But this is a bit too excessive.
|
Ok, if the LLMisms were cleaned up, I think this'd be good. |
4b9892e to
1f3ec9d
Compare
|
Hmm. Working on the code:
|
Move pending state, resolution filter, and replay routing into pending.rs. Introduce PendingKeySession, ReplayPolicy, and dispatch_replayed_events for the resolve vs nested-pending paths.
1f3ec9d to
ac2c638
Compare
Summary
Extracts pending-key session logic into
src/keymap/pending.rsand unifies replay dispatch for the two replay paths.Context
Continues the pending key-event resolution cleanup in
Keymap. Prior steps:InputEventQueuefromKeymap(delay-line pacing + prepend API)pending_resolution_eventsfilter helperrecord_pending_input,was_pendinginhandle_event)input_queue) vs session log (queued_events) at implementation sitesThis PR is the next step: pull pending session concerns out of
keymap.rsand route both replay paths through one dispatcher. Bundled as one PR because extract and unify touch the same call sites (resolve_pending_key_state, nested-pending branch inupdate_pending_state).Not in scope: pending-local ingest pacing (medium-risk follow-up; naive one-buffer bypass still fails
rust-integrationtap-hold/chorded tests).Changes
PendingKeySession— wraps active pending state;record_input,start,take, etc. (replaces ad-hocrecord_pending_input+Option<PendingState>field)pending_resolution_events— moved fromkeymap.rswith unit tests (originally added in keymap: prepend on pending resolve + extract resolution filter #575)ReplayPolicy+dispatch_replayed_events— shared routing for:prepend_pending_input_events)pressed_key_result_outcome— mapsPressedKeyResultfor the pending update loopKeymapkeeps thin glue (resolve_pending_key_state,update_pending_state,process_input)Testing
cargo test -p smart-keymap --libcargo clippy -p smart-keymap -- -D warnings