@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/*
* Copyright ( c ) 2020 Cody McGinnis , Okke Formsma
* Copyright ( c ) 2020 The ZMK Contributors
*
* SPDX - License - Identifier : MIT
*/
@ -29,7 +29,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@@ -29,7 +29,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
// increase if you have keyboard with more keys.
# define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999
enum flavor {
ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0 ,
ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1 ,
@ -71,8 +70,7 @@ struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {};
@@ -71,8 +70,7 @@ 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.
const struct zmk_event_header * captured_events [ ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ] = { } ;
static int capture_event ( const struct zmk_event_header * event )
{
static int capture_event ( const struct zmk_event_header * event ) {
for ( int i = 0 ; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ; i + + ) {
if ( captured_events [ i ] = = NULL ) {
captured_events [ i ] = event ;
@ -82,8 +80,7 @@ static int capture_event(const struct zmk_event_header *event)
@@ -82,8 +80,7 @@ static int capture_event(const struct zmk_event_header *event)
return - ENOMEM ;
}
static struct position_state_changed * find_captured_keydown_event ( u32_t position )
{
static struct position_state_changed * find_captured_keydown_event ( u32_t position ) {
struct position_state_changed * last_match = NULL ;
for ( int i = 0 ; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS ; i + + ) {
const struct zmk_event_header * eh = captured_events [ i ] ;
@ -103,8 +100,7 @@ static struct position_state_changed *find_captured_keydown_event(u32_t position
@@ -103,8 +100,7 @@ static struct position_state_changed *find_captured_keydown_event(u32_t position
const struct zmk_listener zmk_listener_behavior_hold_tap ;
static void release_captured_events ( )
{
static void release_captured_events ( ) {
if ( undecided_hold_tap ! = NULL ) {
return ;
}
@ -125,8 +121,8 @@ static void release_captured_events()
@@ -125,8 +121,8 @@ static void release_captured_events()
// [null, k1_down, k1_up, mt2_up, null, ...]
// ^
// k1_down is captured by the mt2 mod-tap
// !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the first null encountered
// [mt1_down, null, k1_up, mt2_up, null, ...]
// !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the
// first null encountered [mt1_down, null, k1_up, mt2_up, null, ...]
// ^
// k1_up event is captured by the new hold-tap:
// [k1_down, k1_up, null, mt2_up, null, ...]
@ -144,18 +140,21 @@ static void release_captured_events()
@@ -144,18 +140,21 @@ static void release_captured_events()
k_msleep ( 10 ) ;
}
if ( is_position_state_changed ( captured_event ) ) {
struct position_state_changed * position_event = cast_position_state_changed ( captured_event ) ;
LOG_DBG ( " Releasing key position event for position %d %s " , position_event - > position , ( position_event - > state ? " pressed " : " released " ) ) ;
struct position_state_changed * position_event =
cast_position_state_changed ( captured_event ) ;
LOG_DBG ( " Releasing key position event for position %d %s " , position_event - > position ,
( position_event - > state ? " pressed " : " released " ) ) ;
} else {
struct keycode_state_changed * modifier_event = cast_keycode_state_changed ( captured_event ) ;
LOG_DBG ( " Releasing mods changed event 0x%02X %s " , modifier_event - > keycode , ( modifier_event - > state ? " pressed " : " released " ) ) ;
struct keycode_state_changed * modifier_event =
cast_keycode_state_changed ( captured_event ) ;
LOG_DBG ( " Releasing mods changed event 0x%02X %s " , modifier_event - > keycode ,
( modifier_event - > state ? " pressed " : " released " ) ) ;
}
ZMK_EVENT_RAISE_AT ( captured_event , behavior_hold_tap ) ;
}
}
static struct active_hold_tap * find_hold_tap ( u32_t position )
{
static struct active_hold_tap * find_hold_tap ( u32_t position ) {
for ( int i = 0 ; i < ZMK_BHV_HOLD_TAP_MAX_HELD ; i + + ) {
if ( active_hold_taps [ i ] . position = = position ) {
return & active_hold_taps [ i ] ;
@ -164,8 +163,8 @@ static struct active_hold_tap *find_hold_tap(u32_t position)
@@ -164,8 +163,8 @@ static struct active_hold_tap *find_hold_tap(u32_t position)
return NULL ;
}
static struct active_hold_tap * store_hold_tap ( u32_t position , u32_t param_hold , u32_t param_tap , const struct behavior_hold_tap_config * config )
{
static struct active_hold_tap * store_hold_tap ( u32_t position , u32_t param_hold , u32_t param_tap ,
const struct behavior_hold_tap_config * config ) {
for ( int i = 0 ; i < ZMK_BHV_HOLD_TAP_MAX_HELD ; i + + ) {
if ( active_hold_taps [ i ] . position ! = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED ) {
continue ;
@ -181,8 +180,7 @@ static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold,
@@ -181,8 +180,7 @@ static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold,
return NULL ;
}
static void clear_hold_tap ( struct active_hold_tap * hold_tap )
{
static void clear_hold_tap ( struct active_hold_tap * hold_tap ) {
hold_tap - > position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED ;
hold_tap - > is_decided = false ;
hold_tap - > is_hold = false ;
@ -196,8 +194,7 @@ enum decision_moment {
@@ -196,8 +194,7 @@ enum decision_moment {
HT_TIMER_EVENT = 3 ,
} ;
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 ) {
switch ( event ) {
case HT_KEY_UP :
hold_tap - > is_hold = 0 ;
@ -208,12 +205,12 @@ static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_mome
@@ -208,12 +205,12 @@ static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_mome
hold_tap - > is_hold = 1 ;
hold_tap - > is_decided = true ;
break ;
default : return ;
default :
return ;
}
}
static void decide_tap_preferred ( struct active_hold_tap * hold_tap , enum decision_moment event )
{
static void decide_tap_preferred ( struct active_hold_tap * hold_tap , enum decision_moment event ) {
switch ( event ) {
case HT_KEY_UP :
hold_tap - > is_hold = 0 ;
@ -223,12 +220,12 @@ static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision
@@ -223,12 +220,12 @@ static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision
hold_tap - > is_hold = 1 ;
hold_tap - > is_decided = true ;
break ;
default : return ;
default :
return ;
}
}
static void decide_hold_preferred ( struct active_hold_tap * hold_tap , enum decision_moment event )
{
static void decide_hold_preferred ( struct active_hold_tap * hold_tap , enum decision_moment event ) {
switch ( event ) {
case HT_KEY_UP :
hold_tap - > is_hold = 0 ;
@ -239,12 +236,13 @@ static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decisio
@@ -239,12 +236,13 @@ static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decisio
hold_tap - > is_hold = 1 ;
hold_tap - > is_decided = true ;
break ;
default : return ;
default :
return ;
}
}
static inline char * flavor_str ( enum flavor flavor ) {
switch ( flavor ) {
static inline char * flavor_str ( enum flavor flavor ) {
switch ( flavor ) {
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED :
return " hold-preferred " ;
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED :
@ -255,8 +253,7 @@ static inline char* flavor_str(enum flavor flavor) {
@@ -255,8 +253,7 @@ static inline char* flavor_str(enum flavor flavor) {
return " UNKNOWN FLAVOR " ;
}
static void decide_hold_tap ( struct active_hold_tap * hold_tap , enum decision_moment event )
{
static void decide_hold_tap ( struct active_hold_tap * hold_tap , enum decision_moment event ) {
if ( hold_tap - > is_decided ) {
return ;
}
@ -266,7 +263,7 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
@@ -266,7 +263,7 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
return ;
}
switch ( hold_tap - > config - > flavor ) {
switch ( hold_tap - > config - > flavor ) {
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED :
decide_hold_preferred ( hold_tap , event ) ;
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED :
@ -279,28 +276,27 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
@@ -279,28 +276,27 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
return ;
}
LOG_DBG ( " %d decided %s (%s event %d) " ,
hold_tap - > position ,
hold_tap - > is_hold ? " hold " : " tap " ,
flavor_str ( hold_tap - > config - > flavor ) ,
event ) ;
LOG_DBG ( " %d decided %s (%s event %d) " , hold_tap - > position , hold_tap - > is_hold ? " hold " : " tap " ,
flavor_str ( hold_tap - > config - > flavor ) , event ) ;
undecided_hold_tap = NULL ;
struct zmk_behavior_binding * behavior ;
if ( hold_tap - > is_hold ) {
behavior = & hold_tap - > config - > behaviors - > hold ;
struct device * behavior_device = device_get_binding ( behavior - > behavior_dev ) ;
behavior_keymap_binding_pressed ( behavior_device , hold_tap - > position , hold_tap - > param_hold , 0 ) ;
behavior_keymap_binding_pressed ( behavior_device , hold_tap - > position , hold_tap - > param_hold ,
0 ) ;
} else {
behavior = & hold_tap - > config - > behaviors - > tap ;
struct device * behavior_device = device_get_binding ( behavior - > behavior_dev ) ;
behavior_keymap_binding_pressed ( behavior_device , hold_tap - > position , hold_tap - > param_tap , 0 ) ;
behavior_keymap_binding_pressed ( behavior_device , hold_tap - > position , hold_tap - > param_tap ,
0 ) ;
}
release_captured_events ( ) ;
}
static int on_hold_tap_binding_pressed ( struct device * dev , u32_t position , u32_t param_hold , u32_t param_tap )
{
static int on_hold_tap_binding_pressed ( struct device * dev , u32_t position , u32_t param_hold ,
u32_t param_tap ) {
const struct behavior_hold_tap_config * cfg = dev - > config_info ;
if ( undecided_hold_tap ! = NULL ) {
@ -311,7 +307,8 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t
@@ -311,7 +307,8 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t
struct active_hold_tap * hold_tap = store_hold_tap ( position , param_hold , param_tap , cfg ) ;
if ( hold_tap = = NULL ) {
LOG_ERR ( " unable to store hold-tap info, did you press more than %d hold-taps? " , ZMK_BHV_HOLD_TAP_MAX_HELD ) ;
LOG_ERR ( " unable to store hold-tap info, did you press more than %d hold-taps? " ,
ZMK_BHV_HOLD_TAP_MAX_HELD ) ;
return 0 ;
}
@ -319,14 +316,13 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t
@@ -319,14 +316,13 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t
undecided_hold_tap = hold_tap ;
k_delayed_work_submit ( & hold_tap - > work , cfg - > tapping_term_ms ( ) ) ;
// todo: once we get timing info for keypresses, start the timer relative to the original keypress
// don't forget to simulate a timer-event before the event after that time was handled.
// todo: once we get timing info for keypresses, start the timer relative to the original
// keypress don't forget to simulate a timer-event before the event after that time was handled.
return 0 ;
}
static int on_hold_tap_binding_released ( struct device * dev , u32_t position , u32_t _ , u32_t __ )
{
static int on_hold_tap_binding_released ( struct device * dev , u32_t position , u32_t _ , u32_t __ ) {
struct active_hold_tap * hold_tap = find_hold_tap ( position ) ;
if ( hold_tap = = NULL ) {
@ -341,14 +337,15 @@ static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_
@@ -341,14 +337,15 @@ static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_
if ( hold_tap - > is_hold ) {
behavior = & hold_tap - > config - > behaviors - > hold ;
struct device * behavior_device = device_get_binding ( behavior - > behavior_dev ) ;
behavior_keymap_binding_released ( behavior_device , hold_tap - > position , hold_tap - > param_hold , 0 ) ;
behavior_keymap_binding_released ( behavior_device , hold_tap - > position , hold_tap - > param_hold ,
0 ) ;
} else {
behavior = & hold_tap - > config - > behaviors - > tap ;
struct device * behavior_device = device_get_binding ( behavior - > behavior_dev ) ;
behavior_keymap_binding_released ( behavior_device , hold_tap - > position , hold_tap - > param_tap , 0 ) ;
behavior_keymap_binding_released ( behavior_device , hold_tap - > position , hold_tap - > param_tap ,
0 ) ;
}
if ( work_cancel_result = = - EINPROGRESS ) {
// let the timer handler clean up
// if we'd clear now, the timer may call back for an uninitialized active_hold_tap.
@ -367,9 +364,7 @@ static const struct behavior_driver_api behavior_hold_tap_driver_api = {
@@ -367,9 +364,7 @@ static const struct behavior_driver_api behavior_hold_tap_driver_api = {
. binding_released = on_hold_tap_binding_released ,
} ;
static int position_state_changed_listener ( const struct zmk_event_header * eh )
{
static int position_state_changed_listener ( const struct zmk_event_header * eh ) {
struct position_state_changed * ev = cast_position_state_changed ( eh ) ;
if ( undecided_hold_tap = = NULL ) {
@ -390,23 +385,23 @@ static int position_state_changed_listener(const struct zmk_event_header *eh)
@@ -390,23 +385,23 @@ static int position_state_changed_listener(const struct zmk_event_header *eh)
if ( ! ev - > state & & find_captured_keydown_event ( ev - > position ) = = NULL ) {
// no keydown event has been captured, let it bubble.
// we'll catch modifiers later in modifier_state_changed_listener
LOG_DBG ( " %d bubbling %d %s event " , undecided_hold_tap - > position , ev - > position , ev - > state ? " down " : " up " ) ;
LOG_DBG ( " %d bubbling %d %s event " , undecided_hold_tap - > position , ev - > position ,
ev - > state ? " down " : " up " ) ;
return 0 ;
}
LOG_DBG ( " %d capturing %d %s event " , undecided_hold_tap - > position , ev - > position , ev - > state ? " down " : " up " ) ;
LOG_DBG ( " %d capturing %d %s event " , undecided_hold_tap - > position , ev - > position ,
ev - > state ? " down " : " up " ) ;
capture_event ( eh ) ;
decide_hold_tap ( undecided_hold_tap , ev - > state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP ) ;
return ZMK_EV_EVENT_CAPTURED ;
}
static bool is_mod ( struct keycode_state_changed * ev )
{
static bool is_mod ( struct keycode_state_changed * ev ) {
return ev - > usage_page = = USAGE_KEYPAD & & ev - > keycode > = LCTL & & ev - > keycode < = RGUI ;
}
static int keycode_state_changed_listener ( const struct zmk_event_header * eh )
{
static int keycode_state_changed_listener ( const struct zmk_event_header * eh ) {
// we want to catch layer-up events too... how?
struct keycode_state_changed * ev = cast_keycode_state_changed ( eh ) ;
@ -422,14 +417,13 @@ static int keycode_state_changed_listener(const struct zmk_event_header *eh)
@@ -422,14 +417,13 @@ static int keycode_state_changed_listener(const struct zmk_event_header *eh)
// only key-up events will bubble through position_state_changed_listener
// if a undecided_hold_tap is active.
LOG_DBG ( " %d capturing 0x%02X %s event " , undecided_hold_tap - > position , ev - > keycode , ev - > state ? " down " : " up " ) ;
LOG_DBG ( " %d capturing 0x%02X %s event " , undecided_hold_tap - > position , ev - > keycode ,
ev - > state ? " down " : " up " ) ;
capture_event ( eh ) ;
return ZMK_EV_EVENT_CAPTURED ;
}
int behavior_hold_tap_listener ( const struct zmk_event_header * eh )
{
int behavior_hold_tap_listener ( const struct zmk_event_header * eh ) {
if ( is_position_state_changed ( eh ) ) {
return position_state_changed_listener ( eh ) ;
} else if ( is_keycode_state_changed ( eh ) ) {
@ -443,8 +437,7 @@ ZMK_SUBSCRIPTION(behavior_hold_tap, position_state_changed);
@@ -443,8 +437,7 @@ ZMK_SUBSCRIPTION(behavior_hold_tap, position_state_changed);
// this should be modifiers_state_changed, but unfrotunately that's not implemented yet.
ZMK_SUBSCRIPTION ( behavior_hold_tap , keycode_state_changed ) ;
void behavior_hold_tap_timer_work_handler ( struct k_work * item )
{
void behavior_hold_tap_timer_work_handler ( struct k_work * item ) {
struct active_hold_tap * hold_tap = CONTAINER_OF ( item , struct active_hold_tap , work ) ;
if ( hold_tap - > work_is_cancelled ) {
@ -454,8 +447,7 @@ void behavior_hold_tap_timer_work_handler(struct k_work *item)
@@ -454,8 +447,7 @@ void behavior_hold_tap_timer_work_handler(struct k_work *item)
}
}
static int behavior_hold_tap_init ( struct device * dev )
{
static int behavior_hold_tap_init ( struct device * dev ) {
static bool init_first_run = true ;
if ( init_first_run ) {
@ -474,29 +466,27 @@ static struct behavior_hold_tap_data behavior_hold_tap_data;
@@ -474,29 +466,27 @@ static struct behavior_hold_tap_data behavior_hold_tap_data;
# define _TRANSFORM_ENTRY(idx, node) \
{ \
. behavior_dev = DT_LABEL ( DT_INST_PHANDLE_BY_IDX ( node , bindings , idx ) ) , \
. param1 = COND_CODE_0 ( DT_INST_PHA_HAS_CELL_AT_IDX ( node , bindings , idx , param1 ) , ( 0 ) , ( DT_INST_PHA_BY_IDX ( node , bindings , idx , param1 ) ) ) , \
. param2 = COND_CODE_0 ( DT_INST_PHA_HAS_CELL_AT_IDX ( node , bindings , idx , param2 ) , ( 0 ) , ( DT_INST_PHA_BY_IDX ( node , bindings , idx , param2 ) ) ) , \
. param1 = COND_CODE_0 ( DT_INST_PHA_HAS_CELL_AT_IDX ( node , bindings , idx , param1 ) , ( 0 ) , \
( DT_INST_PHA_BY_IDX ( node , bindings , idx , param1 ) ) ) , \
. param2 = COND_CODE_0 ( DT_INST_PHA_HAS_CELL_AT_IDX ( node , bindings , idx , param2 ) , ( 0 ) , \
( DT_INST_PHA_BY_IDX ( node , bindings , idx , param2 ) ) ) , \
} ,
# define KP_INST(n) \
static k_timeout_t behavior_hold_tap_config_ # # n # # _gettime ( ) { return K_MSEC ( DT_INST_PROP ( n , tapping_term_ms ) ) ; } \
static k_timeout_t behavior_hold_tap_config_ # # n # # _gettime ( ) { \
return K_MSEC ( DT_INST_PROP ( n , tapping_term_ms ) ) ; \
} \
static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_ # # n = { \
. hold = _TRANSFORM_ENTRY ( 0 , n ) \
. tap = _TRANSFORM_ENTRY ( 1 , n ) \
} ; \
. hold = _TRANSFORM_ENTRY ( 0 , n ) . tap = _TRANSFORM_ENTRY ( 1 , n ) } ; \
static struct behavior_hold_tap_config behavior_hold_tap_config_ # # n = { \
. behaviors = & behavior_hold_tap_behaviors_ # # n , \
. tapping_term_ms = & behavior_hold_tap_config_ # # n # # _gettime , \
. 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 , \
& behavior_hold_tap_data , \
& behavior_hold_tap_config_ # # n , \
APPLICATION , CONFIG_KERNEL_INIT_PRIORITY_DEFAULT , \
& behavior_hold_tap_driver_api ) ;
DEVICE_AND_API_INIT ( behavior_hold_tap_ # # n , DT_INST_LABEL ( n ) , behavior_hold_tap_init , \
& behavior_hold_tap_data , & behavior_hold_tap_config_ # # n , APPLICATION , \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT , & behavior_hold_tap_driver_api ) ;
DT_INST_FOREACH_STATUS_OKAY ( KP_INST )
# endif