@ -33,16 +33,22 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@@ -33,16 +33,22 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
break ; \
}
struct pending _mod_tap_item {
struct active _mod_tap_item {
u32_t keycode ;
u8_t mods ;
bool pending ;
zmk_mod_flags active_mods ;
} ;
struct captured_keycode_state_change_item {
struct keycode_state_changed * event ;
zmk_mod_flags active_mods ;
} ;
struct behavior_mod_tap_config { } ;
struct behavior_mod_tap_data {
struct pending_mod_tap_item pending_mod_taps [ ZMK_BHV_MOD_TAP_MAX_HELD ] ;
struct pending_mod_tap_item triggered_mod_taps [ ZMK_BHV_MOD_TAP_MAX_HELD ] ;
struct keycode_state_changed * pending_key_presses [ ZMK_BHV_MOD_TAP_MAX_PENDING_KC ] ;
struct active_mod_tap_item active_mod_taps [ ZMK_BHV_MOD_TAP_MAX_HELD ] ;
struct captured_keycode_state_change_item captured_keycode_events [ ZMK_BHV_MOD_TAP_MAX_PENDING_KC ] ;
} ;
bool have_pending_mods ( char * label ) {
@ -50,8 +56,8 @@ bool have_pending_mods(char *label) {
@@ -50,8 +56,8 @@ bool have_pending_mods(char *label) {
struct behavior_mod_tap_data * data = dev - > driver_data ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
if ( data - > pending _mod_taps[ i ] . mods ) {
LOG_DBG ( " Found pending mods for %d and keycode 0x%02X " , data - > pending _mod_taps[ i ] . mods , data - > pending _mod_taps[ i ] . keycode ) ;
if ( data - > active _mod_taps[ i ] . mods ) {
LOG_DBG ( " Found pending mods for %d and keycode 0x%02X " , data - > active _mod_taps[ i ] . mods , data - > active _mod_taps[ i ] . keycode ) ;
return true ;
}
}
@ -59,19 +65,54 @@ bool have_pending_mods(char *label) {
@@ -59,19 +65,54 @@ bool have_pending_mods(char *label) {
return false ;
}
bool have _pending_keycode( struct behavior_mod_tap_data * data , u32_t keycode )
struct captured_keycode_state_change_item * find _pending_keycode( struct behavior_mod_tap_data * data , u32_t keycode )
{
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC ; i + + ) {
if ( data - > pending_key_presse s[ i ] = = NULL ) {
if ( data - > captured_keycode_event s[ i ] . event = = NULL ) {
continue ;
}
if ( data - > pending_key_presse s[ i ] - > keycode = = keycode ) {
return true ;
if ( data - > captured_keycode_event s[ i ] . event - > keycode = = keycode ) {
return & data - > captured_keycode_events [ i ] ;
}
}
return false ;
return NULL ;
}
zmk_mod_flags behavior_mod_tap_active_mods ( struct behavior_mod_tap_data * data )
{
zmk_mod_flags mods = 0 ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
mods | = data - > active_mod_taps [ i ] . mods ;
}
return mods ;
}
int behavior_mod_tap_capture_keycode_event ( struct behavior_mod_tap_data * data , struct keycode_state_changed * ev )
{
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC ; i + + ) {
if ( data - > captured_keycode_events [ i ] . event ! = NULL ) {
continue ;
}
data - > captured_keycode_events [ i ] . event = ev ;
data - > captured_keycode_events [ i ] . active_mods = behavior_mod_tap_active_mods ( data ) ;
return 0 ;
}
return - ENOMEM ;
}
void behavior_mod_tap_update_active_mods_state ( struct behavior_mod_tap_data * data , zmk_mod_flags used_flags )
{
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
if ( ( data - > active_mod_taps [ i ] . mods & used_flags ) = = data - > active_mod_taps [ i ] . mods ) {
data - > active_mod_taps [ i ] . pending = false ;
}
}
}
// How to pass context to subscription?!
@ -81,39 +122,25 @@ int behavior_mod_tap_listener(const struct zmk_event_header *eh)
@@ -81,39 +122,25 @@ int behavior_mod_tap_listener(const struct zmk_event_header *eh)
struct device * dev = device_get_binding ( DT_INST_LABEL ( 0 ) ) ;
struct keycode_state_changed * ev = cast_keycode_state_changed ( eh ) ;
struct behavior_mod_tap_data * data = dev - > driver_data ;
struct captured_keycode_state_change_item * pending_keycode ;
if ( ev - > state ) {
LOG_DBG ( " Have pending mods, capturing keycode 0x%02X event to ressend later " , ev - > keycode ) ;
TOGGLE_FIRST ( data - > pending_key_presses , ZMK_BHV_MOD_TAP_MAX_PENDING_KC , NULL , ev ) ;
behavior_mod_tap_capture_keycode_event ( data , ev ) ;
return ZMK_EV_EVENT_CAPTURED ;
} else if ( have_pending_keycode ( data , ev - > keycode ) ) {
zmk_mod_flags mods = 0 ;
} else if ( ( pending_keycode = find_pending_keycode ( data , ev - > keycode ) ) ! = NULL ) {
LOG_DBG ( " Key released, going to activate mods then send pending key presses " ) ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
memcpy ( & data - > triggered_mod_taps [ i ] , & data - > pending_mod_taps [ i ] , sizeof ( struct pending_mod_tap_item ) ) ;
data - > pending_mod_taps [ i ] . mods = 0 ;
data - > pending_mod_taps [ i ] . keycode = 0 ;
}
LOG_DBG ( " After swapping, do I have pending mods? %s " , ( have_pending_mods ( DT_INST_LABEL ( 0 ) ) ? " true " : " false " ) ) ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
mods | = data - > triggered_mod_taps [ i ] . mods ;
}
LOG_DBG ( " Setting mods: %d " , mods ) ;
zmk_hid_register_mods ( mods ) ;
LOG_DBG ( " Setting mods: %d " , pending_keycode - > active_mods ) ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC ; i + + ) {
if ( data - > pending_key_presses [ i ] = = NULL ) {
continue ;
}
zmk_hid_register_mods ( pending_keycode - > active_mods ) ;
behavior_mod_tap_update_active_mods_state ( data , pending_keycode - > active_mods ) ;
struct keycode_state_changed * ev = data - > pending_key_presses [ i ] ;
data - > pending_key_presses [ i ] = NULL ;
ZMK_EVENT_RAISE ( ev ) ;
ZMK_EVENT_RELEASE ( pending_keycode - > event ) ;
k_msleep ( 10 ) ;
}
pending_keycode - > event = NULL ;
pending_keycode - > active_mods = 0 ;
}
}
return 0 ;
@ -133,82 +160,90 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t m
@@ -133,82 +160,90 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t m
struct behavior_mod_tap_data * data = dev - > driver_data ;
LOG_DBG ( " mods: %d, keycode: 0x%02X " , mods , keycode ) ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
if ( data - > pending _mod_taps[ i ] . mods ! = 0 ) {
if ( data - > active _mod_taps[ i ] . mods ! = 0 ) {
continue ;
}
data - > pending_mod_taps [ i ] . mods = mods ;
data - > pending_mod_taps [ i ] . keycode = keycode ;
zmk_mod_flags active_mods = behavior_mod_tap_active_mods ( data ) ;
data - > active_mod_taps [ i ] . active_mods = active_mods ;
data - > active_mod_taps [ i ] . mods = mods ;
data - > active_mod_taps [ i ] . keycode = keycode ;
data - > active_mod_taps [ i ] . pending = true ;
return 0 ;
}
LOG_WRN ( " Failed to record mod-tap activation, at maximum concurrent mod-tap activations " ) ;
return - ENOMEM ;
}
static int on_keymap_binding_released ( struct device * dev , u32_t position , u32_t mods , u32_t keycode )
{
struct behavior_mod_tap_data * data = dev - > driver_data ;
bool sending_keycode = false ;
bool sent_pending_key_presses = false ;
struct keycode_state_changed * pending_key_presses [ ZMK_BHV_MOD_TAP_MAX_PENDING_KC ] ;
LOG_DBG ( " mods: %d, keycode: %d " , mods , keycode ) ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
if ( data - > triggered_mod_taps [ i ] . mods = = mods & & data - > triggered_mod_taps [ i ] . keycode = = keycode ) {
LOG_DBG ( " Releasing triggered mods: %d " , mods ) ;
zmk_hid_unregister_mods ( mods ) ;
data - > triggered_mod_taps [ i ] . mods = 0 ;
data - > triggered_mod_taps [ i ] . keycode = 0 ;
break ;
}
}
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_HELD ; i + + ) {
if ( data - > pending_mod_taps [ i ] . mods = = mods & & data - > pending_mod_taps [ i ] . keycode = = keycode ) {
sending_keycode = true ;
data - > pending_mod_taps [ i ] . mods = 0 ;
data - > pending_mod_taps [ i ] . keycode = 0 ;
break ;
}
}
struct active_mod_tap_item * item = & data - > active_mod_taps [ i ] ;
if ( item - > mods = = mods & & item - > keycode = = keycode ) {
if ( item - > pending ) {
LOG_DBG ( " Sending un-triggered mod-tap for keycode: 0x%02X " , keycode ) ;
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC ; i + + ) {
pending_key_presses [ i ] = data - > pending_key_presses [ i ] ;
data - > pending_key_presses [ i ] = NULL ;
if ( item - > active_mods ) {
LOG_DBG ( " Registering recorded active mods captured when mod-tap initially activated: 0x%02X " , item - > active_mods ) ;
behavior_mod_tap_update_active_mods_state ( data , item - > active_mods ) ;
zmk_hid_register_mods ( item - > active_mods ) ;
}
if ( sending_keycode ) {
struct keycode_state_changed * key_press = create_keycode_state_changed ( USAGE_KEYPAD , keycode , true ) ;
LOG_DBG ( " Sending un-triggered mod-tap for keycode: 0x%02X " , keycode ) ;
ZMK_EVENT_RAISE ( key_press ) ;
struct keycode_state_changed * key_press = create_keycode_state_changed ( USAGE_KEYPAD , item - > keycode , true ) ;
ZMK_EVENT_RAISE_AFTER ( key_press , behavior_mod_tap ) ;
k_msleep ( 10 ) ;
}
for ( int i = 0 ; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC ; i + + ) {
if ( pending_key_presses [ i ] = = NULL ) {
for ( int j = 0 ; j < ZMK_BHV_MOD_TAP_MAX_PENDING_KC ; j + + ) {
if ( data - > captured_keycode_events [ j ] . event = = NULL ) {
continue ;
}
struct keycode_state_changed * ev = pending_key_presses [ i ] ;
sent_pending_key_presses = true ;
struct keycode_state_changed * ev = data - > captured_keycode_events [ j ] . event ;
data - > captured_keycode_events [ i ] . event = NULL ;
data - > captured_keycode_events [ i ] . active_mods = 0 ;
LOG_DBG ( " Re-sending latched key press for usage page 0x%02X keycode 0x%02X state %s " , ev - > usage_page , ev - > keycode , ( ev - > state ? " pressed " : " released " ) ) ;
ZMK_EVENT_RELEASE ( ev ) ;
k_msleep ( 10 ) ;
}
if ( sending_keycode ) {
struct keycode_state_changed * key_release = create_keycode_state_changed ( USAGE_KEYPAD , keycode , false ) ;
LOG_DBG ( " Sending un-triggered mod-tap release for keycode: 0x%02X " , keycode ) ;
ZMK_EVENT_RAISE ( key_release ) ;
ZMK_EVENT_RAISE_AFTER ( key_release , behavior_mod_tap ) ;
k_msleep ( 10 ) ;
if ( item - > active_mods ) {
LOG_DBG ( " Unregistering recorded active mods captured when mod-tap initially activated: 0x%02X " , item - > active_mods ) ;
zmk_hid_unregister_mods ( item - > active_mods ) ;
zmk_endpoints_send_report ( USAGE_KEYPAD ) ;
}
if ( ! sending_keycode & & ! sent_pending_key_presses ) {
// Need to ensure the mod release is propagated.
} else {
LOG_DBG ( " Releasing triggered mods: %d " , mods ) ;
zmk_hid_unregister_mods ( mods ) ;
zmk_endpoints_send_report ( USAGE_KEYPAD ) ;
}
item - > mods = 0 ;
item - > keycode = 0 ;
item - > active_mods = 0 ;
LOG_DBG ( " Removing mods %d from active_mods for other held mod-taps " , mods ) ;
for ( int j = 0 ; j < ZMK_BHV_MOD_TAP_MAX_HELD ; j + + ) {
if ( data - > active_mod_taps [ j ] . active_mods & mods ) {
LOG_DBG ( " Removing 0x%02X from active mod tap mods 0x%02X keycode 0x%02X " , mods , data - > active_mod_taps [ j ] . mods , data - > active_mod_taps [ j ] . keycode ) ;
data - > active_mod_taps [ j ] . active_mods & = ~ mods ;
}
}
break ;
}
}
return 0 ;