Skip to content

Instantly share code, notes, and snippets.

@caksoylar
Last active July 14, 2022 04:06
Show Gist options
  • Save caksoylar/ebb9e459d129928cb0fc7b89c0aed401 to your computer and use it in GitHub Desktop.
Save caksoylar/ebb9e459d129928cb0fc7b89c0aed401 to your computer and use it in GitHub Desktop.
A patch to disable layer widget updates for temporary layer changes

Hiding momentarily activated layers for Corne-ish Zen

This patch lets you set a config option such that the layer widget on the e-ink display of Corne-ish Zen won't update when you switch to/from layers that are activated momentarily, for instance when using &mo or &lt behaviors. The layer widget will only update for layers that are activated "permanently", i.e. using behaviors like &to or &tog. This reduces the amount of refreshes the e-ink display has to make during normal typing.

To use this feature, you can apply the patch to your ZMK repo on top of the Board-Corne-ish-Zen-dedicated-work-queue branch then enable the feature by adding CONFIG_ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS=y to your corne-ish_zen.conf file.

diff --git a/app/boards/arm/corne-ish_zen/widgets/layer_status.c b/app/boards/arm/corne-ish_zen/widgets/layer_status.c
index 9202262..65ee264 100644
--- a/app/boards/arm/corne-ish_zen/widgets/layer_status.c
+++ b/app/boards/arm/corne-ish_zen/widgets/layer_status.c
@@ -24,6 +24,9 @@ K_MUTEX_DEFINE(layer_status_mutex);
struct {
uint8_t index;
+#if IS_ENABLED(CONFIG_ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS)
+ uint8_t last_perm_index;
+#endif
const char *label;
} layer_status_state;
@@ -32,6 +35,9 @@ void layer_status_init() {
return;
}
style_initialized = true;
+#if IS_ENABLED(CONFIG_ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS)
+ layer_status_state.last_perm_index = 0;
+#endif
lv_style_init(&label_style);
lv_style_set_text_color(&label_style, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_style_set_text_font(&label_style, LV_STATE_DEFAULT, &lv_font_montserrat_16);
@@ -48,7 +54,7 @@ void set_layer_symbol(lv_obj_t *label) {
k_mutex_unlock(&layer_status_mutex);
//LOG_DBG("Layer Label: %s", layer_label);
-
+
if (layer_label == NULL) {
char text[6] = {};
@@ -60,13 +66,34 @@ void set_layer_symbol(lv_obj_t *label) {
}
}
-static void update_state() {
+static bool update_state() {
k_mutex_lock(&layer_status_mutex, K_FOREVER);
+
+#if IS_ENABLED(CONFIG_ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS)
+ bool update_display = false;
+#endif
+
layer_status_state.index = zmk_keymap_highest_layer_active();
layer_status_state.label = zmk_keymap_layer_label(layer_status_state.index);
+
LOG_DBG("Layer changed to %i", layer_status_state.index);
+#if IS_ENABLED(CONFIG_ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS)
+ if (!zmk_keymap_layer_momentary(layer_status_state.index)
+ && layer_status_state.last_perm_index != layer_status_state.index) {
+ layer_status_state.last_perm_index = layer_status_state.index;
+ LOG_DBG("Last perm layer index updated to %i", layer_status_state.index);
+ update_display = true;
+ }
+#endif
+
k_mutex_unlock(&layer_status_mutex);
+
+#if IS_ENABLED(CONFIG_ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS)
+ return update_display;
+#else
+ return true;
+#endif
}
int zmk_widget_layer_status_init(struct zmk_widget_layer_status *widget, lv_obj_t *parent) {
@@ -92,11 +119,11 @@ void layer_status_update_cb(struct k_work *work) {
K_WORK_DEFINE(layer_status_update_work, layer_status_update_cb);
int layer_status_listener(const zmk_event_t *eh) {
- update_state();;
-
- k_work_submit_to_queue(zmk_display_work_q(), &layer_status_update_work);
+ if (update_state()) {
+ k_work_submit_to_queue(zmk_display_work_q(), &layer_status_update_work);
+ }
return 0;
}
ZMK_LISTENER(widget_layer_status, layer_status_listener)
-ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed);
\ No newline at end of file
+ZMK_SUBSCRIPTION(widget_layer_status, zmk_layer_state_changed);
diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h
index 7151930..3d2fec0 100644
--- a/app/include/zmk/keymap.h
+++ b/app/include/zmk/keymap.h
@@ -11,8 +11,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 8259b6c..6dd65f9 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 4beb87e..81df466 100644
--- a/app/src/conditional_layer.c
+++ b/app/src/conditional_layer.c
@@ -47,12 +47,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);
}
}
@@ -77,7 +77,7 @@ static int layer_state_changed_listener(const zmk_event_t *ev) {
// reevaluate the current layer state for each config since activation of one layer can also
// trigger activation of another.
if ((zmk_keymap_layer_state() & mask) == mask) {
- conditional_layer_activate(cfg->then_layer);
+ conditional_layer_activate(cfg->then_layer, zmk_keymap_layers_any_momentary(mask));
} else {
conditional_layer_deactivate(cfg->then_layer);
}
diff --git a/app/src/display/Kconfig b/app/src/display/Kconfig
index c87cf6e..222ca71 100644
--- a/app/src/display/Kconfig
+++ b/app/src/display/Kconfig
@@ -52,6 +52,10 @@ config ZMK_DISPLAY_DEDICATED_THREAD_PRIORITY
endif # ZMK_DISPLAY_WORK_QUEUE_DEDICATED
+config ZMK_DISPLAY_HIDE_MOMENTARY_LAYERS
+ bool "Do not update layer widget for momentary layer changes"
+ default n
+
rsource "widgets/Kconfig"
endif
diff --git a/app/src/keymap.c b/app/src/keymap.c
index 1643f64..81302df 100644
--- a/app/src/keymap.c
+++ b/app/src/keymap.c
@@ -20,6 +20,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/events/sensor_event.h>
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
@@ -74,7 +75,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;
}
@@ -89,6 +90,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));
}
@@ -109,6 +111,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)) {
@@ -118,16 +128,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) {
@@ -135,7 +145,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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment