diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 9ce140bf..6f3df7f5 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -17,8 +17,10 @@ typedef uint32_t zmk_keymap_layers_state_t; uint8_t zmk_keymap_layer_default(); zmk_keymap_layers_state_t zmk_keymap_layer_state(); bool zmk_keymap_layer_active(uint8_t layer); +bool zmk_keymap_layer_momentary(uint8_t layer); +bool zmk_keymap_layers_any_momentary(zmk_keymap_layers_state_t layers_mask); uint8_t zmk_keymap_highest_layer_active(); -int zmk_keymap_layer_activate(uint8_t layer); +int zmk_keymap_layer_activate(uint8_t layer, bool momentary); int zmk_keymap_layer_deactivate(uint8_t layer); int zmk_keymap_layer_toggle(uint8_t layer); int zmk_keymap_layer_to(uint8_t layer); diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c index c2bd0ffc..21a9d8d8 100644 --- a/app/src/behaviors/behavior_momentary_layer.c +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -23,7 +23,7 @@ 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); + return zmk_keymap_layer_activate(binding->param1, true); } static int mo_keymap_binding_released(struct zmk_behavior_binding *binding, diff --git a/app/src/conditional_layer.c b/app/src/conditional_layer.c index 9ba02a5c..f575205a 100644 --- a/app/src/conditional_layer.c +++ b/app/src/conditional_layer.c @@ -49,12 +49,12 @@ static const struct conditional_layer_cfg CONDITIONAL_LAYER_CFGS[] = { static const int32_t NUM_CONDITIONAL_LAYER_CFGS = sizeof(CONDITIONAL_LAYER_CFGS) / sizeof(*CONDITIONAL_LAYER_CFGS); -static void conditional_layer_activate(int8_t layer) { +static void conditional_layer_activate(int8_t layer, bool momentary) { // 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). if (!zmk_keymap_layer_active(layer)) { LOG_DBG("layer %d", layer); - zmk_keymap_layer_activate(layer); + zmk_keymap_layer_activate(layer, momentary); } } @@ -84,6 +84,7 @@ static int layer_state_changed_listener(const zmk_event_t *ev) { int8_t max_then_layer = -1; uint32_t then_layers = 0; uint32_t then_layer_state = 0; + uint32_t momentariness_state = 0; conditional_layer_updates_needed = false; @@ -100,13 +101,17 @@ static int layer_state_changed_listener(const zmk_event_t *ev) { // also trigger activation of another. if ((zmk_keymap_layer_state() & mask) == mask) { then_layer_state |= BIT(cfg->then_layer); + if (zmk_keymap_layers_any_momentary(mask)) { + momentariness_state |= BIT(cfg->then_layer); + } } } for (uint8_t layer = 0; layer <= max_then_layer; layer++) { if ((BIT(layer) & then_layers) != 0U) { if ((BIT(layer) & then_layer_state) != 0U) { - conditional_layer_activate(layer); + bool momentary = BIT(layer) & momentariness_state; + conditional_layer_activate(layer, momentary); } else { conditional_layer_deactivate(layer); } diff --git a/app/src/keymap.c b/app/src/keymap.c index bda69427..f7cfabd0 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -27,6 +27,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0; +static zmk_keymap_layers_state_t _zmk_keymap_layer_momentary = 0; static uint8_t _zmk_keymap_layer_default = 0; #define DT_DRV_COMPAT zmk_keymap @@ -78,7 +79,7 @@ static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN] #endif /* ZMK_KEYMAP_HAS_SENSORS */ -static inline int set_layer_state(uint8_t layer, bool state) { +static inline int set_layer_state(uint8_t layer, bool state, bool momentary) { if (layer >= ZMK_KEYMAP_LAYERS_LEN) { return -EINVAL; } @@ -93,6 +94,7 @@ static inline int set_layer_state(uint8_t layer, bool state) { // Don't send state changes unless there was an actual change if (old_state != _zmk_keymap_layer_state) { LOG_DBG("layer_changed: layer %d state %d", layer, state); + WRITE_BIT(_zmk_keymap_layer_momentary, layer, momentary); ZMK_EVENT_RAISE(create_layer_state_changed(layer, state)); } @@ -113,6 +115,14 @@ bool zmk_keymap_layer_active(uint8_t layer) { return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state); }; +bool zmk_keymap_layer_momentary(uint8_t layer) { + return layer != _zmk_keymap_layer_default && (_zmk_keymap_layer_momentary & (BIT(layer))) == (BIT(layer)); +}; + +bool zmk_keymap_layers_any_momentary(zmk_keymap_layers_state_t layers_mask) { + return (_zmk_keymap_layer_momentary & layers_mask) > 0; +}; + uint8_t zmk_keymap_highest_layer_active() { for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) { if (zmk_keymap_layer_active(layer)) { @@ -122,16 +132,16 @@ uint8_t zmk_keymap_highest_layer_active() { return zmk_keymap_layer_default(); } -int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true); }; +int zmk_keymap_layer_activate(uint8_t layer, bool momentary) { return set_layer_state(layer, true, momentary); }; -int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false); }; +int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false, false); }; int zmk_keymap_layer_toggle(uint8_t layer) { if (zmk_keymap_layer_active(layer)) { return zmk_keymap_layer_deactivate(layer); } - return zmk_keymap_layer_activate(layer); + return zmk_keymap_layer_activate(layer, false); }; int zmk_keymap_layer_to(uint8_t layer) { @@ -139,7 +149,7 @@ int zmk_keymap_layer_to(uint8_t layer) { zmk_keymap_layer_deactivate(i); } - zmk_keymap_layer_activate(layer); + zmk_keymap_layer_activate(layer, false); return 0; }