From 538cf3cd0b4d97afb5f8a97bd1b26c37f2dcdfe6 Mon Sep 17 00:00:00 2001 From: jmding8 <44815547+jmding8@users.noreply.github.com> Date: Sat, 12 Jun 2021 08:49:51 -0700 Subject: [PATCH] :Add required keys for tap-hold behaviors --- app/dts/behaviors/mod_tap.dtsi | 1 + .../behaviors/zmk,behavior-hold-tap.yaml | 4 ++ app/src/behaviors/behavior_hold_tap.c | 53 +++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/app/dts/behaviors/mod_tap.dtsi b/app/dts/behaviors/mod_tap.dtsi index 7a98713c3b2c..4293e61edf21 100644 --- a/app/dts/behaviors/mod_tap.dtsi +++ b/app/dts/behaviors/mod_tap.dtsi @@ -13,6 +13,7 @@ flavor = "hold-preferred"; tapping-term-ms = <200>; bindings = <&kp>, <&kp>; + hold-enabler-keys = <0>; }; }; }; diff --git a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml index f46b36a47fc9..bf0c0175fad5 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml @@ -30,3 +30,7 @@ properties: - "tap-preferred" retro-tap: type: boolean + hold-enabler-keys: + type: array + required: false + default: [] diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index c83305de0ef8..df9ea735e79f 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -58,6 +58,8 @@ struct behavior_hold_tap_config { int quick_tap_ms; enum flavor flavor; bool retro_tap; + int32_t hold_enabler_keys[ZMK_KEYMAP_LEN]; + int32_t hold_enabler_keys_len; }; // this data is specific for each hold-tap @@ -90,6 +92,8 @@ struct last_tapped { struct last_tapped last_tapped; +bool is_key_position_pressed[ZMK_KEYMAP_LEN] = {0}; + 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; @@ -217,16 +221,38 @@ static void clear_hold_tap(struct active_hold_tap *hold_tap) { hold_tap->work_is_cancelled = false; } +static bool +are_any_hold_enabler_keys_pressed(const struct behavior_hold_tap_config *hold_tap_config) { + struct behavior_hold_tap_config config = *hold_tap_config; + if (hold_tap_config->hold_enabler_keys_len == 0) { + return true; + } + for (int i = 0; i < hold_tap_config->hold_enabler_keys_len; i++) { + if (is_key_position_pressed[config.hold_enabler_keys[i]]) { + return true; + } + } + return false; +} + static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) { switch (event) { case HT_KEY_UP: hold_tap->status = STATUS_TAP; return; case HT_OTHER_KEY_UP: - hold_tap->status = STATUS_HOLD_INTERRUPT; + if (are_any_hold_enabler_keys_pressed(hold_tap->config)) { + hold_tap->status = STATUS_HOLD_INTERRUPT; + } else { + hold_tap->status = STATUS_TAP; + } return; case HT_TIMER_EVENT: - hold_tap->status = STATUS_HOLD_TIMER; + if (are_any_hold_enabler_keys_pressed(hold_tap->config)) { + hold_tap->status = STATUS_HOLD_TIMER; + } else { + hold_tap->status = STATUS_TAP; + } return; case HT_QUICK_TAP: hold_tap->status = STATUS_TAP; @@ -242,7 +268,11 @@ static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision hold_tap->status = STATUS_TAP; return; case HT_TIMER_EVENT: - hold_tap->status = STATUS_HOLD_TIMER; + if (are_any_hold_enabler_keys_pressed(hold_tap->config)) { + hold_tap->status = STATUS_HOLD_TIMER; + } else { + hold_tap->status = STATUS_TAP; + } return; case HT_QUICK_TAP: hold_tap->status = STATUS_TAP; @@ -258,10 +288,18 @@ static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decisio hold_tap->status = STATUS_TAP; return; case HT_OTHER_KEY_DOWN: - hold_tap->status = STATUS_HOLD_INTERRUPT; + if (are_any_hold_enabler_keys_pressed(hold_tap->config)) { + hold_tap->status = STATUS_HOLD_INTERRUPT; + } else { + hold_tap->status = STATUS_TAP; + } return; case HT_TIMER_EVENT: - hold_tap->status = STATUS_HOLD_TIMER; + if (are_any_hold_enabler_keys_pressed(hold_tap->config)) { + hold_tap->status = STATUS_HOLD_TIMER; + } else { + hold_tap->status = STATUS_TAP; + } return; case HT_QUICK_TAP: hold_tap->status = STATUS_TAP; @@ -498,6 +536,9 @@ static const struct behavior_driver_api behavior_hold_tap_driver_api = { static int position_state_changed_listener(const zmk_event_t *eh) { struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh); + // Update key position state. + is_key_position_pressed[ev->position] = ev->state; + update_hold_status_for_retro_tap(ev->position); if (undecided_hold_tap == NULL) { @@ -608,6 +649,8 @@ static struct behavior_hold_tap_data behavior_hold_tap_data; .quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \ .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ .retro_tap = DT_INST_PROP(n, retro_tap), \ + .hold_enabler_keys = DT_INST_PROP(n, hold_enabler_keys), \ + .hold_enabler_keys_len = DT_INST_PROP_LEN(n, hold_enabler_keys), \ }; \ 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, \