This module adds leader key functionality to ZMK. When a leader key is pressed, it captures all subsequent key presses, checks them against predefined leader sequences, and triggers the corresponding behavior if a match is found.
The module is a reimplementation of Nick Conway's PR #1380. The most important differences are:
- Works as a module without the need to patch ZMK.
- Sequences are
keycode-based instead ofposition-based. - Multiple leader-key instances with distinct sets of sequences are supported.
- Key codes that terminate the behavior are bubbled to other behaviors.
- Sequences inherit locality from the leader key (useful for
&sys_resetand&bootloader). - Strictly nested sequences are considered bad form and aren't supported.
- The
timeout,immediate-triggerandlayersproperties are removed as their primary intend is to support nested sequences and to work around the single-instance restriction of the original PR.
A one-for-one port of the original PR version as a ZMK module is available in
the legacy branch.
To load the module, add the following entries to remotes and projects in
config/west.yml.
manifest:
remotes:
- name: zmkfirmware
url-base: https://github.com/zmkfirmware
- name: urob
url-base: https://github.com/urob
projects:
- name: zmk
remote: zmkfirmware
revision: v0.3
import: app/west.yml
- name: zmk-leader-key
remote: urob
revision: v0.3 # set to same as ZMK version above
self:
path: configNote: This module uses a version scheme that is synchronized with upstream ZMK. To ensure compatibility, I highly recommend setting the revision of this module to the same as ZMK's.
Leader sequences are defined as child nodes of a leader-key instance. Each
sequence takes two arguments sequence and bindings. Example:
/ {
behaviors {
leader1: leader1 {
compatible = "zmk,behavior-leader-key";
#binding-cells = <0>;
usb { sequence = <U S B>; bindings = <&out OUT_USB>; };
ble { sequence = <B L E>; bindings = <&out OUT_BLE>; };
bt0 { sequence = <B N0>; bindings = <&bt BT_SEL 0>; };
bt1 { sequence = <B N1>; bindings = <&bt BT_SEL 1>; };
bt2 { sequence = <B N2>; bindings = <&bt BT_SEL 2>; };
btc { sequence = <C L E A R>; bindings = <&bt BT_CLR>; };
boot { sequence = <B O O T>; bindings = <&bootloader>; };
reset { sequence = <R E S E T>; bindings = <&sys_reset>; };
};
leader2: leader2 {
compatible = "zmk,behavior-leader-key";
#binding-cells = <0>;
de_ae { sequence = <A E>; bindings = <&de_ae>; };
de_oe { sequence = <O E>; bindings = <&de_oe>; };
de_ue { sequence = <U E>; bindings = <&de_ue>; };
};
};
};This sets up two leader key instances, leader1 and leader2. The first one
has various system related sequences, the second one is for German umlauts (the
&de_* bindings must be defined elsewhere).
Note: By default, modifiers in sequences are treated as a lower bound. For
example, holding LSHFT will trigger sequence LS(A) LS(B) as well as sequence
A B, whereas not holding any modifier will only trigger A B. This is so that
case-sensitive behavior bindings work as expected.
Locality: Sequence bindings inherit their locality from the position of the
leader key. For example, on split keyboards, the BOOT and RESET sequences in
the example above will invoke the bootloader on the side on which &leader1 is
bound. Tip: Add &leader1 to both sides to be able to reset either side.
ignore-keys (optional): If set to a list of key codes, these keys are
ignored when evaluating sequences. For instance, if
ignore-keys = <LSHFT RSHFT>, "shift" is passed through without triggering or
terminating sequences.
CONFIG_ZMK_LEADER_MAX_KEYS_PER_SEQUENCE: Maximum number of keys in a sequence. Default is 5.CONFIG_ZMK_LEADER_MAX_SEQUENCES: Maximum number of sequences per leader key instance. Default is 32.
- The legacy branch ports Nick Conway's PR #1380 as a ZMK module.
- My personal zmk-config contains advanced usage examples.