From 3a6006f8ecd9b1e0ef5f12293fe71555fa5a9d03 Mon Sep 17 00:00:00 2001 From: Richard Goulter Date: Tue, 2 Sep 2025 17:14:02 +0700 Subject: [PATCH 1/6] rust: change KeyPath::add_path_item to create clone --- src/key.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/key.rs b/src/key.rs index 1ed4f89b2..49f32d21e 100644 --- a/src/key.rs +++ b/src/key.rs @@ -44,8 +44,10 @@ impl KeyPath { } /// Adds an item to the KeyPath. - pub fn add_path_item(&mut self, item: u16) { - self.0.insert(1, item).unwrap(); + pub fn add_path_item(&self, item: u16) -> KeyPath { + let mut kp = self.clone(); + kp.0.insert(1, item).unwrap(); + kp } } @@ -156,9 +158,8 @@ impl PressedKeyResult { /// Adds an item to the KeyPath if the pressed key result is pending. pub fn add_path_item(self, item: u16) -> Self { match self { - PressedKeyResult::Pending(mut key_path, pks) => { - key_path.add_path_item(item); - PressedKeyResult::Pending(key_path, pks) + PressedKeyResult::Pending(key_path, pks) => { + PressedKeyResult::Pending(key_path.add_path_item(item), pks) } pkr => pkr, } From c889109a748c295ac7ab66f5c510181a4236e95f Mon Sep 17 00:00:00 2001 From: Richard Goulter Date: Tue, 2 Sep 2025 17:15:43 +0700 Subject: [PATCH 2/6] rust: refactor new_pressed_key usage --- src/key.rs | 28 ++++- src/key/callback.rs | 5 +- src/key/caps_word.rs | 5 +- src/key/chorded.rs | 69 ++++++------ src/key/composite/base.rs | 5 +- src/key/composite/chorded.rs | 10 +- src/key/composite/layered.rs | 10 +- src/key/composite/tap_hold.rs | 10 +- src/key/custom.rs | 5 +- src/key/keyboard.rs | 5 +- src/key/layered.rs | 10 +- src/key/sticky.rs | 5 +- src/key/tap_dance.rs | 24 ++--- src/key/tap_hold.rs | 28 +++-- src/keymap.rs | 198 ++++++++++++++++++++++++---------- 15 files changed, 238 insertions(+), 179 deletions(-) diff --git a/src/key.rs b/src/key.rs index 49f32d21e..1a7cdbca6 100644 --- a/src/key.rs +++ b/src/key.rs @@ -129,11 +129,34 @@ impl IntoIterator for KeyEvents { } } +/// Newtype for invoking new_pressed_key on the key at the given [KeyPath]. +#[derive(Debug)] +pub enum NewPressedKey { + /// Invoke new_pressed_key on the key at the given [KeyPath]. + Key(KeyPath), + /// For keys which do nothing when pressed. + NoOp, +} + +impl NewPressedKey { + /// Constructs a NewPressedKey value. + pub fn key_path(key_path: KeyPath) -> Self { + NewPressedKey::Key(key_path) + } + + /// Constructs a NoOp NewPressedKey value. + pub fn no_op() -> Self { + NewPressedKey::NoOp + } +} + /// Pressed Key which may be pending, or a resolved key state. #[derive(Debug)] pub enum PressedKeyResult { /// Unresolved key state. (e.g. tap-hold or chorded keys when first pressed). Pending(KeyPath, PKS), + /// Resolved as a new pressed key. + NewPressedKey(NewPressedKey), /// Resolved key state. Resolved(KS), } @@ -211,10 +234,7 @@ pub trait Key: Debug { context: &Self::Context, key_path: KeyPath, event: Event, - ) -> ( - Option>, - KeyEvents, - ); + ) -> (Option, KeyEvents); /// Return a reference to the key for the given path. fn lookup( diff --git a/src/key/callback.rs b/src/key/callback.rs index e70abe116..e2476ab96 100644 --- a/src/key/callback.rs +++ b/src/key/callback.rs @@ -47,10 +47,7 @@ impl key::Key for Key { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/caps_word.rs b/src/key/caps_word.rs index 0af2a7a51..5e8b6385c 100644 --- a/src/key/caps_word.rs +++ b/src/key/caps_word.rs @@ -158,10 +158,7 @@ impl key::Key for Key { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/chorded.rs b/src/key/chorded.rs index f0c6d100b..44458c247 100644 --- a/src/key/chorded.rs +++ b/src/key/chorded.rs @@ -320,12 +320,12 @@ where chorded_ctx.config.chords.get(resolved_chord_id as usize) { if resolved_chord_indices.as_slice()[0] == keymap_index { - if let Some((_, k)) = self + if let Some((_, _k)) = self .chords .iter() .find(|(ch_id, _)| *ch_id == resolved_chord_id) { - Some((1 + resolved_chord_id, k)) + Some(1 + resolved_chord_id) } else { panic!("check_resolution has invalid chord id") } @@ -336,13 +336,18 @@ where panic!("check_resolution has invalid chord id") } } - ChordResolution::Passthrough => Some((0, &self.passthrough)), + ChordResolution::Passthrough => Some(0), }; - if let Some((i, k)) = maybe_pathel_key { - let (pkr, pke) = k.new_pressed_key(context, key_path); + if let Some(i) = maybe_pathel_key { // PRESSED KEY PATH: add Chord (0 = passthrough, 1 = 1+chord_id) - (pkr.add_path_item(i as u16), pke) + let new_key_path = key_path.add_path_item(i as u16); + let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path( + new_key_path, + )); + let pke = key::KeyEvents::no_events(); + + (pkr, pke) } else { let pkr = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into()); let pke = key::KeyEvents::no_events(); @@ -407,10 +412,7 @@ impl< context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let keymap_index = key_path.keymap_index(); let ch_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into(); if let Ok(ch_pks) = ch_pks_res { @@ -428,12 +430,12 @@ impl< chorded_ctx.config.chords.get(resolved_chord_id as usize) { if resolved_chord_indices.as_slice()[0] == keymap_index { - if let Some((_, k)) = self + if let Some((_, _k)) = self .chords .iter() .find(|(ch_id, _)| *ch_id == resolved_chord_id) { - Some((1 + resolved_chord_id, k)) + Some(1 + resolved_chord_id) } else { panic!("event's chord resolution has invalid chord id") } @@ -444,7 +446,7 @@ impl< panic!("event's chord resolution has invalid chord id") } } - ChordResolution::Passthrough => Some((0, &self.passthrough)), + ChordResolution::Passthrough => Some(0), }; let ch_r_ev = Event::ChordResolved(ch_state); @@ -453,18 +455,16 @@ impl< ch_r_ev.into(), )); - if let Some((i, nk)) = maybe_pathel_and_key { - let (pkr, mut pke) = nk.new_pressed_key(context, key_path); + if let Some(i) = maybe_pathel_and_key { // PRESSED KEY PATH: add Chord (0 = passthrough, 1 = 1+chord_id) - let pkr = pkr.add_path_item(i as u16); + let new_key_path = key_path.add_path_item(i as u16); - pke.add_event(sch_ev); + let pke = key::KeyEvents::scheduled_event(sch_ev); - (Some(pkr), pke) + (Some(key::NewPressedKey::key_path(new_key_path)), pke) } else { - let pkr = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into()); let pke = key::KeyEvents::scheduled_event(sch_ev); - (Some(pkr), pke) + (Some(key::NewPressedKey::no_op()), pke) } } else { (None, key::KeyEvents::no_events()) @@ -545,8 +545,11 @@ where (pkr, pke) } ChordResolution::Passthrough => { - let (pkr, pke) = self.passthrough.new_pressed_key(context, key_path); - let pkr = pkr.add_path_item(0); // 0 = passthrough key + let new_key_path = key_path.add_path_item(0); // 0 = passthrough key + let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path( + new_key_path, + )); + let pke = key::KeyEvents::no_events(); (pkr, pke) } } @@ -601,42 +604,32 @@ impl< fn handle_event( &self, pending_state: &mut Self::PendingKeyState, - context: &Self::Context, + _context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let keymap_index = key_path.keymap_index(); let ch_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into(); if let Ok(ch_pks) = ch_pks_res { if let Ok(ch_ev) = event.try_into_key_event(|e| e.try_into()) { let ch_state = ch_pks.handle_event(keymap_index, ch_ev); if let Some(ChordResolution::Passthrough) = ch_state { - let nk = &self.passthrough; - let (pkr, mut pke) = nk.new_pressed_key(context, key_path); - let pkr = pkr.add_path_item(0); // 0 = passthrough key + let new_key_path = key_path.add_path_item(0); // 0 = passthrough key let ch_r_ev = Event::ChordResolved(ChordResolution::Passthrough); let sch_ev = key::ScheduledEvent::immediate(key::Event::key_event( keymap_index, ch_r_ev.into(), )); - pke.add_event(sch_ev); + let pke = key::KeyEvents::scheduled_event(sch_ev); - (Some(pkr), pke) + (Some(key::NewPressedKey::key_path(new_key_path)), pke) } else if let Some(ChordResolution::Chord(resolved_chord_id)) = ch_state { let ch_r_ev = Event::ChordResolved(ChordResolution::Chord(resolved_chord_id)); let pke = key::KeyEvents::event(key::Event::key_event(keymap_index, ch_r_ev.into())); - ( - Some(key::PressedKeyResult::Resolved( - key::NoOpKeyState::new().into(), - )), - pke, - ) + (Some(key::NewPressedKey::no_op()), pke) } else { (None, key::KeyEvents::no_events()) } diff --git a/src/key/composite/base.rs b/src/key/composite/base.rs index ccfba5c96..5611593f3 100644 --- a/src/key/composite/base.rs +++ b/src/key/composite/base.rs @@ -60,10 +60,7 @@ impl key::Key for BaseKey { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/composite/chorded.rs b/src/key/composite/chorded.rs index 470c889bb..eb31849ab 100644 --- a/src/key/composite/chorded.rs +++ b/src/key/composite/chorded.rs @@ -66,10 +66,7 @@ impl key::Key for ChordedKey { context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { match self { ChordedKey::Chorded(key) => key.handle_event(pending_state, context, key_path, event), ChordedKey::Auxiliary(key) => key.handle_event(pending_state, context, key_path, event), @@ -115,10 +112,7 @@ impl key::Key for Chorded { context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let Chorded(key) = self; key.handle_event(pending_state, context, key_path, event) } diff --git a/src/key/composite/layered.rs b/src/key/composite/layered.rs index 5ee8beee9..5b4cf1bf3 100644 --- a/src/key/composite/layered.rs +++ b/src/key/composite/layered.rs @@ -62,10 +62,7 @@ impl key::Key for LayeredKey { context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { match self { LayeredKey::Layered(key) => key.handle_event(pending_state, context, key_path, event), LayeredKey::Pass(key) => key.handle_event(pending_state, context, key_path, event), @@ -109,10 +106,7 @@ impl key::Key for Layered { context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let Layered(key) = self; key.handle_event(pending_state, context, key_path, event) } diff --git a/src/key/composite/tap_hold.rs b/src/key/composite/tap_hold.rs index b26fb24b6..1d75dfd19 100644 --- a/src/key/composite/tap_hold.rs +++ b/src/key/composite/tap_hold.rs @@ -69,10 +69,7 @@ impl key::Key for TapHoldKey { context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { match self { TapHoldKey::TapDance(key) => key.handle_event(pending_state, context, key_path, event), TapHoldKey::TapHold(key) => key.handle_event(pending_state, context, key_path, event), @@ -118,10 +115,7 @@ impl key::Key for TapHold { context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let TapHold(key) = self; key.handle_event(pending_state, context, key_path, event) } diff --git a/src/key/custom.rs b/src/key/custom.rs index f78fccc30..feaf28117 100644 --- a/src/key/custom.rs +++ b/src/key/custom.rs @@ -46,10 +46,7 @@ impl key::Key for Key { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/keyboard.rs b/src/key/keyboard.rs index 3abdf5215..15df0b7ff 100644 --- a/src/key/keyboard.rs +++ b/src/key/keyboard.rs @@ -99,10 +99,7 @@ impl key::Key for Key { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/layered.rs b/src/key/layered.rs index af441722d..60b047e5a 100644 --- a/src/key/layered.rs +++ b/src/key/layered.rs @@ -118,10 +118,7 @@ impl key::Key for ModifierKey { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } @@ -409,10 +406,7 @@ impl< _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/sticky.rs b/src/key/sticky.rs index 87e30cd6b..53b50b2ec 100644 --- a/src/key/sticky.rs +++ b/src/key/sticky.rs @@ -280,10 +280,7 @@ impl key::Key for Key { _context: &Self::Context, _key_path: key::KeyPath, _event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { panic!() } diff --git a/src/key/tap_dance.rs b/src/key/tap_dance.rs index fa5cced90..ed6e728b4 100644 --- a/src/key/tap_dance.rs +++ b/src/key/tap_dance.rs @@ -120,10 +120,7 @@ impl< context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let keymap_index = key_path.keymap_index(); let td_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into(); if let Ok(td_pks) = td_pks_res { @@ -132,24 +129,25 @@ impl< td_pks.handle_event(context.into(), keymap_index, td_ev); if let Some(TapDanceResolution(idx)) = maybe_resolution { - let nk = self.definitions[idx as usize].as_ref().unwrap(); - - let (pkr, pke) = nk.new_pressed_key(context, key_path); // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition) - let pkr = pkr.add_path_item(idx as u16); + let new_key_path = key_path.add_path_item(idx as u16); - (Some(pkr), pke) + ( + Some(key::NewPressedKey::key_path(new_key_path)), + pke.into_events(), + ) } else { // check td_pks press_count against key definitions let definition_count = self.definitions.iter().filter(|o| o.is_some()).count(); if td_pks.press_count as usize >= definition_count - 1 { let idx = definition_count - 1; - let nk = self.definitions[idx].as_ref().unwrap(); - let (pkr, pke) = nk.new_pressed_key(context, key_path); // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition) - let pkr = pkr.add_path_item(idx as u16); + let new_key_path = key_path.add_path_item(idx as u16); - (Some(pkr), pke) + ( + Some(key::NewPressedKey::key_path(new_key_path)), + pke.into_events(), + ) } else { (None, pke.into_events()) } diff --git a/src/key/tap_hold.rs b/src/key/tap_hold.rs index 8b738f1db..c593e64e7 100644 --- a/src/key/tap_hold.rs +++ b/src/key/tap_hold.rs @@ -106,7 +106,14 @@ impl Key { } else { // Keymap has not been idle for long enough; // immediately resolve as tap. - self.tap.new_pressed_key(context, key_path) + // PRESSED KEY PATH: add Tap Hold item (0 = tap, 1 = hold) + let tap_key_path = key_path.add_path_item(0); + ( + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path( + tap_key_path, + )), + key::KeyEvents::no_events(), + ) } } None => { @@ -167,25 +174,24 @@ impl< context: &Self::Context, key_path: key::KeyPath, event: key::Event, - ) -> ( - Option>, - key::KeyEvents, - ) { + ) -> (Option, key::KeyEvents) { let keymap_index = key_path.keymap_index(); let th_pks_res: Result<&mut PendingKeyState, _> = pending_state.try_into(); if let Ok(th_pks) = th_pks_res { if let Ok(th_ev) = event.try_into_key_event(|e| e.try_into()) { let th_state = th_pks.handle_event(context.into(), keymap_index, th_ev); if let Some(th_state) = th_state { - let (i, nk) = match th_state { - key::tap_hold::TapHoldState::Tap => (0, &self.tap), - key::tap_hold::TapHoldState::Hold => (1, &self.hold), + let i = match th_state { + key::tap_hold::TapHoldState::Tap => 0, + key::tap_hold::TapHoldState::Hold => 1, }; - let (pkr, pke) = nk.new_pressed_key(context, key_path); // PRESSED KEY PATH: add Tap Hold item (0 = tap, 1 = hold) - let pkr = pkr.add_path_item(i); + let new_key_path = key_path.add_path_item(i); - (Some(pkr), pke) + ( + Some(key::NewPressedKey::key_path(new_key_path)), + key::KeyEvents::no_events(), + ) } else { (None, key::KeyEvents::no_events()) } diff --git a/src/keymap.rs b/src/keymap.rs index 703494425..e4bc2b1da 100644 --- a/src/keymap.rs +++ b/src/keymap.rs @@ -224,6 +224,8 @@ impl< K: key::Key + ?Sized, I: Index, > Keymap +where + KS: From>, { /// Constructs a new keymap with the given key definitions and context. pub const fn new(key_definitions: I, context: Ctx) -> Self { @@ -396,7 +398,7 @@ impl< let pending_key = &self.key_definitions[key_path.keymap_index() as usize]; let pending_key = pending_key.lookup(&key_path[1..]); - let (ks, pke) = pending_key.handle_event( + let (mut maybe_npk, pke) = pending_key.handle_event( pending_key_state, &self.context, key_path.clone(), @@ -406,30 +408,55 @@ impl< pke.into_iter() .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev)); - match ks { - Some(key::PressedKeyResult::Resolved(ks)) => { - self.resolve_pending_key_state(ks); - } - Some(key::PressedKeyResult::Pending(kp, pks)) => { - *key_path = kp; - *pending_key_state = pks; - - // Since the pending key state resolved into another pending key state, - // we re-queue all the input events that had been received. - let orig_input_queue = core::mem::take(&mut self.input_queue); - while let Some(ev) = queued_events.pop() { - match ev { - key::Event::Input(input_ev) => { - self.input_queue.enqueue(input_ev).unwrap(); + while let Some(npk) = maybe_npk.take() { + let pkr = match npk { + key::NewPressedKey::Key(new_key_path) => { + let new_key = &self.key_definitions[new_key_path.keymap_index() as usize]; + let new_key = new_key.lookup(&new_key_path[1..]); + let (pkr, pke) = + new_key.new_pressed_key(&self.context, new_key_path.clone()); + pke.into_iter() + .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev)); + pkr + } + key::NewPressedKey::NoOp => { + let no_op_ks: KS = key::NoOpKeyState::new().into(); + key::PressedKeyResult::Resolved(no_op_ks) + } + }; + + match pkr { + key::PressedKeyResult::Resolved(ks) => { + self.resolve_pending_key_state(ks); + break; + } + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(new_key_path)) => { + maybe_npk = Some(key::NewPressedKey::Key(new_key_path)); + } + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => { + self.resolve_pending_key_state(key::NoOpKeyState::new().into()); + break; + } + key::PressedKeyResult::Pending(kp, pks) => { + *key_path = kp; + *pending_key_state = pks; + + // Since the pending key state resolved into another pending key state, + // we re-queue all the input events that had been received. + let orig_input_queue = core::mem::take(&mut self.input_queue); + while let Some(ev) = queued_events.pop() { + match ev { + key::Event::Input(input_ev) => { + self.input_queue.enqueue(input_ev).unwrap(); + } + _ => {} } - _ => {} } + orig_input_queue.iter().for_each(|&ev| { + self.input_queue.enqueue(ev).unwrap(); + }); } - orig_input_queue.iter().for_each(|&ev| { - self.input_queue.enqueue(ev).unwrap(); - }); } - None => {} } } else { // Update each of the pressed keys with the event. @@ -451,35 +478,51 @@ impl< input::Event::Press { keymap_index } if !self.has_pressed_input_with_keymap_index(keymap_index) => { - let key = &self.key_definitions[keymap_index as usize]; - - let key_path = key::key_path(keymap_index); - let (pk, pke) = key.new_pressed_key(&self.context, key_path); - - pke.into_iter() - .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev)); + let mut maybe_key_path = Some(key::key_path(keymap_index)); + + while let Some(key_path) = maybe_key_path.take() { + let key = &self.key_definitions[key_path.keymap_index() as usize] + .lookup(&key_path[1..]); + + let (pkr, pke) = key.new_pressed_key(&self.context, key_path); + + pke.into_iter() + .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev)); + + match pkr { + key::PressedKeyResult::Resolved(key_state) => { + self.pressed_inputs + .push(input::PressedInput::pressed_key(key_state, keymap_index)) + .unwrap(); + + // The resolved key state has output. Emit this as an event. + if let Some(key_output) = key_state.key_output() { + let km_ev = KeymapEvent::ResolvedKeyOutput { + keymap_index, + key_output, + }; + self.handle_event(key::Event::Keymap(km_ev)); + } + } + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key( + new_key_path, + )) => { + maybe_key_path = Some(new_key_path); + } + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => { + let key_state: KS = key::NoOpKeyState::new().into(); - match pk { - key::PressedKeyResult::Resolved(key_state) => { - self.pressed_inputs - .push(input::PressedInput::pressed_key(key_state, keymap_index)) - .unwrap(); - - // The resolved key state has output. Emit this as an event. - if let Some(key_output) = key_state.key_output() { - let km_ev = KeymapEvent::ResolvedKeyOutput { - keymap_index, - key_output, - }; - self.handle_event(key::Event::Keymap(km_ev)); + self.pressed_inputs + .push(input::PressedInput::pressed_key(key_state, keymap_index)) + .unwrap(); + } + key::PressedKeyResult::Pending(key_path, pending_key_state) => { + self.pending_key_state = Some(PendingState { + key_path, + pending_key_state, + queued_events: heapless::Vec::new(), + }); } - } - key::PressedKeyResult::Pending(key_path, pending_key_state) => { - self.pending_key_state = Some(PendingState { - key_path, - pending_key_state, - queued_events: heapless::Vec::new(), - }); } } } @@ -540,26 +583,67 @@ impl< if let Some(PendingState { key_path, pending_key_state, + queued_events, .. }) = &mut self.pending_key_state { let pending_key = &self.key_definitions[key_path.keymap_index() as usize]; let pending_key = pending_key.lookup(&key_path[1..]); - let (ks, pke) = + let (mut maybe_npk, pke) = pending_key.handle_event(pending_key_state, &self.context, key_path.clone(), ev); pke.into_iter() .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev)); - match ks { - Some(key::PressedKeyResult::Resolved(ks)) => { - self.resolve_pending_key_state(ks); - } - Some(key::PressedKeyResult::Pending(kp, pks)) => { - *key_path = kp; - *pending_key_state = pks; + while let Some(npk) = maybe_npk.take() { + let pkr = match npk { + key::NewPressedKey::Key(new_key_path) => { + let new_key = &self.key_definitions[new_key_path.keymap_index() as usize]; + let new_key = new_key.lookup(&new_key_path[1..]); + let (pkr, pke) = + new_key.new_pressed_key(&self.context, new_key_path.clone()); + pke.into_iter() + .for_each(|sch_ev| self.event_scheduler.schedule_event(sch_ev)); + pkr + } + key::NewPressedKey::NoOp => { + let no_op_ks: KS = key::NoOpKeyState::new().into(); + key::PressedKeyResult::Resolved(no_op_ks) + } + }; + + match pkr { + key::PressedKeyResult::Resolved(ks) => { + self.resolve_pending_key_state(ks); + break; + } + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::Key(new_key_path)) => { + maybe_npk = Some(key::NewPressedKey::Key(new_key_path)); + } + key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp) => { + self.resolve_pending_key_state(key::NoOpKeyState::new().into()); + break; + } + key::PressedKeyResult::Pending(kp, pks) => { + *key_path = kp; + *pending_key_state = pks; + + // Since the pending key state resolved into another pending key state, + // we re-queue all the input events that had been received. + let orig_input_queue = core::mem::take(&mut self.input_queue); + while let Some(ev) = queued_events.pop() { + match ev { + key::Event::Input(input_ev) => { + self.input_queue.enqueue(input_ev).unwrap(); + } + _ => {} + } + } + orig_input_queue.iter().for_each(|&ev| { + self.input_queue.enqueue(ev).unwrap(); + }); + } } - None => {} } } From b13b568130047dc0b03e45d50757d5b984053bc8 Mon Sep 17 00:00:00 2001 From: Richard Goulter Date: Tue, 2 Sep 2025 20:51:15 +0700 Subject: [PATCH 3/6] rust: update key::layered's lookup for [] --- src/key/layered.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/key/layered.rs b/src/key/layered.rs index 60b047e5a..8b13c0034 100644 --- a/src/key/layered.rs +++ b/src/key/layered.rs @@ -420,7 +420,7 @@ impl< KeyState = Self::KeyState, > { match path { - [] => panic!(), + [] => self, [0, path @ ..] => self.base.lookup(path), [layer_index, path @ ..] => self.layered[(layer_index - 1) as usize] .as_ref() From 5711a075ad8dfe8a507d787a26d0b907155e4167 Mon Sep 17 00:00:00 2001 From: Richard Goulter Date: Tue, 2 Sep 2025 20:56:56 +0700 Subject: [PATCH 4/6] rust: reverse direction "add_item_path" is used for --- src/key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/key.rs b/src/key.rs index 1a7cdbca6..a4a6f4036 100644 --- a/src/key.rs +++ b/src/key.rs @@ -46,7 +46,7 @@ impl KeyPath { /// Adds an item to the KeyPath. pub fn add_path_item(&self, item: u16) -> KeyPath { let mut kp = self.clone(); - kp.0.insert(1, item).unwrap(); + kp.0.push(item).unwrap(); kp } } From 37f5f6c97498a4e12f4fee1a01b07ab34d4c3867 Mon Sep 17 00:00:00 2001 From: Richard Goulter Date: Tue, 2 Sep 2025 21:44:58 +0700 Subject: [PATCH 5/6] rust: rename add_path_item to append_path_item --- src/key.rs | 6 +++--- src/key/chorded.rs | 8 ++++---- src/key/layered.rs | 2 +- src/key/tap_dance.rs | 4 ++-- src/key/tap_hold.rs | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/key.rs b/src/key.rs index a4a6f4036..c4628c846 100644 --- a/src/key.rs +++ b/src/key.rs @@ -44,7 +44,7 @@ impl KeyPath { } /// Adds an item to the KeyPath. - pub fn add_path_item(&self, item: u16) -> KeyPath { + pub fn append_path_item(&self, item: u16) -> KeyPath { let mut kp = self.clone(); kp.0.push(item).unwrap(); kp @@ -179,10 +179,10 @@ impl PressedKeyResult { } /// Adds an item to the KeyPath if the pressed key result is pending. - pub fn add_path_item(self, item: u16) -> Self { + pub fn append_path_item(self, item: u16) -> Self { match self { PressedKeyResult::Pending(key_path, pks) => { - PressedKeyResult::Pending(key_path.add_path_item(item), pks) + PressedKeyResult::Pending(key_path.append_path_item(item), pks) } pkr => pkr, } diff --git a/src/key/chorded.rs b/src/key/chorded.rs index 44458c247..98841ec32 100644 --- a/src/key/chorded.rs +++ b/src/key/chorded.rs @@ -341,7 +341,7 @@ where if let Some(i) = maybe_pathel_key { // PRESSED KEY PATH: add Chord (0 = passthrough, 1 = 1+chord_id) - let new_key_path = key_path.add_path_item(i as u16); + let new_key_path = key_path.append_path_item(i as u16); let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path( new_key_path, )); @@ -457,7 +457,7 @@ impl< if let Some(i) = maybe_pathel_and_key { // PRESSED KEY PATH: add Chord (0 = passthrough, 1 = 1+chord_id) - let new_key_path = key_path.add_path_item(i as u16); + let new_key_path = key_path.append_path_item(i as u16); let pke = key::KeyEvents::scheduled_event(sch_ev); @@ -545,7 +545,7 @@ where (pkr, pke) } ChordResolution::Passthrough => { - let new_key_path = key_path.add_path_item(0); // 0 = passthrough key + let new_key_path = key_path.append_path_item(0); // 0 = passthrough key let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path( new_key_path, )); @@ -614,7 +614,7 @@ impl< if let Ok(ch_ev) = event.try_into_key_event(|e| e.try_into()) { let ch_state = ch_pks.handle_event(keymap_index, ch_ev); if let Some(ChordResolution::Passthrough) = ch_state { - let new_key_path = key_path.add_path_item(0); // 0 = passthrough key + let new_key_path = key_path.append_path_item(0); // 0 = passthrough key let ch_r_ev = Event::ChordResolved(ChordResolution::Passthrough); let sch_ev = key::ScheduledEvent::immediate(key::Event::key_event( diff --git a/src/key/layered.rs b/src/key/layered.rs index 8b13c0034..7a9035cbb 100644 --- a/src/key/layered.rs +++ b/src/key/layered.rs @@ -370,7 +370,7 @@ where // PRESSED KEY PATH: add Layer (0 = base, n = layer_index) let (pkr, pke) = passthrough_key.new_pressed_key(context, key_path); - (pkr.add_path_item(layer as u16), pke) + (pkr.append_path_item(layer as u16), pke) } } diff --git a/src/key/tap_dance.rs b/src/key/tap_dance.rs index ed6e728b4..d67064dc6 100644 --- a/src/key/tap_dance.rs +++ b/src/key/tap_dance.rs @@ -130,7 +130,7 @@ impl< if let Some(TapDanceResolution(idx)) = maybe_resolution { // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition) - let new_key_path = key_path.add_path_item(idx as u16); + let new_key_path = key_path.append_path_item(idx as u16); ( Some(key::NewPressedKey::key_path(new_key_path)), @@ -142,7 +142,7 @@ impl< if td_pks.press_count as usize >= definition_count - 1 { let idx = definition_count - 1; // PRESSED KEY PATH: add Tap Dance item (index for the tap-dance definition) - let new_key_path = key_path.add_path_item(idx as u16); + let new_key_path = key_path.append_path_item(idx as u16); ( Some(key::NewPressedKey::key_path(new_key_path)), diff --git a/src/key/tap_hold.rs b/src/key/tap_hold.rs index c593e64e7..ac4fea44a 100644 --- a/src/key/tap_hold.rs +++ b/src/key/tap_hold.rs @@ -107,7 +107,7 @@ impl Key { // Keymap has not been idle for long enough; // immediately resolve as tap. // PRESSED KEY PATH: add Tap Hold item (0 = tap, 1 = hold) - let tap_key_path = key_path.add_path_item(0); + let tap_key_path = key_path.append_path_item(0); ( key::PressedKeyResult::NewPressedKey(key::NewPressedKey::key_path( tap_key_path, @@ -186,7 +186,7 @@ impl< key::tap_hold::TapHoldState::Hold => 1, }; // PRESSED KEY PATH: add Tap Hold item (0 = tap, 1 = hold) - let new_key_path = key_path.add_path_item(i); + let new_key_path = key_path.append_path_item(i); ( Some(key::NewPressedKey::key_path(new_key_path)), From d2d5c5915b2286f62042f502971e8e982c81fdb3 Mon Sep 17 00:00:00 2001 From: Richard Goulter Date: Tue, 2 Sep 2025 22:07:30 +0700 Subject: [PATCH 6/6] rust: factor out use of NoOpKeyState --- src/key/callback.rs | 4 ++-- src/key/caps_word.rs | 4 ++-- src/key/chorded.rs | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/key/callback.rs b/src/key/callback.rs index e2476ab96..e131aed75 100644 --- a/src/key/callback.rs +++ b/src/key/callback.rs @@ -35,10 +35,10 @@ impl key::Key for Key { key::KeyEvents, ) { let &Key { keymap_callback } = self; - let pks = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into()); + let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp); let km_ev = crate::keymap::KeymapEvent::Callback(keymap_callback); let pke = key::KeyEvents::event(key::Event::Keymap(km_ev)); - (pks, pke) + (pkr, pke) } fn handle_event( diff --git a/src/key/caps_word.rs b/src/key/caps_word.rs index 5e8b6385c..56c1d568f 100644 --- a/src/key/caps_word.rs +++ b/src/key/caps_word.rs @@ -148,8 +148,8 @@ impl key::Key for Key { let caps_word_context = context.into(); let keymap_index: u16 = key_path.keymap_index(); let pke = self.new_pressed_key(caps_word_context, keymap_index); - let pks = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into()); - (pks, pke.into_events()) + let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp); + (pkr, pke.into_events()) } fn handle_event( diff --git a/src/key/chorded.rs b/src/key/chorded.rs index 98841ec32..6cd817235 100644 --- a/src/key/chorded.rs +++ b/src/key/chorded.rs @@ -293,7 +293,6 @@ where K::Event: TryInto, K::Event: From, K::PendingKeyState: From, - K::KeyState: From>, { /// Constructs new pressed key. pub fn new_pressed_key( @@ -349,7 +348,7 @@ where (pkr, pke) } else { - let pkr = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into()); + let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp); let pke = key::KeyEvents::no_events(); (pkr, pke) } @@ -520,7 +519,6 @@ where K::Event: TryInto, K::Event: From, K::PendingKeyState: From, - K::KeyState: From>, { /// Constructs new pressed key. pub fn new_pressed_key( @@ -539,7 +537,7 @@ where if let PendingChordState::Resolved(resolution) = chord_resolution { match resolution { ChordResolution::Chord(_resolved_chord_id) => { - let pkr = key::PressedKeyResult::Resolved(key::NoOpKeyState::new().into()); + let pkr = key::PressedKeyResult::NewPressedKey(key::NewPressedKey::NoOp); let pke = key::KeyEvents::no_events(); (pkr, pke)