refactor(docs): Convert the keymaps section into a base folder (#2430)

Co-authored-by: Cem Aksoylar <caksoylar@users.noreply.github.com>
This commit is contained in:
Nicolas Munnich
2024-08-21 19:39:18 +02:00
committed by GitHub
parent 503f6c8e58
commit 5f056f7199
77 changed files with 399 additions and 526 deletions

View File

@@ -0,0 +1,13 @@
This is an _example_ footnote for **code** tables.
- Footnotes are supported per row by each operating system column.
- Footnotes support MDX syntax.
- A footnote's `id` is its filename by convention (i.e. `example`).
- Footnotes must be included and listed in `src/data/footnotes.js` because they're statically compiled.
- Footnotes are assigned within `src/data/hid.js` using `column-id: footnote-id(s)` `K`:`V` pairs (case-sensitive), where:
- `K` is the column's `id`.
- `V` is the footnote's `id`.
- `V` can also be an array of footnote ids (_optional_).
- The footnote system aims to prevent duplication of _sources_ (mdx).
- Footnotes are listed under each table, so try to avoid multiline notes unless it's necessary!
- Footnotes are automatically numbered.

View File

@@ -0,0 +1 @@
Does not exactly replicate original key behavior on macOS, works for Globe+key modifiers but not Fn+key ([#1938](https://github.com/zmkfirmware/zmk/pull/1938#issuecomment-1744579039)).

View File

@@ -0,0 +1,2 @@
Key press is registered, but has no visible effect in tested apps (Gmail, Safari, Notes)
iPhone 6 / iOS 12.4.6

View File

@@ -0,0 +1 @@
Both iOS power keys lock the home screen.

View File

@@ -0,0 +1 @@
Both macOS power keys ignore quick presses, sleep on deliberate press, and display a prompt on long-press.

View File

@@ -0,0 +1,61 @@
---
title: Backlight Behavior
sidebar_label: Backlight
---
## Summary
This page contains [backlight](../../features/backlight.mdx) behaviors supported by ZMK.
## Backlight Action Defines
Backlight actions defines are provided through the [`dt-bindings/zmk/backlight.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/backlight.h) header,
which is added at the top of the keymap file:
```dts
#include <dt-bindings/zmk/backlight.h>
```
This will allow you to reference the actions defined in this header such as `BL_TOG`.
Here is a table describing the action for each define:
| Define | Action |
| ---------- | --------------------------- |
| `BL_ON` | Turn on backlight |
| `BL_OFF` | Turn off backlight |
| `BL_TOG` | Toggle backlight on and off |
| `BL_INC` | Increase brightness |
| `BL_DEC` | Decrease brightness |
| `BL_CYCLE` | Cycle brightness |
| `BL_SET` | Set a specific brightness |
## Behavior Binding
- Reference: `&bl`
- Parameter #1: The backlight action define, e.g. `BL_TOG` or `BL_INC`
- Parameter #2: Only applies to `BL_SET`and is the brightness value
:::note[Backlight settings persistence]
The backlight settings that are changed via the `&bl` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
They will also override the start values set by [`CONFIG_ZMK_BACKLIGHT_*_START` settings](../../config/backlight.md#kconfig).
However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
:::
### Examples
1. Toggle backlight on/off
```dts
&bl BL_TOG
```
1. Sets a specific brightness
```dts
&bl BL_SET 50
```
## Split Keyboards
Backlight behaviors are [global](../../features/split-keyboards.md#global-locality-behaviors): This means that when triggered, they affect both the central and peripheral side of split keyboards.

View File

@@ -0,0 +1,107 @@
---
title: Bluetooth Behavior
sidebar_label: Bluetooth
---
## Summary
The bluetooth behavior allows management of various settings and states related to the bluetooth connection(s)
between the keyboard and the host. By default, ZMK supports five "profiles" for selecting which bonded host
computer/laptop/keyboard should receive the keyboard input; many of the commands here operate on those profiles.
:::note[Connection Management]
When pairing to a host device ZMK saves bond information to the selected
profile. It will not replace this when you initiate pairing with another device.
To pair with a new device, select a profile that doesn't have a pairing with `BT_SEL`, `BT_NXT` or
`BT_PRV` bindings, or clear an already paired profile using `BT_CLR` or `BT_CLR_ALL`.
A ZMK device may show as "connected" on multiple hosts at the same time. This is working as intended, and only the host associated with the active profile will receive keystrokes.
An _inactive_ connected profile can be explicitly disconnected using the `BT_DISC` behavior. This can be helpful in
cases when host devices behave differently when a bluetooth keyboard is connected, for example by hiding their on-screen
keyboard. Note that at present the active bluetooth profile will immediately reconnect if disconnected. This is true
even if OUT_USB is selected. To remain disconnected, another bluetooth profile must be first selected using (e.g.)
`BT_SEL`.
:::
## Bluetooth Command Defines
Bluetooth command defines are provided through the [`dt-bindings/zmk/bt.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/bt.h) header,
which is added at the top of the keymap file:
```dts
#include <dt-bindings/zmk/bt.h>
```
This will allow you to reference the actions defined in this header such as `BT_CLR`.
Here is a table describing the command for each define:
| Define | Action |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile. |
| `BT_CLR_ALL` | Clear bond information between the keyboard and host for all profiles. |
| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end is reached. |
| `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached. |
| `BT_SEL` | Select the 0-indexed profile by number; must include a number as an argument in the keymap to work correctly, e.g. `BT_SEL 0`. |
| `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive; must include a number as an argument in the keymap to work correctly, e.g. `BT_DISC 0`. |
:::note[Selected profile persistence]
The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
:::
## Bluetooth Behavior
The bluetooth behavior completes an bluetooth action given on press.
### Behavior Binding
- Reference: `&bt`
- Parameter #1: The bluetooth command define, e.g. `BT_CLR`
- Parameter #2: Only applies to `BT_SEL` and `BT_DISC`, and is the 0-indexed profile by number
### Examples
1. Behavior binding to clear the paired host for the selected profile:
```dts
&bt BT_CLR
```
1. Behavior binding to select the next profile:
```dts
&bt BT_NXT
```
1. Behavior binding to select the previous profile:
```dts
&bt BT_PRV
```
1. Behavior binding to select the 2nd profile (passed parameters are [zero based](https://en.wikipedia.org/wiki/Zero-based_numbering)):
```dts
&bt BT_SEL 1
```
## Bluetooth Pairing and Profiles
ZMK support bluetooth “profiles” which allows connection to multiple devices (5 by default). Each profile stores the bluetooth MAC address of a peer, which can be empty if a profile has not been paired with a device yet. Upon switching to a profile, ZMK does the following:
- If a profile has not been paired with a peer yet, ZMK automatically advertises itself as connectable. You can discover your keyboard from bluetooth scanning on your laptop / tablet. If you try to connect, it will trigger the _pairing_ procedure. After pairing, the bluetooth MAC address of the peer device will be stored in the current profile. Pairing also negotiates a random key for secure communication between the device and the keyboard.
- If a profile has been paired but the peer is not connected yet, ZMK will also advertise itself as connectable. In the future, the behavior might change to _direct advertising_ which only target the peer with the stored bluetooth MAC address. In this state, if the peer is powered on and moved within the distance of bluetooth signal coverage, it should automatically connect to the keyboard.
- If a profile has been paired and is currently connected, ZMK will not advertise it as connectable.
The bluetooth MAC address and negotiated keys during pairing are stored in the permanent storage on your chip and can be reused even after reflashing the firmware. If for some reason you want to delete the stored information, you can bind the `BT_CLR` behavior described above to a key and use it to clear the _current_ profile.
:::note[Number of Profiles]
Please note there are five available Bluetooth profiles by default. If you need to adjust the number of available profiles, set `CONFIG_BT_MAX_CONN` _and_ `CONFIG_BT_MAX_PAIRED` to the desired number of profiles, `n`, or `n+1` for split keyboards, in your `zmk-config` `.conf` file.
:::
:::note
If you clear bond of a paired profile, make sure you do the same thing on the peer device as well (typically achieved by _removing_ or _forgetting_ the bluetooth connection). Otherwise the peer will try to connect to your keyboard whenever it discovers it. But while the MAC address of both devices could remain the same, the security key no longer match: the peer device still possess the old key negotiated in the previous pairing procedure, but our keyboard firmware has deleted that key. So the connection will fail. If you [enabled USB logging](../../development/usb-logging.mdx), you might see a lot of failed connection attempts due to the reason of “Security failed”.
:::

View File

@@ -0,0 +1,72 @@
---
title: Caps Word Behavior
sidebar_label: Caps Word
---
## Summary
The caps word behavior behaves similar to a caps lock, but will automatically deactivate when any key not in a continue list is pressed, or if the caps word key is pressed again. For smaller keyboards using [mod-taps](mod-tap.md), this can help avoid repeated alternating holds when typing words in all caps.
The modifiers are applied only to the alphabetic (`A` to `Z`) keycodes, to avoid automatically applying them to numeric values, etc.
### Behavior Binding
- Reference: `&caps_word`
Example:
```dts
&caps_word
```
### Configuration
#### Continue list
By default, the caps word will remain active when any alphanumeric character or underscore (`UNDERSCORE`), backspace (`BACKSPACE`), or delete (`DELETE`) characters are pressed. Any other non-modifier keycode sent will turn off caps word. If you would like to override this, you can set a new array of keys in the `continue-list` property in your keymap:
```dts
&caps_word {
continue-list = <UNDERSCORE MINUS>;
};
/ {
keymap {
...
};
};
```
#### Applied modifier(s)
In addition, if you would like _multiple_ modifiers, instead of just `MOD_LSFT`, you can override the `mods` property:
```dts
&caps_word {
mods = <(MOD_LSFT | MOD_LALT)>;
};
/ {
keymap {
...
};
};
```
### Multiple Caps Breaks
If you want to use multiple caps breaks with different codes to break the caps, you can add additional caps words instances to use in your keymap:
```dts
/ {
prog_caps: prog_caps {
compatible = "zmk,behavior-caps-word";
#binding-cells = <0>;
continue-list = <UNDERSCORE>;
};
keymap {
...
};
};
```

View File

@@ -0,0 +1,341 @@
---
title: Hold-Tap Behavior
sidebar_label: Hold-Tap
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
## Summary
Hold-tap is the basis for other behaviors such as layer-tap and mod-tap.
Simply put, the hold-tap key will output the 'hold' behavior if it's held for a while, and output the 'tap' behavior when it's tapped quickly.
### Hold-Tap
The graph below shows how the hold-tap decides between a 'tap' and a 'hold'.
![Simple behavior](../../assets/hold-tap/case1_2.svg)
By default, the hold-tap is configured to also select the 'hold' functionality if another key is tapped while it's active:
![Hold preferred behavior](../../assets/hold-tap/case_hold_preferred.svg)
We call this the 'hold-preferred' flavor of hold-taps. While this flavor may work very well for a ctrl/escape key, it's not very well suited for home-row mods or layer-taps. That's why there are two more flavors to choose from: 'tap-preferred' and 'balanced'.
#### Flavors
- The 'hold-preferred' flavor triggers the hold behavior when the `tapping-term-ms` has expired or another key is pressed.
- The 'balanced' flavor will trigger the hold behavior when the `tapping-term-ms` has expired or another key is pressed and released.
- The 'tap-preferred' flavor triggers the hold behavior when the `tapping-term-ms` has expired. Pressing another key within `tapping-term-ms` does not affect the decision.
- The 'tap-unless-interrupted' flavor triggers a hold behavior only when another key is pressed before `tapping-term-ms` has expired. It triggers the tap behavior in all other situations.
When the hold-tap key is released and the hold behavior has not been triggered, the tap behavior will trigger.
![Hold-tap comparison](../../assets/hold-tap/comparison.svg)
### Basic Usage
For basic usage, please see the [mod-tap](mod-tap.md) and [layer-tap](layers.md#layer-tap) pages.
### Advanced Configuration
#### `tapping-term-ms`
Defines how long a key must be pressed to trigger Hold behavior.
#### `quick-tap-ms`
If you press a tapped hold-tap again within `quick-tap-ms` milliseconds of the first press, it will always trigger the tap behavior. This is useful for things like a backspace, where a quick tap+hold holds backspace pressed. Set this to a negative value to disable. The default is -1 (disabled).
#### `require-prior-idle-ms`
`require-prior-idle-ms` is like `quick-tap-ms` however it will apply for _any_ non-modifier key pressed before it. This effectively disables the hold-tap when typing quickly, which can be quite useful for homerow mods. It can also have the effect of removing the input delay when typing quickly.
For example, the following hold-tap configuration enables `require-prior-idle-ms` with a 125 millisecond term, alongside `quick-tap-ms` with a 200 millisecond term.
```dts
rpi: require_prior_idle {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
flavor = "tap-preferred";
tapping-term-ms = <200>;
quick-tap-ms = <200>;
require-prior-idle-ms = <125>;
bindings = <&kp>, <&kp>;
};
```
If you press `&kp A` and then `&rpi LEFT_SHIFT B` **within** 125 ms, then `ab` will be output. Importantly, `b` will be output immediately since it was within the `require-prior-idle-ms`, without waiting for a timeout or an interrupting key. In other words, the `&rpi LEFT_SHIFT B` binding will only have its underlying hold-tap behavior if it is pressed 125 ms **after** the previous key press; otherwise it will act like `&kp B`.
Note that the greater the value of `require-prior-idle-ms` is, the harder it will be to invoke the hold behavior, making this feature less applicable for use-cases like capitalizing letters while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires.
#### `retro-tap`
If `retro-tap` is enabled, the tap behavior is triggered when releasing the hold-tap key if no other key was pressed in the meantime.
For example, if you press `&mt LEFT_SHIFT A` and then release it without pressing another key, it will output `a`.
```dts
&mt {
retro-tap;
};
```
#### `hold-while-undecided`
If enabled, the hold behavior will immediately be held on hold-tap press, and will release before the behavior is sent in the event the hold-tap resolves into a tap. With most modifiers this will not affect typing, and is useful for using modifiers with the mouse.
:::info[Alt/Win/Cmd behavior]
In some applications/desktop environments, pressing Alt keycodes by itself will have its own behavior like activate a menu and Gui keycodes will bring up the start menu or an application launcher.
:::
#### `hold-while-undecided-linger`
If your tap behavior activates the same modifier as the hold behavior, and you want to avoid a double tap when transitioning from the hold to the tap, you can use `hold-while-undecided-linger`. When enabled, the hold behavior will continue to be held until _after_ the tap behavior is released. For example, if the hold is `&kp LGUI` and the tap is `&sk LGUI`, then with `hold-while-undecided-linger` enabled, the host will see `LGUI` held down continuously until the sticky key is finished, instead of seeing a release and press when transitioning from hold to sticky key.
#### Positional hold-tap and `hold-trigger-key-positions`
Including `hold-trigger-key-positions` in your hold-tap definition turns on the positional hold-tap feature. With positional hold-tap enabled, if you press any key **NOT** listed in `hold-trigger-key-positions` before `tapping-term-ms` expires, it will produce a tap.
In all other situations, positional hold-tap will not modify the behavior of your hold-tap. Positional hold-tap is useful when used with home-row modifiers: for example, if you have a home-row modifier key in the left hand, by including only key positions from the right hand in `hold-trigger-key-positions`, you will only get hold behaviors during cross-hand key combinations.
:::info
Note that `hold-trigger-key-positions` is an array of key position indexes. Key positions are numbered sequentially according to your keymap, starting with 0. So if the first key in your keymap is Q, this key is in position 0. The next key (probably W) will be in position 1, et cetera.
:::
See the following example, which uses a hold-tap behavior definition, configured with the `hold-preferred` flavor, and with positional hold-tap enabled:
```dts
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
/ {
behaviors {
pht: positional_hold_tap {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
flavor = "hold-preferred";
tapping-term-ms = <400>;
quick-tap-ms = <200>;
bindings = <&kp>, <&kp>;
hold-trigger-key-positions = <1>; // <---[[the W key]]
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
// position 0 position 1 position 2
&pht LEFT_SHIFT Q &kp W &kp E
>;
};
};
};
```
- The sequence `(pht_down, E_down, E_up, pht_up)` produces `qe`. The normal hold behavior (LEFT_SHIFT) **IS** modified into a tap behavior (Q) by positional hold-tap because the first key pressed after the hold-tap key is the `E key`, which is in position 2, which **is NOT** included in `hold-trigger-key-positions`.
- The sequence `(pht_down, W_down, W_up, pht_up)` produces `W`. The normal hold behavior (LEFT_SHIFT) **is NOT** modified into a tap behavior (Q) by positional hold-tap because the first key pressed after the hold-tap key is the `W key`, which is in position 1, which **IS** included in `hold-trigger-key-positions`.
- If the `LEFT_SHIFT / Q key` is held by itself for longer than `tapping-term-ms`, a hold behavior is produced. This is because positional hold-tap only modifies the behavior of a hold-tap if another key is pressed before the `tapping-term-ms` period expires.
By default, `hold-trigger-key-positions` are evaluated upon the first _key press_ after
the hold-tap. For homerow mods, this is not always ideal, because it prevents combining multiple modifiers unless they are included in `hold-trigger-key-positions`. To overwrite this behavior, one can set `hold-trigger-on-release`. If set to true, the evaluation of `hold-trigger-key-positions` gets delayed until _key release_. This allows combining multiple modifiers when the next key is _held_, while still deciding the hold-tap in favor of a tap when the next key is _tapped_.
#### Using different behavior types with hold-taps
You can create instances of hold-taps invoking most [behavior types](../index.mdx#behaviors) for hold or tap actions, by referencing their node labels in the `bindings` value.
The two parameters that are passed to the hold-tap in your keymap will be forwarded to the referred behaviors, first one to the hold behavior and second one to the tap.
If you use behaviors that accept no parameters such as [mod-morphs](mod-morph.md) or [macros](macros.md), you can pass a dummy parameter value such as `0` to the hold-tap when you use it in your keymap.
For instance, a hold-tap with node label `caps` and `bindings = <&kp>, <&caps_word>;` can be used in the keymap as below to send the caps lock keycode on hold and invoke the [caps word behavior](caps-word.md) on tap:
```dts
&caps CAPS 0
```
:::info
You cannot use behaviors that expect more than one parameter such as [`&bt`](bluetooth.md) and [`&rgb_ug`](underglow.md) with hold-taps, due to the limitations of the [devicetree keymap format](../../config/index.md#devicetree-files).
One workaround is to create a [macro](macros.md) that invokes those behaviors and use the macro as the hold or tap action.
:::
### Example Use-Cases
<Tabs
defaultValue="homerow_mods"
values={[
{label: 'Homerow Mods', value: 'homerow_mods'},
{label: 'Autoshift', value: 'autoshift'},
{label: 'Toggle-on-Tap, Momentary-on-Hold Layers', value: 'mo_tog'},
]}>
<TabItem value="homerow_mods">
The following are suggested hold-tap configurations that work well with home row mods:
##### Option 1: cross-hand only modifiers, using `tap-unless-interrupted` and positional hold-tap (`hold-trigger-key-positions`)
```dts title="Homerow Mods: Cross-hand Example"
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
/ {
behaviors {
lh_pht: left_positional_hold_tap {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
flavor = "tap-unless-interrupted";
tapping-term-ms = <100>; // <---[[produces tap if held longer than tapping-term-ms]]
quick-tap-ms = <200>;
bindings = <&kp>, <&kp>;
hold-trigger-key-positions = <5 6 7 8 9 10>; // <---[[right-hand keys]]
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
// position 0 pos 1 pos 2 pos 3 pos 4 pos 5 pos 6 pos 7 pos 8 pos 9 pos 10
&lh_pht LSFT A &lh_pht LGUI S &lh_pht LALT D &lh_pht LCTL F &kp G &kp H &kp I &kp J &kp K &kp L &kp SEMI
>;
};
};
};
```
##### Option 2: `tap-preferred`
```dts title="Homerow Mods: Tap-Preferred Example"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
hm: homerow_mods {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
tapping-term-ms = <150>;
quick-tap-ms = <0>;
flavor = "tap-preferred";
bindings = <&kp>, <&kp>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&hm LCTRL A &hm LGUI S &hm LALT D &hm LSHIFT F
>;
};
};
};
```
##### Option 3: `balanced`
```dts title="Homerow Mods: Balanced Example"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
bhm: balanced_homerow_mods {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
tapping-term-ms = <200>; // <---[[moderate duration]]
quick-tap-ms = <0>;
flavor = "balanced";
bindings = <&kp>, <&kp>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&bhm LCTRL A &bhm LGUI S &bhm LALT D &bhm LSHIFT F
>;
};
};
};
```
</TabItem>
<TabItem value="autoshift">
A popular method of implementing Autoshift in ZMK involves a C-preprocessor macro, commonly defined as `AS(keycode)`. This macro applies the `LSHIFT` modifier to the specified `keycode` when `AS(keycode)` is held, and simply performs a [keypress](key-press.md), `&kp keycode`, when the `AS(keycode)` binding is tapped. This simplifies the use of Autoshift in a keymap, as the complete hold-tap bindings for each desired Autoshift key, as in `&as LS(<keycode 1>) <keycode 1> &as LS(<keycode 2>) <keycode 2> ... &as LS(<keycode n>) <keycode n>`, can be quite cumbersome to use when applied to a large portion of the keymap.
```dts title="Hold-Tap Example: Autoshift"
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#define AS(keycode) &as LS(keycode) keycode // Autoshift Macro
/ {
behaviors {
as: auto_shift {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
tapping_term_ms = <135>;
quick_tap_ms = <0>;
flavor = "tap-preferred";
bindings = <&kp>, <&kp>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
AS(Q) AS(W) AS(E) AS(R) AS(T) AS(Y) // Autoshift applied for QWERTY keys
>;
};
};
};
```
</TabItem>
<TabItem value="mo_tog">
This hold-tap example implements a [momentary-layer](layers.md#momentary-layer) when the keybind is held and a [toggle-layer](layers.md#toggle-layer) when it is tapped. Similar to the Autoshift and Sticky Hold use-cases, a `MO_TOG(layer)` macro is defined such that the `&mo` and `&tog` behaviors can target a single layer.
```dts title="Hold-Tap Example: Momentary layer on Hold, Toggle layer on Tap"
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#define MO_TOG(layer) &mo_tog layer layer // Macro to apply momentary-layer-on-hold/toggle-layer-on-tap to a specific layer
/ {
behaviors {
mo_tog: behavior_mo_tog {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
flavor = "hold-preferred";
tapping-term-ms = <200>;
bindings = <&mo>, <&tog>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&mo_tog 2 1 // &mo 2 on hold, &tog 1 on tap
MO_TOG(3) // &mo 3 on hold, &tog 3 on tap
>;
};
};
};
```
</TabItem>
</Tabs>
### Comparison to QMK
The `hold-preferred` flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting in QMK. The `balanced` flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is the QMK default.

View File

@@ -0,0 +1,83 @@
---
title: Behavior Overview
sidebar_label: Overview
---
# Behaviors Overview
"Behaviors" are bindings that are assigned to and triggered by key positions on keymap layers, sensors (like an encoder) or combos. They describe what happens e.g. when a certain key position is pressed or released, or an encoder triggers a rotation event. They can also be recursively invoked by other behaviors, such as macros.
Below is a summary of pre-defined behavior bindings and user-definable behaviors available in ZMK, with references to documentation pages describing them.
## Key Press Behaviors
| Binding | Behavior | Description |
| ------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `&kp` | [Key Press](key-press.md) | Send keycodes to the connected host when a key is pressed |
| `&mt` | [Mod Tap](mod-tap.md) | Sends a different key press depending on whether a key is held or tapped |
| `&kt` | [Key Toggle](key-toggle.md) | Toggles the press of a key. If the key is not currently pressed, key toggle will press it, holding it until the key toggle is pressed again or the key is released in some other way. If the key is currently pressed, key toggle will release it |
| `&sk` | [Sticky Key](sticky-key.md) | Stays pressed until another key is pressed, then is released. It is often used for modifier keys like shift, which allows typing capital letters without holding it down |
| `&gresc` | [Grave Escape](mod-morph.md#behavior-binding) | Sends Grave Accent `` ` `` keycode if shift or GUI is held, sends Escape keycode otherwise |
| `&caps_word` | [Caps Word](caps-word.md) | Behaves similar to caps lock, but automatically deactivates when any key not in a continue list is pressed, or if the caps word key is pressed again |
| `&key_repeat` | [Key Repeat](key-repeat.md) | Sends again whatever keycode was last sent |
## Miscellaneous Behaviors
| Binding | Behavior | Description |
| -------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `&trans` | [Transparent](misc.md#transparent) | Passes the key press down to the next active layer in the stack for processing |
| `&none` | [None](misc.md#none) | Swallows and stops the key press, no keycode will be sent nor will the key press be passed down to the next active layer in the stack |
## Layer Navigation Behaviors
| Binding | Behavior | Description |
| ------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `&mo` | [Momentary Layer](layers.md#momentary-layer) | Enables a layer while a key is pressed |
| `&lt` | [Layer-tap](layers.md#layer-tap) | Enables a layer when a key is held, and outputs a key press when the key is only tapped for a short time |
| `&to` | [To Layer](layers.md#to-layer) | Enables a layer and disables all other layers except the default layer |
| `&tog` | [Toggle Layer](layers.md#toggle-layer) | Enables a layer until the layer is manually disabled |
| `&sl` | [Sticky Layer](sticky-layer.md) | Activates a layer until another key is pressed, then deactivates it |
## Mouse Emulation Behaviors
| Binding | Behavior | Description |
| ------- | ----------------------------------------------------------- | ------------------------------- |
| `&mkp` | [Mouse Button Press](mouse-emulation.md#mouse-button-press) | Emulates pressing mouse buttons |
## Reset Behaviors
| Binding | Behavior | Description |
| ------------- | --------------------------------------- | ---------------------------------------------------------------------------------------- |
| `&sys_reset` | [Reset](reset.md#reset) | Resets the keyboard and re-runs the firmware flashed to the device |
| `&bootloader` | [Bootloader](reset.md#bootloader-reset) | Resets the keyboard and puts it into bootloader mode, allowing you to flash new firmware |
## Output Selection Behaviors
| Binding | Behavior | Description |
| ------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `&bt` | [Bluetooth](bluetooth.md#bluetooth-behavior) | Completes a bluetooth action given on press, for example switching between devices |
| `&out` | [Output Selection](outputs.md#output-selection-behavior) | Allows selecting whether output is sent to the USB or bluetooth connection when both are connected |
## Lighting Behaviors
| Binding | Behavior | Description |
| --------- | ---------------------------------------------- | ---------------------------------------------------------------------------- |
| `&rgb_ug` | [RGB Underglow](underglow.md#behavior-binding) | Controls the RGB underglow, usually placed underneath the keyboard |
| `&bl` | [Backlight](backlight.md#behavior-binding) | Controls the keyboard backlighting, usually placed through or under switches |
## Power Management Behaviors
| Binding | Behavior | Description |
| ------------ | --------------------------------------------- | --------------------------------------------------------------- |
| `&ext_power` | [Power management](power.md#behavior-binding) | Allows enabling or disabling the VCC power output to save power |
| `&soft_off` | [Soft off](soft-off.md#behavior-binding) | Turns the keyboard off. |
## User-Defined Behaviors
| Behavior | Description |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Macros](macros.md) | Allows configuring a list of other behaviors to invoke when the key is pressed and/or released |
| [Hold-Tap](hold-tap.mdx) | Invokes different behaviors depending on key press duration or interrupting keys. This is the basis for [layer-tap](layers.md#layer-tap) and [mod-tap](mod-tap.md) |
| [Tap Dance](tap-dance.mdx) | Invokes different behaviors corresponding to how many times a key is pressed |
| [Mod-Morph](mod-morph.md) | Invokes different behaviors depending on whether a specified modifier is held during a key press |
| [Sensor Rotation](sensor-rotate.md) | Invokes different behaviors depending on whether a sensor is rotated clockwise or counter-clockwise |

View File

@@ -0,0 +1,49 @@
---
title: Key Press Behaviors
sidebar_label: Key Press
---
## Summary
The most basic of behaviors, is the ability to send certain keycode presses and releases in response to activating
a certain key.
The categories of supported keycodes are:
- [Keyboard](../list-of-keycodes.mdx#keyboard)
- [Modifiers](../list-of-keycodes.mdx#modifiers)
- [Keypad](../list-of-keycodes.mdx#keypad)
- [Editing](../list-of-keycodes.mdx#editing)
- [Media](../list-of-keycodes.mdx#media)
- [Applications](../list-of-keycodes.mdx#applications)
- [Input Assist](../list-of-keycodes.mdx#input-assist)
- [Power & Lock](../list-of-keycodes.mdx#power--lock)
For advanced users, user-defined HID usages are also supported but must be encoded, please see [`dt-bindings/zmk/keys.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/keys.h) for further insight.
## Keycode Defines
To make it easier to encode the HID keycode numeric values, most keymaps include
the [`dt-bindings/zmk/keys.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/keys.h) header
provided by ZMK near the top:
```dts
#include <dt-bindings/zmk/keys.h>
```
Doing so makes a set of defines such as `A`, `N1`, etc. available for use with these behaviors
## Key Press
The "key press" behavior sends standard keycodes on press/release.
### Behavior Binding
- Reference: `&kp`
- Parameter: The keycode usage ID from the usage page, e.g. `N4` or `A`
Example:
```dts
&kp A
```

View File

@@ -0,0 +1,38 @@
---
title: Key Repeat Behavior
sidebar_label: Key Repeat
---
## Summary
The key repeat behavior when triggered will send whatever keycode was last sent/triggered.
### Behavior Binding
- Reference: `&key_repeat`
Example:
```dts
&key_repeat
```
### Configuration
#### Usage pages
By default, the key repeat will only track the last pressed key from the HID "Key" usage page, and ignore events from other usages, e.g. Consumer page.
If you'd rather have the repeat also capture and send Consumer page usages, you can update the existing behavior:
```dts
&key_repeat {
usage-pages = <HID_USAGE_KEY HID_USAGE_CONSUMER>;
};
/ {
keymap {
...
};
};
```

View File

@@ -0,0 +1,26 @@
---
title: Key Toggle Behavior
sidebar_label: Key Toggle
---
## Summary
The key toggle behavior toggles the press of a key.
If the key is not currently pressed, key toggle will press it, holding it until the key toggle is pressed again or the key is released in some other way.
If the key _is_ currently pressed, key toggle will release it.
Example uses for key toggle include shift lock, or `ALT-TAB` window switching without holding down the `ALT` modifier.
### Behavior Binding
- Reference: `&kt`
- Parameter: The [keycode](../list-of-keycodes.mdx), e.g. `LALT` or `DOWN_ARROW`
Example:
```dts
&kt LALT
```
You can use any keycode that works for `&kp` as parameter to `&kt`, however, [modified keys](../modifiers.mdx#modifier-functions) such as `LA(A)` will be toggled based on the status of the base keycode (in this case `A`).
In other words, modifiers are ignored when determining whether or not the key is currently pressed.

View File

@@ -0,0 +1,122 @@
---
title: Layer Behaviors
sidebar_label: Layers
---
## Summary
Often, you may want a certain key position to alter which layers are enabled, change the default layer, etc.
Some of those behaviors are still in the works; the ones that are working now are documented here.
:::note
Multiple layers can be active at the same time and activating a layer will not deactivate layers higher up in the "layer stack". See [Layers](../index.mdx#layers) for more information.
:::
## Defines to Refer to Layers
When working with layers, you may have several different key positions with bindings that enable/disable those layers.
To make it easier to refer to those layers in your key bindings, and to change which layers are where later, you can
add a set of `#define`s at the top of your keymap file, and use those layer in your keymap.
For example, if you have three layers, you can add the following to the top of your keymap:
```dts
#define DEFAULT 0
#define LOWER 1
#define RAISE 2
```
This allows you to use those defines, e.g. `LOWER` later in your keymap.
## Momentary Layer
The "momentary layer" behavior enables a layer while a certain key is pressed. Immediately upon
activation of the key, the layer is enabled, and immediately upon release of the key, the layer is disabled
again.
### Behavior Binding
- Reference: `&mo`
- Parameter: The layer number to enable while held, e.g. `1`
Example:
```dts
&mo LOWER
```
## Layer-Tap
The "layer-tap" behavior enables a layer when a key is held, and outputs a [keypress](key-press.md) when the key is only tapped for a short time.
### Behavior Binding
- Reference: `&lt`
- Parameter: The layer number to enable while held, e.g. `1`
- Parameter: The keycode to send when tapped, e.g. `A`
Example:
```dts
&lt LOWER SPACE
```
### Configuration
You can configure a different tapping term or tweak other properties noted in the [hold-tap](hold-tap.mdx#advanced-configuration) documentation page in your keymap:
```dts
&lt {
tapping-term-ms = <200>;
};
/ {
keymap {
...
};
};
```
:::info
Functionally, the layer-tap is a [hold-tap](hold-tap.mdx) of the ["tap-preferred" flavor](hold-tap.mdx#flavors) and a [`tapping-term-ms`](hold-tap.mdx#tapping-term-ms) of 200 that takes in a [`momentary layer`](#momentary-layer) and a [keypress](key-press.md) as its "hold" and "tap" parameters, respectively.
For users who want to send a different [keycode](../list-of-keycodes.mdx) depending on if the same key is held or tapped, see [Mod-Tap](mod-tap.md).
Similarly, for users looking to create a keybind like the layer-tap that depending on how long the key is held, invokes behaviors like [sticky keys](sticky-key.md) or [key toggles](key-toggle.md), see [Hold-Tap](hold-tap.mdx).
:::
## To Layer
The "to layer" behavior enables a layer and disables _all_ other layers _except_ the default layer.
### Behavior Binding
- Reference: `&to`
- Parameter: The layer number to enable, e.g. `1`
Example:
```dts
&to 3
```
## Toggle Layer
The "toggle layer" behavior enables a layer if it is currently disabled, or disables it if enabled.
### Behavior Binding
- Reference: `&tog`
- Parameter: The layer number to enable/disable, e.g. `1`
Example:
```dts
&tog LOWER
```
## Conditional Layers
The "conditional layers" feature enables a particular layer when all layers in a specified set are active.
For more information, see [conditional layers](../conditional-layers.md).

View File

@@ -0,0 +1,331 @@
---
title: Macro Behavior
sidebar_label: Macros
---
## Summary
The macro behavior allows configuring a list of other behaviors to invoke
when the macro is pressed and/or released.
## Macro Definition
Each macro you want to use in your keymap gets defined first, then bound in your keymap.
A macro definition looks like:
```dts
/ {
macros {
zed_em_kay: zed_em_kay {
compatible = "zmk,behavior-macro";
#binding-cells = <0>;
bindings
= <&macro_press &kp LSHFT>
, <&macro_tap &kp Z &kp M &kp K>
, <&macro_release &kp LSHFT>
;
};
};
};
```
:::note
The text before the colon (`:`) in the declaration of the macro node is the "node label", and is the text
used to reference the macro in your keymap.
:::
The macro can then be bound in your keymap by referencing it by the label `&zed_em_kay`, e.g.:
```dts
raise_layer {
bindings = <&zed_em_kay>;
};
```
:::note
For use cases involving sending a single keycode with modifiers, for instance ctrl+tab, the [key press behavior](key-press.md)
with [modifier functions](../modifiers.mdx#modifier-functions) can be used instead of a macro.
:::
### Bindings
Like [hold-taps](hold-tap.mdx), macros are created by composing other behaviors, and any of those behaviors can
be added to the `bindings` list, e.g.:
```dts
bindings
= <&to 1>
, <&bl BL_ON>
, <&kp Z &kp M &kp K &kp EXCLAMATION>
;
```
## Macro Controls
There are a set of special macro controls that can be included in the `bindings` list to modify the
way the macro is processed.
### Binding Activation Mode
Bindings in a macro are activated differently, depending on the current "activation mode" of the macro.
Available modes:
- Tap - The default mode; when in this mode, the macro will press, then release, each behavior in the `bindings` list. This mode is useful for
basic keycode output to hosts, i.e. when activating a `&kp` behavior.
- Press - In this mode, the macro will only trigger a press on each behavior in the `bindings` list. This is useful for holding down modifiers for some duration of a macro, e.g. `&kp LALT`.
- Release - In this mode, the macro will only trigger a release on each behavior in the `bindings` list. This is useful for releasing modifiers previously pressed earlier in the macro processing, e.g. `&kp LALT`.
To modify the activation mode, macro controls can be added at any point in the `bindings` list.
- `&macro_tap`
- `&macro_press`
- `&macro_release`
A concrete example, used to hold a modifier, tap multiple keys, then release the modifier, would look like:
```dts
bindings
= <&macro_press &kp LSHFT>
, <&macro_tap &kp Z &kp M &kp K>
, <&macro_release &kp LSHFT>
;
```
### Processing Continuation on Release
The macro can be paused so that only part of the `bindings` list is processed when the macro is pressed, and the remainder is processed once
the macro itself is released.
To pause the macro until release, use `&macro_pause_for_release`. For example, this macro will press a modifier and activate a layer when the macro is pressed. Once the macro is released, it will release the modifier and deactivate the layer by releasing the `&mo`:
```dts
bindings
= <&macro_press &mo 1 &kp LSHFT>
, <&macro_pause_for_release>
, <&macro_release &mo 1 &kp LSHFT>
;
```
### Wait Time
The wait time setting controls how long of a delay is introduced between behaviors in the `bindings` list. The initial wait time for a macro,
which is equal to the value of [`CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS`](../../config/behaviors.md#macro) by default, can
be set by assigning a value to the `wait-ms` property of the macro, e.g. `wait-ms = <20>;`. If you want to update the wait time at any
point in the macro bindings list, use `&macro_wait_time`, e.g. `&macro_wait_time 30`. A full example:
```dts
wait-ms = <10>;
bindings
= <&kp F &kp A &kp S &kp T>
, <&macro_wait_time 500>
, <&kp S &kp L &kp O &kp W>
;
```
### Tap Time
The tap time setting controls how long a tapped behavior is held in the `bindings` list. The initial tap time for a macro,
which is equal to the value of [`CONFIG_ZMK_MACRO_DEFAULT_TAP_MS`](../../config/behaviors.md#macro) by default, can
be set by assigning a value to the `tap-ms` property of the macro, e.g. `tap-ms = <20>;`. If you want to update the tap time at any
point in a macro bindings list, use `&macro_tap_time`, e.g. `&macro_tap_time 30`. A full example:
```dts
bindings
= <&macro_tap_time 10>
, <&kp S &kp H &kp O &kp R &kp T>
, <&macro_tap_time 500>
, <&kp L &kp O &kp N &kp G>
;
```
### Behavior Queue Limit
Macros use an internal queue to invoke each behavior in the bindings list when triggered, which has a size of 64 by default. Bindings in "press" and "release" modes correspond to one event in the queue, whereas "tap" mode bindings correspond to two (one for press and one for release). As a result, the effective number of actions processed might be less than 64 and this can cause problems for long macros.
To prevent issues with longer macros, you can change the size of this queue via the `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE` setting in your configuration, [typically through your `.conf` file](../../config/index.md). For example, `CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE=512` would allow your macro to type about 256 characters.
Another limit worth noting is that the maximum number of bindings you can pass to a `bindings` field in the [Devicetree](../../config/index.md#devicetree-files) is 256, which also constrains how many behaviors can be invoked by a macro.
## Parameterized Macros
Macros can also be "parameterized", allowing them to be bound in your keymap with unique values passed into them, e.g.:
```dts
raise_layer {
bindings = <&my_one_param_macro A>
};
```
### Defining Parameterized Macros
Parameterized macros must be defined using specific values for the `compatible` and `#binding-cells` properties, depending on how many parameters they require (up to a maximum of two):
```dts
/ {
macros {
// 0 params macro
my_macro: my_macro {
// ...
compatible = "zmk,behavior-macro";
#binding-cells = <0>; // Must be 0
bindings = /* ... */;
};
// 1 param macro
my_one_param_macro: my_one_param_macro {
// ...
compatible = "zmk,behavior-macro-one-param";
#binding-cells = <1>; // Must be 1
bindings = /* ... */;
};
// 2 params macro
my_two_param_macro: my_two_param_macro {
// ...
compatible = "zmk,behavior-macro-two-param";
#binding-cells = <2>; // Must be 2
bindings = /* ... */;
};
};
};
```
### Parameters, Bindings and Controls
There are special macro controls which must be used in order to forward received parameters to the macro's `bindings`. These controls are "one shot" and will determine how received parameters are used on the very next (non-macro control) behavior in the macro's `bindings` list.
For example, to pass the first parameter received into a `&kp` binding, you would use:
```dts
bindings = <&macro_param_1to1>, <&kp MACRO_PLACEHOLDER>;
```
Because `kp` takes one parameter, you can't simply make the second entry `<&kp>` in the `bindings` list. Whatever value you do pass in will be replaced when the macro is triggered, so you can put _any_ value there, e.g. `0`, `A` keycode, etc. To make it very obvious that the parameter there is not actually going to be used, you can use `MACRO_PLACEHOLDER` which is simply an alias for `0`.
The available parameter controls are:
- `&macro_param_1to1` - pass the first parameter of the macro into the first parameter of the next behavior in the `bindings` list.
- `&macro_param_1to2` - pass the first parameter of the macro into the second parameter of the next behavior in the `bindings` list.
* `&macro_param_2to1` - pass the second parameter of the macro into the first parameter of the next behavior in the `bindings` list.
* `&macro_param_2to2` - pass the second parameter of the macro into the second parameter of the next behavior in the `bindings` list.
## Common Patterns
Below are some examples of how the macro behavior can be used for various useful functionality.
### Layer Activation + More
Macros make it easy to combine a [layer behavior](layers.md), e.g. `&mo` with another behavior at the same time.
Common examples are enabling one or more modifiers when the layer is active, or changing the RBG underglow color.
To achieve this, a combination of a 0ms wait time and splitting the press and release between a `&macro_pause_for_release` is used:
#### Layer + modifier
```dts
/**
* Temporarily switches to a layer (`&mo`) while a modifier is held.
* Analogous to QMK's `LM()`, using a parameterized macro.
*
* Params:
* 1. Layer to switch to
* 2. Modifier to press while layer is active
*
* Example:
* `&lm NUM_LAYER LSHIFT`
*/
lm: lm {
compatible = "zmk,behavior-macro-two-param";
wait-ms = <0>;
tap-ms = <0>;
#binding-cells = <2>;
bindings
= <&macro_param_1to1>
, <&macro_press &mo MACRO_PLACEHOLDER>
, <&macro_param_2to1>
, <&macro_press &kp MACRO_PLACEHOLDER>
, <&macro_pause_for_release>
, <&macro_param_2to1>
, <&macro_release &kp MACRO_PLACEHOLDER>
, <&macro_param_1to1>
, <&macro_release &mo MACRO_PLACEHOLDER>
;
};
```
#### Layer + underglow color
To trigger a different underglow when the macro is pressed, and when it is released, we use the macro "press" activation mode whenever triggering the `&rgb_ug` behavior:
```dts
wait-ms = <0>;
tap-ms = <0>;
bindings
= <&macro_press &mo 1>
, <&macro_tap &rgb_ug RGB_COLOR_HSB(128,100,100)>
, <&macro_pause_for_release>
, <&macro_release &mo 1>
, <&macro_tap &rgb_ug RGB_COLOR_HSB(300,100,50)>;
```
### Keycode Sequences
The other common use case for macros is to sending sequences of keycodes to the connected host. Here, a wait and tap time of at least 30ms is recommended to
avoid having HID notifications grouped at the BLE protocol level and then processed out of order:
```dts
wait-ms = <40>;
tap-ms = <40>;
bindings
= <&kp Z &kp M &kp K>
, <&kp SPACE>
, <&kp R &kp O &kp C &kp K &kp S>
;
```
### Unicode Sequences
Many operating systems allow a special sequence to input unicode characters, e.g. [Windows alt codes](https://support.microsoft.com/en-us/office/insert-ascii-or-unicode-latin-based-symbols-and-characters-d13f58d3-7bcb-44a7-a4d5-972ee12e50e0). You can use macros to automate inputting the sequences, e.g. below macro inserts `£` on Windows:
```dts
wait-ms = <40>;
tap-ms = <40>;
bindings
= <&macro_press &kp LALT>
, <&macro_tap &kp KP_N0 &kp KP_N1 &kp KP_N6 &kp KP_N3>
, <&macro_release &kp LALT>
;
```
## Convenience C Macro
To avoid repetition or possible typos when declaring a **zero parameter macro**, a convenience _C_ macro, named `ZMK_MACRO(name, props)` can be used to simplify things:
```dts
ZMK_MACRO(my_zero_param_macro,
wait-ms = <30>;
tap-ms = <40>;
bindings = <&kp Z &kp M &kp K>;
)
```
:::note
`ZMK_MACRO()` **only supports declaring non-parameterized (zero parameter) macros**; parameterized declarations are not currently supported.
:::
This can be used instead of a complete macro definition. During the firmware build process, the example above would produce the complete macro definition below:
```dts
my_zero_param_macro: my_zero_param_macro {
compatible = "zmk,behavior-macro";
#binding-cells = <0>;
wait-ms = <30>;
tap-ms = <40>;
bindings = <&kp Z &kp M &kp K>;
};
```
Using the C macro is entirely optional, and is provided only as a convenience.

View File

@@ -0,0 +1,42 @@
---
title: Miscellaneous Behaviors
sidebar_label: Miscellaneous
---
## Summary
There are a few miscellaneous behaviors that are helpful when working with layers in keymaps,
in particular, with handling what happens in higher layers, and if events are passed to
the next layer or not
## Transparent
The transparent behavior simply ignores key position presses/releases, so they will be
passed down to the next active layer in the stack.
### Behavior Binding
- Reference: `&trans`
- Parameters: None
Example:
```dts
&trans
```
## None
The none behavior simply swallows and stops key position presses/releases, so they will **not**
be passed down to the next active layer in the stack.
### Behavior Binding
- Reference: `&none`
- Parameters: None
Example:
```dts
&none
```

View File

@@ -0,0 +1,121 @@
---
title: Mod-Morph Behavior
sidebar_label: Mod-Morph
---
## Summary
The mod-morph behavior invokes a different behavior depending on whether any of the specified modifiers are being held during the key press.
- If you tap the key by itself, the first behavior binding is activated.
- If you tap the key while holding (any of) the specified modifier(s), the second behavior binding is activated.
## Mod-Morph
### Configuration
Below is an example of how to implement the mod-morph "Grave Escape". When assigned to a key, pressing the key on its own will send an
Escape keycode but pressing it while a shift or GUI modifier is held sends the grave `` ` `` keycode instead:
```dts
/ {
behaviors {
gresc: grave_escape {
compatible = "zmk,behavior-mod-morph";
#binding-cells = <0>;
bindings = <&kp ESC>, <&kp GRAVE>;
mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
};
};
};
```
Note that this specific mod-morph exists in ZMK by default using the binding `&gresc`.
### Behavior Binding
- Reference: `&gresc`
- Parameter: None
Example:
```dts
&gresc
```
### Mods
This is how you determine what modifiers will activate the morphed version of the keycode.
Available Modifiers:
- `MOD_LSFT`
- `MOD_RSFT`
- `MOD_LCTL`
- `MOD_RCTL`
- `MOD_LALT`
- `MOD_RALT`
- `MOD_LGUI`
- `MOD_RGUI`
Example:
```dts
mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
```
### Advanced Configuration
#### `keep-mods`
When a modifier specified in `mods` is being held, it won't be sent along with the morphed keycode unless it is also specified in `keep-mods`. By default `keep-mods` equals `0`, which means no modifier specified in `mods` will be sent along with the morphed keycode.
For example, the following configuration morphs `LEFT_SHIFT` + `BACKSPACE` into `DELETE`, and morphs `RIGHT_SHIFT` + `BACKSPACE` into `RIGHT_SHIFT` + `DELETE`.
```dts
/ {
behaviors {
bspc_del: backspace_delete {
compatible = "zmk,behavior-mod-morph";
#binding-cells = <0>;
bindings = <&kp BACKSPACE>, <&kp DELETE>;
mods = <(MOD_LSFT|MOD_RSFT)>;
keep-mods = <(MOD_RSFT)>;
};
};
};
```
#### Trigger conditions with multiple modifiers
Any modifier used in the `mods` property will activate a mod-morph; it isn't possible to require that multiple modifiers are held _together_ in order to activate it.
However, you can nest multiple mod-morph behaviors to achieve more complex decision logic, where you use one (or two) mod-morph behaviors in the `bindings` fields of another mod-morph.
As an example, consider the following two mod-morphs:
```dts
/ {
behaviors {
morph_BC: morph_BC {
compatible = "zmk,behavior-mod-morph";
#binding-cells = <0>;
bindings = <&kp B>, <&kp C>;
mods = <(MOD_LCTL|MOD_RCTL)>;
};
morph_ABC: morph_ABC {
compatible = "zmk,behavior-mod-morph";
#binding-cells = <0>;
bindings = <&kp A>, <&morph_BC>;
mods = <(MOD_LSFT|MOD_RSFT)>;
};
};
};
```
When you assign `&morph_ABC` to a key position and press it, it will output `A` by default. If you press it while a shift modifier is held it will output `B`, and if you are also holding a control modifier it will output `C` instead.
:::note[Karabiner-Elements (macOS) interfering with mod-morphs]
If the first modified key press sends the modifier along with the morphed keycode and [Karabiner-Elements](https://karabiner-elements.pqrs.org/) is running, disable the "Modify Events" toggle from Karabiner's "Devices" settings page for the keyboard running ZMK.
:::

View File

@@ -0,0 +1,54 @@
---
title: Mod-Tap Behavior
sidebar_label: Mod-Tap
---
## Summary
The Mod-Tap behavior sends a different keypress, depending on whether it's held or tapped.
- If you hold the key for longer than 200ms, the first keycode ("mod") is sent.
- If you tap the key (release before 200ms), the second keycode ("tap") is sent.
If you press another key within the 200ms, the 'mod' behavior is also activated.
## Mod-Tap
The Mod-Tap behavior either acts as a held modifier, or as a tapped keycode.
### Behavior Binding
- Reference: `&mt`
- Parameter #1: The keycode to be sent when activating as a modifier, e.g. `LSHIFT`
- Parameter #2: The keycode to sent when used as a tap, e.g. `A`, `B`.
Example:
```dts
&mt LSHIFT A
```
### Configuration
You can configure a different tapping term in your keymap:
```dts
&mt {
tapping-term-ms = <400>;
};
/ {
keymap {
...
};
};
```
:::info
Under the hood, the mod-tap is simply a [hold-tap](hold-tap.mdx) of the ["hold-preferred" flavor](hold-tap.mdx#flavors) with a [`tapping-term-ms`](hold-tap.mdx#tapping-term-ms) of 200 that takes in two [keypresses](key-press.md) as its "hold" and "tap" parameters. This means that the mod-tap can be used to invoke **any** [keycode](../list-of-keycodes.mdx), and is not limited to only activating [modifier keys](../modifiers.mdx) when it is held.
For users who want to momentarily access a specific [layer](../index.mdx#layers) while a key is held and send a keycode when the same key is tapped, see [Layer-Tap](layers.md#layer-tap).
Similarly, for users looking to create a keybind like the mod-tap that invokes behaviors _other_ than [keypresses](key-press.md), like [sticky keys](sticky-key.md) or [key toggles](key-toggle.md), see [Hold-Tap](hold-tap.mdx).
:::

View File

@@ -0,0 +1,71 @@
---
title: Mouse Emulation Behaviors
sidebar_label: Mouse Emulation
---
## Summary
Mouse emulation behaviors send mouse events. Currently, only mouse button presses are supported, but movement
and scroll action support is planned for the future.
:::warning[Refreshing the HID descriptor]
Enabling or disabling the mouse emulation feature modifies the HID report descriptor and requires it to be [refreshed](../../features/bluetooth.md#refreshing-the-hid-descriptor).
The mouse functionality will not work over BLE until that is done.
:::
## Configuration Option
This feature can be enabled or disabled explicitly via a config option:
```
CONFIG_ZMK_MOUSE=y
```
If you use the mouse key press behavior in your keymap, the feature will automatically be enabled for you.
## Mouse Button Defines
To make it easier to encode the HID mouse button numeric values, include
the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header
provided by ZMK near the top:
```
#include <dt-bindings/zmk/mouse.h>
```
## Mouse Button Press
This behavior can press/release up to 5 mouse buttons.
### Behavior Binding
- Reference: `&mkp`
- Parameter: A `uint8` with bits 0 through 4 each referring to a button.
The following defines can be passed for the parameter:
| Define | Action |
| :------------ | :------------- |
| `MB1`, `LCLK` | Left click |
| `MB2`, `RCLK` | Right click |
| `MB3`, `MCLK` | Middle click |
| `MB4` | Mouse button 4 |
| `MB5` | Mouse button 5 |
Mouse buttons 4 and 5 typically map to "back" and "forward" actions in most applications.
### Examples
The following will send a left click press when the binding is triggered:
```
&mkp LCLK
```
This example will send press of the fourth mouse button when the binding is triggered:
```
&mkp MB4
```

View File

@@ -0,0 +1,70 @@
---
title: Output Selection Behavior
sidebar_label: Output Selection
---
## Summary
The output behavior allows selecting whether keyboard output is sent to the
USB or bluetooth connection when both are connected. This allows connecting a
keyboard to USB for power but outputting to a different device over bluetooth.
By default, output is sent to USB when both USB and BLE are connected.
Once you select a different output, it will be remembered until you change it again.
:::note[Powering the keyboard via USB]
ZMK is not always able to detect if the other end of a USB connection accepts keyboard input or not.
So if you are using USB only to power your keyboard (for example with a charger or a portable power bank), you will want
to select the BLE output through below behavior to be able to send keystrokes to the selected bluetooth profile.
:::
## Output Command Defines
Output command defines are provided through the [`dt-bindings/zmk/outputs.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/outputs.h)
header, which is added at the top of the keymap file:
```dts
#include <dt-bindings/zmk/outputs.h>
```
This allows you to reference the actions defined in this header:
| Define | Action |
| --------- | ----------------------------------------------- |
| `OUT_USB` | Prefer sending to USB |
| `OUT_BLE` | Prefer sending to the current bluetooth profile |
| `OUT_TOG` | Toggle between USB and BLE |
## Output Selection Behavior
The output selection behavior changes the preferred output on press.
### Behavior Binding
- Reference: `&out`
- Parameter #1: Command, e.g. `OUT_BLE`
:::note[Output selection persistence]
The endpoint that is selected by the `&out` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
:::
### Examples
1. Behavior binding to prefer sending keyboard output to USB
```dts
&out OUT_USB
```
1. Behavior binding to prefer sending keyboard output to the current bluetooth profile
```dts
&out OUT_BLE
```
1. Behavior binding to toggle between preferring USB and BLE
```dts
&out OUT_TOG
```

View File

@@ -0,0 +1,73 @@
---
title: Power Management Behaviors
sidebar_label: Power Management
---
## Summary
These page contains some of the power management behaviors currently supported by ZMK.
## External Power Control
The External power control behavior allows enabling or disabling the VCC power output
to save power. Some of the LEDs will consume power even in OFF state. To preserve
battery life in this scenario, some controller boards have support to disable the
external power completely.
The following boards currently support this feature:
- nRFMicro
- nice!nano
## External Power Control Command Defines
External power control command defines are provided through the [`dt-bindings/zmk/ext_power.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/ext_power.h) header,
which is added at the top of the keymap file:
```dts
#include <dt-bindings/zmk/ext_power.h>
```
This will allow you to reference the actions defined in this header such as `EXT_POWER_OFF_CMD`.
Here is a table describing the command for each define:
| Define | Action | Alias |
| ---------------------- | --------------------------- | -------- |
| `EXT_POWER_OFF_CMD` | Disable the external power. | `EP_OFF` |
| `EXT_POWER_ON_CMD` | Enable the external power. | `EP_ON` |
| `EXT_POWER_TOGGLE_CMD` | Toggle the external power. | `EP_TOG` |
### Behavior Binding
- Reference: `&ext_power`
- Parameter#1: Command, e.g `EP_ON`
:::note[External power state persistence]
The on/off state that is set by the `&ext_power` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
:::
### Example:
1. Behavior binding to enable the external power
```dts
&ext_power EP_ON
```
1. Behavior binding to disable the external power
```dts
&ext_power EP_OFF
```
1. Behavior binding to toggle the external power
```dts
&ext_power EP_TOG
```
## Split Keyboards
Power management behaviors are [global](../../features/split-keyboards.md#global-locality-behaviors): This means that when triggered, they affects both the central and peripheral side of split keyboards.

View File

@@ -0,0 +1,47 @@
---
title: Reset Behaviors
sidebar_label: Reset
---
## Summary
There are two available behaviors that can be used to trigger a reset of the keyboard.
The first is a soft reset, that will simply reset and re-run the currently flashed
firmware; the second when triggered will reset into the bootloader, allowing you to
flash a new firmware to the keyboard.
## Reset
The basic reset behavior will reset the keyboard and re-run the firmware flashed
to the device
### Behavior Binding
- Reference: `&sys_reset`
- Parameters: None
Example:
```dts
&sys_reset
```
## Bootloader Reset
The bootloader reset behavior will reset the keyboard and put it into bootloader mode, allowing
you to flash a new firmware.
### Behavior Binding
- Reference: `&bootloader`
- Parameters: None
Example:
```dts
&bootloader
```
## Split Keyboards
Both basic and bootloader reset behaviors are [source-specific](../../features/split-keyboards.md#source-locality-behaviors): This means that it affects the side of the keyboard that contains the behavior binding for split keyboards. For example if you press a key with the `&sys_reset` binding on the left half of the keyboard, the left half will be reset. If you want to be able to reset both sides you can put the bindings on both sides of the keyboard and activate it on the side you would like to reset.

View File

@@ -0,0 +1,75 @@
---
title: Sensor Rotation
sidebar_label: Sensor Rotation
---
## Summary
The Sensor Rotation behavior triggers a different behavior, depending on whether the sensor is rotated clockwise or counter-clockwise. Two variants of this behavior are available, allowing either fully specifying the
two behaviors and their parameters together, or allowing binding the sensor rotation with different clockwise and counterclockwise parameters in the keymap itself.
## Sensor Rotation
The standard sensor rotation behavior allows fully binding behaviors to be invoked:
- If rotated clockwise, the first bound behavior is triggered.
- If rotated counter-clockwise, the second bound behavior is triggered.
### Configuration
Here is an example that binds the [RGB Underglow Behavior](underglow.md) to change the RGB brightness:
```dts
/ {
behaviors {
rgb_encoder: rgb_encoder {
compatible = "zmk,behavior-sensor-rotate";
#sensor-binding-cells = <0>;
bindings = <&rgb_ug RGB_BRI>, <&rgb_ug RGB_BRD>;
};
};
keymap {
compatible = "zmk,keymap";
base {
...
sensor-bindings = <&rgb_encoder>;
}
};
};
```
## Variable Sensor Rotation
The variable sensor rotation behavior is configured with two behaviors that each expect a single parameter,
allowing the sensor rotation instance to be bound with two parameters at usage time.
- If rotated clockwise, the first bound behavior is triggered with the first parameter passed to the sensor rotation.
- If rotated counter-clockwise, the second bound behavior is triggered with the second parameter passed to the sensor rotation.
### Configuration
Here is an example, showing how send key presses on rotation:
First, defining the sensor rotation itself, binding the [Key Press Behavior](key-press.md) twice, then binding it in the `sensor-bindings` property of a keymap layer:
```dts
/ {
behaviors {
rot_kp: sensor_rotate_kp {
compatible = "zmk,behavior-sensor-rotate-var";
#sensor-binding-cells = <2>;
bindings = <&kp>, <&kp>;
};
};
keymap {
compatible = "zmk,keymap";
base {
...
sensor-bindings = <&rot_kp PG_UP PG_DN>;
}
}
};
```

View File

@@ -0,0 +1,40 @@
---
title: Soft Off Behavior
sidebar_label: Soft Off
---
## Summary
The soft off behavior is used to force the keyboard into an off state. Depending on the specific keyboard hardware, the keyboard can be turned back on again either with a dedicated on/off button that is available, or using the reset button found on the device.
Refer to the [soft off config](../../config/power.md#soft-off) for details on enabling soft off in order to use this behavior.
For more information, see the [Soft Off Feature](../../features/soft-off.md) page.
### Behavior Binding
- Reference: `&soft_off`
Example:
```
&soft_off
```
### Configuration
#### Hold time
By default, the keyboard will be turned off as soon as the key bound to the behavior is released, even if the key is only tapped briefly. If you would prefer that the key need be held a certain amount of time before releasing, you can set the `hold-time-ms` to a non-zero value in your keymap:
```
&soft_off {
hold-time-ms = <5000>; // Only turn off it the key is held for 5 seconds or longer.
};
/ {
keymap {
...
};
};
```

View File

@@ -0,0 +1,90 @@
---
title: Sticky Key Behavior
sidebar_label: Sticky Key
---
## Summary
A sticky key stays pressed until another key is pressed. It is often used for 'sticky shift'. By using a sticky shift, you don't have to hold the shift key to write a capital.
### Behavior Binding
- Reference: `&sk`
- Parameter #1: The keycode , e.g. `LSHIFT`
Example:
```dts
&sk LSHIFT
```
You can use any keycode that works for `&kp` as parameter to `&sk`:
```dts
&sk LG(LS(LA(LCTRL)))
```
### Configuration
#### `release-after-ms`
By default, sticky keys stay pressed for a second if you don't press any other key. You can configure this with the `release-after-ms` setting.
#### `quick-release`
Some typists may find that using a sticky shift key interspersed with rapid typing results in two or more capitalized letters instead of one. This happens as the sticky key is active until the next key is released, under which other keys may be pressed and will receive the modifier. You can enable the `quick-release` setting to instead deactivate the sticky key on the next key being pressed, as opposed to released.
#### `lazy`
By default, sticky keys are activated on press until another key is pressed. You can enable the `lazy` setting to instead activate the sticky key right _before_ the other key is pressed. This is useful for mouse interaction or situations where you don't want the host to see anything during a sticky-key timeout, for example `&sk LGUI`, which can trigger a menu if pressed alone.
Note that tapping a lazy sticky key will not trigger other behaviors such as the release of other sticky keys or layers. If you want to use a lazy sticky key to activate the release of a sticky layer, potential solutions include wrappping the sticky key in a simple macro which presses the sticky behavior around the sticky key press, doing the same with `&mo LAYER`, or triggering a tap of some key like `K_CANCEL` on sticky key press.
#### `ignore-modifiers`
This setting is enabled by default. It ensures that if a sticky key modifier is pressed before a previously pressed sticky key is released, the modifiers will get combined so you can add more sticky keys or press a regular key to apply the modifiers. This is to accommodate _callum-style mods_ where you are prone to rolling sticky keys. If you want sticky key modifiers to only chain after release, you can disable this setting. Please note that activating multiple modifiers via [modifier functions](../modifiers.mdx#modifier-functions) such as `&sk LS(LALT)`, require `ignore-modifiers` enabled in order to function properly.0
#### Example
```dts
&sk {
release-after-ms = <2000>;
quick-release;
/delete-property/ ignore-modifiers;
};
/ {
keymap {
...
};
};
```
This configuration would apply to all sticky keys. This may not be appropriate if using `quick-release` as you'll lose the ability to chain sticky key modifiers. A better approach for this use case would be to create a new behavior:
```dts
/ {
behaviors {
skq: sticky_key_quick_release {
compatible = "zmk,behavior-sticky-key";
#binding-cells = <1>;
bindings = <&kp>;
release-after-ms = <1000>;
quick-release;
ignore-modifiers;
};
};
keymap {
...
};
};
```
### Advanced Usage
Sticky keys can be combined; if you tap `&sk LCTRL` and then `&sk LSHIFT` and then `&kp A`, the output will be ctrl+shift+a.
### Comparison to QMK
In QMK, sticky keys are known as 'one shot mods'.

View File

@@ -0,0 +1,45 @@
---
title: Sticky Layer Behavior
sidebar_label: Sticky Layer
---
## Summary
A sticky layer stays pressed until another key is pressed. By using a sticky layer, you don't have to hold the layer key to access a layer. Instead, tap the sticky layer key to activate the layer until the next keypress.
By default, sticky layers stay pressed for a second if you don't press any other key. You can configure this with the `release-after-ms` setting (see below).
### Behavior Binding
- Reference: `&sl`
- Parameter #1: The layer to activate , e.g. `1`
Example:
```dts
&sl 1
```
### Configuration
You can configure a different `release-after-ms` in your keymap:
```dts
&sl {
release-after-ms = <2000>;
};
/ {
keymap {
...
};
};
```
### Advanced Usage
Sticky layers behave slightly different from sticky keys. They are configured to `quick-release`. This means that the layer is released immediately when another key is pressed. "Normal" sticky keys are not `quick-release`; they are released when the next key is released. This makes it possible to combine sticky layers and sticky keys as such: tap `&sl 1`, tap `&sk LSHIFT` on layer 1, tap `&kp A` on base layer to output shift+A.
### Comparison to QMK
In QMK, sticky layers are known as 'one shot layers'.

View File

@@ -0,0 +1,107 @@
---
title: Tap-Dance Behavior
sidebar_label: Tap-Dance
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
## Summary
A tap-dance key invokes a different behavior (e.g. `kp`) corresponding to how many times it is pressed. For example, you could configure a tap-dance key that acts as `LSHIFT` if tapped once, or Caps _Lock_ if tapped twice. The expandability of the number of [`bindings`](#bindings) attached to a particular tap-dance is a great way to add more functionality to a single key, especially for keyboards with a limited number of keys. Tap-dances are completely custom, so for every unique tap-dance key,a new tap-dance must be defined in your keymap's `behaviors`.
Tap-dances are designed to resolve immediately when interrupted by another keypress. Meaning, when a keybind is pressed other than any active tap-dances, the tap-dance will activate according to the current value of its counter before the interrupting keybind is registered.
### Configuration
#### `tapping-term-ms`
Defines the maximum elapsed time after the last tap-dance keybind press before a binding is selected from [`bindings`](#bindings). Default value is `200`ms.
#### `bindings`
An array of one or more keybinds. This list can include [any ZMK keycode](../list-of-keycodes.mdx) and any listed ZMK behavior, like [hold-taps](hold-tap.mdx), or [sticky keys](sticky-key.md). The index of a keybind in the `bindings` array corresponds to the number of times the tap-dance binding is pressed. For example, in the [basic tap-dance counter](#basic-example-counter) shown below, `&kp N2` is the second binding in the array of `bindings`: we then see an output of `2` when the `td0` binding is pressed twice.
The number of bindings in this array also determines the tap-dance's maximum number of keypresses. When a tap-dance reaches its maximum number of keypresses, it will immediately invoke the last behavior in its list of `bindings`, rather than waiting for [`tapping-term-ms`](#tapping-term-ms) to expire before the output is displayed.
### Example Usage
<Tabs
defaultValue="basic"
values={[
{label: 'Basic Example: Counter', value: 'basic'},
{label: 'Advanced Example: Mod-Tap Nested inside Tap-Dance', value: 'advanced'},
]}>
<TabItem value="basic">
This example configures a tap-dance named `td0` that outputs the number of times its binding is pressed from 1-3.
```dts title="Basic Tap-Dance Example: Counter"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
td0: tap_dance_0 {
compatible = "zmk,behavior-tap-dance";
#binding-cells = <0>;
tapping-term-ms = <200>;
bindings = <&kp N1>, <&kp N2>, <&kp N3>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&td0
>;
};
};
};
```
The following image describes the behavior of this particular tap-dance.
![Timing Diagram](../../assets/tap-dance/timing_diagram.svg)
:::note
Alphanumeric [`key press`](key-press.md) bindings, like those used for `td0`, will release as soon as an interrupting key press occurs. For instance, if a modifier key like `LSHIFT` were to replace the `N1` binding in the last example above, it would remain pressed until `td0`'s binding is released and the output would instead be `J`. Any following alphanumeric key presses would be capitalized as long as `td0` is held down.
:::
</TabItem>
<TabItem value="advanced">
This example configures a mod-tap inside a tap-dance named `td_mt` that outputs `CAPSLOCK` on a single tap, `LSHIFT` on a single press and hold, and `LCTRL` when the tap-dance is pressed twice.
```dts title="Advanced Tap-Dance Example: Nested Mod-Tap"
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
behaviors {
td_mt: tap_dance_mod_tap {
compatible = "zmk,behavior-tap-dance";
#binding-cells = <0>;
tapping-term-ms = <200>;
bindings = <&mt LSHIFT CAPSLOCK>, <&kp LCTRL>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&td_mt
>;
};
};
};
```
</TabItem>
</Tabs>

View File

@@ -0,0 +1,80 @@
---
title: RGB Underglow Behavior
sidebar_label: RGB Underglow
---
## Summary
This page contains [RGB Underglow](../../features/underglow.md) behaviors supported by ZMK.
## RGB Action Defines
RGB actions defines are provided through the [`dt-bindings/zmk/rgb.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/rgb.h) header,
which is added at the top of the keymap file:
```dts
#include <dt-bindings/zmk/rgb.h>
```
This will allow you to reference the actions defined in this header such as `RGB_TOG`.
Here is a table describing the action for each define:
| Define | Action |
| --------------- | ---------------------------------------------------------------------------------------------- |
| `RGB_ON` | Turns the RGB feature on |
| `RGB_OFF` | Turns the RGB feature off |
| `RGB_TOG` | Toggles the RGB feature on and off |
| `RGB_HUI` | Increases the hue of the RGB feature |
| `RGB_HUD` | Decreases the hue of the RGB feature |
| `RGB_SAI` | Increases the saturation of the RGB feature |
| `RGB_SAD` | Decreases the saturation of the RGB feature |
| `RGB_BRI` | Increases the brightness of the RGB feature |
| `RGB_BRD` | Decreases the brightness of the RGB feature |
| `RGB_SPI` | Increases the speed of the RGB feature effect's animation |
| `RGB_SPD` | Decreases the speed of the RGB feature effect's animation |
| `RGB_EFF` | Cycles the RGB feature's effect forwards |
| `RGB_EFR` | Cycles the RGB feature's effect reverse |
| `RGB_COLOR_HSB` | Sets a specific [HSB (HSV)](https://en.wikipedia.org/wiki/HSL_and_HSV) value for the underglow |
## Behavior Binding
- Reference: `&rgb_ug`
- Parameter #1: The RGB action define, e.g. `RGB_TOG` or `RGB_BRI`
- Parameter #2: Only applies to `RGB_COLOR_HSB` and is the HSB representation of the color to set (see below for an example)
:::note[HSB Values]
When specifying HSB values you'll need to use `RGB_COLOR_HSB(h, s, b)` in your keymap file.
Value Limits:
- Hue values can _not_ exceed 360 (degrees)
- Saturation values can _not_ exceed 100 (percent)
- Brightness values can _not_ exceed 100 (percent)
:::
:::note[RGB settings persistence]
The RGB settings that are changed via the `&rgb_ug` behavior will be saved to flash storage and hence persist across restarts and firmware flashes.
They will also override the start values set by [`CONFIG_ZMK_RGB_*_START` settings](../../config/underglow.md#kconfig).
However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../../config/system.md#general) milliseconds in order to reduce potential wear on the flash memory.
:::
## Examples
1. Toggle underglow on/off
```dts
&rgb_ug RGB_TOG
```
1. Set a specific HSB color (green)
```dts
&rgb_ug RGB_COLOR_HSB(128,100,100)
```
## Split Keyboards
RGB underglow behaviors are [global](../../features/split-keyboards.md#global-locality-behaviors): This means that when triggered, they affect both the central and peripheral side of split keyboards.

View File

@@ -0,0 +1,51 @@
---
title: Combos
---
## Summary
Combo keys are a way to combine multiple keypresses to output a different key. For example, you can hit the Q and W keys on your keyboard to output escape.
### Configuration
Combos configured in your `.keymap` file, but are separate from the `keymap` node found there, since they are processed before the normal keymap. They are specified like this:
```dts
/ {
combos {
compatible = "zmk,combos";
combo_esc {
timeout-ms = <50>;
key-positions = <0 1>;
bindings = <&kp ESC>;
};
};
};
```
- The name of the combo doesn't really matter, but convention is to start the node name with `combo_`.
- The `compatible` property should always be `"zmk,combos"` for combos.
- All the keys in `key-positions` must be pressed within `timeout-ms` milliseconds to trigger the combo.
- `key-positions` is an array of key positions. See the info section below about how to figure out the positions on your board.
- `layers = <0 1...>` will allow limiting a combo to specific layers. This is an _optional_ parameter, when omitted it defaults to global scope.
- `bindings` is the behavior that is activated when the behavior is pressed.
- (advanced) you can specify `slow-release` if you want the combo binding to be released when all key-positions are released. The default is to release the combo as soon as any of the keys in the combo is released.
- (advanced) you can specify a `require-prior-idle-ms` value much like for [hold-taps](behaviors/hold-tap.mdx#require-prior-idle-ms). If any non-modifier key is pressed within `require-prior-idle-ms` before a key in the combo, the combo will not trigger.
:::info
Key positions are numbered like the keys in your keymap, starting at 0. So, if the first key in your keymap is `Q`, this key is in position `0`. The next key (possibly `W`) will have position 1, etcetera.
:::
### Advanced Usage
- Partially overlapping combos like `0 1` and `0 2` are supported.
- Fully overlapping combos like `0 1` and `0 1 2` are supported.
- You are not limited to `&kp` bindings. You can use all ZMK behaviors there, like `&mo`, `&bt`, `&mt`, `&lt` etc.
:::note[Source-specific behaviors on split keyboards]
Invoking a [source-specific behavior](../features/split-keyboards.md#source-locality-behaviors) such as one of the [reset behaviors](behaviors/reset.md) using a combo will always trigger it on the central side of the keyboard, regardless of the side that the keys corresponding to `key-positions` are on.
:::
See [combo configuration](../config/combos.md) for advanced configuration options.

View File

@@ -0,0 +1,56 @@
---
title: Conditional Layers
---
Conditional layers support activating a particular layer (called the `then-layer`) when all layers
in a specified set (called the `if-layers`) are active. This feature generalizes what's commonly
known as tri-layer support, allowing activation of two layers (usually called "lower" and "raise")
to trigger a third (usually called "adjust").
Another way to think of this feature is as a simple combo system for layers, just like the usual
[combos for behaviors](combos.md).
## Configuration
Conditional layers are configured via a `conditional_layers` node in your `.keymap` file as follows:
```dts
/ {
conditional_layers {
compatible = "zmk,conditional-layers";
tri_layer {
if-layers = <1 2>;
then-layer = <3>;
};
};
};
```
Each conditional layer configuration may have whatever name you like, but it's helpful to choose
something self explanatory like `tri_layer`. The following properties are supported:
- `if-layers` specifies a set of layer numbers, all of which must be active for the conditional
layer to trigger.
- `then-layer` specifies a layer number that should be activated if and only if all the layers
specified in the `if-layers` property are active.
Therefore, in this example, layer 3 ("adjust") will be activated if and only if both layers 1
("lower") and 2 ("raise") are active.
:::tip
Since higher-numbered layers are processed first, a `then-layer` should generally have a higher
number than its associated `if-layers` so the `then-layer` can be accessed when active.
:::
:::info
Activating a `then-layer` in one conditional layer configuration can trigger the `if-layers`
condition in another configuration, possibly repeatedly.
:::
:::warning
When configured as a `then-layer`, a layer's activation status is entirely controlled by the
conditional layers feature. Even if the layer is activated for another reason (such as a
[momentary layer](behaviors/layers.md#momentary-layer) behavior), it will be immediately
deactivated if the associated `then-layers` configuration is not met. As such, we recommend
avoiding using regular layer behaviors for `then-layer` targets.
:::

171
docs/docs/keymaps/index.mdx Normal file
View File

@@ -0,0 +1,171 @@
---
title: Keymaps & Behaviors
sidebar_label: Keymaps
---
import KeymapExample from "../keymap-example.md";
ZMK uses a declarative approach to keymaps instead of using C code for all keymap configuration.
Right now, ZMK uses the devicetree syntax to declare those keymaps; future work is envisioned for
supporting dynamic loading of declarative keymaps, e.g. over USB Mass Storage or via a custom BLE
service.
:::note
For advanced users looking to implement custom behaviors for their keymaps, this will be possible
in the future by allowing user configs to add to the CMake application built by Zephyr.
:::
## Big Picture
All keyboard definitions (complete boards or shields) include the _default_ keymap for that keyboard,
so ZMK can produce a "stock" firmware for that keyboard without any further modifications. For users
looking to customize their keyboard's behavior, they can copy the stock `.keymap` file into their
user config directory, and customize the keymap to their liking.
## Behaviors
ZMK implements the concept of "behaviors", which can be bound to a certain key position, sensor (encoder),
or layer, to perform certain actions when events occur for that binding (e.g. when a certain key position
is pressed or released, or an encoder triggers a rotation event).
For example, the simplest behavior in ZMK is the "key press" behavior, which responds to key position
(a certain spot on the keyboard), and when that position is pressed, send a keycode to the host, and
when the key position is released, updates the host to notify of the keycode being released.
For the full set of possible behaviors, see the [overview page for behaviors](behaviors/index.mdx).
## Layers
Like many mechanical keyboard firmwares, ZMK keymaps are composed of a collection of layers, with a
minimum of at least one layer that is the default, usually near the bottom of the "layer stack". Each layer
in ZMK contains a set of bindings that bind a certain behavior to a certain key position in that layer.
| ![Diagram of three layers](../assets/features/keymaps/layer-diagram.png) |
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| _A simplified diagram showing three layers. The layout of each layer is the same (they all contain four keys), but the behavior bindings within each layer can be different._ |
All layers are assigned and referred to by a natural number, with the base layer being layer `0`. It is common to [use the C preprocessor to "name" layers](behaviors/layers.md#defines-to-refer-to-layers), making them more legible.
The default layer (the base layer with index 0) is always enabled. Certain bound behaviors may enable/disable additional layers.
When a key location is pressed/released, the _highest-valued currently active_ layer is used. The press/release event is sent to the behavior bound at that position in said layer, for it to perform whatever actions it wants to in reaction to the event. The behavior can choose to "consume" the event, or "pass it along" and let the next highest-valued active layer _also_ get the event (whose behavior may continue "passing it along").
Note that the _activation_ order isn't relevant for determining the priority of active layers, it is determined _only_ by the definition order.
:::tip
If you wish to use multiple base layers (with a [toggle](behaviors/layers.md#toggle-layer)), e.g. one for QWERTY and another for Colemak layouts, you will want these layers to have the lowest value possible. In other words, one should be layer `0`, and the other should be layer `1`. This allows other momentary layers activated on top of them to work with both.
:::
## Behavior Bindings
Binding a behavior at a certain key position may include up to two extra parameters that are used to
alter the behavior when that specific key position is activated/deactivated. For example, when binding
the "key press" (`kp`) behavior at a certain key position, you must specify _which_ keycode should
be used for that key position.
```dts
&kp A
```
In this case, the `A` is actually a define for the raw HID keycode, to make keymaps easier to read and write.
For example of a binding that uses two parameters, you can see how "mod-tap" (`mt`) is bound:
```dts
&mt LSHIFT D
```
Here, the first parameter is the set of modifiers that should be used for the "hold" behavior, and the second
parameter is the keycode that should be sent when triggering the "tap" behavior.
## Keymap File
A keymap file is composed of several sections, that together make up a valid devicetree file for describing the keymap and its layers.
### Includes
The devicetree files are actually preprocessed before being finally leveraged by Zephyr. This allows using standard C defines to create meaningful placeholders
for what would otherwise be cryptic integer keycodes, etc. This also allows bringing in _other_ devicetree nodes from separate files.
The top two lines of most keymaps should include:
```dts
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
```
The first defines the nodes for all the available behaviors in ZMK, which will be referenced in the behavior bindings. This is how bindings like `&kp` can reference the key press behavior defined with an anchor name of `kp`.
The second include brings in the defines for all the keycodes (e.g. `A`, `N1`, `C_PLAY`) and the modifiers (e.g. `LSHIFT`) used for various behavior bindings.
### Root Devicetree Node
All the remaining keymap nodes will be nested inside of the root devicetree node, like so:
```dts
/ {
// Everything else goes here!
};
```
### Keymap Node
Nested under the devicetree root, is the keymap node. The node _name_ itself is not critical, but the node **MUST** have a property
`compatible = "zmk,keymap"` in order to be used by ZMK.
```dts
keymap {
compatible = "zmk,keymap";
// Layer nodes go here!
};
```
### Layers
Each layer of your keymap will be nested under the keymap node. Here is an example of a layer in a 6-key macropad.
```dts
keymap {
compatible = "zmk,keymap";
default_layer { // Layer 0
// ----------------------------------------------
// | Z | M | K |
// | A | B | C |
bindings = <
&kp Z &kp M &kp K
&kp A &kp B &kp C
>;
};
};
```
Each layer should have:
1. A `bindings` property this will be a list of [behavior bindings](behaviors/index.mdx), one for each key position for the keyboard.
1. (Optional) A `sensor-bindings` property that will be a list of behavior bindings for each sensor on the keyboard. (Currently, only encoders are supported as sensor hardware, but in the future devices like trackpoints would be supported the same way)
### Multiple Layers
Layers are numbered in the order that they appear in keymap node - the first layer is `0`, the second layer is `1`, etc.
Here is an example of a trio of layers for a simple 6-key macropad:
<KeymapExample />
:::note
Even if layer `1` was to be activated after `2`, layer `2` would still have priority as it is higher valued. Behaviors such as [To Layer (`&to`)](behaviors/layers.md#to-layer) can be used to enable one layer _and disable all other non-default layers_, though.
:::
### Complete Example
Some examples of complete keymaps for a keyboard are:
- [`corne.keymap`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/corne/corne.keymap)
- [`kyria.keymap`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/kyria.keymap)
- [`lily58.keymap`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/lily58/lily58.keymap)
:::tip
Every keyboard comes with a "default keymap". For additional examples, the [ZMK tree's `app/boards` folder](https://github.com/zmkfirmware/zmk/blob/main/app/boards) can be browsed.
:::

View File

@@ -0,0 +1,137 @@
---
title: List of Keycodes
sidebar_label: List of Keycodes
---
import OsLegend from "@site/src/components/codes/OsLegend";
import ToastyContainer from "@site/src/components/codes/ToastyContainer";
import Table from "@site/src/components/codes/Table";
This is the reference page for keycodes used by behaviors. Use the table of contents (on the right or the top) for easy navigation.
:::warning
Take extra notice of the spelling of the keycodes, especially the shorthand spelling.
Otherwise, it will result in an elusive parsing error!
:::
:::info[Keyboard vs. Consumer keycodes]
In the below tables, there are keycode pairs with similar names where one variant has a `K_` prefix and another `C_`.
These variants correspond to similarly named usages from different [HID usage pages](https://usb.org/sites/default/files/hut1_2.pdf#page=16),
namely the "keyboard/keypad" and "consumer" ones respectively.
In practice, some OS and applications might listen to only one of the variants.
You can use the values in the compatibility columns below to assist you in selecting which one to use.
:::
<OsLegend />
<ToastyContainer />
## Keyboard
### Letters
<Table group="keyboard-letters" />
### Numbers
<Table group="keyboard-numbers" />
### Symbols / Punctuation
<Table group="keyboard-symbols" />
### Control & Whitespace
<Table group="keyboard-control-whitespace" />
### Navigation
<Table group="keyboard-navigation" />
### Locks
<Table group="keyboard-locks" />
### F Keys
<Table group="keyboard-fkeys" />
### International
<Table group="keyboard-international" />
### Language
<Table group="keyboard-language" />
### Miscellaneous
<Table group="keyboard-miscellaneous" />
## Modifiers
The [Modifiers](modifiers.mdx) page includes further information.
<Table group="keyboard-modifiers" />
## Keypad
<Table group="keypad" />
### Numbers
<Table group="keypad-numbers" />
### Symbols / Operations
<Table group="keypad-operations" />
## Editing
### Cut, Copy, Paste
<Table group="cut-copy-paste" />
### Undo, Redo
<Table group="undo-redo" />
## Media
### Sound / Volume
<Table group="sound" />
### Display
<Table group="display" />
### Media Controls
<Table group="media-controls" />
### Consumer Menus
<Table group="consumer-menus" />
### Consumer Controls
<Table group="consumer-controls" />
## Applications
### Application Controls
<Table group="application-controls" />
### Applications (Launch)
<Table group="applications" />
## Input Assist
<Table group="input-assist" />
## Power & Lock
<Table group="power" />

View File

@@ -0,0 +1,32 @@
---
title: Modifiers
sidebar_label: Modifiers
---
Modifiers are the special keyboard keys: _shift_, _alt_, _control_ & _GUI_. Their keycodes can be found in the [list of keycodes](./list-of-keycodes.mdx#modifiers).
Modifiers can be used both as [keys](#modifier-keys) and as [functions](#modifier-functions).
### Modifier Keys
These act like any other keycode.
- e.g. `&kp LEFT_GUI` pushes and releases the left GUI key.
### Modifier Functions
Modifier functions add one or more modifiers to a code.
These functions take the form: `XX(code)`
- Modifier functions apply a modifier to a code:
- `&kp LS(A)` = `LEFT_SHIFT`+`A` (a capitalized **A**).
- They can be combined:
- `&kp LC(RA(B))` = `LEFT_CONTROL`+`RIGHT_ALT`+`B`
- They can be applied to a modifier keycode to create combined modifier keys:
- `&kp LS(LALT)` = `LEFT_SHIFT` + `LEFT_ALT`
- Some basic keycodes already include a modifier function in their definition:
- `DOLLAR` = `LS(NUMBER_4)`
- There are left- and right-handed versions of each modifier (also see [table in the list of keycodes](./list-of-keycodes.mdx#modifiers)):
- `LS(x)`, `LC(x)`, `LA(x)`, `LG(x)`, `RS(x)`, `RC(x)`, `RA(x)`, `RG(x)`
- Modified keys can safely be rolled-over. Modifier functions are released when another key is pressed.
- Press `&kp LS(A)`, then press `&kp B`, release `&kp LS(A)` and release `&kp B` results in **Ab**. Only the A is capitalized.