feat(leader-key): add overlap timeout property

This commit is contained in:
Nick Conway 2025-06-16 14:02:26 -04:00
parent ab5125a098
commit f117af5769
No known key found for this signature in database
GPG Key ID: AA850592E4C1D453
2 changed files with 34 additions and 12 deletions

View File

@ -11,6 +11,9 @@ properties:
timeout-ms:
type: int
default: -1
overlap-timeout-ms:
type: int
default: 200
child-binding:
description: "A leader sequence"

View File

@ -25,6 +25,7 @@ static bool leader_status;
static int32_t press_count;
static int32_t release_count;
static int32_t timeout_ms;
static int32_t overlap_timeout_ms;
static int32_t active_leader_position;
static bool first_release;
static struct k_work_delayable release_timer;
@ -52,6 +53,7 @@ struct leader_seq_cfg {
struct behavior_leader_key_config {
int32_t timeout_ms;
int32_t overlap_timeout_ms;
struct leader_seq_cfg *sequences;
size_t sequences_len;
};
@ -188,9 +190,16 @@ static int stop_timer() {
return timer_cancel_result;
}
static void reset_timer(int32_t timestamp) {
release_at = timestamp + timeout_ms;
static void reset_timer(int32_t timestamp, bool is_overlap) {
int32_t wait_time_ms = timeout_ms;
if (is_overlap) {
wait_time_ms = overlap_timeout_ms;
}
release_at = timestamp + wait_time_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");
@ -204,12 +213,13 @@ static void activate_leader_key(const struct behavior_leader_key_config *cfg, ui
press_count = 0;
release_count = 0;
timeout_ms = cfg->timeout_ms;
overlap_timeout_ms = cfg->overlap_timeout_ms;
active_leader_position = position;
first_release = false;
active_leader_cfg = cfg;
if (timeout_ms > 0) {
reset_timer(k_uptime_get());
reset_timer(k_uptime_get(), false);
}
for (int i = 0; i < CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE; i++) {
@ -217,7 +227,7 @@ static void activate_leader_key(const struct behavior_leader_key_config *cfg, ui
}
};
static void zmk_leader_deactivate() {
static void deactivate_leader_key() {
LOG_DBG("leader key deactivated");
leader_status = false;
clear_candidates();
@ -227,17 +237,21 @@ 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");
LOG_DBG("deactivating leader 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();
deactivate_leader_key();
}
static int position_state_changed_listener(const zmk_event_t *ev) {
@ -278,7 +292,7 @@ static int position_state_changed_listener(const zmk_event_t *ev) {
return 0;
}
if (num_candidates == 0) {
zmk_leader_deactivate();
deactivate_leader_key();
return ZMK_EV_EVENT_HANDLED;
}
@ -292,12 +306,16 @@ static int position_state_changed_listener(const zmk_event_t *ev) {
num_comp_candidates--;
}
if (num_candidates == 1 && num_comp_candidates == 0) {
zmk_leader_deactivate();
deactivate_leader_key();
}
}
if (timeout_ms > 0 || num_comp_candidates < num_candidates) {
reset_timer(data->timestamp);
if (timeout_ms > 0) {
reset_timer(data->timestamp, false);
}
if (num_comp_candidates < num_candidates) {
reset_timer(data->timestamp, true);
}
}
return ZMK_EV_EVENT_HANDLED;
@ -343,7 +361,7 @@ ZMK_SUBSCRIPTION(leader, zmk_position_state_changed);
{ \
.virtual_key_position = ZMK_VIRTUAL_KEY_POSITION_LEADER(__COUNTER__), \
.is_pressed = false, \
.immediate_trigger = DT_PROP(n, immediate_trigger), \
.immediate_trigger = DT_PROP(n, immediate_trigger), \
.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), \
@ -353,7 +371,8 @@ ZMK_SUBSCRIPTION(leader, zmk_position_state_changed);
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), \
.timeout_ms = DT_INST_PROP(n, timeout_ms), \
.overlap_timeout_ms = DT_INST_PROP(n, overlap_timeout_ms), \
.sequences = leader_sequences_##n, \
.sequences_len = ARRAY_SIZE(leader_sequences_##n)}; \
BEHAVIOR_DT_INST_DEFINE(n, behavior_leader_key_init, NULL, NULL, \