feat: lock a momentary layer

This commit is contained in:
Dylan MacKenzie 2023-11-02 13:11:57 -07:00
parent 40adb3858d
commit 832f490ca2
7 changed files with 108 additions and 9 deletions

View file

@ -49,6 +49,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources(app PRIVATE src/behaviors/behavior_key_repeat.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) 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.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_mod_morph.c)
target_sources(app PRIVATE src/behaviors/behavior_outputs.c) target_sources(app PRIVATE src/behaviors/behavior_outputs.c)
target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c)

View file

@ -7,6 +7,7 @@
#include <behaviors/gresc.dtsi> #include <behaviors/gresc.dtsi>
#include <behaviors/sticky_key.dtsi> #include <behaviors/sticky_key.dtsi>
#include <behaviors/momentary_layer.dtsi> #include <behaviors/momentary_layer.dtsi>
#include <behaviors/momentary_layer_lock.dtsi>
#include <behaviors/toggle_layer.dtsi> #include <behaviors/toggle_layer.dtsi>
#include <behaviors/to_layer.dtsi> #include <behaviors/to_layer.dtsi>
#include <behaviors/reset.dtsi> #include <behaviors/reset.dtsi>

View 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";
label = "MO_LOCK";
#binding-cells = <1>;
};
};
};

View file

@ -0,0 +1,8 @@
# Copyright (c) 2023 The ZMK Contributors
# SPDX-License-Identifier: MIT
description: Momentary layer on press/release behavior
compatible: "zmk,behavior-momentary-layer-lock"
include: one_param.yaml

View 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();

View file

@ -12,32 +12,51 @@
#include <zmk/keymap.h> #include <zmk/keymap.h>
#include <zmk/behavior.h> #include <zmk/behavior.h>
#include <zmk/momentary_layer.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct behavior_mo_config {}; 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 behavior_mo_init(const struct device *dev) { return 0; };
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); int layer = binding->param1;
return zmk_keymap_layer_activate(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, 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); 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); return zmk_keymap_layer_deactivate(binding->param1);
} }
static const struct behavior_driver_api behavior_mo_driver_api = { static const struct behavior_driver_api behavior_mo_driver_api = {
.binding_pressed = mo_keymap_binding_pressed, .binding_released = mo_keymap_binding_released}; .binding_pressed = mo_keymap_binding_pressed, .binding_released = mo_keymap_binding_released};
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, 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);

View file

@ -0,0 +1,40 @@
/*
* 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)
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) {
int fallback_layer = binding->param1;
zmk_keymap_layers_state_t locked = zmk_lock_active_momentary_layers();
if (!locked && fallback_layer >= 0) {
return zmk_keymap_layer_to(fallback_layer);
}
return 0;
}
static const struct behavior_driver_api behavior_mo_lock_driver_api = {
.binding_pressed = mo_lock_keymap_binding_pressed};
DEVICE_DT_INST_DEFINE(0, behavior_mo_lock_init, NULL, NULL, NULL, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_lock_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */