From a685d88744dcf2c9f901fff2d136a129c83d83ab Mon Sep 17 00:00:00 2001 From: innovaker <66737976+innovaker@users.noreply.github.com> Date: Wed, 11 Nov 2020 21:24:19 +0000 Subject: refactor(docs): Change `feature` to `features` Makes a better URL. --- docs/blog/2020-08-12-zmk-sotf-1.md | 6 +- docs/docs/customization.md | 2 +- docs/docs/dev-guide-new-shield.md | 2 +- docs/docs/feature/displays.md | 6 -- docs/docs/feature/encoders.md | 44 --------- docs/docs/feature/keymaps.md | 182 ------------------------------------- docs/docs/feature/underglow.md | 131 -------------------------- docs/docs/features/displays.md | 6 ++ docs/docs/features/encoders.md | 44 +++++++++ docs/docs/features/keymaps.md | 182 +++++++++++++++++++++++++++++++++++++ docs/docs/features/underglow.md | 131 ++++++++++++++++++++++++++ docs/docs/intro.md | 6 +- docs/sidebars.js | 8 +- 13 files changed, 375 insertions(+), 375 deletions(-) delete mode 100644 docs/docs/feature/displays.md delete mode 100644 docs/docs/feature/encoders.md delete mode 100644 docs/docs/feature/keymaps.md delete mode 100644 docs/docs/feature/underglow.md create mode 100644 docs/docs/features/displays.md create mode 100644 docs/docs/features/encoders.md create mode 100644 docs/docs/features/keymaps.md create mode 100644 docs/docs/features/underglow.md (limited to 'docs') diff --git a/docs/blog/2020-08-12-zmk-sotf-1.md b/docs/blog/2020-08-12-zmk-sotf-1.md index b5b2046..afa0340 100644 --- a/docs/blog/2020-08-12-zmk-sotf-1.md +++ b/docs/blog/2020-08-12-zmk-sotf-1.md @@ -15,13 +15,13 @@ With interest and Discord activity growing, it seemed important to lay out the p There's been lots of various activity in ZMK land! -- [Nicell](https://github.com/Nicell) (nice!nano creator) contributed initial [RGB Underglow](/docs/feature/underglow) ([#64](https://github.com/zmkfirmware/zmk/pull/64)) support to ZMK. +- [Nicell](https://github.com/Nicell) (nice!nano creator) contributed initial [RGB Underglow](/docs/features/underglow) ([#64](https://github.com/zmkfirmware/zmk/pull/64)) support to ZMK. - Tons of [documentation](/docs) work. -- Refactoring ([#73](https://github.com/zmkfirmware/zmk/pull/73), [#74](https://github.com/zmkfirmware/zmk/pull/74)) of [keymaps](/docs/feature/keymaps) to make them simpler for users. +- Refactoring ([#73](https://github.com/zmkfirmware/zmk/pull/73), [#74](https://github.com/zmkfirmware/zmk/pull/74)) of [keymaps](/docs/features/keymaps) to make them simpler for users. - Mod-Tap Behavior (docs coming!) is much improved ([#69](https://github.com/zmkfirmware/zmk/pull/69)) and usable now. - An initial [`setup.sh`](http://localhost:3000/docs/user-setup#user-config-setup-script) script was created, allowing users to quickly bootstrap a "user config" setup and push it to GitHub, where GitHub Actions will build the firmware for you. - Corne shield ([#80](https://github.com/zmkfirmware/zmk/pull/80)) shield definition was added. -- Initial [encoder](/docs/feature/encoders) support ([#61](https://github.com/zmkfirmware/zmk/pull/61)) was added. +- Initial [encoder](/docs/features/encoders) support ([#61](https://github.com/zmkfirmware/zmk/pull/61)) was added. ## Bugs and Showstoppers diff --git a/docs/docs/customization.md b/docs/docs/customization.md index d3372da..d0d3749 100644 --- a/docs/docs/customization.md +++ b/docs/docs/customization.md @@ -26,7 +26,7 @@ various config settings that can be commented/uncommented to modify how your fir ## Keymap Once you have the basic user config completed, you can find the keymap file in `config/.keymap` and customize from there. -Refer to the [Keymap](/docs/feature/keymaps) documentation to learn more. +Refer to the [Keymap](/docs/features/keymaps) documentation to learn more. ## Publishing diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 70a847c..f095ab5 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -477,7 +477,7 @@ Add the following line to your keymap file to add default encoder behavior bindi sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; ``` -Add additional bindings as necessary to match the default number of encoders on your board. See the [Encoders](/docs/feature/encoders) and [Keymap](/docs/feature/keymaps) feature documentation for more details. +Add additional bindings as necessary to match the default number of encoders on your board. See the [Encoders](/docs/features/encoders) and [Keymap](/docs/features/keymaps) feature documentation for more details. diff --git a/docs/docs/feature/displays.md b/docs/docs/feature/displays.md deleted file mode 100644 index 2b3d001..0000000 --- a/docs/docs/feature/displays.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: OLED Displays -sidebar_label: OLED Displays ---- - -TODO: Documentation on OLED displays. diff --git a/docs/docs/feature/encoders.md b/docs/docs/feature/encoders.md deleted file mode 100644 index b78f89e..0000000 --- a/docs/docs/feature/encoders.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Encoders -sidebar_label: Encoders ---- - -Existing support for encoders in ZMK is focused around the five pin EC11 rotary encoder with push button design used in the majority of current keyboard and macropad designs. - -## Enabling EC11 Encoders - -To enable encoders for boards that have existing encoder support, uncomment the `EC11_CONFIG=y` and `CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y` lines in your board's .conf file in your `zmk-config/config` folder. Save and push your changes, then download and flash the new firmware. - -## Customizing EC11 Encoder Behavior - -Encoder behavior in ZMK is configured in two different locations as the push button and rotation behaviors are handled in two separate ways. - -### Push Button - -Keyboards and macropads with encoder support will typically take the two EC11 pins responsible for the push button and include them as part of the matrix for the keys. To configure what is sent by the push button, find the encoder's position in the keyboard matrix and assign it a behavior the same as you would any other key. - -### Rotation - -Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`, which is defined in each keymap layer in the following format: - -``` -sensor-bindings = ; -``` - -- `BINDING`, for now, has only one behavior available; `&inc_dec_kp` for key presses (see [Key Press](/docs/behavior/key-press) for details on available keycodes). -- `CW_KEY` is the keycode activated by a clockwise turn. -- `CCW_KEY` is the keycode activated by a counter-clockwise turn. - -Additional encoders can be configured by adding more `BINDING CW_KEY CCW_KEY` sets immediately after the first. - -As an example, a complete `sensor-bindings` for a Kyria with two encoders could look like: - -``` -sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; -``` - -Here, the left encoder is configured to control volume up and down while the right encoder sends either Page Up or Page Down. - -## Adding Encoder Support - -See the [New Keyboard Shield](/docs/dev-guide-new-shield#encoders) documentation for how to add or modify additional encoders to your shield. diff --git a/docs/docs/feature/keymaps.md b/docs/docs/feature/keymaps.md deleted file mode 100644 index c4c16c3..0000000 --- a/docs/docs/feature/keymaps.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -title: Keymaps & Behaviors -sidebar_label: Keymaps ---- - -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, start at the [Key Press](/docs/behavior/key-press) behavior. - -## 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 -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._ | - -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. - -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. - -## 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 specific _which_ keycode should -be used for that key position. - -``` -&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: - -``` -&mt LSHFT 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: - -``` -#include -#include -``` - -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. `LSHFT`) used for various behavior bindings. - -### Root devicetree Node - -ALl the remaining keymap nodes will be nested inside of the root devicetree node, like so: - -```devicetree -/ { - // 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. - -``` - keymap { - compatible = "zmk,keymap"; - - // Layer nodes go here! - }; -``` - -### 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: - -``` - 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 | - 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 QUOTE - &kp LSHFT &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 - >; - - sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; - }; - }; -``` - -Each layer should have: - -1. A `bindings` property this will be a list of behaviour bindings, 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) - -For the full set of possible behaviors, start at the [Key Press](/docs/behavior/key-press) behavior. - -### 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: - -``` -#include -#include - -/ { - 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 | - 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 QUOTE - &kp LSHFT &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 - >; - - sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; - }; - }; -}; -``` diff --git a/docs/docs/feature/underglow.md b/docs/docs/feature/underglow.md deleted file mode 100644 index 2cea913..0000000 --- a/docs/docs/feature/underglow.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: RGB Underglow -sidebar_label: RGB Underglow ---- - -RGB underglow is a feature used to control "strips" of RGB LEDs. Most of the time this is called underglow and creates a glow underneath the board using a ring of LEDs around the edge, hence the name. However, this can be extended to be used to control anything from a single LED to a long string of LEDs anywhere on the keyboard. - -ZMK supports all the RGB LEDs supported by Zephyr. Here's the current list supported: - -- WS2812-ish (WS2812B, WS2813, SK6812, or compatible) -- APA102 -- LPD880x (LPD8803, LPD8806, or compatible) - -Of the compatible types, the WS2812 LED family is by far the most popular type. Currently each of these types of LEDs are expected to be run using SPI with a couple of exceptions. - -Here you can see the RGB underglow feature in action using WS2812 LEDs. - -
- -
- -## Enabling RGB Underglow - -To enable RGB underglow on your board or shield, simply enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `X_STRIP` configuration values in the `.conf` file of your user config directory as such: - -``` -CONFIG_ZMK_RGB_UNDERGLOW=y -# Use the STRIP config specific to the LEDs you're using -CONFIG_WS2812_STRIP=y -``` - -If your board or shield does not have RGB underglow configured, refer to [Adding RGB Underglow to a Board](#adding-rgb-underglow-to-a-board). - -## Configuring RGB Underglow - -There are various Kconfig options used to configure the RGB underglow feature. These can all be set in the `.conf` file. - -| Option | Description | Default | -| ------------------------------------ | ---------------------------------------------- | ------- | -| `CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP` | Hue step in degrees of 360 used by RGB actions | 10 | -| `CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP` | Saturation step in percent used by RGB actions | 10 | -| `CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP` | Brightness step in percent used by RGB actions | 10 | -| `CONFIG_ZMK_RGB_UNDERGLOW_HUE_START` | Default hue 0-359 in degrees | 0 | -| `CONFIG_ZMK_RGB_UNDERGLOW_SAT_START` | Default saturation 0-100 in percent | 100 | -| `CONFIG_ZMK_RGB_UNDERGLOW_BRT_START` | Default brightness 0-100 in percent | 100 | -| `CONFIG_ZMK_RGB_UNDERGLOW_SPD_START` | Default effect speed 1-5 | 3 | -| `CONFIG_ZMK_RGB_UNDERGLOW_EFF_START` | Default effect integer from the effect enum | 0 | -| `CONFIG_ZMK_RGB_UNDERGLOW_ON_START` | Default on state | y | - -## Adding RGB Underglow to a Board - -RGB underglow is always added to a board, not a shield. This is a consequence of needing to configure SPI to control the LEDs. -If you have a shield with RGB underglow, you must add a `boards/` directory within your shield folder to define the RGB underglow individually for each board that supports the shield. -Inside the `boards/` folder, you define a `.overlay` for each different board. -For example, the Kyria shield has a `boards/nice_nano.overlay` file that defines the RGB underglow for the `nice_nano` board specifically. - -The first step to adding support for underglow is to select you SPI output. With nRF52 boards, you can just use `&spi1` and define the pins you want to use. -For other boards, you must select an SPI definition that has the `MOSI` pin as your data pin going to your LED strip. - -Here's an example of an nRF52 SPI definition: - -``` -&spi1 { - compatible = "nordic,nrf-spim"; - status = "okay"; - mosi-pin = <6>; - // Unused pins, needed for SPI definition, but not used by the ws2812 driver itself. - sck-pin = <5>; - miso-pin = <7>; - - led_strip: ws2812@0 { - compatible = "worldsemi,ws2812-spi"; - label = "WS2812"; - - /* SPI */ - reg = <0>; /* ignored, but necessary for SPI bindings */ - spi-max-frequency = <4000000>; - - /* WS2812 */ - chain-length = <10>; /* number of LEDs */ - spi-one-frame = <0x70>; - spi-zero-frame = <0x40>; - }; -}; -``` - -:::info - -If you are configuring SPI for an nRF52840 (or other nRF52) based board, double check that you are using pins that aren't restricted to low frequency I/O. -Ignoring these restrictions may result in poor wireless performance. You can find the list of low frequency I/O pins [here](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fpin.html&cp=4_0_0_6_0). - -::: - -Here's another example for a non-nRF52 board on `spi1`: - -``` -&spi1 { - - led_strip: ws2812@0 { - compatible = "worldsemi,ws2812-spi"; - label = "WS2812"; - - /* SPI */ - reg = <0>; - spi-max-frequency = <5250000>; - - /* WS2812 */ - chain-length = <10>; /* number of LEDs */ - spi-one-frame = <0x70>; /* make sure to configure this properly for your SOC */ - spi-zero-frame = <0x40>; /* make sure to configure this properly for your SOC */ - }; -}; -``` - -Once you have your `led_strip` properly defined you need to add it to the root devicetree node `chosen` element: - -``` -/ { - chosen { - zmk,underglow = &led_strip; - }; -}; -``` - -Finally you need to enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `X_STRIP` configuration values in the `.conf` file of your board (or set a default in the `Kconfig.defconfig`): - -``` -CONFIG_ZMK_RGB_UNDERGLOW=y -# Use the STRIP config specific to the LEDs you're using -CONFIG_WS2812_STRIP=y -``` diff --git a/docs/docs/features/displays.md b/docs/docs/features/displays.md new file mode 100644 index 0000000..2b3d001 --- /dev/null +++ b/docs/docs/features/displays.md @@ -0,0 +1,6 @@ +--- +title: OLED Displays +sidebar_label: OLED Displays +--- + +TODO: Documentation on OLED displays. diff --git a/docs/docs/features/encoders.md b/docs/docs/features/encoders.md new file mode 100644 index 0000000..b78f89e --- /dev/null +++ b/docs/docs/features/encoders.md @@ -0,0 +1,44 @@ +--- +title: Encoders +sidebar_label: Encoders +--- + +Existing support for encoders in ZMK is focused around the five pin EC11 rotary encoder with push button design used in the majority of current keyboard and macropad designs. + +## Enabling EC11 Encoders + +To enable encoders for boards that have existing encoder support, uncomment the `EC11_CONFIG=y` and `CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y` lines in your board's .conf file in your `zmk-config/config` folder. Save and push your changes, then download and flash the new firmware. + +## Customizing EC11 Encoder Behavior + +Encoder behavior in ZMK is configured in two different locations as the push button and rotation behaviors are handled in two separate ways. + +### Push Button + +Keyboards and macropads with encoder support will typically take the two EC11 pins responsible for the push button and include them as part of the matrix for the keys. To configure what is sent by the push button, find the encoder's position in the keyboard matrix and assign it a behavior the same as you would any other key. + +### Rotation + +Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`, which is defined in each keymap layer in the following format: + +``` +sensor-bindings = ; +``` + +- `BINDING`, for now, has only one behavior available; `&inc_dec_kp` for key presses (see [Key Press](/docs/behavior/key-press) for details on available keycodes). +- `CW_KEY` is the keycode activated by a clockwise turn. +- `CCW_KEY` is the keycode activated by a counter-clockwise turn. + +Additional encoders can be configured by adding more `BINDING CW_KEY CCW_KEY` sets immediately after the first. + +As an example, a complete `sensor-bindings` for a Kyria with two encoders could look like: + +``` +sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; +``` + +Here, the left encoder is configured to control volume up and down while the right encoder sends either Page Up or Page Down. + +## Adding Encoder Support + +See the [New Keyboard Shield](/docs/dev-guide-new-shield#encoders) documentation for how to add or modify additional encoders to your shield. diff --git a/docs/docs/features/keymaps.md b/docs/docs/features/keymaps.md new file mode 100644 index 0000000..c4c16c3 --- /dev/null +++ b/docs/docs/features/keymaps.md @@ -0,0 +1,182 @@ +--- +title: Keymaps & Behaviors +sidebar_label: Keymaps +--- + +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, start at the [Key Press](/docs/behavior/key-press) behavior. + +## 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 +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._ | + +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. + +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. + +## 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 specific _which_ keycode should +be used for that key position. + +``` +&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: + +``` +&mt LSHFT 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: + +``` +#include +#include +``` + +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. `LSHFT`) used for various behavior bindings. + +### Root devicetree Node + +ALl the remaining keymap nodes will be nested inside of the root devicetree node, like so: + +```devicetree +/ { + // 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. + +``` + keymap { + compatible = "zmk,keymap"; + + // Layer nodes go here! + }; +``` + +### 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: + +``` + 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 | + 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 QUOTE + &kp LSHFT &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 + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +``` + +Each layer should have: + +1. A `bindings` property this will be a list of behaviour bindings, 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) + +For the full set of possible behaviors, start at the [Key Press](/docs/behavior/key-press) behavior. + +### 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: + +``` +#include +#include + +/ { + 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 | + 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 QUOTE + &kp LSHFT &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 + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; +``` diff --git a/docs/docs/features/underglow.md b/docs/docs/features/underglow.md new file mode 100644 index 0000000..2cea913 --- /dev/null +++ b/docs/docs/features/underglow.md @@ -0,0 +1,131 @@ +--- +title: RGB Underglow +sidebar_label: RGB Underglow +--- + +RGB underglow is a feature used to control "strips" of RGB LEDs. Most of the time this is called underglow and creates a glow underneath the board using a ring of LEDs around the edge, hence the name. However, this can be extended to be used to control anything from a single LED to a long string of LEDs anywhere on the keyboard. + +ZMK supports all the RGB LEDs supported by Zephyr. Here's the current list supported: + +- WS2812-ish (WS2812B, WS2813, SK6812, or compatible) +- APA102 +- LPD880x (LPD8803, LPD8806, or compatible) + +Of the compatible types, the WS2812 LED family is by far the most popular type. Currently each of these types of LEDs are expected to be run using SPI with a couple of exceptions. + +Here you can see the RGB underglow feature in action using WS2812 LEDs. + +
+ +
+ +## Enabling RGB Underglow + +To enable RGB underglow on your board or shield, simply enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `X_STRIP` configuration values in the `.conf` file of your user config directory as such: + +``` +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y +``` + +If your board or shield does not have RGB underglow configured, refer to [Adding RGB Underglow to a Board](#adding-rgb-underglow-to-a-board). + +## Configuring RGB Underglow + +There are various Kconfig options used to configure the RGB underglow feature. These can all be set in the `.conf` file. + +| Option | Description | Default | +| ------------------------------------ | ---------------------------------------------- | ------- | +| `CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP` | Hue step in degrees of 360 used by RGB actions | 10 | +| `CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP` | Saturation step in percent used by RGB actions | 10 | +| `CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP` | Brightness step in percent used by RGB actions | 10 | +| `CONFIG_ZMK_RGB_UNDERGLOW_HUE_START` | Default hue 0-359 in degrees | 0 | +| `CONFIG_ZMK_RGB_UNDERGLOW_SAT_START` | Default saturation 0-100 in percent | 100 | +| `CONFIG_ZMK_RGB_UNDERGLOW_BRT_START` | Default brightness 0-100 in percent | 100 | +| `CONFIG_ZMK_RGB_UNDERGLOW_SPD_START` | Default effect speed 1-5 | 3 | +| `CONFIG_ZMK_RGB_UNDERGLOW_EFF_START` | Default effect integer from the effect enum | 0 | +| `CONFIG_ZMK_RGB_UNDERGLOW_ON_START` | Default on state | y | + +## Adding RGB Underglow to a Board + +RGB underglow is always added to a board, not a shield. This is a consequence of needing to configure SPI to control the LEDs. +If you have a shield with RGB underglow, you must add a `boards/` directory within your shield folder to define the RGB underglow individually for each board that supports the shield. +Inside the `boards/` folder, you define a `.overlay` for each different board. +For example, the Kyria shield has a `boards/nice_nano.overlay` file that defines the RGB underglow for the `nice_nano` board specifically. + +The first step to adding support for underglow is to select you SPI output. With nRF52 boards, you can just use `&spi1` and define the pins you want to use. +For other boards, you must select an SPI definition that has the `MOSI` pin as your data pin going to your LED strip. + +Here's an example of an nRF52 SPI definition: + +``` +&spi1 { + compatible = "nordic,nrf-spim"; + status = "okay"; + mosi-pin = <6>; + // Unused pins, needed for SPI definition, but not used by the ws2812 driver itself. + sck-pin = <5>; + miso-pin = <7>; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "WS2812"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* number of LEDs */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + }; +}; +``` + +:::info + +If you are configuring SPI for an nRF52840 (or other nRF52) based board, double check that you are using pins that aren't restricted to low frequency I/O. +Ignoring these restrictions may result in poor wireless performance. You can find the list of low frequency I/O pins [here](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fpin.html&cp=4_0_0_6_0). + +::: + +Here's another example for a non-nRF52 board on `spi1`: + +``` +&spi1 { + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "WS2812"; + + /* SPI */ + reg = <0>; + spi-max-frequency = <5250000>; + + /* WS2812 */ + chain-length = <10>; /* number of LEDs */ + spi-one-frame = <0x70>; /* make sure to configure this properly for your SOC */ + spi-zero-frame = <0x40>; /* make sure to configure this properly for your SOC */ + }; +}; +``` + +Once you have your `led_strip` properly defined you need to add it to the root devicetree node `chosen` element: + +``` +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; +``` + +Finally you need to enable the `CONFIG_ZMK_RGB_UNDERGLOW` and `X_STRIP` configuration values in the `.conf` file of your board (or set a default in the `Kconfig.defconfig`): + +``` +CONFIG_ZMK_RGB_UNDERGLOW=y +# Use the STRIP config specific to the LEDs you're using +CONFIG_WS2812_STRIP=y +``` diff --git a/docs/docs/intro.md b/docs/docs/intro.md index c76e4b7..55456d3 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -22,9 +22,9 @@ ZMK is currently missing some features found in other popular firmware. This tab | [Hold-Tap](behavior/hold-tap) (which includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | ✅ | | [Keyboard Codes](codes/#keyboard) | ✅ | ✅ | ✅ | | [Media](codes/#media-controls) & [Consumer](codes/#consumer-controls) Codes | ✅ | ✅ | ✅ | -| [Encoders](feature/encoders)[^1] | ✅ | | ✅ | -| [OLED Display Support](feature/displays)[^2] | 🚧 | 🚧 | ✅ | -| [RGB Underglow](feature/underglow) | ✅ | ✅ | ✅ | +| [Encoders](features/encoders)[^1] | ✅ | | ✅ | +| [OLED Display Support](features/displays)[^2] | 🚧 | 🚧 | ✅ | +| [RGB Underglow](features/underglow) | ✅ | ✅ | ✅ | | One Shot Keys | 🚧 | ✅ | ✅ | | Combo Keys | 🚧 | | ✅ | | Macros | 🚧 | ✅ | ✅ | diff --git a/docs/sidebars.js b/docs/sidebars.js index 15d531e..d64d96c 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -9,10 +9,10 @@ module.exports = { "troubleshooting", ], Features: [ - "feature/keymaps", - "feature/displays", - "feature/encoders", - "feature/underglow", + "features/keymaps", + "features/displays", + "features/encoders", + "features/underglow", ], Behaviors: [ "behavior/key-press", -- cgit v1.2.3