@ -40,6 +40,7 @@ struct behavior_hold_tap_config {
int tapping_term_ms ;
int tapping_term_ms ;
char * hold_behavior_dev ;
char * hold_behavior_dev ;
char * tap_behavior_dev ;
char * tap_behavior_dev ;
int quick_tap_ms ;
enum flavor flavor ;
enum flavor flavor ;
} ;
} ;
@ -67,6 +68,24 @@ struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {};
// We capture most position_state_changed events and some modifiers_state_changed events.
// We capture most position_state_changed events and some modifiers_state_changed events.
const zmk_event_t * captured_events [ ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ] = { } ;
const zmk_event_t * captured_events [ ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ] = { } ;
// Keep track of which key was tapped most recently for 'quick_tap_ms'
struct last_tapped {
int32_t position ;
int64_t tap_deadline ;
} ;
struct last_tapped last_tapped ;
static void store_last_tapped ( struct active_hold_tap * hold_tap ) {
last_tapped . position = hold_tap - > position ;
last_tapped . tap_deadline = hold_tap - > timestamp + hold_tap - > config - > quick_tap_ms ;
}
static bool is_quick_tap ( struct active_hold_tap * hold_tap ) {
return last_tapped . position = = hold_tap - > position & &
last_tapped . tap_deadline > hold_tap - > timestamp ;
}
static int capture_event ( const zmk_event_t * event ) {
static int capture_event ( const zmk_event_t * event ) {
for ( int i = 0 ; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ; i + + ) {
for ( int i = 0 ; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ; i + + ) {
if ( captured_events [ i ] = = NULL ) {
if ( captured_events [ i ] = = NULL ) {
@ -191,6 +210,7 @@ enum decision_moment {
HT_OTHER_KEY_DOWN = 1 ,
HT_OTHER_KEY_DOWN = 1 ,
HT_OTHER_KEY_UP = 2 ,
HT_OTHER_KEY_UP = 2 ,
HT_TIMER_EVENT = 3 ,
HT_TIMER_EVENT = 3 ,
HT_QUICK_TAP = 4 ,
} ;
} ;
static void decide_balanced ( struct active_hold_tap * hold_tap , enum decision_moment event ) {
static void decide_balanced ( struct active_hold_tap * hold_tap , enum decision_moment event ) {
@ -204,6 +224,10 @@ static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_mome
hold_tap - > is_hold = 1 ;
hold_tap - > is_hold = 1 ;
hold_tap - > is_decided = true ;
hold_tap - > is_decided = true ;
break ;
break ;
case HT_QUICK_TAP :
hold_tap - > is_hold = 0 ;
hold_tap - > is_decided = true ;
break ;
default :
default :
return ;
return ;
}
}
@ -219,6 +243,10 @@ static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision
hold_tap - > is_hold = 1 ;
hold_tap - > is_hold = 1 ;
hold_tap - > is_decided = true ;
hold_tap - > is_decided = true ;
break ;
break ;
case HT_QUICK_TAP :
hold_tap - > is_hold = 0 ;
hold_tap - > is_decided = true ;
break ;
default :
default :
return ;
return ;
}
}
@ -235,6 +263,10 @@ static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decisio
hold_tap - > is_hold = 1 ;
hold_tap - > is_hold = 1 ;
hold_tap - > is_decided = true ;
hold_tap - > is_decided = true ;
break ;
break ;
case HT_QUICK_TAP :
hold_tap - > is_hold = 0 ;
hold_tap - > is_decided = true ;
break ;
default :
default :
return ;
return ;
}
}
@ -293,6 +325,7 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
binding . behavior_dev = hold_tap - > config - > tap_behavior_dev ;
binding . behavior_dev = hold_tap - > config - > tap_behavior_dev ;
binding . param1 = hold_tap - > param_tap ;
binding . param1 = hold_tap - > param_tap ;
binding . param2 = 0 ;
binding . param2 = 0 ;
store_last_tapped ( hold_tap ) ;
}
}
behavior_keymap_binding_pressed ( & binding , event ) ;
behavior_keymap_binding_pressed ( & binding , event ) ;
release_captured_events ( ) ;
release_captured_events ( ) ;
@ -320,6 +353,10 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
LOG_DBG ( " %d new undecided hold_tap " , event . position ) ;
LOG_DBG ( " %d new undecided hold_tap " , event . position ) ;
undecided_hold_tap = hold_tap ;
undecided_hold_tap = hold_tap ;
if ( is_quick_tap ( hold_tap ) ) {
decide_hold_tap ( hold_tap , HT_QUICK_TAP ) ;
}
// if this behavior was queued we have to adjust the timer to only
// if this behavior was queued we have to adjust the timer to only
// wait for the remaining time.
// wait for the remaining time.
int32_t tapping_term_ms_left = ( hold_tap - > timestamp + cfg - > tapping_term_ms ) - k_uptime_get ( ) ;
int32_t tapping_term_ms_left = ( hold_tap - > timestamp + cfg - > tapping_term_ms ) - k_uptime_get ( ) ;
@ -492,6 +529,7 @@ static struct behavior_hold_tap_data behavior_hold_tap_data;
. tapping_term_ms = DT_INST_PROP ( n , tapping_term_ms ) , \
. tapping_term_ms = DT_INST_PROP ( n , tapping_term_ms ) , \
. hold_behavior_dev = DT_LABEL ( DT_INST_PHANDLE_BY_IDX ( n , bindings , 0 ) ) , \
. hold_behavior_dev = DT_LABEL ( DT_INST_PHANDLE_BY_IDX ( n , bindings , 0 ) ) , \
. tap_behavior_dev = DT_LABEL ( DT_INST_PHANDLE_BY_IDX ( n , bindings , 1 ) ) , \
. tap_behavior_dev = DT_LABEL ( DT_INST_PHANDLE_BY_IDX ( n , bindings , 1 ) ) , \
. quick_tap_ms = DT_INST_PROP ( n , quick_tap_ms ) , \
. flavor = DT_ENUM_IDX ( DT_DRV_INST ( n ) , flavor ) , \
. flavor = DT_ENUM_IDX ( DT_DRV_INST ( n ) , flavor ) , \
} ; \
} ; \
DEVICE_AND_API_INIT ( behavior_hold_tap_ # # n , DT_INST_LABEL ( n ) , behavior_hold_tap_init , \
DEVICE_AND_API_INIT ( behavior_hold_tap_ # # n , DT_INST_LABEL ( n ) , behavior_hold_tap_init , \