From 8bba1fb7384c473bc6aa8ba700f3ee5eabadee4e Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 31 Jul 2020 14:38:10 -0400 Subject: [PATCH] Major mod-tap improvements. * Track active mods when mods or keycode events occur. * Use the tracked mods when releasing or generating keycode events. * Track pending/used status in one array, for improved storage efficency. --- app/src/behaviors/behavior_mod_tap.c | 211 ++++++++++++++++----------- 1 file changed, 123 insertions(+), 88 deletions(-) diff --git a/app/src/behaviors/behavior_mod_tap.c b/app/src/behaviors/behavior_mod_tap.c index df3eec27..b7d4f4ee 100644 --- a/app/src/behaviors/behavior_mod_tap.c +++ b/app/src/behaviors/behavior_mod_tap.c @@ -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) { 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) { 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_presses[i] == NULL) { + if (data->captured_keycode_events[i].event == NULL) { continue; } - if (data->pending_key_presses[i]->keycode == keycode) { - return true; + if (data->captured_keycode_events[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) 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); + LOG_DBG("Setting mods: %d", pending_keycode->active_mods); - zmk_hid_register_mods(mods); + zmk_hid_register_mods(pending_keycode->active_mods); + behavior_mod_tap_update_active_mods_state(data, 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_EVENT_RELEASE(pending_keycode->event); + k_msleep(10); - struct keycode_state_changed *ev = data->pending_key_presses[i]; - data->pending_key_presses[i] = NULL; - ZMK_EVENT_RAISE(ev); - 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 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; - } - } - - 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; - } + 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); + + 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); + } + 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); - 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); - k_msleep(10); - } - + 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 = 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); + } - for (int i = 0; i < ZMK_BHV_MOD_TAP_MAX_PENDING_KC; i++) { - if (pending_key_presses[i] == NULL) { - continue; - } + 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_AFTER(key_release, behavior_mod_tap); + k_msleep(10); - struct keycode_state_changed *ev = pending_key_presses[i]; - sent_pending_key_presses = true; - 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 (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) { - 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); - } + + } else { + LOG_DBG("Releasing triggered mods: %d", mods); + zmk_hid_unregister_mods(mods); + zmk_endpoints_send_report(USAGE_KEYPAD); + } - if (!sending_keycode && !sent_pending_key_presses) { - // Need to ensure the mod release is propagated. - 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;