diff --git a/app/src/behaviors/behavior_default_layer.c b/app/src/behaviors/behavior_default_layer.c index 64613dae..b186462f 100644 --- a/app/src/behaviors/behavior_default_layer.c +++ b/app/src/behaviors/behavior_default_layer.c @@ -20,12 +20,22 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + struct default_layer_settings_t { + bool using_global_setting; + uint8_t global_default; uint8_t endpoint_defaults[ZMK_ENDPOINT_COUNT]; }; static struct default_layer_settings_t default_layers = {0}; +static struct k_work_delayable df_layers_save_work; + +static void zmk_default_layers_save_state_work(struct k_work *_work) { + settings_save_one("default_layer/settings", &default_layers, sizeof(default_layers)); +} + static int apply_default_layer_config(struct zmk_endpoint_instance endpoint) { uint8_t index = zmk_endpoint_instance_to_index(endpoint); uint8_t layer = default_layers.endpoint_defaults[index]; @@ -75,14 +85,14 @@ static int default_layer_init(void) { return ret; } + k_work_init_delayable(&df_layers_save_work, zmk_default_layers_save_state_work); + settings_load_subtree("default_layer"); return apply_default_layer_config(zmk_endpoints_selected()); } SYS_INIT(default_layer_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); -#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) - static int save_default_layer_setting(uint8_t layer, struct zmk_endpoint_instance endpoint) { if (layer >= ZMK_KEYMAP_LAYERS_LEN) { return -EINVAL; @@ -91,14 +101,12 @@ static int save_default_layer_setting(uint8_t layer, struct zmk_endpoint_instanc uint8_t index = zmk_endpoint_instance_to_index(endpoint); default_layers.endpoint_defaults[index] = layer; - int ret = settings_save_one("default_layer/settings", &default_layers, sizeof(default_layers)); - if (ret < 0) { - LOG_WRN("Could not update the settings."); - return ret; - } + char endpoint_str[ZMK_ENDPOINT_STR_LEN]; + zmk_endpoint_instance_to_str(endpoint, endpoint_str, sizeof(endpoint_str)); + LOG_INF("Updated default layer (%d) for %s.", layer, endpoint_str); - LOG_INF("Updated default layer (%d) for endpoint (%d).", layer, index); - return 0; + int ret = k_work_reschedule(&df_layers_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE)); + return MIN(0, ret); } static int behavior_default_layer_init(const struct device *dev) { return 0; } diff --git a/docs/docs/behaviors/index.mdx b/docs/docs/behaviors/index.mdx index 4a05f565..24d73ae6 100644 --- a/docs/docs/behaviors/index.mdx +++ b/docs/docs/behaviors/index.mdx @@ -37,6 +37,7 @@ Below is a summary of pre-defined behavior bindings and user-definable behaviors | `&to` | [To Layer](layers.md#to-layer) | Enables a layer and disables all other layers except the default layer | | `&tog` | [Toggle Layer](layers.md#toggle-layer) | Enables a layer until the layer is manually disabled | | `&sl` | [Sticky Layer](sticky-layer.md) | Activates a layer until another key is pressed, then deactivates it | +| `&df` | [Default Layer](layers.md#default-layer) | Change the default layer. Persisted across power reset. | ## Mouse emulation behaviors diff --git a/docs/docs/behaviors/layers.md b/docs/docs/behaviors/layers.md index 3efb50bf..2367c4a6 100644 --- a/docs/docs/behaviors/layers.md +++ b/docs/docs/behaviors/layers.md @@ -156,9 +156,16 @@ For more information, see [conditional layers](../features/conditional-layers.md ## Default Layer -The default layer behavior allows configuring a different default layer, for example to test DVORAK while keeping QWERTY on another layer, or moving a couple keycodes around for Windows/Mac usage. +?> What is the default layer? -This is stored on a per-endpoint basis, so you can configure USB to use QWERTY, and the first BLE endpoint to use DVORAK. +It is the first one you define on your keymap (unless changed using this behavior). It is _special_ in two aspects: + +- It can't be disabled by other behaviors. +- It is the only one active when the board starts running. + +This behavior allows configuring a different default layer, for example to test DVORAK while keeping QWERTY on another layer, or moving a couple keycodes around for Windows/Mac usage. + +This setting is stored on a per-endpoint basis, so you can configure USB to use QWERTY, and the first BLE endpoint to use DVORAK. The stored settings are read and applied when the keyboard boots (receives powers) and also when the selected endpoint changes. diff --git a/docs/docs/config/keymap.md b/docs/docs/config/keymap.md index f0498b8c..b02c40e2 100644 --- a/docs/docs/config/keymap.md +++ b/docs/docs/config/keymap.md @@ -13,7 +13,7 @@ Applies to: `compatible = "zmk,keymap"` Definition file: [zmk/app/dts/bindings/zmk,keymap.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Ckeymap.yaml) -The `zmk,keymap` node itself has no properties. It should have one child node per layer of the keymap, starting with the default layer (layer 0). +The `zmk,keymap` node itself has no properties. It should have one child node per layer of the keymap, the first one being the default layer (until changed with [`&df`](layers.md#default-layer)). Each child node can have the following properties: