diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 1041e10e5..d78fb96fc 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -54,7 +54,6 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MACRO app PRIVATE src/behaviors/behavior_macro.c) - target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_LEADER_KEY app PRIVATE src/leader.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_LEADER_KEY app PRIVATE src/behaviors/behavior_leader_key.c) target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c) diff --git a/app/Kconfig.behaviors b/app/Kconfig.behaviors index 8a93d2b5d..c1c10fb18 100644 --- a/app/Kconfig.behaviors +++ b/app/Kconfig.behaviors @@ -138,4 +138,4 @@ config ZMK_BEHAVIOR_MACRO config ZMK_BEHAVIOR_LEADER_KEY bool default y - depends on DT_HAS_ZMK_BEHAVIOR_LEADER_KEY_ENABLED || DT_HAS_ZMK_BEHAVIOR_LEADER_SEQUENCES_ENABLED + depends on DT_HAS_ZMK_BEHAVIOR_LEADER_KEY_ENABLED diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 2d39acdd3..653b085d5 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -28,4 +28,3 @@ #include #include #include -#include diff --git a/app/dts/behaviors/leader_key.dtsi b/app/dts/behaviors/leader_key.dtsi deleted file mode 100644 index 8cf420ca7..000000000 --- a/app/dts/behaviors/leader_key.dtsi +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2022 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - - / { - behaviors { - /omit-if-no-ref/ leader: leader_key { - compatible = "zmk,behavior-leader-key"; - label = "LEADER"; - #binding-cells = <0>; - }; - }; -}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-leader-key.yaml b/app/dts/bindings/behaviors/zmk,behavior-leader-key.yaml index 9647044d4..f21fb75b5 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-leader-key.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-leader-key.yaml @@ -11,3 +11,16 @@ properties: timeout-ms: type: int default: -1 + +child-binding: + description: "A leader sequence" + + properties: + bindings: + type: phandle-array + required: true + key-positions: + type: array + required: true + immediate-trigger: + type: boolean diff --git a/app/dts/bindings/zmk,leader-sequences.yaml b/app/dts/bindings/zmk,leader-sequences.yaml deleted file mode 100644 index f26a8b90b..000000000 --- a/app/dts/bindings/zmk,leader-sequences.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2022, The ZMK Contributors -# SPDX-License-Identifier: MIT - -description: Leader sequence container - -compatible: "zmk,leader-sequences" - -child-binding: - description: "A leader sequence" - - properties: - bindings: - type: phandle-array - required: true - key-positions: - type: array - required: true - layers: - type: array - default: [-1] - immediate-trigger: - type: boolean diff --git a/app/include/zmk/leader.h b/app/include/zmk/leader.h deleted file mode 100644 index 49f477c26..000000000 --- a/app/include/zmk/leader.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2022 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#pragma once - -void zmk_leader_activate(int32_t timeout, uint32_t position); -void zmk_leader_deactivate(); diff --git a/app/src/behaviors/behavior_leader_key.c b/app/src/behaviors/behavior_leader_key.c index 864e19432..448ba2413 100644 --- a/app/src/behaviors/behavior_leader_key.c +++ b/app/src/behaviors/behavior_leader_key.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 The ZMK Contributors + * Copyright (c) 2025 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -13,29 +13,314 @@ #include #include #include +#include +#include #include -#include +#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -struct behavior_leader_key_config { - int32_t timeout_ms; +static bool leader_status; +static int32_t press_count; +static int32_t release_count; +static int32_t timeout_ms; +static int32_t active_leader_position; +static bool first_release; +static struct k_work_delayable release_timer; +static int64_t release_at; +// static bool timer_started; +static bool timer_cancelled; + +#if IS_ENABLED(CONFIG_ZMK_SPLIT) +static uint8_t source; +#endif + +struct leader_seq_cfg { + int32_t key_positions[CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE]; + int32_t key_position_len; + + bool immediate_trigger; + bool is_pressed; + + // the virtual key position is a key position outside the range used by the keyboard. + // it is necessary so hold-taps can uniquely identify a behavior. + int32_t virtual_key_position; + + struct zmk_behavior_binding behavior; }; -static int behavior_leader_key_init(const struct device *dev) { return 0; } +struct behavior_leader_key_config { + int32_t timeout_ms; + struct leader_seq_cfg *sequences; + size_t sequences_len; +}; + +// leader_pressed_keys is filled with an event when a key is pressed. +// The keys are removed from this array when they are released. +// Once this array is empty, the behavior is released. +static const struct zmk_position_state_changed + *leader_pressed_keys[CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE] = {NULL}; + +static uint32_t current_sequence[CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE] = {-1}; + +// the set of candidate leader based on the currently leader_pressed_keys +static int num_candidates; + +static struct leader_seq_cfg *sequence_candidates[CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY]; +static int num_comp_candidates; +static struct leader_seq_cfg + *completed_sequence_candidates[CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY]; + +const static struct behavior_leader_key_config *active_leader_cfg; + +static bool has_current_sequence(struct leader_seq_cfg *sequence, int count) { + for (int i = 0; i < count; i++) { + if (sequence->key_positions[i] != current_sequence[i]) { + return false; + } + } + return true; +} + +static bool is_in_current_sequence(int32_t position) { + for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) { + if (position == current_sequence[i]) { + return true; + } + } + return false; +} + +static bool is_duplicate(struct leader_seq_cfg *seq) { + for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) { + if (sequence_candidates[i] == seq) { + return true; + } + } + return false; +} + +static bool release_key_in_sequence(int32_t position) { + for (int i = 0; i < release_count; i++) { + if (leader_pressed_keys[i] && position == leader_pressed_keys[i]->position) { + leader_pressed_keys[i] = NULL; + return true; + } + } + return false; +} + +static bool all_keys_released() { + for (int i = 0; i < press_count; i++) { + if (leader_pressed_keys[i] != NULL) { + return false; + } + } + return true; +} + +static void clear_candidates() { + for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY; i++) { + sequence_candidates[i] = NULL; + completed_sequence_candidates[i] = NULL; + } +} + +static void leader_find_candidates(int32_t position, int count) { + clear_candidates(); + num_candidates = 0; + num_comp_candidates = 0; + + for (int i = 0; i < active_leader_cfg->sequences_len; i++) { + struct leader_seq_cfg *sequence = &(active_leader_cfg->sequences[i]); + + if (sequence == NULL) { + continue; + } + + if (sequence->key_positions[count] == position && has_current_sequence(sequence, count) && + !is_duplicate(sequence)) { + sequence_candidates[num_candidates] = sequence; + num_candidates++; + if (sequence->key_position_len == count + 1) { + completed_sequence_candidates[num_comp_candidates] = sequence; + num_comp_candidates++; + } + } + } +} + +const struct zmk_listener zmk_listener_leader; + +static inline int press_leader_behavior(struct leader_seq_cfg *sequence, int32_t timestamp) { + struct zmk_behavior_binding_event event = { + .position = sequence->virtual_key_position, +#if IS_ENABLED(CONFIG_ZMK_SPLIT) + .source = source, +#endif + .timestamp = timestamp, + }; + + sequence->is_pressed = true; + return behavior_keymap_binding_pressed(&sequence->behavior, event); +} + +static inline int release_leader_behavior(struct leader_seq_cfg *sequence, int32_t timestamp) { + struct zmk_behavior_binding_event event = { + .position = sequence->virtual_key_position, +#if IS_ENABLED(CONFIG_ZMK_SPLIT) + .source = source, +#endif + .timestamp = timestamp, + }; + + sequence->is_pressed = false; + return behavior_keymap_binding_released(&sequence->behavior, event); +} + +static int stop_timer() { + int timer_cancel_result = k_work_cancel_delayable(&release_timer); + if (timer_cancel_result == -EINPROGRESS) { + // too late to cancel, we'll let the timer handler clear up. + timer_cancelled = true; + } + return timer_cancel_result; +} + +static void reset_timer(int32_t timestamp) { + release_at = timestamp + timeout_ms; + int32_t ms_left = release_at - k_uptime_get(); + if (ms_left > 0) { + k_work_schedule(&release_timer, K_MSEC(ms_left)); + LOG_DBG("Successfully reset leader timer"); + } +} + +static void activate_leader_key(const struct behavior_leader_key_config *cfg, uint32_t position) { + LOG_DBG("leader key activated"); + leader_status = true; + press_count = 0; + release_count = 0; + timeout_ms = cfg->timeout_ms; + active_leader_position = position; + first_release = false; + active_leader_cfg = cfg; + + if (timeout_ms > 0) { + reset_timer(k_uptime_get()); + } + + for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) { + leader_pressed_keys[i] = NULL; + } +}; + +static void zmk_leader_deactivate() { + LOG_DBG("leader key deactivated"); + leader_status = false; + clear_candidates(); +}; + +static void behavior_leader_key_timer_handler(struct k_work *item) { + if (!leader_status) { + return; + } + if (timer_cancelled) { + return; + } + LOG_DBG("Leader deactivated due to timeout"); + for (int i = 0; i < num_comp_candidates; i++) { + if (!completed_sequence_candidates[i]->is_pressed) { + press_leader_behavior(completed_sequence_candidates[i], k_uptime_get()); + release_leader_behavior(completed_sequence_candidates[i], k_uptime_get()); + } + } + zmk_leader_deactivate(); +} + +static int position_state_changed_listener(const zmk_event_t *ev) { + struct zmk_position_state_changed *data = as_zmk_position_state_changed(ev); + + if (data == NULL) { + return 0; + } + + if (!leader_status && !data->state && !all_keys_released()) { + if (release_key_in_sequence(data->position)) { + return ZMK_EV_EVENT_HANDLED; + } + return 0; + } + + if (leader_status) { + if (data->state) { // keydown + leader_find_candidates(data->position, press_count); + LOG_DBG("leader cands: %d comp: %d", num_candidates, num_comp_candidates); + stop_timer(); + current_sequence[press_count] = data->position; + leader_pressed_keys[press_count] = data; + press_count++; + for (int i = 0; i < num_comp_candidates; i++) { + LOG_DBG("leader i is %d", i); + struct leader_seq_cfg *seq = completed_sequence_candidates[i]; + if (seq->immediate_trigger || (num_candidates == 1 && num_comp_candidates == 1)) { + press_leader_behavior(seq, data->timestamp); + } + } + } else { // keyup + if (data->position == active_leader_position && !first_release) { + first_release = true; + return 0; + } + if (!is_in_current_sequence(data->position)) { + return 0; + } + if (num_candidates == 0) { + zmk_leader_deactivate(); + return ZMK_EV_EVENT_HANDLED; + } + + release_count++; + release_key_in_sequence(data->position); + + for (int i = 0; i < num_comp_candidates; i++) { + struct leader_seq_cfg *seq = completed_sequence_candidates[i]; + if (seq->is_pressed && all_keys_released()) { + release_leader_behavior(seq, data->timestamp); + num_comp_candidates--; + } + if (num_candidates == 1 && num_comp_candidates == 0) { + zmk_leader_deactivate(); + } + } + + if (timeout_ms > 0 || num_comp_candidates < num_candidates) { + reset_timer(data->timestamp); + } + } + return ZMK_EV_EVENT_HANDLED; + } + + return 0; +} static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_leader_key_config *cfg = dev->config; - zmk_leader_activate(cfg->timeout_ms, event.position); +#if IS_ENABLED(CONFIG_ZMK_SPLIT) + source = event.source; +#endif + + activate_leader_key(cfg, event.position); return ZMK_BEHAVIOR_OPAQUE; } static int on_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { - return 0; + return ZMK_BEHAVIOR_OPAQUE; } static const struct behavior_driver_api behavior_leader_key_driver_api = { @@ -43,9 +328,30 @@ static const struct behavior_driver_api behavior_leader_key_driver_api = { .binding_released = on_keymap_binding_released, }; +static int behavior_leader_key_init(const struct device *dev) { + k_work_init_delayable(&release_timer, behavior_leader_key_timer_handler); + return 0; +} + +ZMK_LISTENER(leader, position_state_changed_listener); +ZMK_SUBSCRIPTION(leader, zmk_position_state_changed); + +#define SEQUENCE_ITEM(i, n, prop) DT_PROP_BY_IDX(n, prop, i) + +#define PROP_SEQUENCES(n, prop) \ + { \ + .virtual_key_position = ZMK_VIRTUAL_KEY_POSITION_LEADER(__COUNTER__), \ + .is_pressed = false, \ + .key_position_len = DT_PROP_LEN(n, prop), \ + .key_positions = {LISTIFY(DT_PROP_LEN(n, prop), SEQUENCE_ITEM, (, ), n, prop)}, \ + .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, n), \ + } + #define LEAD_INST(n) \ + static struct leader_seq_cfg leader_sequences_##n[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP_VARGS(n, PROP_SEQUENCES, (, ), key_positions)}; \ static struct behavior_leader_key_config behavior_leader_key_config_##n = { \ - .timeout_ms = DT_INST_PROP(n, timeout_ms)}; \ + .sequences = leader_sequences_##n, .sequences_len = ARRAY_SIZE(leader_sequences_##n)}; \ BEHAVIOR_DT_INST_DEFINE(n, behavior_leader_key_init, NULL, NULL, \ &behavior_leader_key_config_##n, POST_KERNEL, \ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_leader_key_driver_api); diff --git a/app/src/leader.c b/app/src/leader.c deleted file mode 100644 index ad063aa73..000000000 --- a/app/src/leader.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 2022 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#define DT_DRV_COMPAT zmk_leader_sequences - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) - -static bool leader_status; -static int32_t press_count; -static int32_t release_count; -static int32_t timeout_ms; -static int32_t active_leader_position; -static int8_t layer; -static bool first_release; -static struct k_work_delayable release_timer; -static int64_t release_at; -// static bool timer_started; -static bool timer_cancelled; - -struct leader_seq_cfg { - int32_t key_positions[CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE]; - int32_t key_position_len; - - bool immediate_trigger; - bool is_pressed; - // the virtual key position is a key position outside the range used by the keyboard. - // it is necessary so hold-taps can uniquely identify a behavior. - int32_t virtual_key_position; - struct zmk_behavior_binding behavior; - int32_t layers_len; - int8_t layers[]; -}; - -// leader_pressed_keys is filled with an event when a key is pressed. -// The keys are removed from this array when they are released. -// Once this array is empty, the behavior is released. -static const struct zmk_position_state_changed - *leader_pressed_keys[CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE] = {NULL}; - -static uint32_t current_sequence[CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE] = {-1}; -// the set of candidate leader based on the currently leader_pressed_keys -static int num_candidates; -static struct leader_seq_cfg *sequence_candidates[CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY]; -static int num_comp_candidates; -static struct leader_seq_cfg - *completed_sequence_candidates[CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY]; -// a lookup dict that maps a key position to all sequences on that position -static struct leader_seq_cfg - *sequence_lookup[ZMK_KEYMAP_LEN][CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY] = {NULL}; - -// Store the leader key pointer in the leader array, one pointer for each key position -// The leader are sorted shortest-first, then by virtual-key-position. -static int intitialiaze_leader_sequences(struct leader_seq_cfg *seq) { - for (int i = 0; i < seq->key_position_len; i++) { - int32_t position = seq->key_positions[i]; - if (position >= ZMK_KEYMAP_LEN) { - LOG_ERR("Unable to initialize leader, key position %d does not exist", position); - return -EINVAL; - } - - struct leader_seq_cfg *new_seq = seq; - bool set = false; - for (int j = 0; j < CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY; j++) { - struct leader_seq_cfg *sequence_at_j = sequence_lookup[position][j]; - if (sequence_at_j == NULL) { - sequence_lookup[position][j] = new_seq; - set = true; - break; - } - if (sequence_at_j->key_position_len < new_seq->key_position_len || - (sequence_at_j->key_position_len == new_seq->key_position_len && - sequence_at_j->virtual_key_position < new_seq->virtual_key_position)) { - continue; - } - // put new_seq in this spot, move all other leader up. - sequence_lookup[position][j] = new_seq; - new_seq = sequence_at_j; - } - if (!set) { - LOG_ERR( - "Too many leader for key position %d, CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY %d.", - position, CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY); - return -ENOMEM; - } - } - return 0; -} - -static bool sequence_active_on_layer(struct leader_seq_cfg *sequence) { - if (sequence->layers[0] == -1) { - // -1 in the first layer position is global layer scope - return true; - } - for (int j = 0; j < sequence->layers_len; j++) { - if (sequence->layers[j] == layer) { - return true; - } - } - return false; -} - -static bool has_current_sequence(struct leader_seq_cfg *sequence, int count) { - for (int i = 0; i < count; i++) { - if (sequence->key_positions[i] != current_sequence[i]) { - return false; - } - } - return true; -} - -static bool is_in_current_sequence(int32_t position) { - for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) { - if (position == current_sequence[i]) { - return true; - } - } - return false; -} - -static bool is_duplicate(struct leader_seq_cfg *seq) { - for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) { - if (sequence_candidates[i] == seq) { - return true; - } - } - return false; -} - -static bool release_key_in_sequence(int32_t position) { - for (int i = 0; i < release_count; i++) { - if (leader_pressed_keys[i] && position == leader_pressed_keys[i]->position) { - leader_pressed_keys[i] = NULL; - return true; - } - } - return false; -} - -static bool all_keys_released() { - for (int i = 0; i < press_count; i++) { - if (NULL != leader_pressed_keys[i]) { - return false; - } - } - return true; -} - -static void clear_candidates() { - for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY; i++) { - sequence_candidates[i] = NULL; - completed_sequence_candidates[i] = NULL; - } -} - -static void leader_find_candidates(int32_t position, int count) { - clear_candidates(); - num_candidates = 0; - num_comp_candidates = 0; - for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_SEQUENCES_PER_KEY; i++) { - struct leader_seq_cfg *sequence = sequence_lookup[position][i]; - if (sequence == NULL) { - continue; - } - if (sequence_active_on_layer(sequence) && sequence->key_positions[count] == position && - has_current_sequence(sequence, count) && !is_duplicate(sequence)) { - sequence_candidates[num_candidates] = sequence; - num_candidates++; - if (sequence->key_position_len == count + 1) { - completed_sequence_candidates[num_comp_candidates] = sequence; - num_comp_candidates++; - } - } - } -} - -const struct zmk_listener zmk_listener_leader; - -static inline int press_leader_behavior(struct leader_seq_cfg *sequence, int32_t timestamp) { - struct zmk_behavior_binding_event event = { - .position = sequence->virtual_key_position, - .timestamp = timestamp, - }; - - sequence->is_pressed = true; - return behavior_keymap_binding_pressed(&sequence->behavior, event); -} - -static inline int release_leader_behavior(struct leader_seq_cfg *sequence, int32_t timestamp) { - struct zmk_behavior_binding_event event = { - .position = sequence->virtual_key_position, - .timestamp = timestamp, - }; - - sequence->is_pressed = false; - return behavior_keymap_binding_released(&sequence->behavior, event); -} - -static int stop_timer() { - int timer_cancel_result = k_work_cancel_delayable(&release_timer); - if (timer_cancel_result == -EINPROGRESS) { - // too late to cancel, we'll let the timer handler clear up. - timer_cancelled = true; - } - return timer_cancel_result; -} - -static void reset_timer(int32_t timestamp) { - release_at = timestamp + timeout_ms; - int32_t ms_left = release_at - k_uptime_get(); - if (ms_left > 0) { - k_work_schedule(&release_timer, K_MSEC(ms_left)); - LOG_DBG("Successfully reset leader timer"); - } -} - -void zmk_leader_activate(int32_t timeout, uint32_t position) { - LOG_DBG("leader key activated"); - leader_status = true; - press_count = 0; - release_count = 0; - timeout_ms = timeout; - active_leader_position = position; - layer = zmk_keymap_highest_layer_active(); - first_release = false; - - if (timeout_ms > 0) { - reset_timer(k_uptime_get()); - } - - for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) { - leader_pressed_keys[i] = NULL; - } -}; - -void zmk_leader_deactivate() { - LOG_DBG("leader key deactivated"); - leader_status = false; - clear_candidates(); -}; - -void behavior_leader_key_timer_handler(struct k_work *item) { - if (!leader_status) { - return; - } - if (timer_cancelled) { - return; - } - LOG_DBG("Leader deactivated due to timeout"); - for (int i = 0; i < num_comp_candidates; i++) { - if (!completed_sequence_candidates[i]->is_pressed) { - press_leader_behavior(completed_sequence_candidates[i], k_uptime_get()); - release_leader_behavior(completed_sequence_candidates[i], k_uptime_get()); - } - } - zmk_leader_deactivate(); -} - -static int position_state_changed_listener(const zmk_event_t *ev) { - struct zmk_position_state_changed *data = as_zmk_position_state_changed(ev); - if (data == NULL) { - return 0; - } - - if (!leader_status && !data->state && !all_keys_released()) { - if (release_key_in_sequence(data->position)) { - return ZMK_EV_EVENT_HANDLED; - } - return 0; - } - - if (leader_status) { - if (data->state) { // keydown - leader_find_candidates(data->position, press_count); - LOG_DBG("leader cands: %d comp: %d", num_candidates, num_comp_candidates); - stop_timer(); - current_sequence[press_count] = data->position; - leader_pressed_keys[press_count] = data; - press_count++; - for (int i = 0; i < num_comp_candidates; i++) { - struct leader_seq_cfg *seq = completed_sequence_candidates[i]; - if (seq->immediate_trigger || (num_candidates == 1 && num_comp_candidates == 1)) { - press_leader_behavior(seq, data->timestamp); - } - } - } else { // keyup - if (data->position == active_leader_position && !first_release) { - first_release = true; - return 0; - } - if (!is_in_current_sequence(data->position)) { - return 0; - } - if (num_candidates == 0) { - zmk_leader_deactivate(); - return ZMK_EV_EVENT_HANDLED; - } - - release_count++; - release_key_in_sequence(data->position); - - for (int i = 0; i < num_comp_candidates; i++) { - struct leader_seq_cfg *seq = completed_sequence_candidates[i]; - if (seq->is_pressed && all_keys_released()) { - release_leader_behavior(seq, data->timestamp); - num_comp_candidates--; - } - if (num_candidates == 1 && num_comp_candidates == 0) { - zmk_leader_deactivate(); - } - } - - if (timeout_ms > 0 || num_comp_candidates < num_candidates) { - reset_timer(data->timestamp); - } - } - return ZMK_EV_EVENT_HANDLED; - } - - return 0; -} - -ZMK_LISTENER(leader, position_state_changed_listener); -ZMK_SUBSCRIPTION(leader, zmk_position_state_changed); - -#define LEADER_INST(n) \ - static struct leader_seq_cfg sequence_config_##n = { \ - .virtual_key_position = ZMK_VIRTUAL_KEY_POSITION_LEADER(__COUNTER__), \ - .immediate_trigger = DT_PROP(n, immediate_trigger), \ - .is_pressed = false, \ - .key_positions = DT_PROP(n, key_positions), \ - .key_position_len = DT_PROP_LEN(n, key_positions), \ - .behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, n), \ - .layers = DT_PROP(n, layers), \ - .layers_len = DT_PROP_LEN(n, layers), \ - }; - -#define INTITIALIAZE_LEADER_SEQUENCES(n) intitialiaze_leader_sequences(&sequence_config_##n); - -DT_INST_FOREACH_CHILD(0, LEADER_INST) - -static int leader_init(void) { - k_work_init_delayable(&release_timer, behavior_leader_key_timer_handler); - DT_INST_FOREACH_CHILD(0, INTITIALIAZE_LEADER_SEQUENCES); - return 0; -} - -SYS_INIT(leader_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); - -#endif diff --git a/app/tests/leader/behavior_keymap_layers.dtsi b/app/tests/leader/behavior_keymap_layers.dtsi deleted file mode 100644 index 931c8303c..000000000 --- a/app/tests/leader/behavior_keymap_layers.dtsi +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#include - -/ { - leader-sequences { - compatible = "zmk,leader-sequences"; - - leader_seq_one { - key-positions = <0>; - bindings = <&kp A>; - layers = <2>; - }; - - leader_seq_two { - key-positions = <1>; - bindings = <&kp B>; - }; - - }; - - keymap { - compatible = "zmk,keymap"; - label ="Default keymap"; - - default_layer { - bindings = < - &kp N1 &kp N2 - &kp N3 &leader - >; - }; - }; -}; diff --git a/app/tests/leader/none-layer/events.patterns b/app/tests/leader/none-layer/events.patterns deleted file mode 100644 index e73813454..000000000 --- a/app/tests/leader/none-layer/events.patterns +++ /dev/null @@ -1,2 +0,0 @@ -s/.*hid_listener_keycode_//p -s/.*zmk_leader.*:/leader:/p diff --git a/app/tests/leader/none-layer/keycode_events.snapshot b/app/tests/leader/none-layer/keycode_events.snapshot deleted file mode 100644 index c476ce63b..000000000 --- a/app/tests/leader/none-layer/keycode_events.snapshot +++ /dev/null @@ -1,2 +0,0 @@ -leader: leader key activated -leader: leader key deactivated diff --git a/app/tests/leader/none-layer/native_posix_64.keymap b/app/tests/leader/none-layer/native_posix_64.keymap deleted file mode 100644 index 1441719c8..000000000 --- a/app/tests/leader/none-layer/native_posix_64.keymap +++ /dev/null @@ -1,10 +0,0 @@ -#include "../behavior_keymap_layers.dtsi" - -&kscan { - events = < - ZMK_MOCK_PRESS(1,1,10) - ZMK_MOCK_RELEASE(1,1,10) - ZMK_MOCK_PRESS(0,0,10) - ZMK_MOCK_RELEASE(0,0,2000) - >; -};