Skip to content

Commit

Permalink
Leader key, zmkfirmware#1380
Browse files Browse the repository at this point in the history
  • Loading branch information
j-w-e committed Jun 5, 2024
1 parent 7eca7e6 commit 16b6c4c
Show file tree
Hide file tree
Showing 69 changed files with 1,151 additions and 0 deletions.
2 changes: 2 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ 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/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)
target_sources(app PRIVATE src/behaviors/behavior_outputs.c)
Expand All @@ -60,6 +61,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_INPUT_TWO_AXIS app PRIVATE src/behaviors/behavior_input_two_axis.c)
target_sources(app PRIVATE src/combo.c)
target_sources_ifdef(CONFIG_ZMK_LEADER app PRIVATE src/leader.c)
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
target_sources(app PRIVATE src/behavior_queue.c)
target_sources(app PRIVATE src/conditional_layer.c)
Expand Down
25 changes: 25 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,19 @@ config ZMK_COMBO_MAX_KEYS_PER_COMBO
#Combo options
endmenu

menu "Leader Options"

config ZMK_LEADER_MAX_KEYS_PER_SEQUENCE
int "Maximum number of key presses in a leader sequence"
default 4

config ZMK_LEADER_MAX_SEQUENCES_PER_KEY
int "Maximum number of leader sequences that a key can belong to"
default 5

#Leader options
endmenu

menu "Behavior Options"

config ZMK_BEHAVIORS_QUEUE_SIZE
Expand All @@ -474,6 +487,18 @@ config ZMK_MACRO_DEFAULT_TAP_MS
int "Default time to wait (in milliseconds) between the press and release events of a tapped behavior in macros"
default 30

DT_COMPAT_ZMK_LEADER := zmk,leader-sequences

config ZMK_LEADER
bool
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_LEADER))

DT_COMPAT_ZMK_BEHAVIOR_LEADER_KEY := zmk,behavior-leader-key

config ZMK_BEHAVIOR_LEADER_KEY
bool
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BEHAVIOR_LEADER_KEY))

endmenu

menu "Advanced"
Expand Down
1 change: 1 addition & 0 deletions app/dts/behaviors.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@
#include <behaviors/macros.dtsi>
#include <behaviors/soft_off.dtsi>
#include <behaviors/mouse_keys.dtsi>
#include <behaviors/leader_key.dtsi>
15 changes: 15 additions & 0 deletions app/dts/behaviors/leader_key.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* 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>;
};
};
};
15 changes: 15 additions & 0 deletions app/dts/bindings/behaviors/zmk,behavior-leader-key.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2022 The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Leader key behavior

compatible: "zmk,behavior-leader-key"

include: zero_param.yaml

properties:
timerless:
type: boolean
timeout-ms:
type: int
default: 200
22 changes: 22 additions & 0 deletions app/dts/bindings/zmk,leader-sequences.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# 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
10 changes: 10 additions & 0 deletions app/include/zmk/leader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#pragma once

void zmk_leader_activate(int32_t timeout, bool timeout_on_activation, uint32_t position);
void zmk_leader_deactivate();
5 changes: 5 additions & 0 deletions app/include/zmk/virtual_key_position.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@
* Gets the virtual key position to use for the combo with the given index.
*/
#define ZMK_VIRTUAL_KEY_POSITION_COMBO(index) (ZMK_KEYMAP_LEN + ZMK_KEYMAP_SENSORS_LEN + (index))

/**
* Gets the virtual key position to use for the leader sequence with the given index.
*/
#define ZMK_VIRTUAL_KEY_POSITION_LEADER(index) (ZMK_KEYMAP_LEN + ZMK_KEYMAP_SENSORS_LEN + (index))
54 changes: 54 additions & 0 deletions app/src/behaviors/behavior_leader_key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#define DT_DRV_COMPAT zmk_behavior_leader_key

#include <zephyr/device.h>
#include <drivers/behavior.h>
#include <zephyr/logging/log.h>

#include <zmk/hid.h>
#include <zmk/event_manager.h>
#include <zmk/events/keycode_state_changed.h>
#include <zmk/behavior.h>
#include <zmk/leader.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

struct behavior_leader_key_config {
int32_t timeout_ms;
bool timerless;
};

static int behavior_leader_key_init(const struct device *dev) { 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, cfg->timerless, 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;
}

static const struct behavior_driver_api behavior_leader_key_driver_api = {
.binding_pressed = on_keymap_binding_pressed,
.binding_released = on_keymap_binding_released,
};

#define LEAD_INST(n) \
static struct behavior_leader_key_config behavior_leader_key_config_##n = { \
.timerless = DT_INST_PROP(n, timerless), .timeout_ms = DT_INST_PROP(n, timeout_ms)}; \
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);

DT_INST_FOREACH_STATUS_OKAY(LEAD_INST)
Loading

0 comments on commit 16b6c4c

Please sign in to comment.