Merge b73904c624
into 9e7fcde868
This commit is contained in:
commit
5124284055
28 changed files with 486 additions and 9 deletions
|
@ -53,6 +53,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MACRO app PRIVATE src/behaviors/behavior_macro.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer_lock.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_outputs.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <behaviors/gresc.dtsi>
|
||||
#include <behaviors/sticky_key.dtsi>
|
||||
#include <behaviors/momentary_layer.dtsi>
|
||||
#include <behaviors/momentary_layer_lock.dtsi>
|
||||
#include <behaviors/toggle_layer.dtsi>
|
||||
#include <behaviors/to_layer.dtsi>
|
||||
#include <behaviors/reset.dtsi>
|
||||
|
|
15
app/dts/behaviors/momentary_layer_lock.dtsi
Normal file
15
app/dts/behaviors/momentary_layer_lock.dtsi
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
/omit-if-no-ref/ molock: behavior_momentary_layer_lock {
|
||||
compatible = "zmk,behavior-momentary-layer-lock";
|
||||
#binding-cells = <0>;
|
||||
bindings = <&to 0>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Momentary layer on press/release behavior
|
||||
|
||||
compatible: "zmk,behavior-momentary-layer-lock"
|
||||
|
||||
include: zero_param.yaml
|
||||
|
||||
properties:
|
||||
bindings:
|
||||
type: phandle-array
|
||||
required: true
|
15
app/include/zmk/momentary_layer.h
Normal file
15
app/include/zmk/momentary_layer.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
// Locks all active momentary layers so they are not disabled when the key is
|
||||
// released.
|
||||
//
|
||||
// Returns a set of the layers that were locked.
|
||||
zmk_keymap_layers_state_t zmk_lock_active_momentary_layers();
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/momentary_layer.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
|
@ -37,19 +38,41 @@ static const struct behavior_parameter_metadata metadata = {
|
|||
#endif
|
||||
|
||||
struct behavior_mo_config {};
|
||||
struct behavior_mo_data {};
|
||||
struct behavior_mo_data {
|
||||
zmk_keymap_layers_state_t active_momentary_layers;
|
||||
zmk_keymap_layers_state_t ignore_on_release;
|
||||
};
|
||||
|
||||
static const struct behavior_mo_config behavior_mo_config = {};
|
||||
static struct behavior_mo_data behavior_mo_data;
|
||||
|
||||
zmk_keymap_layers_state_t zmk_lock_active_momentary_layers() {
|
||||
return behavior_mo_data.ignore_on_release = behavior_mo_data.active_momentary_layers;
|
||||
}
|
||||
|
||||
static int behavior_mo_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
||||
return zmk_keymap_layer_activate(binding->param1);
|
||||
int layer = binding->param1;
|
||||
LOG_DBG("position %d layer %d", event.position, layer);
|
||||
WRITE_BIT(behavior_mo_data.active_momentary_layers, layer, true);
|
||||
return zmk_keymap_layer_activate(layer);
|
||||
}
|
||||
|
||||
static int mo_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
||||
int layer = binding->param1;
|
||||
LOG_DBG("position %d layer %d", event.position, layer);
|
||||
WRITE_BIT(behavior_mo_data.active_momentary_layers, layer, false);
|
||||
|
||||
// If the layer is locked, don't deactivate it. Instead clear the
|
||||
// ignore_on_release flag so the next press/release will.
|
||||
if (behavior_mo_data.ignore_on_release & BIT(layer)) {
|
||||
WRITE_BIT(behavior_mo_data.ignore_on_release, layer, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return zmk_keymap_layer_deactivate(binding->param1);
|
||||
}
|
||||
|
||||
|
@ -61,9 +84,5 @@ static const struct behavior_driver_api behavior_mo_driver_api = {
|
|||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||
};
|
||||
|
||||
static const struct behavior_mo_config behavior_mo_config = {};
|
||||
|
||||
static struct behavior_mo_data behavior_mo_data;
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_mo_init, NULL, &behavior_mo_data, &behavior_mo_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api);
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api);
|
96
app/src/behaviors/behavior_momentary_layer_lock.c
Normal file
96
app/src/behaviors/behavior_momentary_layer_lock.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_momentary_layer_lock
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/momentary_layer.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
struct behavior_mo_lock_config {
|
||||
struct zmk_behavior_binding fallback_binding;
|
||||
};
|
||||
|
||||
struct behavior_mo_lock_data {
|
||||
bool is_fallback_binding_pressed;
|
||||
};
|
||||
|
||||
static int behavior_mo_lock_init(const struct device *dev) { return 0; };
|
||||
|
||||
static int mo_lock_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("%d molock pressed", event.position);
|
||||
|
||||
zmk_keymap_layers_state_t locked_layers = zmk_lock_active_momentary_layers();
|
||||
|
||||
if (!locked_layers) {
|
||||
LOG_DBG("no layers locked, falling back to %s", binding->behavior_dev);
|
||||
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
const struct behavior_mo_lock_config *config = dev->config;
|
||||
struct zmk_behavior_binding fallback_binding = config->fallback_binding;
|
||||
struct behavior_mo_lock_data *data = dev->data;
|
||||
|
||||
data->is_fallback_binding_pressed = true;
|
||||
return behavior_keymap_binding_pressed(&fallback_binding, event);
|
||||
} else {
|
||||
LOG_DBG("locked layers: %#08x", locked_layers);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mo_lock_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("%d molock released", event.position);
|
||||
|
||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||
struct behavior_mo_lock_data *data = dev->data;
|
||||
|
||||
if (data->is_fallback_binding_pressed) {
|
||||
const struct behavior_mo_lock_config *config = dev->config;
|
||||
struct zmk_behavior_binding fallback_binding = config->fallback_binding;
|
||||
|
||||
data->is_fallback_binding_pressed = false;
|
||||
return behavior_keymap_binding_released(&fallback_binding, event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KP_INST(n) \
|
||||
static struct behavior_mo_lock_config behavior_mo_lock_config_##n = { \
|
||||
.fallback_binding = \
|
||||
{ \
|
||||
.behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)), \
|
||||
.param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(n, bindings, 0, param1), (0), \
|
||||
(DT_INST_PHA_BY_IDX(n, bindings, 0, param1))), \
|
||||
.param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(n, bindings, 0, param2), (0), \
|
||||
(DT_INST_PHA_BY_IDX(n, bindings, 0, param))), \
|
||||
}, \
|
||||
}; \
|
||||
static struct behavior_mo_lock_data behavior_mo_lock_data_##n; \
|
||||
\
|
||||
BEHAVIOR_DT_INST_DEFINE(n, behavior_mo_lock_init, NULL, &behavior_mo_lock_data_##n, \
|
||||
&behavior_mo_lock_config_##n, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_lock_driver_api);
|
||||
|
||||
static const struct behavior_driver_api behavior_mo_lock_driver_api = {
|
||||
.binding_pressed = mo_lock_keymap_binding_pressed,
|
||||
.binding_released = mo_lock_keymap_binding_released,
|
||||
};
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
3
app/tests/momentary-layer-lock/1-normal/events.patterns
Normal file
3
app/tests/momentary-layer-lock/1-normal/events.patterns
Normal file
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*set_layer_state: layer_changed:/layer_changed:/p
|
||||
s/.*mo_keymap_binding/mo/p
|
|
@ -0,0 +1,5 @@
|
|||
mo_pressed: position 1 layer 1
|
||||
layer_changed: layer 1 state 1
|
||||
mo_released: position 1 layer 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*set_layer_state: layer_changed:/layer_changed:/p
|
||||
s/.*mo_keymap_binding/mo/p
|
|
@ -0,0 +1,10 @@
|
|||
mo_pressed: position 1 layer 1
|
||||
layer_changed: layer 1 state 1
|
||||
mo_released: position 1 layer 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
mo_pressed: position 1 layer 1
|
||||
mo_released: position 1 layer 1
|
||||
layer_changed: layer 1 state 0
|
||||
kp_pressed: usage_page 0x07 keycode 0x27 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x27 implicit_mods 0x00 explicit_mods 0x00
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*set_layer_state: layer_changed:/layer_changed:/p
|
||||
s/.*mo_keymap_binding/mo/p
|
|
@ -0,0 +1,9 @@
|
|||
mo_pressed: position 1 layer 1
|
||||
layer_changed: layer 1 state 1
|
||||
mo_released: position 1 layer 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
layer_changed: layer 1 state 0
|
||||
layer_changed: layer 0 state 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x27 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x27 implicit_mods 0x00 explicit_mods 0x00
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
3
app/tests/momentary-layer-lock/4-relock/events.patterns
Normal file
3
app/tests/momentary-layer-lock/4-relock/events.patterns
Normal file
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*set_layer_state: layer_changed:/layer_changed:/p
|
||||
s/.*mo_keymap_binding/mo/p
|
|
@ -0,0 +1,9 @@
|
|||
mo_pressed: position 1 layer 1
|
||||
layer_changed: layer 1 state 1
|
||||
mo_released: position 1 layer 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
mo_pressed: position 1 layer 1
|
||||
mo_released: position 1 layer 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
3
app/tests/momentary-layer-lock/5-custom/events.patterns
Normal file
3
app/tests/momentary-layer-lock/5-custom/events.patterns
Normal file
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*set_layer_state: layer_changed:/layer_changed:/p
|
||||
s/.*mo_keymap_binding/mo/p
|
|
@ -0,0 +1,5 @@
|
|||
mo_pressed: position 1 layer 1
|
||||
layer_changed: layer 1 state 1
|
||||
mo_released: position 1 layer 1
|
||||
kp_pressed: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x1E implicit_mods 0x00 explicit_mods 0x00
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,1,10)
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*set_layer_state: layer_changed:/layer_changed:/p
|
||||
s/.*mo_keymap_binding/mo/p
|
|
@ -0,0 +1,2 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(1,1,10)
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
>;
|
||||
};
|
27
app/tests/momentary-layer-lock/behavior_keymap.dtsi
Normal file
27
app/tests/momentary-layer-lock/behavior_keymap.dtsi
Normal file
|
@ -0,0 +1,27 @@
|
|||
/ {
|
||||
behaviors{
|
||||
kp_molock: kp_molock {
|
||||
compatible = "zmk,behavior-momentary-layer-lock";
|
||||
label = "KP_MOLOCK";
|
||||
#binding-cells = <0>;
|
||||
bindings = <&kp F>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&kp N0 &mo 1
|
||||
&molock &kp_molock>;
|
||||
};
|
||||
|
||||
layer_1 {
|
||||
bindings = <
|
||||
&kp N1 &trans
|
||||
&trans &trans>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -153,6 +153,68 @@ Example:
|
|||
|
||||
It is possible to use "toggle layer" to have keys that raise and lower the layers as well.
|
||||
|
||||
## Momentary Layer Lock
|
||||
|
||||
Even if you mostly use [momentary layers](#momentary-layer) instead of `&to` or `&tog`, it's occasionally useful to permanently enable a layer without needing to hold anything down. Instead of creating an additional `&tog` or `&to` binding for each such layer, you can use `&molock`.
|
||||
|
||||
If `&molock` is pressed while any number of `&mo` bindings are being held, those momentary layers will not be deactivated when the corresponding `&mo` key is released. As a result, those momentary layers become "locked" until that `&mo` key is pressed and released a second time or the layer becomes deactivated by some other means (e.g. a `&tog` binding for that layer or a `&to` binding for any other one).
|
||||
|
||||
If `&molock` is pressed while no `&mo` bindings are being held, it triggers a user-configurable fallback behavior. The default fallback behavior returns to the base layer (`&to 0`), deactivating any locked momentary layers in the process.
|
||||
|
||||
### Behavior Binding
|
||||
|
||||
- Reference: `&molock`
|
||||
|
||||
Example:
|
||||
|
||||
```dts
|
||||
&molock
|
||||
```
|
||||
|
||||
Lock a symbol layer:
|
||||
|
||||
```dts
|
||||
#define BASE 0
|
||||
#define SYMS 1
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
base_layer {
|
||||
bindings = <&mo SYMS &kp Z &kp M &kp K >;
|
||||
};
|
||||
symbol_layer {
|
||||
bindings = <&trans &kp PLUS &kp MINUS &molock>;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Holding down the leftmost key (`&mo SYMS`), then pressing and releasing the rightmost key (`&molock`), will lock the symbol layer. Even after releasing the leftmost key, the symbol layer remains active.
|
||||
|
||||
To return to the base layer, press and release either the leftmost key (triggering the `&mo SYMS` behavior a second time) or the rightmost key (triggering the default fallback behavior for `&molock`).
|
||||
|
||||
### Configuration
|
||||
|
||||
You can configure a different fallback behavior by overriding the `bindings` property of the built-in `&molock` behavior. For example, to return to layer 1 (instead of layer 0):
|
||||
|
||||
```dts
|
||||
&molock {
|
||||
bindings = <&to 1>;
|
||||
};
|
||||
```
|
||||
|
||||
You can also create any number of custom `&molock` behaviors by using `compatible = "zmk,behavior-momentary-layer-lock"` like so:
|
||||
|
||||
```dts
|
||||
// Presses F if triggered while no momentary layers are active
|
||||
kp_molock: kp_molock {
|
||||
compatible = "zmk,behavior-momentary-layer-lock";
|
||||
bindings = <&kp F>;
|
||||
};
|
||||
```
|
||||
|
||||
## Conditional Layers
|
||||
|
||||
The "conditional layers" feature enables a particular layer when all layers in a specified set are active.
|
||||
|
|
|
@ -221,6 +221,29 @@ Applies to: `compatible = "zmk,behavior-sensor-rotate-var"`
|
|||
|
||||
With `compatible = "zmk,behavior-sensor-rotate-var"`, this behavior forwards the first parameter it receives to the parameter of the first behavior specified in `bindings`, and second parameter to the parameter of the second behavior.
|
||||
|
||||
## Momentary Layer Lock
|
||||
|
||||
Creates a custom behavior that locks any active momentary layers or triggers the fallback behavior specified in `bindings` if none are active.
|
||||
|
||||
See the [momentary layer lock](../behaviors/layers.md#momentary-layer-lock) documentation for more details and examples.
|
||||
|
||||
### Devicetree
|
||||
|
||||
Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-momentary-layer-lock.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-momentary-layer-lock.yaml)
|
||||
|
||||
Applies to: `compatible = "zmk,behavior-momentary-layer-lock"`
|
||||
|
||||
| Property | Type | Description |
|
||||
| ---------------- | ------------- | ------------------------------------------------------- |
|
||||
| `#binding-cells` | int | Must be `0` |
|
||||
| `bindings` | phandle array | A behavior to trigger if no momentary layers are active |
|
||||
|
||||
You can use the following nodes to tweak the default behaviors:
|
||||
|
||||
| Node | Behavior |
|
||||
| --------- | ------------------------------------------------------------------- |
|
||||
| `&molock` | [Momentary Layer Lock](../behaviors/layers.md#momentary-layer-lock) |
|
||||
|
||||
## Sticky Key
|
||||
|
||||
Creates a custom behavior that triggers a behavior and keeps it pressed it until another key is pressed and released.
|
||||
|
|
Loading…
Add table
Reference in a new issue