Skip to content

feat(behaviors): Leader key#1380

Open
nickconway wants to merge 15 commits intozmkfirmware:mainfrom
nickconway:leader-key
Open

feat(behaviors): Leader key#1380
nickconway wants to merge 15 commits intozmkfirmware:mainfrom
nickconway:leader-key

Conversation

@nickconway
Copy link
Copy Markdown
Contributor

Adds leader key functionality

@nickconway nickconway force-pushed the leader-key branch 5 times, most recently from c986393 to ddbc05d Compare July 9, 2022 17:30
@nickconway nickconway marked this pull request as ready for review July 9, 2022 19:01
@nickconway nickconway changed the title [WIP] feat(behaviors): Leader key feat(behaviors): Leader key Jul 9, 2022
@dxmh dxmh added enhancement New feature or request behaviors labels Jul 11, 2022
Copy link
Copy Markdown

@AlexCzar AlexCzar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much, leader key is a very nice feature to have. Just a couple of questions/suggestions regarding the documentation.
Can't wait for this to be merged 👍🏽

Copy link
Copy Markdown
Contributor

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One important high level question on the design.

Thanks!

@petejohanson petejohanson self-assigned this Oct 8, 2022
@rmwphd rmwphd mentioned this pull request Dec 15, 2022
@grezp
Copy link
Copy Markdown

grezp commented Feb 22, 2023

Any update on this branch merging to main?

@vladsolokha
Copy link
Copy Markdown

I don't understand the difference of this "leader key" and a sticky layer. Can someone differentiate?

@cougarten
Copy link
Copy Markdown

I don't understand the difference of this "leader key" and a sticky layer. Can someone differentiate?

you can do more than 2 key presses and it can chain arbitrary long sequences as the triggers.

e.g. "super > s > e" for "leader key" > "shortcuts" > "email" to trigger spelling your email address (or anything you want).

@ujl123
Copy link
Copy Markdown

ujl123 commented Apr 12, 2023

I don't understand the difference of this "leader key" and a sticky layer. Can someone differentiate?

Other uses I use leader keys in QMK is (all are for windows)

Leader Key + B O O T = qmk reset
Leader Key + R G B = toggle rgb
Leader Key + Q = Alt F4
Leader key + Z Z Z = system shutdown
Leader key + T O P = CTRL + SHIFT + ESC (task manager in windows)
Leader Key + MKDIR = CTRL + SHIFT + N (new folder)
Leader Key + RM = shift delete (hard delete in windows)
Leader KEy + PIN = windows pin (not recommended storing passwords on your keyboard but I'm lazy).

I'm hoping that this gets reviewed and can be merged into the main branch though as this is a major component that makes my 32 key keyboard work in QMK (along with tap mods, tap dances autoshifts, custom autoshift keys)

Copy link
Copy Markdown
Contributor

@petejohanson petejohanson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more items from my first pass at looking at this again. Thanks again for working on this!

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you press this again while it's active, should the behavior be to deactivate to interrupt it?

@arabshapt
Copy link
Copy Markdown

Please try to finish this feature... I will soon try to merge it on my branch, but it would be great to have it on master. I do not understand how people are not showing more interest for it. If it is easy to add key sequences(similar to vimrc) then it would be even better, but I think that can be done with a custom function... The main thing is having it on master and bugfree:) Thank you all but especially @nickconway and @petejohanson for working on it🙂

@arabshapt
Copy link
Copy Markdown

Is there any limitation regarding number of sequences that can be created? For combos there are (I think) 5 combos that can use the same key position. Could one create e.g. 900 sequences: leader + letter_1 + letter_2 = shortcut/macro?
So three key taps, around 900 unique sequences. Would it be possible with this implementation?

@tvdab
Copy link
Copy Markdown

tvdab commented Feb 25, 2024

I was a happy user of the leader key feature in my previous zmk build. Recently I tried updating my firmware to the latest release of zmk (c9c620d) and also update from zephyr sdk 0.15 to 0.16. Everything seems to work, except for the leader key. The leader key acts like a transparent key. Also running the test tests/leader/basic fails:

❯ west test tests/leader/basic
Running tests/leader/basic:
--- tests/leader/basic/keycode_events.snapshot	2024-02-25 22:11:10.516535082 +0100
+++ build/tests/leader/basic/keycode_events.log	2024-02-25 22:35:07.778445825 +0100
@@ -1,4 +1,2 @@
-leader: leader key activated
-pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
-released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
-leader: leader key deactivated
+pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
+released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
FAILED: tests/leader/basic

Could someone verify if the leader key works with zephyr sdk 0.16 and a recent version of zmk? Maybe I'm doing something wrong...

@caksoylar
Copy link
Copy Markdown
Contributor

I am guessing this needs to be rebased for #2028.

@tvdab
Copy link
Copy Markdown

tvdab commented Mar 30, 2024

I found why it wasn't working in Zephyr 3.5. This is what needs to be changed in order to make it work again:

--- a/app/src/behaviors/behavior_leader_key.c
+++ b/app/src/behaviors/behavior_leader_key.c
@@ -47,8 +47,8 @@ static const struct behavior_driver_api behavior_leader_key_driver_api = {
 #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)};       \
-    DEVICE_DT_INST_DEFINE(n, behavior_leader_key_init, NULL, NULL,                                 \
-                          &behavior_leader_key_config_##n, APPLICATION,                            \
+    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) 

There are probably more changes to be made (#2028) to update everything to zephyr 3.5.

@nickconway nickconway requested a review from a team as a code owner April 14, 2024 15:32
@magoz
Copy link
Copy Markdown

magoz commented May 11, 2024

Looking forward to this, great work!

j-w-e added a commit to j-w-e/zmk that referenced this pull request Jun 5, 2024
@nickconway nickconway requested a review from a team as a code owner August 18, 2024 01:23
@urob
Copy link
Copy Markdown
Contributor

urob commented Sep 11, 2024

I have been using this for a while now and really loving it! Just a few small comments to nitpick here:

Keycode vs position-based?

I see advantages for both sides. But overall I tend to think that this one might be more useful being keycode based.

The main reason is that in my experience leader sequences are almost always mnemonic (or are otherwise remembered in terms of their alphanumeric sequence). With this presumption, making them keycode based simplifies configuration and increases portability across layouts without much of a downside.

Purpose of layer option

I don't quite see the use case for this one. With the current position-based model, the sequence tracks every key press. So the active layer is a deterministic function of the layer on which &leader is placed and the sequence of keys, which can be matched against &leader_sequence. While it doesn't hurt to have the option, it might be unnecessary clutter?

(Similar, with a keycode-based model I can't really think of a use case either.)

Small bug?

Suppose I have two overlapping sequences:

  • <0> mapping to &kp A
  • <0 1> mapping to &kp B

Then the typing the sequence <0 2> within the leader term will eat up the sequence and not produce anything. I would expect it to match <0> and generate &kp A, and then terminate the processing of the sequence so that <2> can be processed by whatever behavior it is bound to.

@urob
Copy link
Copy Markdown
Contributor

urob commented Nov 25, 2024

If anyone is interested using this as a module that works without having to patch the ZMK firmware, I just pushed one to https://github.com/urob/zmk-leader-key.

For now it's a one-for-one adaption of Nick's PR but I am planning some changes going forward.

EDIT: I ended up reimplementing the behavior, making some changes to fit my personal needs (keycode-based, allow multiple instances, ...). For anyone who prefers the original PR, there's a legacy branch that makes that available as module as well.

@nickconway
Copy link
Copy Markdown
Contributor Author

I've merged in a bunch of changes just now, support for multiple instances, using child nodes, etc. Using the child nodes depends on a fix that hasn't yet been merged in yet (zephyrproject-rtos/zephyr#62417) but if I use a fork with the fix everything works as expected! (thanks so much @urob for maintaining your module all this time and finding that fix)

@jamesgour
Copy link
Copy Markdown

@nickconway what is the latest on this? :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

behaviors enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.