Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mini-feat(docs) Improvements to the layer documentation #2390

Merged
merged 4 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/docs/behaviors/layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ sidebar_label: Layers
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](../features/keymaps.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.
Expand Down
61 changes: 47 additions & 14 deletions docs/docs/features/keymaps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ sidebar_label: Keymaps
---

import KeymapExample from "../keymap-example.md";
import KeymapExampleFile from "../keymap-example-file.md";
caksoylar marked this conversation as resolved.
Show resolved Hide resolved

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
Expand Down Expand Up @@ -38,21 +37,24 @@ For the full set of possible behaviors, see the [overview page for behaviors](..
## 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 "stack". Each layer
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) |
caksoylar marked this conversation as resolved.
Show resolved Hide resolved
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| _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._ |

In addition to the base default layer (which can be changed), certain bound behaviors may also
enable/disable additional layers "on top" of the default layer.
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.

When a key location is pressed/released, the stack of all active layers from "top to bottom" is used,
and the event is sent to the behavior bound at that position in each layer, for it to perform whatever
actions it wants to in reaction to the event. Those behaviors can choose to "handle" the event, and stop
it from being passed to any lower layers, or may choose to "pass it along", and let the next layer
in the stack _also_ get the event.
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").
Nick-Munnich marked this conversation as resolved.
Show resolved Hide resolved

Nick-Munnich marked this conversation as resolved.
Show resolved Hide resolved
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

Expand Down Expand Up @@ -121,18 +123,49 @@ Nested under the devicetree root, is the keymap node. The node _name_ itself is

### Layers

Each layer of your keymap will be nested under the keymap node. Here is a sample
that defines just one layer for this keymap:
Each layer of your keymap will be nested under the keymap node. Here is an example of a layer in a 6-key macropad.

<KeymapExample />
```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

Putting this all together, a complete [`kyria.keymap`](https://github.com/zmkfirmware/zmk/blob/main/app/boards/shields/kyria/kyria.keymap) looks like:
Some examples of complete keymaps for a keyboard are:

<KeymapExampleFile />
- [`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.
:::
36 changes: 24 additions & 12 deletions docs/docs/keymap-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,32 @@
keymap {
compatible = "zmk,keymap";

default_layer {
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------
// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ |
// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' |
// | SHIFT | Z | X | C | V | B | CTRL+A | CTRL+C | | CTRL+V | CTRL+X | N | M | , | . | / | R CTRL |
// | GUI | DEL | RETURN | SPACE | ESCAPE | | RETURN | SPACE | TAB | BSPC | R ALT |
default_layer { // Layer 0
// ----------------------------------------------
caksoylar marked this conversation as resolved.
Show resolved Hide resolved
// | Z | M | K |
// | &mo 1 | LEFT SHIFT | &mo 2 |
bindings = <
&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH
&kp TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT
&kp LSHIFT &kp Z &kp X &kp C &kp V &kp B &kp LC(A) &kp LC(C) &kp LC(V) &kp LC(X) &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL
&kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT
&kp Z &kp M &kp K
&mo 1 &kp LSHIFT &mo 2
>;
};
abc { // Layer 1
// ----------------------------------------------
// | A | B | C |
// | &trans | &trans | &trans |
bindings = <
&kp A &kp B &kp C
&trans &trans &trans
>;
};
xyz { // Layer 2
// ----------------------------------------------
// | X | Y | Z |
// | LEFT CTRL | LEFT ALT | &trans |
bindings = <
&kp X &kp Y &kp Z
&kp LCTRL &kp LALT &trans
>;

sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>;
};
};
```