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

feat(docs): Add a split keyboards feature page #2406

Merged
merged 4 commits into from
Aug 8, 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
2 changes: 1 addition & 1 deletion docs/docs/behaviors/backlight.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNC

## Split Keyboards

Backlight behaviors are global: This means that when triggered, they affect both the central and peripheral side of 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.
2 changes: 1 addition & 1 deletion docs/docs/behaviors/power.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ However it will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE`](../con

## Split Keyboards

Power management behaviors are global: This means that when triggered, they affects both the central and peripheral side of 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.
6 changes: 1 addition & 5 deletions docs/docs/behaviors/reset.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,4 @@ Example:

## Split Keyboards

Both basic and bootloader reset behaviors are source-specific: 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.

:::note[Peripheral invocation]
The peripheral side of the keyboard has to be paired and connected to the central side in order to be able to activate these behaviors, even if it is possible to trigger the behavior using only keys on that side. This is because the key bindings are processed on the central side which would then instruct the peripheral side to reset.
:::
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.
2 changes: 1 addition & 1 deletion docs/docs/behaviors/underglow.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,4 @@ However the settings will only be saved after [`CONFIG_ZMK_SETTINGS_SAVE_DEBOUNC

## Split Keyboards

RGB underglow behaviors are global: This means that when triggered, they affect both the central and peripheral side of 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.
2 changes: 1 addition & 1 deletion docs/docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ When building with a `zmk-config` folder, ZMK will search the `zmk-config/config

These files hold your personal settings for the keyboard. All files are optional. If present, they override any configuration set in the board or shield folders. Otherwise, the default configuration and/or keymap is used.

When using a split keyboard, you can use a single file without the `_left` or `_right` suffix to configure both sides. For example, `corne.conf` and `corne.keymap` will apply to both `corne_left` and `corne_right`. If a shared config file exists, any left or right files will be ignored.
When using a [split keyboard](../features/split-keyboards.md), you can use a single file without the `_left` or `_right` suffix to configure both sides. For example, `corne.conf` and `corne.keymap` will apply to both `corne_left` and `corne_right`. If a shared config file exists, any left or right files will be ignored.

### Board Folder

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/config/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Note that `CONFIG_BT_MAX_CONN` and `CONFIG_BT_MAX_PAIRED` should be set to the s

### Split keyboards

Following split keyboard settings are defined in [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/Kconfig) (generic) and [zmk/app/src/split/bluetooth/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/bluetooth/Kconfig) (bluetooth).
Following [split keyboard](../features/split-keyboards.md) settings are defined in [zmk/app/src/split/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/Kconfig) (generic) and [zmk/app/src/split/bluetooth/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/split/bluetooth/Kconfig) (bluetooth).

| Config | Type | Description | Default |
| ------------------------------------------------------- | ---- | -------------------------------------------------------------------------- | ------------------------------------------ |
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ It is also possible to build firmware locally on your computer by following the

For normal keyboards, follow the same flashing instructions as before to flash your updated firmware.

For split keyboards, only the central (left) side will need to be reflashed if you are just updating your keymap.
For [split keyboards](features/split-keyboards.md#building-and-flashing-firmware), only the central (left) side will need to be reflashed if you are just updating your keymap.
More troubleshooting information for split keyboards can be found [here](troubleshooting/connection-issues.mdx#split-keyboard-halves-unable-to-pair).

## Building Additional Keyboards
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/development/new-behavior.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
endif()
```

