@@ -45,6 +45,7 @@ enum status {
45
45
};
46
46
47
47
enum decision_moment {
48
+ HT_KEY_DOWN ,
48
49
HT_KEY_UP ,
49
50
HT_OTHER_KEY_DOWN ,
50
51
HT_OTHER_KEY_UP ,
@@ -59,6 +60,8 @@ struct behavior_hold_tap_config {
59
60
int quick_tap_ms ;
60
61
bool global_quick_tap ;
61
62
enum flavor flavor ;
63
+ bool hold_while_undecided ;
64
+ bool hold_while_undecided_deferred ;
62
65
bool retro_tap ;
63
66
bool hold_trigger_on_release ;
64
67
int32_t hold_trigger_key_positions_len ;
@@ -358,47 +361,87 @@ static inline const char *decision_moment_str(enum decision_moment decision_mome
358
361
}
359
362
}
360
363
361
- static int press_binding (struct active_hold_tap * hold_tap ) {
362
- if (hold_tap -> config -> retro_tap && hold_tap -> status == STATUS_HOLD_TIMER ) {
363
- return 0 ;
364
- }
364
+ static int press_hold_binding (struct active_hold_tap * hold_tap ) {
365
+ struct zmk_behavior_binding_event event = {
366
+ .position = hold_tap -> position ,
367
+ .timestamp = hold_tap -> timestamp ,
368
+ };
365
369
370
+ struct zmk_behavior_binding binding = {0 };
371
+ binding .behavior_dev = hold_tap -> config -> hold_behavior_dev ;
372
+ binding .param1 = hold_tap -> param_hold ;
373
+ return behavior_keymap_binding_pressed (& binding , event );
374
+ }
375
+
376
+ static int press_tap_binding (struct active_hold_tap * hold_tap ) {
366
377
struct zmk_behavior_binding_event event = {
367
378
.position = hold_tap -> position ,
368
379
.timestamp = hold_tap -> timestamp ,
369
380
};
370
381
371
382
struct zmk_behavior_binding binding = {0 };
372
- if (hold_tap -> status == STATUS_HOLD_TIMER || hold_tap -> status == STATUS_HOLD_INTERRUPT ) {
373
- binding .behavior_dev = hold_tap -> config -> hold_behavior_dev ;
374
- binding .param1 = hold_tap -> param_hold ;
375
- } else {
376
- binding .behavior_dev = hold_tap -> config -> tap_behavior_dev ;
377
- binding .param1 = hold_tap -> param_tap ;
378
- store_last_hold_tapped (hold_tap );
379
- }
383
+ binding .behavior_dev = hold_tap -> config -> tap_behavior_dev ;
384
+ binding .param1 = hold_tap -> param_tap ;
385
+ store_last_hold_tapped (hold_tap );
380
386
return behavior_keymap_binding_pressed (& binding , event );
381
387
}
382
388
383
- static int release_binding (struct active_hold_tap * hold_tap ) {
384
- if (hold_tap -> config -> retro_tap && hold_tap -> status == STATUS_HOLD_TIMER ) {
385
- return 0 ;
386
- }
389
+ static int release_hold_binding (struct active_hold_tap * hold_tap ) {
390
+ struct zmk_behavior_binding_event event = {
391
+ .position = hold_tap -> position ,
392
+ .timestamp = hold_tap -> timestamp ,
393
+ };
387
394
395
+ struct zmk_behavior_binding binding = {0 };
396
+ binding .behavior_dev = hold_tap -> config -> hold_behavior_dev ;
397
+ binding .param1 = hold_tap -> param_hold ;
398
+ return behavior_keymap_binding_released (& binding , event );
399
+ }
400
+
401
+ static int release_tap_binding (struct active_hold_tap * hold_tap ) {
388
402
struct zmk_behavior_binding_event event = {
389
403
.position = hold_tap -> position ,
390
404
.timestamp = hold_tap -> timestamp ,
391
405
};
392
406
393
407
struct zmk_behavior_binding binding = {0 };
408
+ binding .behavior_dev = hold_tap -> config -> tap_behavior_dev ;
409
+ binding .param1 = hold_tap -> param_tap ;
410
+ return behavior_keymap_binding_released (& binding , event );
411
+ }
412
+
413
+ static int press_binding (struct active_hold_tap * hold_tap ) {
414
+ if (hold_tap -> config -> retro_tap && hold_tap -> status == STATUS_HOLD_TIMER ) {
415
+ return 0 ;
416
+ }
417
+
394
418
if (hold_tap -> status == STATUS_HOLD_TIMER || hold_tap -> status == STATUS_HOLD_INTERRUPT ) {
395
- binding .behavior_dev = hold_tap -> config -> hold_behavior_dev ;
396
- binding .param1 = hold_tap -> param_hold ;
419
+ if (hold_tap -> config -> hold_while_undecided ) {
420
+ // the hold is already active, so we don't need to press it again
421
+ return 0 ;
422
+ } else {
423
+ return press_hold_binding (hold_tap );
424
+ }
397
425
} else {
398
- binding .behavior_dev = hold_tap -> config -> tap_behavior_dev ;
399
- binding .param1 = hold_tap -> param_tap ;
426
+ if (hold_tap -> config -> hold_while_undecided &&
427
+ !hold_tap -> config -> hold_while_undecided_deferred ) {
428
+ // time to release the hold before pressing the tap
429
+ release_hold_binding (hold_tap );
430
+ }
431
+ return press_tap_binding (hold_tap );
432
+ }
433
+ }
434
+
435
+ static int release_binding (struct active_hold_tap * hold_tap ) {
436
+ if (hold_tap -> config -> retro_tap && hold_tap -> status == STATUS_HOLD_TIMER ) {
437
+ return 0 ;
438
+ }
439
+
440
+ if (hold_tap -> status == STATUS_HOLD_TIMER || hold_tap -> status == STATUS_HOLD_INTERRUPT ) {
441
+ return release_hold_binding (hold_tap );
442
+ } else {
443
+ return release_tap_binding (hold_tap );
400
444
}
401
- return behavior_keymap_binding_released (& binding , event );
402
445
}
403
446
404
447
static bool is_first_other_key_pressed_trigger_key (struct active_hold_tap * hold_tap ) {
@@ -445,6 +488,12 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap,
445
488
return ;
446
489
}
447
490
491
+ if (hold_tap -> config -> hold_while_undecided && decision_moment == HT_KEY_DOWN ) {
492
+ LOG_DBG ("%d hold behavior pressed while undecided" , hold_tap -> position );
493
+ press_hold_binding (hold_tap );
494
+ return ;
495
+ }
496
+
448
497
// If the hold-tap behavior is still undecided, attempt to decide it.
449
498
switch (hold_tap -> config -> flavor ) {
450
499
case FLAVOR_HOLD_PREFERRED :
@@ -532,6 +581,8 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
532
581
decide_hold_tap (hold_tap , HT_QUICK_TAP );
533
582
}
534
583
584
+ decide_hold_tap (hold_tap , HT_KEY_DOWN );
585
+
535
586
// if this behavior was queued we have to adjust the timer to only
536
587
// wait for the remaining time.
537
588
int32_t tapping_term_ms_left = (hold_tap -> timestamp + cfg -> tapping_term_ms ) - k_uptime_get ();
@@ -559,6 +610,10 @@ static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding,
559
610
decide_retro_tap (hold_tap );
560
611
release_binding (hold_tap );
561
612
613
+ if (hold_tap -> config -> hold_while_undecided && hold_tap -> config -> hold_while_undecided_deferred ) {
614
+ release_hold_binding (hold_tap );
615
+ }
616
+
562
617
if (work_cancel_result == - EINPROGRESS ) {
563
618
// let the timer handler clean up
564
619
// if we'd clear now, the timer may call back for an uninitialized active_hold_tap.
@@ -652,6 +707,12 @@ static int keycode_state_changed_listener(const zmk_event_t *eh) {
652
707
return ZMK_EV_EVENT_BUBBLE ;
653
708
}
654
709
710
+ // hold-while-undecided can produce a mod, but we don't want to capture it.
711
+ if (undecided_hold_tap -> config -> hold_while_undecided &&
712
+ undecided_hold_tap -> status == STATUS_UNDECIDED ) {
713
+ return ZMK_EV_EVENT_BUBBLE ;
714
+ }
715
+
655
716
// only key-up events will bubble through position_state_changed_listener
656
717
// if a undecided_hold_tap is active.
657
718
LOG_DBG ("%d capturing 0x%02X %s event" , undecided_hold_tap -> position , ev -> keycode ,
@@ -705,6 +766,8 @@ static int behavior_hold_tap_init(const struct device *dev) {
705
766
.quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \
706
767
.global_quick_tap = DT_INST_PROP(n, global_quick_tap), \
707
768
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
769
+ .hold_while_undecided = DT_INST_PROP(n, hold_while_undecided), \
770
+ .hold_while_undecided_deferred = DT_INST_PROP(n, hold_while_undecided_deferred), \
708
771
.retro_tap = DT_INST_PROP(n, retro_tap), \
709
772
.hold_trigger_on_release = DT_INST_PROP(n, hold_trigger_on_release), \
710
773
.hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \
0 commit comments