Merge branch 'zmkfirmware:main' into patch-1
This commit is contained in:
commit
f9ae59652c
35 changed files with 788 additions and 364 deletions
|
@ -22,7 +22,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: pip install -r app/scripts/requirements.txt
|
||||
run: pip install --break-system-packages -r app/scripts/requirements.txt
|
||||
- name: West init
|
||||
run: west init -l app
|
||||
- name: Update modules (west update)
|
||||
|
|
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
|
@ -4,6 +4,7 @@
|
|||
"ms-python.python",
|
||||
"ms-vscode.cpptools",
|
||||
"plorefice.devicetree",
|
||||
"twxs.cmake"
|
||||
"twxs.cmake",
|
||||
"unifiedjs.vscode-mdx"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_HOLD_TAP app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_STICKY_KEY app PRIVATE src/behaviors/behavior_sticky_key.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_caps_word.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MACRO app PRIVATE src/behaviors/behavior_macro.c)
|
||||
|
|
|
@ -40,6 +40,28 @@ endchoice
|
|||
|
||||
endif
|
||||
|
||||
|
||||
config ZMK_BEHAVIOR_HOLD_TAP
|
||||
bool
|
||||
default y
|
||||
depends on DT_HAS_ZMK_BEHAVIOR_HOLD_TAP_ENABLED
|
||||
|
||||
if ZMK_BEHAVIOR_HOLD_TAP
|
||||
|
||||
config ZMK_BEHAVIOR_HOLD_TAP_MAX_HELD
|
||||
int "Hold Tap Max Held"
|
||||
default 10
|
||||
help
|
||||
Max number of simultaneously held hold-taps
|
||||
|
||||
config ZMK_BEHAVIOR_HOLD_TAP_MAX_CAPTURED_EVENTS
|
||||
int "Hold Tap Max Captured Events"
|
||||
default 40
|
||||
help
|
||||
Max number of captured system events while waiting to resolve hold taps
|
||||
|
||||
endif
|
||||
|
||||
config ZMK_BEHAVIOR_KEY_TOGGLE
|
||||
bool
|
||||
default y
|
||||
|
@ -51,6 +73,21 @@ config ZMK_BEHAVIOR_MOUSE_KEY_PRESS
|
|||
depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED
|
||||
imply ZMK_MOUSE
|
||||
|
||||
config ZMK_BEHAVIOR_STICKY_KEY
|
||||
bool
|
||||
default y
|
||||
depends on DT_HAS_ZMK_BEHAVIOR_STICKY_KEY_ENABLED
|
||||
|
||||
if ZMK_BEHAVIOR_STICKY_KEY
|
||||
|
||||
config ZMK_BEHAVIOR_STICKY_KEY_MAX_HELD
|
||||
int "Sticky Key Max Held"
|
||||
default 10
|
||||
help
|
||||
Max number of simultaneously held sticky keys
|
||||
|
||||
endif
|
||||
|
||||
config ZMK_BEHAVIOR_SOFT_OFF
|
||||
bool
|
||||
default y
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define DT_DRV_COMPAT zmk_kscan_composite
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/pm/device.h>
|
||||
#include <zephyr/drivers/kscan.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
@ -26,10 +27,10 @@ struct kscan_composite_child_config {
|
|||
.row_offset = DT_PROP(inst, row_offset), \
|
||||
.column_offset = DT_PROP(inst, column_offset)},
|
||||
|
||||
const struct kscan_composite_child_config kscan_composite_children[] = {
|
||||
DT_FOREACH_CHILD(MATRIX_NODE_ID, CHILD_CONFIG)};
|
||||
|
||||
struct kscan_composite_config {};
|
||||
struct kscan_composite_config {
|
||||
const struct kscan_composite_child_config *children;
|
||||
size_t children_len;
|
||||
};
|
||||
|
||||
struct kscan_composite_data {
|
||||
kscan_callback_t callback;
|
||||
|
@ -38,51 +39,80 @@ struct kscan_composite_data {
|
|||
};
|
||||
|
||||
static int kscan_composite_enable_callback(const struct device *dev) {
|
||||
for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
|
||||
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
|
||||
const struct kscan_composite_config *cfg = dev->config;
|
||||
|
||||
kscan_enable_callback(cfg->child);
|
||||
for (int i = 0; i < cfg->children_len; i++) {
|
||||
const struct kscan_composite_child_config *child_cfg = &cfg->children[i];
|
||||
|
||||
#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)
|
||||
if (!pm_device_runtime_is_enabled(dev) && pm_device_runtime_is_enabled(child_cfg->child)) {
|
||||
pm_device_runtime_get(child_cfg->child);
|
||||
}
|
||||
#elif IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
pm_device_action_run(child_cfg->child, PM_DEVICE_ACTION_RESUME);
|
||||
#endif // IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
|
||||
kscan_enable_callback(child_cfg->child);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kscan_composite_disable_callback(const struct device *dev) {
|
||||
for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
|
||||
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
|
||||
const struct kscan_composite_config *cfg = dev->config;
|
||||
for (int i = 0; i < cfg->children_len; i++) {
|
||||
const struct kscan_composite_child_config *child_cfg = &cfg->children[i];
|
||||
|
||||
kscan_disable_callback(cfg->child);
|
||||
kscan_disable_callback(child_cfg->child);
|
||||
|
||||
#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)
|
||||
if (!pm_device_runtime_is_enabled(dev) && pm_device_runtime_is_enabled(child_cfg->child)) {
|
||||
pm_device_runtime_put(child_cfg->child);
|
||||
}
|
||||
#elif IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
pm_device_action_run(child_cfg->child, PM_DEVICE_ACTION_SUSPEND);
|
||||
#endif // IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KSCAN_COMP_INST_DEV(n) DEVICE_DT_GET(DT_DRV_INST(n)),
|
||||
|
||||
static const struct device *all_instances[] = {DT_INST_FOREACH_STATUS_OKAY(KSCAN_COMP_INST_DEV)};
|
||||
|
||||
static void kscan_composite_child_callback(const struct device *child_dev, uint32_t row,
|
||||
uint32_t column, bool pressed) {
|
||||
// TODO: Ideally we can get this passed into our callback!
|
||||
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
|
||||
struct kscan_composite_data *data = dev->data;
|
||||
for (int i = 0; i < ARRAY_SIZE(all_instances); i++) {
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
|
||||
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
|
||||
const struct device *dev = all_instances[i];
|
||||
const struct kscan_composite_config *cfg = dev->config;
|
||||
struct kscan_composite_data *data = dev->data;
|
||||
|
||||
if (cfg->child != child_dev) {
|
||||
continue;
|
||||
for (int c = 0; c < cfg->children_len; c++) {
|
||||
const struct kscan_composite_child_config *child_cfg = &cfg->children[c];
|
||||
|
||||
if (child_cfg->child != child_dev) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data->callback(dev, row + child_cfg->row_offset, column + child_cfg->column_offset,
|
||||
pressed);
|
||||
}
|
||||
|
||||
data->callback(dev, row + cfg->row_offset, column + cfg->column_offset, pressed);
|
||||
}
|
||||
}
|
||||
|
||||
static int kscan_composite_configure(const struct device *dev, kscan_callback_t callback) {
|
||||
const struct kscan_composite_config *cfg = dev->config;
|
||||
struct kscan_composite_data *data = dev->data;
|
||||
|
||||
if (!callback) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) {
|
||||
const struct kscan_composite_child_config *cfg = &kscan_composite_children[i];
|
||||
for (int i = 0; i < cfg->children_len; i++) {
|
||||
const struct kscan_composite_child_config *child_cfg = &cfg->children[i];
|
||||
|
||||
kscan_config(cfg->child, &kscan_composite_child_callback);
|
||||
kscan_config(child_cfg->child, &kscan_composite_child_callback);
|
||||
}
|
||||
|
||||
data->callback = callback;
|
||||
|
@ -95,6 +125,10 @@ static int kscan_composite_init(const struct device *dev) {
|
|||
|
||||
data->dev = dev;
|
||||
|
||||
#if IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
pm_device_init_suspended(dev);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -104,9 +138,32 @@ static const struct kscan_driver_api mock_driver_api = {
|
|||
.disable_callback = kscan_composite_disable_callback,
|
||||
};
|
||||
|
||||
static const struct kscan_composite_config kscan_composite_config = {};
|
||||
#if IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
|
||||
static struct kscan_composite_data kscan_composite_data;
|
||||
static int kscan_composite_pm_action(const struct device *dev, enum pm_device_action action) {
|
||||
switch (action) {
|
||||
case PM_DEVICE_ACTION_SUSPEND:
|
||||
return kscan_composite_disable_callback(dev);
|
||||
case PM_DEVICE_ACTION_RESUME:
|
||||
return kscan_composite_enable_callback(dev);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
DEVICE_DT_INST_DEFINE(0, kscan_composite_init, NULL, &kscan_composite_data, &kscan_composite_config,
|
||||
POST_KERNEL, CONFIG_ZMK_KSCAN_COMPOSITE_INIT_PRIORITY, &mock_driver_api);
|
||||
#endif // IS_ENABLED(CONFIG_PM_DEVICE)
|
||||
|
||||
#define KSCAN_COMP_DEV(n) \
|
||||
static const struct kscan_composite_child_config kscan_composite_children_##n[] = { \
|
||||
DT_INST_FOREACH_CHILD(n, CHILD_CONFIG)}; \
|
||||
static const struct kscan_composite_config kscan_composite_config_##n = { \
|
||||
.children = kscan_composite_children_##n, \
|
||||
.children_len = ARRAY_SIZE(kscan_composite_children_##n), \
|
||||
}; \
|
||||
static struct kscan_composite_data kscan_composite_data_##n; \
|
||||
PM_DEVICE_DT_INST_DEFINE(n, kscan_composite_pm_action); \
|
||||
DEVICE_DT_INST_DEFINE(n, kscan_composite_init, PM_DEVICE_DT_INST_GET(n), \
|
||||
&kscan_composite_data_##n, &kscan_composite_config_##n, POST_KERNEL, \
|
||||
CONFIG_ZMK_KSCAN_COMPOSITE_INIT_PRIORITY, &mock_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KSCAN_COMP_DEV)
|
||||
|
|
|
@ -24,8 +24,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
#define ZMK_BHV_HOLD_TAP_MAX_HELD 10
|
||||
#define ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS 40
|
||||
#define ZMK_BHV_HOLD_TAP_MAX_HELD CONFIG_ZMK_BEHAVIOR_HOLD_TAP_MAX_HELD
|
||||
#define ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS CONFIG_ZMK_BEHAVIOR_HOLD_TAP_MAX_CAPTURED_EVENTS
|
||||
|
||||
// increase if you have keyboard with more keys.
|
||||
#define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999
|
||||
|
|
|
@ -26,7 +26,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#define KEY_PRESS DEVICE_DT_NAME(DT_INST(0, zmk_behavior_key_press))
|
||||
|
||||
#define ZMK_BHV_STICKY_KEY_MAX_HELD 10
|
||||
#define ZMK_BHV_STICKY_KEY_MAX_HELD CONFIG_ZMK_BEHAVIOR_STICKY_KEY_MAX_HELD
|
||||
|
||||
#define ZMK_BHV_STICKY_KEY_POSITION_FREE UINT32_MAX
|
||||
|
||||
|
|
|
@ -36,7 +36,12 @@ static int zmk_gpio_key_wakeup_trigger_init(const struct device *dev) {
|
|||
static int gpio_key_wakeup_trigger_pm_resume(const struct device *dev) {
|
||||
const struct gpio_key_wakeup_trigger_config *config = dev->config;
|
||||
|
||||
int ret = gpio_pin_interrupt_configure_dt(&config->trigger, GPIO_INT_LEVEL_ACTIVE);
|
||||
int ret = gpio_pin_configure_dt(&config->trigger, GPIO_INPUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure wakeup trigger key GPIO pin as input (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = gpio_pin_interrupt_configure_dt(&config->trigger, GPIO_INT_LEVEL_ACTIVE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure wakeup trigger key GPIO pin interrupt (%d)", ret);
|
||||
return ret;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
@ -33,7 +37,7 @@ again.
|
|||
### Behavior Binding
|
||||
|
||||
- Reference: `&mo`
|
||||
- Parameter: The layer number to enable/disable, e.g. `1`
|
||||
- Parameter: The layer number to enable while held, e.g. `1`
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -48,7 +52,7 @@ The "layer-tap" behavior enables a layer when a key is held, and outputs a [keyp
|
|||
### Behavior Binding
|
||||
|
||||
- Reference: `<`
|
||||
- Parameter: The layer number to enable when held, e.g. `1`
|
||||
- Parameter: The layer number to enable while held, e.g. `1`
|
||||
- Parameter: The keycode to send when tapped, e.g. `A`
|
||||
|
||||
Example:
|
||||
|
@ -99,7 +103,7 @@ Example:
|
|||
|
||||
## Toggle Layer
|
||||
|
||||
The "toggle layer" behavior enables a layer until the layer is manually disabled.
|
||||
The "toggle layer" behavior enables a layer if it is currently disabled, or disables it if enabled.
|
||||
|
||||
### Behavior Binding
|
||||
|
||||
|
@ -112,43 +116,6 @@ Example:
|
|||
&tog LOWER
|
||||
```
|
||||
|
||||
"Toggle layer" for a :
|
||||
|
||||
```dts
|
||||
#define DEFAULT 0
|
||||
#define NAVI 1
|
||||
|
||||
#define NONE 0
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&tog NAVI &kp KP_DIVIDE &kp KP_MULTIPLY &kp KP_MINUS
|
||||
&kp NUMBER_7 &kp NUMBER_8 &kp NUMBER_9 &kp KP_PLUS
|
||||
&kp NUMBER_4 &kp NUMBER_5 &kp NUMBER_6 &kp KP_PLUS
|
||||
&kp NUMBER_1 &kp NUMBER_2 &kp NUMBER_3 &kp RETURN
|
||||
&kp NUMBER_0 &kp NUMBER_0 &kp DOT &kp RETURN
|
||||
>;
|
||||
};
|
||||
|
||||
nav_layer {
|
||||
bindings = <
|
||||
&tog NAVI &kp KP_DIVIDE &kp KP_MULTIPLY &kp KP_MINUS
|
||||
&kp HOME &kp UP &kp PAGE_UP &kp KP_PLUS
|
||||
&kp LEFT &none &kp RIGHT &kp KP_PLUS
|
||||
&kp END &kp DOWN &kp PAGE_DOWN &kp RETURN
|
||||
&kp INSERT &kp INSERT &kp DEL &kp RETURN
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
It is possible to use "toggle layer" to have keys that raise and lower the layers as well.
|
||||
|
||||
## Conditional Layers
|
||||
|
||||
The "conditional layers" feature enables a particular layer when all layers in a specified set are active.
|
||||
|
|
|
@ -5,18 +5,17 @@ sidebar_label: Mod-Morph
|
|||
|
||||
## Summary
|
||||
|
||||
The Mod-Morph behavior sends a different keypress, depending on whether a specified modifier is being held during the keypress.
|
||||
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 keycode is sent.
|
||||
- If you tap the key while holding the specified modifier, the second keycode is sent.
|
||||
- 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
|
||||
|
||||
The Mod-Morph behavior acts as one of two keycodes, depending on if the required modifier is being held during the keypress.
|
||||
|
||||
### Configuration
|
||||
|
||||
An example of how to implement the mod-morph "Grave Escape":
|
||||
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
|
||||
/ {
|
||||
|
@ -31,7 +30,7 @@ An example of how to implement the mod-morph "Grave Escape":
|
|||
};
|
||||
```
|
||||
|
||||
Note that this specific mod-morph exists in ZMK by default using code `&gresc`.
|
||||
Note that this specific mod-morph exists in ZMK by default using the binding `&gresc`.
|
||||
|
||||
### Behavior Binding
|
||||
|
||||
|
@ -67,7 +66,7 @@ mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
|
|||
|
||||
### Advanced Configuration
|
||||
|
||||
`keep-mods`
|
||||
#### `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.
|
||||
|
||||
|
@ -87,6 +86,34 @@ For example, the following configuration morphs `LEFT_SHIFT` + `BACKSPACE` into
|
|||
};
|
||||
```
|
||||
|
||||
#### 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -51,6 +51,13 @@ Creates a custom behavior that triggers one behavior when a key is held or a dif
|
|||
|
||||
See the [hold-tap behavior](../behaviors/hold-tap.mdx) documentation for more details and examples.
|
||||
|
||||
### Kconfig
|
||||
|
||||
| Config | Type | Description | Default |
|
||||
| -------------------------------------------------- | ---- | -------------------------------------------------------------------------------------------- | ------- |
|
||||
| `CONFIG_ZMK_BEHAVIOR_HOLD_TAP_MAX_HELD` | int | Maximum number of simultaneous held hold-taps | 10 |
|
||||
| `CONFIG_ZMK_BEHAVIOR_HOLD_TAP_MAX_CAPTURED_EVENTS` | int | Maximum number of system events to capture while deferring a hold or tap decision resolution | 40 |
|
||||
|
||||
### Devicetree
|
||||
|
||||
Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-hold-tap.yaml)
|
||||
|
@ -227,6 +234,12 @@ Creates a custom behavior that triggers a behavior and keeps it pressed it until
|
|||
|
||||
See the [sticky key behavior](../behaviors/sticky-key.md) and [sticky layer behavior](../behaviors/sticky-layer.md) documentation for more details and examples.
|
||||
|
||||
### Kconfig
|
||||
|
||||
| Config | Type | Description | Default |
|
||||
| ----------------------------------------- | ---- | ----------------------------------------------- | ------- |
|
||||
| `CONFIG_ZMK_BEHAVIOR_STICKY_KEY_MAX_HELD` | int | Maximum number of simultaneous held sticky keys | 10 |
|
||||
|
||||
### Devicetree
|
||||
|
||||
Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-sticky-key.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-sticky-key.yaml)
|
||||
|
|
|
@ -9,10 +9,10 @@ See [Configuration Overview](index.md) for instructions on how to change these s
|
|||
|
||||
## Kconfig
|
||||
|
||||
| Option | Type | Description | Default |
|
||||
| -------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
|
||||
| `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` | bool | Enables a combination of settings that are planned to be default in future versions of ZMK to improve connection stability. This includes changes to timing on BLE pairing initiation, restores use of the updated/new LLCP implementation, and disables 2M PHY support. | n |
|
||||
| `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC` | bool | Enables a combination of settings that are planned to be officially supported in the future. This includes enabling BT Secure Connection passkey entry, and allows overwrite of keys from previously paired hosts. | n |
|
||||
| `CONFIG_ZMK_BLE_EXPERIMENTAL_FEATURES` | bool | Aggregate config that enables both `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` and `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC`. | n |
|
||||
| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts.) | n |
|
||||
| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y |
|
||||
| Option | Type | Description | Default |
|
||||
| -------------------------------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
|
||||
| `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` | bool | Enables a combination of settings that are planned to be default in future versions of ZMK to improve connection stability. Currently this only disables 2M PHY support. | n |
|
||||
| `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC` | bool | Enables a combination of settings that are planned to be officially supported in the future. This includes enabling BT Secure Connection passkey entry, and allows overwrite of keys from previously paired hosts. | n |
|
||||
| `CONFIG_ZMK_BLE_EXPERIMENTAL_FEATURES` | bool | Aggregate config that enables both `CONFIG_ZMK_BLE_EXPERIMENTAL_CONN` and `CONFIG_ZMK_BLE_EXPERIMENTAL_SEC`. | n |
|
||||
| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts.) | n |
|
||||
| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y |
|
||||
|
|
|
@ -24,22 +24,22 @@ 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
|
||||
|
||||
ZMK will search for config files in either of:
|
||||
ZMK will search for config files in:
|
||||
|
||||
- [`zmk/app/boards/arm/<board>`](https://github.com/zmkfirmware/zmk/tree/main/app/boards/arm)
|
||||
- `zmk-config/config/boards/arm/<board>`
|
||||
- `zmk-config/boards/arm/<board>`
|
||||
- `<module>/boards/arm/<board>`
|
||||
- `zmk-config/config/boards/arm/<board>` (For backwards compatibility only, do not use.)
|
||||
|
||||
...where `<board>` is the name of the board. These files describe the hardware of the board.
|
||||
...where `<board>` is the name of the board and `<module>` is the root directory of any [included module](../features/modules.mdx). These files describe the hardware of the board.
|
||||
|
||||
ZMK will search the board folder for the following config files:
|
||||
ZMK will search the board folder for the following config files _in addition_ to [Zephyr board-defining files](https://docs.zephyrproject.org/3.5.0/hardware/porting/board_porting.html#create-your-board-directory):
|
||||
|
||||
- `<board>_defconfig` (Kconfig)
|
||||
- `<board>.conf` (Kconfig)
|
||||
- `<board>.dts` (Devicetree)
|
||||
- `<board>.keymap` (Devicetree, keyboards with onboard controllers only)
|
||||
|
||||
Shared config files (excluding any `_left` or `_right` suffix) are not currently supported in board folders.
|
||||
|
@ -48,17 +48,18 @@ For more documentation on creating and configuring a new board, see [Zephyr's bo
|
|||
|
||||
### Shield Folder
|
||||
|
||||
When building with a shield, ZMK will search for config files in either of:
|
||||
When building with a shield, ZMK will search for config files in:
|
||||
|
||||
- [`zmk/app/boards/shields/<shield>`](https://github.com/zmkfirmware/zmk/tree/main/app/boards/shields)
|
||||
- `zmk-config/config/boards/shields/<shield>`
|
||||
- `zmk-config/boards/shields/<shield>`
|
||||
- `<module>/boards/shields/<shield>`
|
||||
- `zmk-config/config/boards/shields/<shield>` (For backwards compatibility only, do not use.)
|
||||
|
||||
...where `<shield>` is the name of the shield. These files describe the hardware of the shield that the board is plugged into.
|
||||
...where `<shield>` is the name of the shield and `<module>` is the root directory of any [included module](../features/modules.mdx). These files describe the hardware of the shield that the board is plugged into.
|
||||
|
||||
ZMK will search the shield folder for the following config files:
|
||||
ZMK will search the shield folder for the following config files _in addition_ to [Zephyr shield-defining files](https://docs.zephyrproject.org/3.5.0/hardware/porting/shields.html#shield-porting-and-configuration):
|
||||
|
||||
- `<shield>.conf` (Kconfig)
|
||||
- `<shield>.overlay` (Devicetree)
|
||||
- `<shield>.keymap` (Devicetree)
|
||||
|
||||
Shared config files (excluding any `_left` or `_right` suffix) are not currently supported in shield folders.
|
||||
|
|
|
@ -342,7 +342,7 @@ Transforms should be used any time the physical layout of a keyboard's keys does
|
|||
|
||||
Transforms can also be used for keyboards with multiple layouts. You can define multiple matrix transform nodes, one for each layout, and users can select which one they want from the `/chosen` node in their keymaps.
|
||||
|
||||
See the [new shield guide](../development/new-shield.mdx#optional-matrix-transform) for more documentation on how to define a matrix transform.
|
||||
See the [new shield guide](../development/new-shield.mdx#matrix-transform) for more documentation on how to define a matrix transform.
|
||||
|
||||
### Devicetree
|
||||
|
||||
|
|
|
@ -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 |
|
||||
| ------------------------------------------------------- | ---- | -------------------------------------------------------------------------- | ------------------------------------------ |
|
||||
|
@ -125,6 +125,7 @@ Following split keyboard settings are defined in [zmk/app/src/split/Kconfig](htt
|
|||
| `CONFIG_ZMK_SPLIT_ROLE_CENTRAL` | bool | `y` for central device, `n` for peripheral | |
|
||||
| `CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS` | bool | Enable split keyboard support for passing indicator state to peripherals | n |
|
||||
| `CONFIG_ZMK_SPLIT_BLE` | bool | Use BLE to communicate between split keyboard halves | y |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS` | int | Number of peripherals that will connect to the central | 1 |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING` | bool | Enable fetching split peripheral battery levels to the central side | n |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_PROXY` | bool | Enable central reporting of split battery levels to hosts | n |
|
||||
| `CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_QUEUE_SIZE` | int | Max number of battery level events to queue when received from peripherals | `CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS` |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -108,6 +108,10 @@ west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Doc
|
|||
The above command must still be invoked from the `zmk/app` directory as noted above, rather than the config directory. Otherwise, you will encounter errors such as `ERROR: source directory "." does not contain a CMakeLists.txt; is this really what you want to build?`. Alternatively you can add the `-s /path/to/zmk/app` flag to your `west` command.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
If your config is also a [module](../features/modules.mdx), then you should also add the root (the folder in which the `zephyr` folder is found) of your `zmk-config` as an [external module to build with](#building-with-external-modules).
|
||||
:::
|
||||
|
||||
In order to make your `zmk-config` folder available when building within the VSCode Remote Container, you need to create a docker volume named `zmk-config`
|
||||
by binding it to the full path of your config directory. If you have run the VSCode Remote Container before, it is likely that docker has created this
|
||||
volume automatically -- we need to delete the default volume before binding it to the correct path. Follow the following steps:
|
||||
|
|
|
@ -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)`
|
||||
|
|
|
@ -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
|
||||
|
@ -51,6 +51,13 @@ Follow these steps to create your new repository:
|
|||
- Select Public or Private, depending on your preference.
|
||||
- Click the green "Create repository" button
|
||||
|
||||
The repository is a combination of the directories and files required of a ZMK config, and those required of a shield module. To create a shield module, the following components are needed:
|
||||
|
||||
- The `boards/shields` directory, where the keyboard's files will go
|
||||
- The `zephyr/module.yml` file, which identifies and describes the module. See the [Zephyr documentation](https://docs.zephyrproject.org/3.5.0/develop/modules.html#module-yaml-file-description) for details on customising this file. For the purposes of creating a shield module, the default found in the template can be left untouched.
|
||||
|
||||
Neither of these should be moved out of their parent directory. The other files and directories such as `config` are not necessary for the purposes of a shield module, but rather intended to be used for user configuration and testing.
|
||||
|
||||
## New Shield Directory
|
||||
|
||||
:::note
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
---
|
||||
title: Beta Testing
|
||||
sidebar_label: Beta Testing
|
||||
---
|
||||
|
||||
import Tabs from "@theme/Tabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
|
||||
You may find that ZMK does not support a feature or keyboard that you are interesting in using. You may find that someone
|
||||
has already taken the time to submit the feature you need as a [Pull Request](https://github.com/zmkfirmware/zmk/pulls). If you find the feature you need as a pull request,
|
||||
this page is for you!
|
||||
|
||||
## Developer Repositories and Branches
|
||||
|
||||
For a developer to submit a pull request to ZMK, they must first clone the original ZMK repository. After they have a copy
|
||||
of the source code, they may create a feature branch to work within. When they have finished, they will publish the feature
|
||||
branch and create the pull request.
|
||||
|
||||
### Finding the Repository Page from the Pull Request
|
||||
|
||||

|
||||
|
||||
### Finding the Repository URL
|
||||
|
||||

|
||||
|
||||
### Finding the Repository Branch
|
||||
|
||||

|
||||
|
||||
## Testing Features
|
||||
|
||||
Testing features will require you to modify the `west.yml` file. You will need to add a new remote for the pull request you
|
||||
would like to test, and change the selected remote and revision (or branch) for the `zmk` project.
|
||||
|
||||
### Examples
|
||||
|
||||
<Tabs
|
||||
defaultValue="zmk"
|
||||
values={[
|
||||
{label: 'Default', value: 'zmk'},
|
||||
{label: 'PR685: Macros', value: 'macros'},
|
||||
{label: 'PR649: Add &sleep behavior', value: 'sleep'},
|
||||
]}>
|
||||
<TabItem value="zmk">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: zmkfirmware
|
||||
revision: main
|
||||
import: app/west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="macros">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
- name: okke-formsma
|
||||
url-base: https://github.com/okke-formsma
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: okke-formsma
|
||||
revision: macros
|
||||
import: app/west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="sleep">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
- name: mcrosson
|
||||
url-base: https://github.com/mcrosson
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: mcrosson
|
||||
revision: feat-behavior-sleep
|
||||
import: app/west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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`, `<` 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.
|
||||
|
|
|
@ -4,7 +4,6 @@ sidebar_label: Keymaps
|
|||
---
|
||||
|
||||
import KeymapExample from "../keymap-example.md";
|
||||
import KeymapExampleFile from "../keymap-example-file.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
|
||||
|
@ -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.
|
||||
|
||||
|  |
|
||||
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| _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").
|
||||
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
:::
|
||||
|
|
194
docs/docs/features/modules.mdx
Normal file
194
docs/docs/features/modules.mdx
Normal file
|
@ -0,0 +1,194 @@
|
|||
---
|
||||
title: Modules
|
||||
sidebar_label: Modules
|
||||
---
|
||||
|
||||
import Tabs from "@theme/Tabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
|
||||
ZMK makes use of [Zephyr modules](https://docs.zephyrproject.org/3.5.0/develop/modules.html) to include additional source code or configuration files into its build. You can think of them as similar to plugins or themes. The most common uses of this feature are:
|
||||
|
||||
- Building firmware for a keyboard external to ZMK's tree
|
||||
- Adding functionality to ZMK, such as a driver or a behavior
|
||||
|
||||
A common ZMK setup thus consists of the following separate components, commonly housed in their respective Git repositories:
|
||||
|
||||
- A single ZMK config maintained by the user, containing the `.conf` and `.keymap` files for one or multiple keyboards. This is also where files from ZMK or modules should be overridden/modified, if there is a need.
|
||||
- Any number of ZMK modules, maintained by the module's owner. Some modules may contain multiple keyboards or functionalities. If all of your keyboards and functionalities are internal to ZMK's tree, then no modules are necessary.
|
||||
- The ZMK firmware itself, maintained by its contributors.
|
||||
|
||||
:::note
|
||||
The shift to using modules for keyboards is a relatively recent one, and not all designs may be properly configured to be used as a module. If this is the case for your keyboard, then we would strongly suggest asking your vendor or designer to rectify this.
|
||||
:::
|
||||
|
||||
## Building With Modules
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
When [using GitHub Actions to build ZMK](../user-setup.mdx), adding modules is as simple as modifying the `west.yml` found in your `zmk-config`'s `config` directory. The recommended way of doing so is:
|
||||
|
||||
1. Find the URL base (the parent URL) for the module and add it as an entry to the [remotes](https://docs.zephyrproject.org/3.5.0/develop/west/manifest.html#remotes).
|
||||
2. Add the module as an entry to the [projects](https://docs.zephyrproject.org/3.5.0/develop/west/manifest.html#projects).
|
||||
Aside from the mandatory `name`, `remote`, and the commonly used `revision` properties, take note of the `import` property under `projects`. Some modules may have other modules as dependencies. This property allows the specifying of an additional west manifest file found in the tree of the module, which will automatically import all dependencies.
|
||||
|
||||
For more information on `west.yml`, see [West Manifests](https://docs.zephyrproject.org/3.5.0/develop/west/manifest.html).
|
||||
|
||||
#### Examples
|
||||
|
||||
<Tabs
|
||||
defaultValue="zmk"
|
||||
values={[
|
||||
{label: 'Default', value: 'zmk'},
|
||||
{label: 'Module A', value: 'ma'},
|
||||
{label: 'Modules A + B', value: 'mab'},
|
||||
]}>
|
||||
<TabItem value="zmk">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: zmkfirmware
|
||||
revision: main
|
||||
import: app/west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="ma">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
- name: module_a_base
|
||||
url-base: https://github.com/alice
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: zmkfirmware
|
||||
revision: main
|
||||
import: app/west.yml
|
||||
- name: module_a
|
||||
remote: module_a_base
|
||||
revision: main
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="mab">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
- name: module_a_base
|
||||
url-base: https://github.com/alice
|
||||
- name: module_b_base
|
||||
url-base: https://github.com/bob
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: zmkfirmware
|
||||
revision: main
|
||||
import: app/west.yml
|
||||
- name: module_a
|
||||
remote: module_a_base
|
||||
revision: main
|
||||
- name: module_b
|
||||
remote: module_b_base
|
||||
revision: main
|
||||
import: west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Building Locally
|
||||
|
||||
To add a module to your build when building locally, you will need to clone/copy said module into your local file tree. You can then build using the module as described in [Building with External Modules](../development/build-flash.mdx#building-with-external-modules).
|
||||
|
||||
## Beta Testing
|
||||
|
||||
You may find that there are some features which you desire for which there is a [Pull Request](https://github.com/zmkfirmware/zmk/pulls), but no module. If this is the case, you can still make use of the feature.
|
||||
|
||||
### Developer Repositories and Branches
|
||||
|
||||
For a developer to submit a pull request to ZMK, they must first clone the original ZMK repository. After they have a copy
|
||||
of the source code, they may create a feature branch to work within. When they have finished, they will publish the feature
|
||||
branch and create the pull request.
|
||||
|
||||
#### Finding the repository page from the Pull Request
|
||||
|
||||

|
||||
|
||||
#### Finding the repository URL
|
||||
|
||||

|
||||
|
||||
#### Finding the repository branch
|
||||
|
||||

|
||||
|
||||
## Testing Features
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
When [using GitHub Actions to build ZMK](../user-setup.mdx), once you have obtained the correct URL, you'll need to modify the `west.yml` file similarly to [Building With Modules](#building-with-modules). Add the remote for the branch like in said section. The difference is that you will need to change the selected remote and revision (or branch) for the `zmk` project.
|
||||
|
||||
#### Example
|
||||
|
||||
<Tabs
|
||||
defaultValue="zmk"
|
||||
values={[
|
||||
{label: 'Default', value: 'zmk'},
|
||||
{label: 'Alterative', value: 'alt'},
|
||||
]}>
|
||||
<TabItem value="zmk">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: zmkfirmware
|
||||
revision: main
|
||||
import: app/west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="alt">
|
||||
|
||||
```yaml
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zmkfirmware
|
||||
url-base: https://github.com/zmkfirmware
|
||||
- name: forkedzmk
|
||||
url-base: https://github.com/forkedzmk
|
||||
projects:
|
||||
- name: zmk
|
||||
remote: forkedzmk
|
||||
revision: specificpr
|
||||
import: app/west.yml
|
||||
self:
|
||||
path: config
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Building Locally
|
||||
|
||||
When building from a pull request locally, you'll need to [perform the local user setup](../development/setup/index.md), but using the repository of the pull request rather than the official ZMK repository. You can then [build and flash](../development/build-flash.mdx) as usual.
|
101
docs/docs/features/split-keyboards.md
Normal file
101
docs/docs/features/split-keyboards.md
Normal file
|
@ -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,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
|
||||
// ----------------------------------------------
|
||||
// | 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>;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
|
@ -23,12 +23,18 @@ If you get an error stating `Keymap node not found, check a keymap is available
|
|||
|
||||
### Devicetree Errors
|
||||
|
||||
#### "parse error"
|
||||
|
||||
A `devicetree error` followed by a reference to the line number on `<keyboard>.keymap` refers to an issue at the exact line position in that file. For example, below error message indicates a missing `;` at line 109 of the `cradio.keymap` file:
|
||||
|
||||
```
|
||||
devicetree error: /__w/zmk-config/zmk-config/config/cradio.keymap:109 (column 4): parse error: expected ';' or ','
|
||||
```
|
||||
|
||||
Note that the provided number for the column corresponds to the numbering after the preprocessor expansion and it will likely not match the column numbers in your keymap.
|
||||
|
||||
#### "lacks #binding-cells"
|
||||
|
||||
A `devicetree error` followed by an `empty_file.c` reference with `lacks #binding-cells` string indicates possible problems with improper parameters for specific bindings:
|
||||
|
||||
```
|
||||
|
@ -37,6 +43,8 @@ devicetree error: <Node /soc/gpio@50000300 in '/tmp/tmp.vJq9sMwkcY/zephyr/misc/e
|
|||
|
||||
This error can be triggered by incorrect binding syntax such as `&kp BT_SEL 0` instead of `&bt BT_SEL 0`.
|
||||
|
||||
#### "devicetree_generated.h[...] undeclared here"
|
||||
|
||||
A `devicetree_generated.h` error that follows with an "undeclared here" string indicates a problem with key bindings, like behavior nodes (e.g. `&kp` or `&mt`) with incorrect number of parameters:
|
||||
|
||||
```
|
||||
|
|
|
@ -22,9 +22,13 @@ export const Uf2Tabs = (props) => (
|
|||
|
||||
);
|
||||
|
||||
:::tip
|
||||
[USB logging](../development/usb-logging.mdx) can be very helpful for diagnosing issues with ZMK. However, when connected to USB your ZMK device will output to USB by default. To troubleshoot wireless connection issues using logging, you will need to [change the preferred output endpoint](../behaviors/outputs.md).
|
||||
:::
|
||||
|
||||
## 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.
|
||||
|
@ -91,6 +95,32 @@ The settings reset firmware has Bluetooth disabled to prevent the two sides from
|
|||
|
||||
:::
|
||||
|
||||
## Unable to Connect to Device
|
||||
|
||||
### Additional Bluetooth Options
|
||||
|
||||
Some devices and operating systems may have additional restrictions that they require be met before allowing a bluetooth peripheral to pair with them. If your keyboard is visible to your host but you are having issues trouble connecting or no input is registered, this might be the cause. Some of ZMK's [experimental bluetooth settings](../config/bluetooth.md) may suffice to resolve the issue. In particular:
|
||||
|
||||
- Disabling PHY 2Mbps ([`CONFIG_BT_CTLR_PHY_2M=n`](https://docs.zephyrproject.org/3.5.0/kconfig.html#CONFIG_BT_CTLR_PHY_2M)) helps to pair and connect for certain wireless chipset firmware versions, particularly on Windows (Realtek and Intel chips) and older Intel Macs with Broadcom chipsets.
|
||||
- Enabling passkey entry ([`CONFIG_ZMK_BLE_PASSKEY_ENTRY=y`](../config/bluetooth.md)) helps for certain Windows computers (work-managed ones in particular). This may also manifest in not sending keystrokes.
|
||||
|
||||
### Issues With Dual Boot Setups
|
||||
|
||||
Since ZMK associates pairing/bond keys with hardware addresses of hosts, you cannot pair to two different operating systems in a dual boot system at the same time.
|
||||
While you can find [documented workarounds](https://wiki.archlinux.org/title/bluetooth#Dual_boot_pairing) that involve copying pairing keys across operating systems and use both OS with a single profile, they can be fairly involved and should be followed with caution.
|
||||
|
||||
### Mitigating a Faulty Oscillator
|
||||
|
||||
Rarely, due to a manufacturing error, a device may have a faulty oscillator. This prevents it from functioning correctly wirelessly and can be difficult to diagnose. Some microcontrollers such as the `nRF52840` allow for the usage of an internal oscillator instead of an external one. This results in increased power draw but can be a solution if your device does indeed have a faulty oscillator.
|
||||
|
||||
For the `nRF52840`, the flag to set to use the internal oscillator is:
|
||||
|
||||
```
|
||||
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
|
||||
```
|
||||
|
||||
Other microcontrollers may have similar configuration options [found in the Zephyr documentation](https://docs.zephyrproject.org/3.5.0/search.html?q=CONFIG_CLOCK_CONTROL&check_keywords=yes&area=default). Do note that not all microcontrollers allow for the use of an internal oscillator, though.
|
||||
|
||||
## Issues While Connected
|
||||
|
||||
### Unreliable/Weak Connection
|
||||
|
@ -111,11 +141,6 @@ This setting can also improve the connection strength between the keyboard halve
|
|||
|
||||
If you want to test Bluetooth output on your keyboard and are powering it through the USB connection rather than a battery, you will be able to pair with a host device but may not see keystrokes sent. In this case you need to use the [output selection behavior](../behaviors/outputs.md) to prefer sending keystrokes over Bluetooth rather than USB. This might be necessary even if you are not powering from a device capable of receiving USB inputs, such as a USB charger.
|
||||
|
||||
### Issues With Dual Boot Setups
|
||||
|
||||
Since ZMK associates pairing/bond keys with hardware addresses of hosts, you cannot pair to two different operating systems in a dual boot system at the same time.
|
||||
While you can find [documented workarounds](https://wiki.archlinux.org/title/bluetooth#Dual_boot_pairing) that involve copying pairing keys across operating systems and use both OS with a single profile, they can be fairly involved and should be followed with caution.
|
||||
|
||||
### macOS Connected but Not Working
|
||||
|
||||
If you attempt to pair a ZMK keyboard from macOS in a way that causes a bonding issue, macOS may report the keyboard as connected, but fail to actually work. If this occurs:
|
||||
|
@ -138,3 +163,5 @@ If this doesn't help, try following the procedure above but replace step 3 with
|
|||
|
||||
- Restart the Windows device
|
||||
- Open "Device Manager," turn on "Show hidden devices" from the "View" menu, then find and delete the keyboard under the "Bluetooth" item
|
||||
|
||||
Some Windows devices may also require passkey entry, described under ["Unable to Connect to Device"](#unable-to-connect-to-device).
|
||||
|
|
|
@ -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.
|
||||
|
||||
:::
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
|
261
docs/sidebars.js
261
docs/sidebars.js
|
@ -1,120 +1,151 @@
|
|||
module.exports = {
|
||||
docs: {
|
||||
"Getting Started": [
|
||||
"intro",
|
||||
"hardware",
|
||||
"faq",
|
||||
"user-setup",
|
||||
"customization",
|
||||
{
|
||||
type: "category",
|
||||
label: "Troubleshooting",
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "troubleshooting/index",
|
||||
docs: [
|
||||
{
|
||||
type: "category",
|
||||
label: "Getting Started",
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "intro",
|
||||
},
|
||||
collapsed: false,
|
||||
items: [
|
||||
"hardware",
|
||||
"faq",
|
||||
"user-setup",
|
||||
"customization",
|
||||
{
|
||||
type: "category",
|
||||
label: "Troubleshooting",
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "troubleshooting/index",
|
||||
},
|
||||
collapsed: true,
|
||||
items: [
|
||||
"troubleshooting/building-issues",
|
||||
"troubleshooting/flashing-issues",
|
||||
"troubleshooting/connection-issues",
|
||||
],
|
||||
},
|
||||
collapsed: true,
|
||||
items: [
|
||||
"troubleshooting/building-issues",
|
||||
"troubleshooting/flashing-issues",
|
||||
"troubleshooting/connection-issues",
|
||||
],
|
||||
],
|
||||
},
|
||||
{
|
||||
Features: [
|
||||
"features/keymaps",
|
||||
"features/bluetooth",
|
||||
"features/split-keyboards",
|
||||
"features/combos",
|
||||
"features/conditional-layers",
|
||||
"features/debouncing",
|
||||
"features/displays",
|
||||
"features/encoders",
|
||||
"features/modules",
|
||||
"features/underglow",
|
||||
"features/backlight",
|
||||
"features/battery",
|
||||
"features/soft-off",
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Behaviors",
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "behaviors/index",
|
||||
},
|
||||
],
|
||||
Features: [
|
||||
"features/keymaps",
|
||||
"features/bluetooth",
|
||||
"features/combos",
|
||||
"features/conditional-layers",
|
||||
"features/debouncing",
|
||||
"features/displays",
|
||||
"features/encoders",
|
||||
"features/underglow",
|
||||
"features/backlight",
|
||||
"features/battery",
|
||||
"features/soft-off",
|
||||
"features/beta-testing",
|
||||
],
|
||||
Behaviors: [
|
||||
"behaviors/index",
|
||||
"behaviors/key-press",
|
||||
"behaviors/layers",
|
||||
"behaviors/misc",
|
||||
"behaviors/hold-tap",
|
||||
"behaviors/mod-tap",
|
||||
"behaviors/mod-morph",
|
||||
"behaviors/macros",
|
||||
"behaviors/key-toggle",
|
||||
"behaviors/sticky-key",
|
||||
"behaviors/sticky-layer",
|
||||
"behaviors/tap-dance",
|
||||
"behaviors/caps-word",
|
||||
"behaviors/key-repeat",
|
||||
"behaviors/sensor-rotate",
|
||||
"behaviors/mouse-emulation",
|
||||
"behaviors/reset",
|
||||
"behaviors/bluetooth",
|
||||
"behaviors/outputs",
|
||||
"behaviors/underglow",
|
||||
"behaviors/backlight",
|
||||
"behaviors/power",
|
||||
"behaviors/soft-off",
|
||||
],
|
||||
Codes: [
|
||||
"codes/index",
|
||||
"codes/keyboard-keypad",
|
||||
"codes/modifiers",
|
||||
"codes/editing",
|
||||
"codes/media",
|
||||
"codes/applications",
|
||||
"codes/input-assist",
|
||||
"codes/power",
|
||||
],
|
||||
Configuration: [
|
||||
"config/index",
|
||||
"config/backlight",
|
||||
"config/battery",
|
||||
"config/behaviors",
|
||||
"config/bluetooth",
|
||||
"config/combos",
|
||||
"config/displays",
|
||||
"config/encoders",
|
||||
"config/keymap",
|
||||
"config/kscan",
|
||||
"config/power",
|
||||
"config/underglow",
|
||||
"config/system",
|
||||
],
|
||||
Development: [
|
||||
"development/clean-room",
|
||||
"development/pre-commit",
|
||||
"development/documentation",
|
||||
{
|
||||
type: "category",
|
||||
label: "Setup",
|
||||
collapsed: true,
|
||||
items: [
|
||||
"development/setup/index",
|
||||
"development/setup/docker",
|
||||
"development/setup/native",
|
||||
],
|
||||
collapsed: true,
|
||||
items: [
|
||||
"behaviors/key-press",
|
||||
"behaviors/layers",
|
||||
"behaviors/misc",
|
||||
"behaviors/hold-tap",
|
||||
"behaviors/mod-tap",
|
||||
"behaviors/mod-morph",
|
||||
"behaviors/macros",
|
||||
"behaviors/key-toggle",
|
||||
"behaviors/sticky-key",
|
||||
"behaviors/sticky-layer",
|
||||
"behaviors/tap-dance",
|
||||
"behaviors/caps-word",
|
||||
"behaviors/key-repeat",
|
||||
"behaviors/sensor-rotate",
|
||||
"behaviors/mouse-emulation",
|
||||
"behaviors/reset",
|
||||
"behaviors/bluetooth",
|
||||
"behaviors/outputs",
|
||||
"behaviors/underglow",
|
||||
"behaviors/backlight",
|
||||
"behaviors/power",
|
||||
"behaviors/soft-off",
|
||||
],
|
||||
},
|
||||
{
|
||||
Codes: [
|
||||
"codes/index",
|
||||
"codes/keyboard-keypad",
|
||||
"codes/modifiers",
|
||||
"codes/editing",
|
||||
"codes/media",
|
||||
"codes/applications",
|
||||
"codes/input-assist",
|
||||
"codes/power",
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "Configuration",
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "config/index",
|
||||
},
|
||||
"development/build-flash",
|
||||
"development/boards-shields-keymaps",
|
||||
"development/posix-board",
|
||||
"development/tests",
|
||||
"development/usb-logging",
|
||||
"development/ide-integration",
|
||||
{
|
||||
type: "category",
|
||||
label: "Guides",
|
||||
collapsed: false,
|
||||
items: [
|
||||
"development/new-shield",
|
||||
"development/hardware-metadata-files",
|
||||
"development/new-behavior",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
collapsed: true,
|
||||
items: [
|
||||
"config/backlight",
|
||||
"config/battery",
|
||||
"config/behaviors",
|
||||
"config/bluetooth",
|
||||
"config/combos",
|
||||
"config/displays",
|
||||
"config/encoders",
|
||||
"config/keymap",
|
||||
"config/kscan",
|
||||
"config/power",
|
||||
"config/underglow",
|
||||
"config/system",
|
||||
],
|
||||
},
|
||||
{
|
||||
Development: [
|
||||
"development/clean-room",
|
||||
"development/pre-commit",
|
||||
"development/documentation",
|
||||
{
|
||||
type: "category",
|
||||
label: "Setup",
|
||||
collapsed: true,
|
||||
items: [
|
||||
"development/setup/index",
|
||||
"development/setup/docker",
|
||||
"development/setup/native",
|
||||
],
|
||||
},
|
||||
"development/build-flash",
|
||||
"development/boards-shields-keymaps",
|
||||
"development/posix-board",
|
||||
"development/tests",
|
||||
"development/usb-logging",
|
||||
"development/ide-integration",
|
||||
{
|
||||
type: "category",
|
||||
label: "Guides",
|
||||
collapsed: false,
|
||||
items: [
|
||||
"development/new-shield",
|
||||
"development/hardware-metadata-files",
|
||||
"development/new-behavior",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue