mirror of
https://github.com/zmkfirmware/zmk.git
synced 2026-03-19 20:45:18 -05:00
feat: Allow layer behaviors to "lock" layers on (#2717)
* refactor(core)!: Allow layer behaviors to "lock" layers on Co-authored-by: Cem Aksoylar <caksoylar@users.noreply.github.com> * docs: Added documentation note on locking layers Co-authored-by: Cem Aksoylar <caksoylar@users.noreply.github.com> --------- Co-authored-by: Cem Aksoylar <caksoylar@users.noreply.github.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
compatible = "zmk,behavior-to-layer";
|
compatible = "zmk,behavior-to-layer";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
display-name = "To Layer";
|
display-name = "To Layer";
|
||||||
|
locking;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
compatible = "zmk,behavior-toggle-layer";
|
compatible = "zmk,behavior-toggle-layer";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
display-name = "Toggle Layer";
|
display-name = "Toggle Layer";
|
||||||
|
locking;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,3 +6,8 @@ description: Momentary layer on press/release behavior
|
|||||||
compatible: "zmk,behavior-momentary-layer"
|
compatible: "zmk,behavior-momentary-layer"
|
||||||
|
|
||||||
include: one_param.yaml
|
include: one_param.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
locking:
|
||||||
|
type: boolean
|
||||||
|
description: Whether to "lock" the layer active, preventing behaviors without the "locking" property from deactivating the layer
|
||||||
|
|||||||
@@ -6,3 +6,8 @@ description: To Layer
|
|||||||
compatible: "zmk,behavior-to-layer"
|
compatible: "zmk,behavior-to-layer"
|
||||||
|
|
||||||
include: one_param.yaml
|
include: one_param.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
locking:
|
||||||
|
type: boolean
|
||||||
|
description: Whether to "lock" the layer active, preventing behaviors without the "locking" property from deactivating the layer
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ include: one_param.yaml
|
|||||||
properties:
|
properties:
|
||||||
toggle-mode:
|
toggle-mode:
|
||||||
type: string
|
type: string
|
||||||
required: false
|
|
||||||
default: "flip"
|
default: "flip"
|
||||||
enum:
|
enum:
|
||||||
- "on"
|
- "on"
|
||||||
- "off"
|
- "off"
|
||||||
- "flip"
|
- "flip"
|
||||||
|
locking:
|
||||||
|
type: boolean
|
||||||
|
description: Whether to "lock" the layer active, preventing behaviors without the "locking" property from deactivating the layer
|
||||||
|
|||||||
@@ -12,12 +12,13 @@
|
|||||||
struct zmk_layer_state_changed {
|
struct zmk_layer_state_changed {
|
||||||
uint8_t layer;
|
uint8_t layer;
|
||||||
bool state;
|
bool state;
|
||||||
|
bool locked;
|
||||||
int64_t timestamp;
|
int64_t timestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
ZMK_EVENT_DECLARE(zmk_layer_state_changed);
|
ZMK_EVENT_DECLARE(zmk_layer_state_changed);
|
||||||
|
|
||||||
static inline int raise_layer_state_changed(uint8_t layer, bool state) {
|
static inline int raise_layer_state_changed(uint8_t layer, bool state, bool locked) {
|
||||||
return raise_zmk_layer_state_changed((struct zmk_layer_state_changed){
|
return raise_zmk_layer_state_changed((struct zmk_layer_state_changed){
|
||||||
.layer = layer, .state = state, .timestamp = k_uptime_get()});
|
.layer = layer, .state = state, .locked = locked, .timestamp = k_uptime_get()});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,12 +43,14 @@ zmk_keymap_layer_id_t zmk_keymap_layer_index_to_id(zmk_keymap_layer_index_t laye
|
|||||||
|
|
||||||
zmk_keymap_layer_id_t zmk_keymap_layer_default(void);
|
zmk_keymap_layer_id_t zmk_keymap_layer_default(void);
|
||||||
zmk_keymap_layers_state_t zmk_keymap_layer_state(void);
|
zmk_keymap_layers_state_t zmk_keymap_layer_state(void);
|
||||||
|
zmk_keymap_layers_state_t zmk_keymap_layer_locks(void);
|
||||||
bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer);
|
bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer);
|
||||||
|
bool zmk_keymap_layer_locked(zmk_keymap_layer_id_t layer);
|
||||||
zmk_keymap_layer_index_t zmk_keymap_highest_layer_active(void);
|
zmk_keymap_layer_index_t zmk_keymap_highest_layer_active(void);
|
||||||
int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer);
|
int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer, bool locking);
|
||||||
int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer);
|
int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer, bool locking);
|
||||||
int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer);
|
int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer, bool locking);
|
||||||
int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer);
|
int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer, bool locking);
|
||||||
const char *zmk_keymap_layer_name(zmk_keymap_layer_id_t layer);
|
const char *zmk_keymap_layer_name(zmk_keymap_layer_id_t layer);
|
||||||
|
|
||||||
const struct zmk_behavior_binding *zmk_keymap_get_layer_binding_at_idx(zmk_keymap_layer_id_t layer,
|
const struct zmk_behavior_binding *zmk_keymap_get_layer_binding_at_idx(zmk_keymap_layer_id_t layer,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static const struct behavior_parameter_value_metadata param_values[] = {
|
static const struct behavior_parameter_value_metadata param_values[] = {
|
||||||
@@ -36,16 +38,22 @@ static const struct behavior_parameter_metadata metadata = {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct behavior_mo_config {
|
||||||
|
bool locking;
|
||||||
|
};
|
||||||
|
|
||||||
static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event) {
|
struct zmk_behavior_binding_event event) {
|
||||||
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
||||||
return zmk_keymap_layer_activate(binding->param1);
|
const struct behavior_mo_config *cfg = zmk_behavior_get_binding(binding->behavior_dev)->config;
|
||||||
|
return zmk_keymap_layer_activate(binding->param1, cfg->locking);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mo_keymap_binding_released(struct zmk_behavior_binding *binding,
|
static int mo_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event) {
|
struct zmk_behavior_binding_event event) {
|
||||||
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
||||||
return zmk_keymap_layer_deactivate(binding->param1);
|
const struct behavior_mo_config *cfg = zmk_behavior_get_binding(binding->behavior_dev)->config;
|
||||||
|
return zmk_keymap_layer_deactivate(binding->param1, cfg->locking);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_mo_driver_api = {
|
static const struct behavior_driver_api behavior_mo_driver_api = {
|
||||||
@@ -56,5 +64,13 @@ static const struct behavior_driver_api behavior_mo_driver_api = {
|
|||||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
#define MO_INST(n) \
|
||||||
&behavior_mo_driver_api);
|
static const struct behavior_mo_config behavior_mo_config_##n = { \
|
||||||
|
.locking = DT_INST_PROP_OR(n, locking, false), \
|
||||||
|
}; \
|
||||||
|
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_mo_config_##n, POST_KERNEL, \
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(MO_INST)
|
||||||
|
|
||||||
|
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||||
@@ -17,10 +17,15 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||||
|
|
||||||
|
struct behavior_to_config {
|
||||||
|
bool locking;
|
||||||
|
};
|
||||||
|
|
||||||
static int to_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int to_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event) {
|
struct zmk_behavior_binding_event event) {
|
||||||
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
LOG_DBG("position %d layer %d", event.position, binding->param1);
|
||||||
zmk_keymap_layer_to(binding->param1);
|
const struct behavior_to_config *cfg = zmk_behavior_get_binding(binding->behavior_dev)->config;
|
||||||
|
zmk_keymap_layer_to(binding->param1, cfg->locking);
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +64,13 @@ static const struct behavior_driver_api behavior_to_driver_api = {
|
|||||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
#define TO_INST(n) \
|
||||||
&behavior_to_driver_api);
|
static const struct behavior_to_config behavior_to_config_##n = { \
|
||||||
|
.locking = DT_INST_PROP_OR(n, locking, false), \
|
||||||
|
}; \
|
||||||
|
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_to_config_##n, POST_KERNEL, \
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_to_driver_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(TO_INST)
|
||||||
|
|
||||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ enum toggle_mode {
|
|||||||
|
|
||||||
struct behavior_tog_config {
|
struct behavior_tog_config {
|
||||||
enum toggle_mode toggle_mode;
|
enum toggle_mode toggle_mode;
|
||||||
|
bool locking;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
@@ -34,11 +35,11 @@ static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
|||||||
const struct behavior_tog_config *cfg = zmk_behavior_get_binding(binding->behavior_dev)->config;
|
const struct behavior_tog_config *cfg = zmk_behavior_get_binding(binding->behavior_dev)->config;
|
||||||
switch (cfg->toggle_mode) {
|
switch (cfg->toggle_mode) {
|
||||||
case ON:
|
case ON:
|
||||||
return zmk_keymap_layer_activate(binding->param1);
|
return zmk_keymap_layer_activate(binding->param1, cfg->locking);
|
||||||
case OFF:
|
case OFF:
|
||||||
return zmk_keymap_layer_deactivate(binding->param1);
|
return zmk_keymap_layer_deactivate(binding->param1, cfg->locking);
|
||||||
case FLIP:
|
case FLIP:
|
||||||
return zmk_keymap_layer_toggle(binding->param1);
|
return zmk_keymap_layer_toggle(binding->param1, cfg->locking);
|
||||||
default:
|
default:
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
};
|
};
|
||||||
@@ -79,13 +80,14 @@ static const struct behavior_driver_api behavior_tog_driver_api = {
|
|||||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KT_INST(n) \
|
#define TG_INST(n) \
|
||||||
static const struct behavior_tog_config behavior_tog_config_##n = { \
|
static const struct behavior_tog_config behavior_tog_config_##n = { \
|
||||||
.toggle_mode = DT_ENUM_IDX(DT_DRV_INST(n), toggle_mode), \
|
.toggle_mode = DT_ENUM_IDX(DT_DRV_INST(n), toggle_mode), \
|
||||||
|
.locking = DT_INST_PROP_OR(n, locking, false), \
|
||||||
}; \
|
}; \
|
||||||
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_tog_config_##n, POST_KERNEL, \
|
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_tog_config_##n, POST_KERNEL, \
|
||||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tog_driver_api);
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tog_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(KT_INST)
|
DT_INST_FOREACH_STATUS_OKAY(TG_INST)
|
||||||
|
|
||||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||||
|
|||||||
@@ -49,28 +49,31 @@ static const struct conditional_layer_cfg CONDITIONAL_LAYER_CFGS[] = {
|
|||||||
static const int32_t NUM_CONDITIONAL_LAYER_CFGS =
|
static const int32_t NUM_CONDITIONAL_LAYER_CFGS =
|
||||||
sizeof(CONDITIONAL_LAYER_CFGS) / sizeof(*CONDITIONAL_LAYER_CFGS);
|
sizeof(CONDITIONAL_LAYER_CFGS) / sizeof(*CONDITIONAL_LAYER_CFGS);
|
||||||
|
|
||||||
static void conditional_layer_activate(int8_t layer) {
|
// Ensures all layer updates are processed if one conditional layer activates another.
|
||||||
|
static bool conditional_layer_updates_needed;
|
||||||
|
// Tracks which layers have been locked by conditional layer activations.
|
||||||
|
static uint32_t layer_locked_by_conditional = 0;
|
||||||
|
|
||||||
|
static void conditional_layer_activate(int8_t layer, bool locking) {
|
||||||
// This may trigger another event that could, in turn, activate additional then-layers. However,
|
// This may trigger another event that could, in turn, activate additional then-layers. However,
|
||||||
// the process will eventually terminate (at worst, when every layer is active).
|
// the process will eventually terminate (at worst, when every layer is active).
|
||||||
if (!zmk_keymap_layer_active(layer)) {
|
if (!zmk_keymap_layer_active(layer) || (locking && !zmk_keymap_layer_locked(layer))) {
|
||||||
LOG_DBG("layer %d", layer);
|
LOG_DBG("layer %d", layer);
|
||||||
zmk_keymap_layer_activate(layer);
|
zmk_keymap_layer_activate(layer, locking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void conditional_layer_deactivate(int8_t layer) {
|
static void conditional_layer_deactivate(int8_t layer, bool locking) {
|
||||||
// This may deactivate a then-layer that's already active via another mechanism (e.g., a
|
// This may deactivate a then-layer that's already active via another mechanism (e.g., a
|
||||||
// momentary layer behavior). However, the same problem arises when multiple keys with the same
|
// momentary layer behavior). However, the same problem arises when multiple keys with the same
|
||||||
// &mo binding are held and then one is released, so it's probably not an issue in practice.
|
// &mo binding are held and then one is released, so it's probably not an issue in practice.
|
||||||
if (zmk_keymap_layer_active(layer)) {
|
if (zmk_keymap_layer_active(layer) && (!zmk_keymap_layer_locked(layer) || locking)) {
|
||||||
LOG_DBG("layer %d", layer);
|
LOG_DBG("layer %d", layer);
|
||||||
zmk_keymap_layer_deactivate(layer);
|
zmk_keymap_layer_deactivate(layer, locking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int layer_state_changed_listener(const zmk_event_t *ev) {
|
static int layer_state_changed_listener(const zmk_event_t *ev) {
|
||||||
static bool conditional_layer_updates_needed;
|
|
||||||
|
|
||||||
conditional_layer_updates_needed = true;
|
conditional_layer_updates_needed = true;
|
||||||
|
|
||||||
// Semaphore ensures we don't re-enter the loop in the middle of doing update, and
|
// Semaphore ensures we don't re-enter the loop in the middle of doing update, and
|
||||||
@@ -84,7 +87,6 @@ static int layer_state_changed_listener(const zmk_event_t *ev) {
|
|||||||
int8_t max_then_layer = -1;
|
int8_t max_then_layer = -1;
|
||||||
uint32_t then_layers = 0;
|
uint32_t then_layers = 0;
|
||||||
uint32_t then_layer_state = 0;
|
uint32_t then_layer_state = 0;
|
||||||
|
|
||||||
conditional_layer_updates_needed = false;
|
conditional_layer_updates_needed = false;
|
||||||
|
|
||||||
// On layer state changes, examines each conditional layer config to determine if then-layer
|
// On layer state changes, examines each conditional layer config to determine if then-layer
|
||||||
@@ -92,23 +94,29 @@ static int layer_state_changed_listener(const zmk_event_t *ev) {
|
|||||||
for (int i = 0; i < NUM_CONDITIONAL_LAYER_CFGS; i++) {
|
for (int i = 0; i < NUM_CONDITIONAL_LAYER_CFGS; i++) {
|
||||||
const struct conditional_layer_cfg *cfg = CONDITIONAL_LAYER_CFGS + i;
|
const struct conditional_layer_cfg *cfg = CONDITIONAL_LAYER_CFGS + i;
|
||||||
zmk_keymap_layers_state_t mask = cfg->if_layers_state_mask;
|
zmk_keymap_layers_state_t mask = cfg->if_layers_state_mask;
|
||||||
then_layers |= BIT(cfg->then_layer);
|
WRITE_BIT(then_layers, cfg->then_layer, true);
|
||||||
max_then_layer = MAX(max_then_layer, cfg->then_layer);
|
max_then_layer = MAX(max_then_layer, cfg->then_layer);
|
||||||
|
|
||||||
// Activate then-layer if and only if all if-layers are already active. Note that we
|
// Activate then-layer if and only if all if-layers are already active. Note that we
|
||||||
// reevaluate the current layer state for each config since activation of one layer can
|
// reevaluate the current layer state for each config since activation of one layer can
|
||||||
// also trigger activation of another.
|
// also trigger activation of another.
|
||||||
if ((zmk_keymap_layer_state() & mask) == mask) {
|
if ((zmk_keymap_layer_state() & mask) == mask) {
|
||||||
then_layer_state |= BIT(cfg->then_layer);
|
WRITE_BIT(then_layer_state, cfg->then_layer, true);
|
||||||
|
}
|
||||||
|
// Same as above, but for the lock status
|
||||||
|
if ((zmk_keymap_layer_locks() & mask) == mask) {
|
||||||
|
WRITE_BIT(layer_locked_by_conditional, cfg->then_layer, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t layer = 0; layer <= max_then_layer; layer++) {
|
for (uint8_t layer = 0; layer <= max_then_layer; layer++) {
|
||||||
if ((BIT(layer) & then_layers) != 0U) {
|
if ((BIT(layer) & then_layers) != 0U) {
|
||||||
|
bool locking = (BIT(layer) & layer_locked_by_conditional) != 0U;
|
||||||
if ((BIT(layer) & then_layer_state) != 0U) {
|
if ((BIT(layer) & then_layer_state) != 0U) {
|
||||||
conditional_layer_activate(layer);
|
conditional_layer_activate(layer, locking);
|
||||||
} else {
|
} else {
|
||||||
conditional_layer_deactivate(layer);
|
conditional_layer_deactivate(layer, locking);
|
||||||
|
WRITE_BIT(layer_locked_by_conditional, layer, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||||||
#include <zmk/events/layer_state_changed.h>
|
#include <zmk/events/layer_state_changed.h>
|
||||||
#include <zmk/events/sensor_event.h>
|
#include <zmk/events/sensor_event.h>
|
||||||
|
|
||||||
|
static zmk_keymap_layers_state_t _zmk_keymap_layer_locks = 0;
|
||||||
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
||||||
static zmk_keymap_layer_id_t _zmk_keymap_layer_default = 0;
|
static zmk_keymap_layer_id_t _zmk_keymap_layer_default = 0;
|
||||||
|
|
||||||
@@ -130,7 +131,7 @@ uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
|||||||
|
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
static inline int set_layer_state(zmk_keymap_layer_id_t layer_id, bool state) {
|
static inline int set_layer_state(zmk_keymap_layer_id_t layer_id, bool state, bool locking) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) {
|
if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -141,12 +142,22 @@ static inline int set_layer_state(zmk_keymap_layer_id_t layer_id, bool state) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Non-forcing disables should not change a locked active layer
|
||||||
|
if (!locking && !state && (_zmk_keymap_layer_locks & BIT(layer_id))) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state;
|
zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state;
|
||||||
|
zmk_keymap_layers_state_t old_locks = _zmk_keymap_layer_locks;
|
||||||
WRITE_BIT(_zmk_keymap_layer_state, layer_id, state);
|
WRITE_BIT(_zmk_keymap_layer_state, layer_id, state);
|
||||||
|
if (locking) {
|
||||||
|
WRITE_BIT(_zmk_keymap_layer_locks, layer_id, state);
|
||||||
|
}
|
||||||
// Don't send state changes unless there was an actual change
|
// Don't send state changes unless there was an actual change
|
||||||
if (old_state != _zmk_keymap_layer_state) {
|
if (old_state != _zmk_keymap_layer_state || old_locks != _zmk_keymap_layer_locks) {
|
||||||
LOG_DBG("layer_changed: layer %d state %d", layer_id, state);
|
LOG_DBG("layer_changed: layer %d state %d locked %d", layer_id, state, locking);
|
||||||
ret = raise_layer_state_changed(layer_id, state);
|
|
||||||
|
ret = raise_layer_state_changed(layer_id, state, locking);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG_WRN("Failed to raise layer state changed (%d)", ret);
|
LOG_WRN("Failed to raise layer state changed (%d)", ret);
|
||||||
}
|
}
|
||||||
@@ -165,6 +176,8 @@ zmk_keymap_layer_id_t zmk_keymap_layer_default(void) { return _zmk_keymap_layer_
|
|||||||
|
|
||||||
zmk_keymap_layers_state_t zmk_keymap_layer_state(void) { return _zmk_keymap_layer_state; }
|
zmk_keymap_layers_state_t zmk_keymap_layer_state(void) { return _zmk_keymap_layer_state; }
|
||||||
|
|
||||||
|
zmk_keymap_layers_state_t zmk_keymap_layer_locks(void) { return _zmk_keymap_layer_locks; }
|
||||||
|
|
||||||
bool zmk_keymap_layer_active_with_state(zmk_keymap_layer_id_t layer,
|
bool zmk_keymap_layer_active_with_state(zmk_keymap_layer_id_t layer,
|
||||||
zmk_keymap_layers_state_t state_to_test) {
|
zmk_keymap_layers_state_t state_to_test) {
|
||||||
// The default layer is assumed to be ALWAYS ACTIVE so we include an || here to ensure nobody
|
// The default layer is assumed to be ALWAYS ACTIVE so we include an || here to ensure nobody
|
||||||
@@ -176,6 +189,10 @@ bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer) {
|
|||||||
return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state);
|
return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool zmk_keymap_layer_locked(zmk_keymap_layer_id_t layer) {
|
||||||
|
return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_locks);
|
||||||
|
}
|
||||||
|
|
||||||
zmk_keymap_layer_index_t zmk_keymap_highest_layer_active(void) {
|
zmk_keymap_layer_index_t zmk_keymap_highest_layer_active(void) {
|
||||||
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1;
|
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1;
|
||||||
layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); layer_idx--) {
|
layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); layer_idx--) {
|
||||||
@@ -192,26 +209,28 @@ zmk_keymap_layer_index_t zmk_keymap_highest_layer_active(void) {
|
|||||||
return LAYER_ID_TO_INDEX(zmk_keymap_layer_default());
|
return LAYER_ID_TO_INDEX(zmk_keymap_layer_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer) { return set_layer_state(layer, true); };
|
int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer, bool locking) {
|
||||||
|
return set_layer_state(layer, true, locking);
|
||||||
int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer) {
|
|
||||||
return set_layer_state(layer, false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer) {
|
int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer, bool locking) {
|
||||||
if (zmk_keymap_layer_active(layer)) {
|
return set_layer_state(layer, false, locking);
|
||||||
return zmk_keymap_layer_deactivate(layer);
|
};
|
||||||
|
|
||||||
|
int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer, bool locking) {
|
||||||
|
if (zmk_keymap_layer_active(layer) && (!locking || zmk_keymap_layer_locked(layer))) {
|
||||||
|
return zmk_keymap_layer_deactivate(layer, locking);
|
||||||
}
|
}
|
||||||
|
|
||||||
return zmk_keymap_layer_activate(layer);
|
return zmk_keymap_layer_activate(layer, locking);
|
||||||
};
|
};
|
||||||
|
|
||||||
int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer) {
|
int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer, bool locking) {
|
||||||
for (int i = ZMK_KEYMAP_LAYERS_LEN - 1; i >= 0; i--) {
|
for (int i = ZMK_KEYMAP_LAYERS_LEN - 1; i >= 0; i--) {
|
||||||
zmk_keymap_layer_deactivate(i);
|
zmk_keymap_layer_deactivate(i, locking);
|
||||||
}
|
}
|
||||||
|
|
||||||
zmk_keymap_layer_activate(layer);
|
zmk_keymap_layer_activate(layer, locking);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ static void update_layer_state(struct temp_layer_state *state, bool activate) {
|
|||||||
|
|
||||||
state->is_active = activate;
|
state->is_active = activate;
|
||||||
if (activate) {
|
if (activate) {
|
||||||
zmk_keymap_layer_activate(state->toggle_layer);
|
zmk_keymap_layer_activate(state->toggle_layer, false);
|
||||||
LOG_DBG("Layer %d activated", state->toggle_layer);
|
LOG_DBG("Layer %d activated", state->toggle_layer);
|
||||||
} else {
|
} else {
|
||||||
zmk_keymap_layer_deactivate(state->toggle_layer);
|
zmk_keymap_layer_deactivate(state->toggle_layer, false);
|
||||||
LOG_DBG("Layer %d deactivated", state->toggle_layer);
|
LOG_DBG("Layer %d deactivated", state->toggle_layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
s/.*hid_listener_keycode/kp/p
|
||||||
|
s/.*mo_keymap_binding/mo/p
|
||||||
|
s/.*tog_keymap_binding/tog/p
|
||||||
|
s/.*conditional_layer/cl/p
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
tog_pressed: position 2 layer 1
|
||||||
|
tog_released: position 2 layer 1
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
mo_pressed: position 3 layer 2
|
||||||
|
cl_activate: layer 3
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
tog_pressed: position 1 layer 3
|
||||||
|
tog_released: position 1 layer 3
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
mo_released: position 3 layer 2
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include <behaviors.dtsi>
|
||||||
|
#include <dt-bindings/zmk/keys.h>
|
||||||
|
#include <dt-bindings/zmk/kscan_mock.h>
|
||||||
|
|
||||||
|
&tog {
|
||||||
|
toggle-mode = "on";
|
||||||
|
};
|
||||||
|
|
||||||
|
/ {
|
||||||
|
conditional_layers {
|
||||||
|
compatible = "zmk,conditional-layers";
|
||||||
|
tri_layer {
|
||||||
|
if-layers = <1 2>;
|
||||||
|
then-layer = <3>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
keymap {
|
||||||
|
compatible = "zmk,keymap";
|
||||||
|
default_layer {
|
||||||
|
bindings = <
|
||||||
|
&kp A &tog 3
|
||||||
|
&tog 1 &mo 2
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
layer_1 {
|
||||||
|
bindings = <
|
||||||
|
&kp B &trans
|
||||||
|
&trans &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
layer_2 {
|
||||||
|
bindings = <
|
||||||
|
&kp C &trans
|
||||||
|
&trans &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
layer_3 {
|
||||||
|
bindings = <
|
||||||
|
&kp D &trans
|
||||||
|
&trans &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&kscan {
|
||||||
|
events = <
|
||||||
|
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)
|
||||||
|
ZMK_MOCK_PRESS(1,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)
|
||||||
|
ZMK_MOCK_RELEASE(1,1,10)
|
||||||
|
ZMK_MOCK_PRESS(0,0,10)
|
||||||
|
ZMK_MOCK_RELEASE(0,0,10)
|
||||||
|
>;
|
||||||
|
};
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
s/.*hid_listener_keycode/kp/p
|
||||||
|
s/.*mo_keymap_binding/mo/p
|
||||||
|
s/.*tog_keymap_binding/tog/p
|
||||||
|
s/.*conditional_layer/cl/p
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
tog_pressed: position 2 layer 1
|
||||||
|
tog_released: position 2 layer 1
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
tog_pressed: position 3 layer 2
|
||||||
|
cl_activate: layer 3
|
||||||
|
tog_released: position 3 layer 2
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
mo_pressed: position 1 layer 3
|
||||||
|
mo_released: position 1 layer 3
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
tog_pressed: position 2 layer 1
|
||||||
|
cl_deactivate: layer 3
|
||||||
|
tog_released: position 2 layer 1
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#include <behaviors.dtsi>
|
||||||
|
#include <dt-bindings/zmk/keys.h>
|
||||||
|
#include <dt-bindings/zmk/kscan_mock.h>
|
||||||
|
|
||||||
|
/ {
|
||||||
|
conditional_layers {
|
||||||
|
compatible = "zmk,conditional-layers";
|
||||||
|
tri_layer {
|
||||||
|
if-layers = <1 2>;
|
||||||
|
then-layer = <3>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
keymap {
|
||||||
|
compatible = "zmk,keymap";
|
||||||
|
default_layer {
|
||||||
|
bindings = <
|
||||||
|
&kp A &mo 3
|
||||||
|
&tog 1 &tog 2
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
layer_1 {
|
||||||
|
bindings = <
|
||||||
|
&kp B &trans
|
||||||
|
&trans &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
layer_2 {
|
||||||
|
bindings = <
|
||||||
|
&kp C &trans
|
||||||
|
&trans &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
layer_3 {
|
||||||
|
bindings = <
|
||||||
|
&kp D &trans
|
||||||
|
&trans &trans
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&kscan {
|
||||||
|
events = <
|
||||||
|
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)
|
||||||
|
ZMK_MOCK_PRESS(1,1,10)
|
||||||
|
ZMK_MOCK_RELEASE(1,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)
|
||||||
|
ZMK_MOCK_PRESS(1,0,10)
|
||||||
|
ZMK_MOCK_RELEASE(1,0,10)
|
||||||
|
ZMK_MOCK_PRESS(0,0,10)
|
||||||
|
ZMK_MOCK_RELEASE(0,0,10)
|
||||||
|
>;
|
||||||
|
};
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
layer_changed: layer 2 state 1
|
layer_changed: layer 2 state 1 locked 1
|
||||||
pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 1
|
||||||
layer_changed: layer 2 state 1
|
layer_changed: layer 2 state 1 locked 1
|
||||||
pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
movement_set: Mouse movement set to -1/0
|
movement_set: Mouse movement set to -1/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
@@ -12,5 +12,5 @@ movement_set: Mouse movement set to 0/0
|
|||||||
movement_set: Mouse movement set to -3/0
|
movement_set: Mouse movement set to -3/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
movement_set: Mouse movement set to 0/0
|
movement_set: Mouse movement set to 0/0
|
||||||
layer_changed: layer 1 state 0
|
layer_changed: layer 1 state 0 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Dispatching handle_position_state_changed
|
Dispatching handle_position_state_changed
|
||||||
Position excluded, continuing
|
Position excluded, continuing
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
movement_set: Mouse movement set to -1/0
|
movement_set: Mouse movement set to -1/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
@@ -17,7 +17,7 @@ movement_set: Mouse movement set to 0/0
|
|||||||
Dispatching handle_position_state_changed
|
Dispatching handle_position_state_changed
|
||||||
Dispatching handle_position_state_changed
|
Dispatching handle_position_state_changed
|
||||||
Position not excluded, deactivating layer
|
Position not excluded, deactivating layer
|
||||||
layer_changed: layer 1 state 0
|
layer_changed: layer 1 state 0 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
Position excluded, continuing
|
Position excluded, continuing
|
||||||
Dispatching handle_position_state_changed
|
Dispatching handle_position_state_changed
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
Dispatching handle_position_state_changed
|
Dispatching handle_position_state_changed
|
||||||
Position excluded, continuing
|
Position excluded, continuing
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
movement_set: Mouse movement set to -1/0
|
movement_set: Mouse movement set to -1/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ movement_set: Mouse movement set to 0/0
|
|||||||
movement_set: Mouse movement set to -1/0
|
movement_set: Mouse movement set to -1/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
movement_set: Mouse movement set to 0/0
|
movement_set: Mouse movement set to 0/0
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
movement_set: Mouse movement set to -2/0
|
movement_set: Mouse movement set to -2/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
@@ -146,5 +146,5 @@ movement_set: Mouse movement set to 0/0
|
|||||||
movement_set: Mouse movement set to -9/0
|
movement_set: Mouse movement set to -9/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
movement_set: Mouse movement set to 0/0
|
movement_set: Mouse movement set to 0/0
|
||||||
layer_changed: layer 1 state 0
|
layer_changed: layer 1 state 0 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
movement_set: Mouse movement set to -1/0
|
movement_set: Mouse movement set to -1/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
@@ -12,10 +12,10 @@ movement_set: Mouse movement set to 0/0
|
|||||||
movement_set: Mouse movement set to -3/0
|
movement_set: Mouse movement set to -3/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
movement_set: Mouse movement set to 0/0
|
movement_set: Mouse movement set to 0/0
|
||||||
layer_changed: layer 1 state 0
|
layer_changed: layer 1 state 0 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
Deactivating layer that was activated by this processor
|
Deactivating layer that was activated by this processor
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 0
|
||||||
Dispatching handle_layer_state_changed
|
Dispatching handle_layer_state_changed
|
||||||
movement_set: Mouse movement set to -1/0
|
movement_set: Mouse movement set to -1/0
|
||||||
scroll_set: Mouse scroll set to 0/0
|
scroll_set: Mouse scroll set to 0/0
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
||||||
to_pressed: position 1 layer 1
|
to_pressed: position 1 layer 1
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 1
|
||||||
to_released: position 1 layer 1
|
to_released: position 1 layer 1
|
||||||
kp_pressed: usage_page 0x07 keycode 0x0E implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x0E implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x07 keycode 0x0E implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x0E implicit_mods 0x00 explicit_mods 0x00
|
||||||
to_pressed: position 0 layer 0
|
to_pressed: position 0 layer 0
|
||||||
layer_changed: layer 1 state 0
|
layer_changed: layer 1 state 0 locked 1
|
||||||
layer_changed: layer 0 state 1
|
layer_changed: layer 0 state 1 locked 1
|
||||||
to_released: position 0 layer 0
|
to_released: position 0 layer 0
|
||||||
kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00
|
||||||
to_pressed: position 0 layer 0
|
to_pressed: position 0 layer 0
|
||||||
to_released: position 0 layer 0
|
to_released: position 0 layer 0
|
||||||
to_pressed: position 1 layer 1
|
to_pressed: position 1 layer 1
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 1
|
||||||
to_released: position 1 layer 1
|
to_released: position 1 layer 1
|
||||||
|
|||||||
@@ -3,13 +3,23 @@
|
|||||||
#include <dt-bindings/zmk/kscan_mock.h>
|
#include <dt-bindings/zmk/kscan_mock.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
|
behaviors {
|
||||||
|
tog_off: toggle_layer_off_only {
|
||||||
|
compatible = "zmk,behavior-toggle-layer";
|
||||||
|
#binding-cells = <1>;
|
||||||
|
display-name = "Toggle Layer Off";
|
||||||
|
toggle-mode = "off";
|
||||||
|
locking;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
keymap {
|
keymap {
|
||||||
compatible = "zmk,keymap";
|
compatible = "zmk,keymap";
|
||||||
|
|
||||||
default_layer {
|
default_layer {
|
||||||
bindings = <
|
bindings = <
|
||||||
&kp B &tog 1
|
&kp B &tog 1
|
||||||
&kp D &to 1>;
|
&mo 2 &to 1>;
|
||||||
};
|
};
|
||||||
|
|
||||||
lower_layer {
|
lower_layer {
|
||||||
@@ -20,8 +30,8 @@
|
|||||||
|
|
||||||
raise_layer {
|
raise_layer {
|
||||||
bindings = <
|
bindings = <
|
||||||
&kp W &kp U
|
&kp W &tog 2
|
||||||
&kp X &kp M>;
|
&tog_off 2 &mo 2>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
3
app/tests/toggle-layer/locking/events.patterns
Normal file
3
app/tests/toggle-layer/locking/events.patterns
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
s/.*hid_listener_keycode/kp/p
|
||||||
|
s/.*tog_keymap_binding/tog/p
|
||||||
|
s/.*mo_keymap_binding/mo/p
|
||||||
16
app/tests/toggle-layer/locking/keycode_events.snapshot
Normal file
16
app/tests/toggle-layer/locking/keycode_events.snapshot
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
mo_pressed: position 2 layer 2
|
||||||
|
tog_pressed: position 1 layer 2
|
||||||
|
tog_released: position 1 layer 2
|
||||||
|
mo_released: position 2 layer 2
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x1A implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x1A implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
mo_pressed: position 3 layer 2
|
||||||
|
mo_released: position 3 layer 2
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x1A implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x1A implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
tog_pressed: position 1 layer 2
|
||||||
|
tog_released: position 1 layer 2
|
||||||
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
25
app/tests/toggle-layer/locking/native_posix_64.keymap
Normal file
25
app/tests/toggle-layer/locking/native_posix_64.keymap
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#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,0,10)
|
||||||
|
ZMK_MOCK_RELEASE(0,0,10)
|
||||||
|
ZMK_MOCK_PRESS(1,0,10)
|
||||||
|
ZMK_MOCK_PRESS(0,1,10)
|
||||||
|
ZMK_MOCK_RELEASE(0,1,10)
|
||||||
|
ZMK_MOCK_RELEASE(1,0,10)
|
||||||
|
ZMK_MOCK_PRESS(0,0,10)
|
||||||
|
ZMK_MOCK_RELEASE(0,0,10)
|
||||||
|
ZMK_MOCK_PRESS(1,1,10)
|
||||||
|
ZMK_MOCK_RELEASE(1,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)
|
||||||
|
>;
|
||||||
|
};
|
||||||
@@ -3,12 +3,12 @@ tog_released: position 1 layer 1
|
|||||||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
to_pressed: position 3 layer 1
|
to_pressed: position 3 layer 1
|
||||||
layer_changed: layer 1 state 1
|
layer_changed: layer 1 state 1 locked 1
|
||||||
to_released: position 3 layer 1
|
to_released: position 3 layer 1
|
||||||
kp_pressed: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x0C keycode 0xB5 implicit_mods 0x00 explicit_mods 0x00
|
||||||
tog_pressed: position 1 layer 1
|
tog_pressed: position 1 layer 1
|
||||||
layer_changed: layer 1 state 0
|
layer_changed: layer 1 state 0 locked 1
|
||||||
tog_released: position 1 layer 1
|
tog_released: position 1 layer 1
|
||||||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
@@ -154,6 +154,29 @@ You can use the following node to tweak the default behavior:
|
|||||||
| ----- | ------------------------------------------------ |
|
| ----- | ------------------------------------------------ |
|
||||||
| `&kt` | [Key toggle](../keymaps/behaviors/key-toggle.md) |
|
| `&kt` | [Key toggle](../keymaps/behaviors/key-toggle.md) |
|
||||||
|
|
||||||
|
## Momentary Layer
|
||||||
|
|
||||||
|
Creates a custom behavior that toggles a layer on when pressed, and off when released.
|
||||||
|
|
||||||
|
See the [momentary layer behavior](../keymaps/behaviors/layers.md#momentary-layer) documentation for more details and examples.
|
||||||
|
|
||||||
|
### Devicetree
|
||||||
|
|
||||||
|
Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-momentary-layer.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-momentary-layer.yaml)
|
||||||
|
|
||||||
|
Applies to: `compatible = "zmk,behavior-momentary-layer"`
|
||||||
|
|
||||||
|
| Property | Type | Description | Default |
|
||||||
|
| ---------------- | ---- | --------------------------------------------------------------- | ------- |
|
||||||
|
| `#binding-cells` | int | Must be `<1>` | |
|
||||||
|
| `locking` | bool | Whether the behavior can lock and unlock layers in the on state | false |
|
||||||
|
|
||||||
|
You can use the following node to tweak the default behavior:
|
||||||
|
|
||||||
|
| Node | Behavior |
|
||||||
|
| ----- | ----------------------------------------------------------------- |
|
||||||
|
| `&mo` | [Momentary Layer](../keymaps/behaviors/layers.md#momentary-layer) |
|
||||||
|
|
||||||
## Layer Toggle
|
## Layer Toggle
|
||||||
|
|
||||||
Creates a custom behavior that toggles a layer on, off, or switches between the two states.
|
Creates a custom behavior that toggles a layer on, off, or switches between the two states.
|
||||||
@@ -166,10 +189,11 @@ Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-layer-toggle.yaml]
|
|||||||
|
|
||||||
Applies to: `compatible = "zmk,behavior-layer-toggle"`
|
Applies to: `compatible = "zmk,behavior-layer-toggle"`
|
||||||
|
|
||||||
| Property | Type | Description | Default |
|
| Property | Type | Description | Default |
|
||||||
| ---------------- | ---- | ------------------------------ | ------- |
|
| ---------------- | ---- | --------------------------------------------------------------- | ------- |
|
||||||
| `#binding-cells` | int | Must be `<1>` | |
|
| `#binding-cells` | int | Must be `<1>` | |
|
||||||
| `toggle-mode` | | One of `on`, `off`, and `flip` | `flip` |
|
| `toggle-mode` | | One of `on`, `off`, and `flip` | `flip` |
|
||||||
|
| `locking` | bool | Whether the behavior can lock and unlock layers in the on state | false |
|
||||||
|
|
||||||
You can use the following node to tweak the default behavior:
|
You can use the following node to tweak the default behavior:
|
||||||
|
|
||||||
@@ -177,6 +201,29 @@ You can use the following node to tweak the default behavior:
|
|||||||
| ------ | ----------------------------------------------------------- |
|
| ------ | ----------------------------------------------------------- |
|
||||||
| `&tog` | [Layer toggle](../keymaps/behaviors/layers.md#toggle-layer) |
|
| `&tog` | [Layer toggle](../keymaps/behaviors/layers.md#toggle-layer) |
|
||||||
|
|
||||||
|
## To Layer
|
||||||
|
|
||||||
|
Creates a custom behavior that toggles a layer on and toggles all other layers off, barring the default layer.
|
||||||
|
|
||||||
|
See the [to layer behavior](../keymaps/behaviors/layers.md#to-layer) documentation for more details and examples.
|
||||||
|
|
||||||
|
### Devicetree
|
||||||
|
|
||||||
|
Definition file: [zmk/app/dts/bindings/behaviors/zmk,behavior-to-layer.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/behaviors/zmk%2Cbehavior-to-layer.yaml)
|
||||||
|
|
||||||
|
Applies to: `compatible = "zmk,behavior-to-layer"`
|
||||||
|
|
||||||
|
| Property | Type | Description | Default |
|
||||||
|
| ---------------- | ---- | --------------------------------------------------------------- | ------- |
|
||||||
|
| `#binding-cells` | int | Must be `<1>` | |
|
||||||
|
| `locking` | bool | Whether the behavior can lock and unlock layers in the on state | false |
|
||||||
|
|
||||||
|
You can use the following node to tweak the default behavior:
|
||||||
|
|
||||||
|
| Node | Behavior |
|
||||||
|
| ----- | --------------------------------------------------- |
|
||||||
|
| `&to` | [To Layer](../keymaps/behaviors/layers.md#to-layer) |
|
||||||
|
|
||||||
## Macro
|
## Macro
|
||||||
|
|
||||||
Creates a custom behavior which triggers a sequence of other behaviors.
|
Creates a custom behavior which triggers a sequence of other behaviors.
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ Define a new behavior and assign `"on"` or `"off"` to `toggle-mode`:
|
|||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
display-name = "Toggle Layer On";
|
display-name = "Toggle Layer On";
|
||||||
toggle-mode = "on";
|
toggle-mode = "on";
|
||||||
|
locking;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -89,6 +90,14 @@ Define a new behavior and assign `"on"` or `"off"` to `toggle-mode`:
|
|||||||
|
|
||||||
You can then use `&tog_on` in place of `&tog` whenever you wish to only toggle a layer on, and not toggle it off. An `"off"` version of the behavior can be defined similarly.
|
You can then use `&tog_on` in place of `&tog` whenever you wish to only toggle a layer on, and not toggle it off. An `"off"` version of the behavior can be defined similarly.
|
||||||
|
|
||||||
|
## Layer Locking
|
||||||
|
|
||||||
|
When the behaviors `&to` and `&tog` toggle a layer on, they will "lock" the layer in the active state. This prevents the layer from being deactivated by any behavior which is not a `&to` or a `&tog`.
|
||||||
|
|
||||||
|
In particular, if you activate a layer momentarily using e.g. `&mo 1`, tapping e.g. `&tog 1` as defined above will prevent the layer from deactivating after releasing `&mo 1`. You can then press `&tog 1` again to deactivate the layer.
|
||||||
|
|
||||||
|
For custom toggle, to, and momentary layer behaviors, this can be enabled by giving your behavior the `locking;` property.
|
||||||
|
|
||||||
## Conditional Layers
|
## Conditional Layers
|
||||||
|
|
||||||
The "conditional layers" feature enables a particular layer when all layers in a specified set are active.
|
The "conditional layers" feature enables a particular layer when all layers in a specified set are active.
|
||||||
|
|||||||
Reference in New Issue
Block a user