@@ -544,12 +544,18 @@ impl<'a, T: std::fmt::Debug> WaitingState<'a, T> {
544544 return Some ( WaitingAction :: Hold ) ;
545545 }
546546 }
547- HoldTapConfig :: HoldOnOtherKeyPressWithGap ( min_gap) => {
548- if queued. iter ( ) . any ( |s| s. event . is_press ( ) ) {
549- if self . ticks >= min_gap {
550- return Some ( WaitingAction :: Hold ) ;
551- } else {
552- return Some ( WaitingAction :: Tap ) ;
547+ HoldTapConfig :: ReleaseOrder => {
548+ // Like PermissiveHold: if another key was pressed AND released
549+ // (while modifier is still held), resolve as Hold.
550+ // If modifier is released first, the fallthrough below handles Tap.
551+ let mut queued = queued. iter ( ) ;
552+ while let Some ( q) = queued. next ( ) {
553+ if q. event . is_press ( ) {
554+ let ( i, j) = q. event . coord ( ) ;
555+ let target = Event :: Release ( i, j) ;
556+ if queued. clone ( ) . any ( |q| q. event == target) {
557+ return Some ( WaitingAction :: Hold ) ;
558+ }
553559 }
554560 }
555561 }
@@ -2520,28 +2526,25 @@ mod test {
25202526 }
25212527
25222528 #[ test]
2523- fn hold_on_press_with_gap_clean_tap ( ) {
2524- // Clean tap: press and release the tap-hold key with no other keys.
2525- // Should emit the tap action (Space).
2529+ fn release_order_clean_tap ( ) {
2530+ // Press and release modifier with no other keys → Tap.
25262531 static LAYERS : Layers < 2 , 1 > = & [ [ [
25272532 HoldTap ( & HoldTapAction {
25282533 on_press_reset_timeout_to : None ,
25292534 timeout : u16:: MAX ,
25302535 hold : k ( LAlt ) ,
25312536 timeout_action : k ( Space ) ,
25322537 tap : k ( Space ) ,
2533- config : HoldTapConfig :: HoldOnOtherKeyPressWithGap ( 100 ) ,
2538+ config : HoldTapConfig :: ReleaseOrder ,
25342539 tap_hold_interval : 0 ,
25352540 } ) ,
25362541 k ( Enter ) ,
25372542 ] ] ] ;
25382543 let mut layout = Layout :: new ( LAYERS ) ;
25392544
2540- // Press the tap-hold key
25412545 layout. event ( Press ( 0 , 0 ) ) ;
25422546 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
25432547 assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2544- // Wait a bit, then release (no other key pressed)
25452548 for _ in 0 ..50 {
25462549 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
25472550 assert_keys ( & [ ] , layout. keycodes ( ) ) ;
@@ -2554,116 +2557,71 @@ mod test {
25542557 }
25552558
25562559 #[ test]
2557- fn hold_on_press_with_gap_fast_typing_overlap ( ) {
2558- // Fast typing overlap: another key pressed within min_gap (100ms).
2559- // Should resolve as tap: emit Space then Enter.
2560+ fn release_order_hold ( ) {
2561+ // Modifier down → other down → other up first → Hold.
25602562 static LAYERS : Layers < 2 , 1 > = & [ [ [
25612563 HoldTap ( & HoldTapAction {
25622564 on_press_reset_timeout_to : None ,
25632565 timeout : u16:: MAX ,
25642566 hold : k ( LAlt ) ,
25652567 timeout_action : k ( Space ) ,
25662568 tap : k ( Space ) ,
2567- config : HoldTapConfig :: HoldOnOtherKeyPressWithGap ( 100 ) ,
2569+ config : HoldTapConfig :: ReleaseOrder ,
25682570 tap_hold_interval : 0 ,
25692571 } ) ,
25702572 k ( Enter ) ,
25712573 ] ] ] ;
25722574 let mut layout = Layout :: new ( LAYERS ) ;
25732575
2574- // Press the tap-hold key
25752576 layout. event ( Press ( 0 , 0 ) ) ;
25762577 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
25772578 assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2578- // Wait only 30ms, then press another key (within the 100ms gap)
2579- for _ in 0 ..29 {
2580- assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2581- assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2582- }
25832579 layout. event ( Press ( 0 , 1 ) ) ;
2584- // Next tick: gap is 30 ticks < 100 min_gap, so resolves as Tap
2585- assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2586- assert_keys ( & [ Space ] , layout. keycodes ( ) ) ;
2587- // Buffered Enter gets dequeued
2588- assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2589- assert_keys ( & [ Space , Enter ] , layout. keycodes ( ) ) ;
2590- }
2591-
2592- #[ test]
2593- fn hold_on_press_with_gap_intentional_hold ( ) {
2594- // Intentional hold: another key pressed after min_gap (100ms).
2595- // Should resolve as hold: activate LAlt, then Enter is processed with LAlt active.
2596- static LAYERS : Layers < 2 , 1 > = & [ [ [
2597- HoldTap ( & HoldTapAction {
2598- on_press_reset_timeout_to : None ,
2599- timeout : u16:: MAX ,
2600- hold : k ( LAlt ) ,
2601- timeout_action : k ( Space ) ,
2602- tap : k ( Space ) ,
2603- config : HoldTapConfig :: HoldOnOtherKeyPressWithGap ( 100 ) ,
2604- tap_hold_interval : 0 ,
2605- } ) ,
2606- k ( Enter ) ,
2607- ] ] ] ;
2608- let mut layout = Layout :: new ( LAYERS ) ;
2609-
2610- // Press the tap-hold key
2611- layout. event ( Press ( 0 , 0 ) ) ;
26122580 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
26132581 assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2614- // Wait 150ms (past the 100ms gap threshold)
2615- for _ in 0 ..149 {
2616- assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2617- assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2618- }
2619- layout. event ( Press ( 0 , 1 ) ) ;
2620- // Next tick: gap is 150 ticks >= 100 min_gap, so resolves as Hold
2582+ // Other key releases first → Hold
2583+ layout. event ( Release ( 0 , 1 ) ) ;
26212584 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
26222585 assert_keys ( & [ LAlt ] , layout. keycodes ( ) ) ;
2623- // Buffered Enter gets dequeued
26242586 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
26252587 assert_keys ( & [ LAlt , Enter ] , layout. keycodes ( ) ) ;
2626- // Release both
2627- layout. event ( Release ( 0 , 1 ) ) ;
26282588 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
26292589 assert_keys ( & [ LAlt ] , layout. keycodes ( ) ) ;
2590+ // Release modifier
26302591 layout. event ( Release ( 0 , 0 ) ) ;
26312592 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
26322593 assert_keys ( & [ ] , layout. keycodes ( ) ) ;
26332594 }
26342595
26352596 #[ test]
2636- fn hold_on_press_with_gap_exact_boundary ( ) {
2637- // Exactly at min_gap: should resolve as hold (>= check) .
2597+ fn release_order_tap ( ) {
2598+ // Modifier down → other down → modifier up first → Tap .
26382599 static LAYERS : Layers < 2 , 1 > = & [ [ [
26392600 HoldTap ( & HoldTapAction {
26402601 on_press_reset_timeout_to : None ,
26412602 timeout : u16:: MAX ,
26422603 hold : k ( LAlt ) ,
26432604 timeout_action : k ( Space ) ,
26442605 tap : k ( Space ) ,
2645- config : HoldTapConfig :: HoldOnOtherKeyPressWithGap ( 100 ) ,
2606+ config : HoldTapConfig :: ReleaseOrder ,
26462607 tap_hold_interval : 0 ,
26472608 } ) ,
26482609 k ( Enter ) ,
26492610 ] ] ] ;
26502611 let mut layout = Layout :: new ( LAYERS ) ;
26512612
2652- // Press the tap-hold key
26532613 layout. event ( Press ( 0 , 0 ) ) ;
26542614 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
26552615 assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2656- // Wait exactly 100 ticks
2657- for _ in 0 ..99 {
2658- assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2659- assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2660- }
26612616 layout. event ( Press ( 0 , 1 ) ) ;
2662- // Next tick: gap is exactly 100 ticks == 100 min_gap, resolves as Hold
26632617 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2664- assert_keys ( & [ LAlt ] , layout. keycodes ( ) ) ;
2618+ assert_keys ( & [ ] , layout. keycodes ( ) ) ;
2619+ // Modifier releases first → Tap
2620+ layout. event ( Release ( 0 , 0 ) ) ;
26652621 assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2666- assert_keys ( & [ LAlt , Enter ] , layout. keycodes ( ) ) ;
2622+ assert_keys ( & [ Space ] , layout. keycodes ( ) ) ;
2623+ assert_eq ! ( CustomEvent :: NoEvent , layout. tick( ) ) ;
2624+ assert_keys ( & [ Space , Enter ] , layout. keycodes ( ) ) ;
26672625 }
26682626
26692627 #[ test]
0 commit comments