@@ -544,7 +544,7 @@ impl<'a, T: std::fmt::Debug> WaitingState<'a, T> {
544544 return Some ( WaitingAction :: Hold ) ;
545545 }
546546 }
547- HoldTapConfig :: ReleaseOrder { buffer } => {
547+ HoldTapConfig :: Order { buffer, .. } => {
548548 // Like PermissiveHold: if another key was pressed AND released
549549 // (while modifier is still held), resolve as Hold.
550550 // If modifier is released first, the fallthrough below handles Tap.
@@ -555,6 +555,7 @@ impl<'a, T: std::fmt::Debug> WaitingState<'a, T> {
555555 let mut queued = queued. iter ( ) ;
556556 while let Some ( q) = queued. next ( ) {
557557 if q. event . is_press ( ) {
558+ // Elapsed ticks since this key entered the queue, compared against buffer window.
558559 let press_tick = self . ticks . saturating_sub ( q. since ) ;
559560 if press_tick < buffer {
560561 continue ;
@@ -1869,6 +1870,30 @@ impl<'a, const C: usize, const R: usize, T: 'a + Copy + std::fmt::Debug> Layout<
18691870 return custom;
18701871 }
18711872 }
1873+ // Per-action require-prior-idle for tap-hold-order.
1874+ if let HoldTapConfig :: Order {
1875+ require_prior_idle_ms,
1876+ ..
1877+ } = config
1878+ {
1879+ if * require_prior_idle_ms > 0 {
1880+ let prior_idle_tap = self
1881+ . historical_inputs
1882+ . iter_hevents ( )
1883+ . find ( |prior| {
1884+ prior. event . 0 == REAL_KEY_ROW && prior. event != coord
1885+ } )
1886+ . is_some_and ( |prior| {
1887+ prior. ticks_since_occurrence <= * require_prior_idle_ms
1888+ } ) ;
1889+ if prior_idle_tap {
1890+ let custom =
1891+ self . do_action ( tap, coord, delay, is_oneshot, layer_stack) ;
1892+ self . last_press_tracker . update_coord ( coord) ;
1893+ return custom;
1894+ }
1895+ }
1896+ }
18721897 let mut custom = CustomEvent :: NoEvent ;
18731898 if * tap_hold_interval == 0
18741899 || coord != self . last_press_tracker . coord
@@ -2534,7 +2559,7 @@ mod test {
25342559 }
25352560
25362561 #[ test]
2537- fn release_order_clean_tap ( ) {
2562+ fn order_clean_tap ( ) {
25382563 // Press and release modifier with no other keys → Tap.
25392564 static LAYERS : Layers < 2 , 1 > = & [ [ [
25402565 HoldTap ( & HoldTapAction {
@@ -2543,7 +2568,7 @@ mod test {
25432568 hold : k ( LAlt ) ,
25442569 timeout_action : k ( Space ) ,
25452570 tap : k ( Space ) ,
2546- config : HoldTapConfig :: ReleaseOrder { buffer : 0 } ,
2571+ config : HoldTapConfig :: Order { buffer : 0 , require_prior_idle_ms : 0 } ,
25472572 tap_hold_interval : 0 ,
25482573 } ) ,
25492574 k ( Enter ) ,
@@ -2565,7 +2590,7 @@ mod test {
25652590 }
25662591
25672592 #[ test]
2568- fn release_order_hold ( ) {
2593+ fn order_hold ( ) {
25692594 // Modifier down → other down → other up first → Hold.
25702595 static LAYERS : Layers < 2 , 1 > = & [ [ [
25712596 HoldTap ( & HoldTapAction {
@@ -2574,7 +2599,7 @@ mod test {
25742599 hold : k ( LAlt ) ,
25752600 timeout_action : k ( Space ) ,
25762601 tap : k ( Space ) ,
2577- config : HoldTapConfig :: ReleaseOrder { buffer : 0 } ,
2602+ config : HoldTapConfig :: Order { buffer : 0 , require_prior_idle_ms : 0 } ,
25782603 tap_hold_interval : 0 ,
25792604 } ) ,
25802605 k ( Enter ) ,
@@ -2602,7 +2627,7 @@ mod test {
26022627 }
26032628
26042629 #[ test]
2605- fn release_order_tap ( ) {
2630+ fn order_tap ( ) {
26062631 // Modifier down → other down → modifier up first → Tap.
26072632 static LAYERS : Layers < 2 , 1 > = & [ [ [
26082633 HoldTap ( & HoldTapAction {
@@ -2611,7 +2636,7 @@ mod test {
26112636 hold : k ( LAlt ) ,
26122637 timeout_action : k ( Space ) ,
26132638 tap : k ( Space ) ,
2614- config : HoldTapConfig :: ReleaseOrder { buffer : 0 } ,
2639+ config : HoldTapConfig :: Order { buffer : 0 , require_prior_idle_ms : 0 } ,
26152640 tap_hold_interval : 0 ,
26162641 } ) ,
26172642 k ( Enter ) ,
@@ -2632,6 +2657,58 @@ mod test {
26322657 assert_keys ( & [ Space , Enter ] , layout. keycodes ( ) ) ;
26332658 }
26342659
2660+ #[ test]
2661+ fn order_multi_key_hold ( ) {
2662+ // TH down → A down → B down → A up (while B still held) → TH up.
2663+ // A's press+release cycle completes while TH is held → Hold.
2664+ static LAYERS : Layers < 3 , 1 > = & [ [ [
2665+ HoldTap ( & HoldTapAction {
2666+ on_press_reset_timeout_to : None ,
2667+ timeout : u16:: MAX ,
2668+ hold : k ( LAlt ) ,
2669+ timeout_action : k ( Space ) ,
2670+ tap : k ( Space ) ,
2671+ config : HoldTapConfig :: Order { buffer : 0 , require_prior_idle_ms : 0 } ,
2672+ tap_hold_interval : 0 ,
2673+ } ) ,
2674+ k ( Enter ) ,
2675+ k ( Tab ) ,
2676+ ] ] ] ;
2677+ let mut layout = Layout :: new ( LAYERS ) ;
2678+
2679+ // TH down
2680+ layout. event ( Press ( 0 , 0 ) ) ;
2681+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2682+ assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2683+ // A down
2684+ layout. event ( Press ( 0 , 1 ) ) ;
2685+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2686+ assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2687+ // B down
2688+ layout. event ( Press ( 0 , 2 ) ) ;
2689+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2690+ assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2691+ // A up — A's press+release cycle is complete → Hold resolves
2692+ layout. event ( Release ( 0 , 1 ) ) ;
2693+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2694+ assert_keys ( & [ LAlt ] , layout. keycodes ( ) ) ;
2695+ // Queued keys replay: Enter press, Tab press, Enter release
2696+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2697+ assert_keys ( & [ LAlt , Enter ] , layout. keycodes ( ) ) ;
2698+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2699+ assert_keys ( & [ LAlt , Enter , Tab ] , layout. keycodes ( ) ) ;
2700+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2701+ assert_keys ( & [ LAlt , Tab ] , layout. keycodes ( ) ) ;
2702+ // Release B
2703+ layout. event ( Release ( 0 , 2 ) ) ;
2704+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2705+ assert_keys ( & [ LAlt ] , layout. keycodes ( ) ) ;
2706+ // Release TH
2707+ layout. event ( Release ( 0 , 0 ) ) ;
2708+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2709+ assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2710+ }
2711+
26352712 #[ test]
26362713 fn permissive_hold ( ) {
26372714 static LAYERS : Layers < 2 , 1 > = & [ [ [
0 commit comments