For behaviors that do not require central locality, the following options for updating `app/CmakeLists.txt` also exist:
For behaviors that do not require [central locality](../features/split-keyboards.md#behaviors-with-locality), the following options for updating `app/CMakeLists.txt` also exist:

- Behavior applies to unibody, or central or peripheral half of keyboard: place `target_sources(app PRIVATE <behavior_name>.c)` line _before_ `if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)`
- Behavior applies to _only_ central half of split keyboard: place `target_sources(app PRIVATE <behavior_name>.c)` after `if (CONFIG_ZMK_SPLIT AND CONFIG_ZMK_SPLIT_ROLE_CENTRAL)`
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/development/new-shield.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The high level steps are:
It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/3.5.0/hardware/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing.

:::note
ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place.
ZMK support for [split keyboards](../features/split-keyboards.md) requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place.
:::

## New Zephyr Module Repository
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/features/battery.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar_label: Battery Level

If your keyboard has a battery sensor, ZMK will report its battery level to the connected bluetooth host and show it on the keyboard's display, if it has one.

For split keyboards, only the battery level of the central (usually left) side is reported over bluetooth by default. ZMK can be [configured to report the battery levels for peripherals](../config/battery.md#peripheral-battery-monitoring), but not many host systems will display this information without additional configuration or the use of third party utilities.
For [split keyboards](split-keyboards.md), only the battery level of the central (usually left) side is reported over bluetooth by default. ZMK can be [configured to report the battery levels for peripherals](../config/battery.md#peripheral-battery-monitoring), but not many host systems will display this information without additional configuration or the use of third party utilities.

:::note

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/features/bluetooth.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Bluetooth
sidebar_label: Bluetooth
---

ZMK's bluetooth functionality allows users to connect their keyboards to hosts using Bluetooth Low Energy (BLE) technology. It also is used for split keyboards to connect the two halves wirelessly.
ZMK's bluetooth functionality allows users to connect their keyboards to hosts using Bluetooth Low Energy (BLE) technology. It also is used for [split keyboards](split-keyboards.md) to connect the two halves wirelessly.

:::note

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/features/combos.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Key positions are numbered like the keys in your keymap, starting at 0. So, if t
- 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 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.
Invoking a [source-specific behavior](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](/docs/config/combos) for advanced configuration options.
See [combo configuration](../config/combos.md) for advanced configuration options.
101 changes: 101 additions & 0 deletions docs/docs/features/split-keyboards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: Split Keyboards
sidebar_label: Split Keyboards
---

ZMK supports setups where a keyboard is split into two or more physical parts (also called "sides" or "halves" when split in two), each with their own controller running ZMK. The parts communicate with each other to work as a single keyboard device.

:::note[Split communication protocols]
Currently ZMK only supports split keyboards that communicate with each other wirelessly over BLE.
As such, only controllers that support BLE can be used with ZMK split keyboards.

Supporting split communication over wired protocols is planned, allowing for ZMK split keyboards using non-wireless controllers.
:::

## Central and Peripheral Roles

In split keyboards running ZMK, one part is assigned the "central" role which receives key position and sensor events from the other parts that are called "peripherals."
The central runs the necessary keymap logic to convert received events into HID events such as keycodes and then communicates with the connected host devices, e.g. over USB or bluetooth.

The internal keyboard state (like active layers) is handled exclusively by the central.
Peripherals _cannot_ communicate with host devices on their own, since they can only communicate with the central.
They will not present as keyboard devices when connected over USB and will not advertise as pairable BLE keyboards.

By convention, for a keyboard split into two "halves" the left half is set as the central and the right as a peripheral.

:::info[Battery life impact]
For BLE-based split keyboards, the central uses significantly more power than the peripherals because its radio needs to periodically wake up to check for incoming transmissions.
You can refer to the [power profiler](/power-profiler) to see battery life estimates for different roles.
:::

### Configuration

The [new shield guide](../development/new-shield.mdx) details how to define a split keyboard shield with two parts, enabling the split feature and setting up the necessary roles for each part.

Also see the reference section on [split keyboards configuration](../config/system.md#split-keyboards) where the relevant symbols include `CONFIG_ZMK_SPLIT` that enables the feature, `CONFIG_ZMK_SPLIT_ROLE_CENTRAL` which sets the central role and `CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS` that sets the number of peripherals.

### Latency Considerations

Since peripherals communicate through centrals, the key and sensor events originating from them will naturally have a larger latency, especially with a wireless split communication protocol.
For the currently used BLE-based transport, split communication increases the average latency by 3.75ms with a worst case increase of 7.5ms.

## Building and Flashing Firmware

ZMK split keyboards require building and flashing different firmware files for each split part.
For instance when [using the GitHub workflow](../user-setup.mdx) to build two part split keyboards, two firmware files that typically contain `<keyboard>_left` and `<keyboard>_right` in the file names will be produced.
These files need to be flashed to the respective controllers of the two halves.

:::tip[Updating your keymap]
Since the keymap processing is primarily done on the central side, for keymap changes it will typically be enough to flash the controller of the central half.
However if you make changes to [config files](../config/index.md) that should apply to all parts, you need to flash to all parts.
Any changes in ZMK related to split keyboard features might also necessitate doing this.
:::

## Pairing for Wireless Split Keyboards

Split keyboards with BLE-based split communications (i.e. all officially supported split keyboards) have an internal pairing procedure between the central and each peripheral.
When the central has an open slot for a peripheral, it will advertise for connections (which will not be visible to non-ZMK devices).
Then, any peripheral that has not yet bonded to a peripheral will pair to it.
Similar to how [bluetooth profiles](bluetooth.md) are managed between the keyboard and host devices, the bonding information will be stored with the corresponding hardware addresses of the other keyboard part, on both the central and peripheral.

In practice, this means that your split keyboard parts will automatically pair and work the first time they are all on at the same time.
However, if this process somehow went wrong or you used controllers in a different split keyboard configuration before, you will need to explicitly clear the stored bond information so that the parts can pair properly.
For this, please follow [the specified procedure](../troubleshooting/connection-issues.mdx#split-keyboard-halves-unable-to-pair) in the troubleshooting section.

:::warning
If the central keyboard part is either advertising for a pairing or waiting for disconnected peripherals, it will consume more power and drain batteries faster.
:::

## Behaviors with Locality

Most ZMK [behaviors](../behaviors/index.mdx) are processed exclusively on the central of the split keyboard as it handles the keymap state and any communication with the host devices.
However, certain behaviors have "global" or "source" localities, where they can affect the peripherals when invoked.

### Global Locality Behaviors

These are behaviors that affect all keyboard parts, such as changing lighting effects:

- [RGB underglow behaviors](../behaviors/underglow.md)
- [Backlight behaviors](../behaviors/backlight.md)
- [Power management behaviors](../behaviors/power.md)
- [Soft off behavior](../behaviors/soft-off.md)

### Source Locality Behaviors

These behaviors only affect the keyboard part that they are invoked from:

- [Reset behaviors](../behaviors/reset.md)

:::warning[Nesting behaviors with locality]
Currently there is [an issue](https://github.com/zmkfirmware/zmk/issues/1494) preventing both global and source locality behaviors from working as expected if they are invoked from another behavior, such as a hold-tap, tap dance or a mod-morph.
For this reason it is recommended that these behaviors are placed directly on a keymap layer.
:::

:::note[Peripheral invocation]
Peripherals must be paired and connected to the central in order to be able to activate these behaviors, even if it is possible to trigger the behavior using only keys on a particular peripheral.
This is because the key bindings are processed on the central side which would then instruct the peripheral side to run the behavior's effect.
:::

:::note[Combos]
[Combos](combos.md) always invoke behaviors with source locality on the central.
:::
2 changes: 1 addition & 1 deletion docs/docs/troubleshooting/connection-issues.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const Uf2Tabs = (props) => (

## Split Keyboard Halves Unable to Pair

Split keyboard halves will automatically pair with one another, but there are some cases where this breaks, and the pairing needs to be reset, for example:
[Split keyboard](../features/split-keyboards.md) halves will automatically pair with one another, but there are some cases where this breaks, and the pairing needs to be reset, for example:

- Switching which halves are the central/peripheral.
- Replacing the controller for one of the halves.
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/user-setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ connect to it wirelessly.
For split keyboards, only the central half (typically the left side) will send keyboard outputs over USB or advertise to other devices
over bluetooth. Peripheral half will only send keystrokes to the central once they are paired and connected. For this reason it is
recommended to test the left half of a split keyboard first.
Please refer to [split keyboards documentation](features/split-keyboards.md) for more information.

:::

Expand All @@ -221,6 +222,7 @@ ZMK supports multiple BLE “profiles”, which allows you to connect to and swi
### Connecting Split Keyboard Halves

For split keyboards, after flashing each half individually you can connect them together by resetting them at the same time. Within a few seconds of resetting, both halves should automatically connect to each other.
Please refer to [the pairing section in the split keyboards documentation](features/split-keyboards.md#pairing-for-wireless-split-keyboards) for more information.

:::note

Expand Down
1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module.exports = {
Features: [
"features/keymaps",
"features/bluetooth",
"features/split-keyboards",
"features/combos",
"features/conditional-layers",
"features/debouncing",
Expand Down