summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorPete Johanson <peter@peterjohanson.com>2020-07-31 14:38:10 -0400
committerPete Johanson <peter@peterjohanson.com>2020-07-31 14:38:10 -0400
commit8bba1fb7384c473bc6aa8ba700f3ee5eabadee4e (patch)
tree600cf3d6f57315a6986e2a37ddbb7d56fd5ba329 /app
parentf548f2a87c670a2b56507bc104e1af39fa3846e7 (diff)
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.
Diffstat (limited to 'app')
-rw-r--r--app/src/behaviors/behavior_mod_tap.c211
1 files changed, 123 insertions, 88 deletions
diff --git a/app/src/behaviors/behavior_mod_tap.c b/app/src/behaviors/behavior_mod_tap.c
index df3eec2..b7d4f4e 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;