From 4ca22b09ed4cd91b1d6c238fb708f762bd6a3d8d Mon Sep 17 00:00:00 2001 From: David Scarpetti Date: Sat, 8 Aug 2026 21:14:46 -0600 Subject: [PATCH] Add layer_dismiss module: a key that drops the layer that delivered it KC_LAYER_DISMISS (alias LY_DSMS) is the lowering half of a toggle: on release it turns off whichever layer resolved the keypress, and emits nothing of its own. TG() raises and lowers one hardcoded layer. Layer Lock holds the current layer on. This is the missing third primitive, letting the current layer go from any position it is bound on. On the base layer the key is a deliberate no-op: the root cannot be dismissed. Motivating use: automouse layers. Neither timeout-based deactivation nor exit-on-any-keypress fits users who want mouse keys to keep the layer and chosen positions to dismiss it. Binding KC_LAYER_DISMISS across a mouse layer's unused positions makes each of them a consumed tap-to-wake exit: the layer drops, nothing types, and the next keystroke lands on the layout below. Dropping on release keeps rollover safe: a fast second keystroke still resolves through the layer's transparency. The keycode is generic: any transient layer can carry dismiss positions, and per-position policy lives in the keymap rather than in firmware configuration. --- README.md | 3 +++ layer_dismiss/layer_dismiss.c | 45 +++++++++++++++++++++++++++++++++++ layer_dismiss/qmk_module.json | 11 +++++++++ 3 files changed, 59 insertions(+) create mode 100644 layer_dismiss/layer_dismiss.c create mode 100644 layer_dismiss/qmk_module.json diff --git a/README.md b/README.md index 4ed3bfa..06c0ef5 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,6 @@ Available modules: - `oryx`: Includes the raw hid protocol to connect keyboards to Oryx's live training / Keymapp live view / typ.ing live view - `keycolors`: Includes per-layer key color change +- `layer_dismiss`: Adds `KC_LAYER_DISMISS` (`LY_DSMS`), an assignable key that + turns off the layer that delivered it, on release, emitting nothing: the + lowering half of a toggle, aimed at whichever layer resolved the keypress diff --git a/layer_dismiss/layer_dismiss.c b/layer_dismiss/layer_dismiss.c new file mode 100644 index 0000000..bfad36f --- /dev/null +++ b/layer_dismiss/layer_dismiss.c @@ -0,0 +1,45 @@ +// Copyright 2026 David Scarpetti +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Layer Dismiss: an assignable key that turns off the layer that delivered +// it, on release, and produces no output of its own. Where TG() both raises +// and lowers one specific layer, KC_LAYER_DISMISS is just the lowering half, +// aimed at whichever layer resolved the keypress, so the same binding works +// on any layer it is placed on. It pairs conceptually with Layer Lock, which +// holds a layer on. This lets one go. On the base layer the key is a +// deliberate no-op: the root cannot be dismissed. +// +// Bound across the unused positions of a transiently-raised layer (for +// example an automouse layer), it turns every foreign tap into a consumed +// "wake" gesture: the layer drops, nothing types, and the next keystroke +// lands on the layout below. Dropping on release rather than press means a +// rolled-over second keystroke still resolves through the layer's +// transparency to the layout below, so fast typing after a wake tap loses +// nothing. +// +// Composed with automouse, dropping on release also yields a hold behavior +// for free: while the key is held, automouse counts it as layer activity +// and keeps refreshing its timer, so the layer stays open through any +// pause, and release then drops it instantly. Tap dismisses, hold +// sustains, release exits. The sustain depends on module order: automouse +// must be listed before layer_dismiss in the keymap's modules list, so +// that automouse sees the held key's press before this module consumes it. +// Listed the other way, tap-to-dismiss still works but a hold no longer +// counts as activity. + +#include QMK_KEYBOARD_H + +ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(1, 0, 0); + +bool process_record_layer_dismiss(uint16_t keycode, keyrecord_t *record) { + if (keycode == KC_LAYER_DISMISS) { + if (!record->event.pressed) { + uint8_t layer = layer_switch_get_layer(record->event.key); + if (layer > 0) { + layer_off(layer); + } + } + return false; + } + return true; +} diff --git a/layer_dismiss/qmk_module.json b/layer_dismiss/qmk_module.json new file mode 100644 index 0000000..dcbe530 --- /dev/null +++ b/layer_dismiss/qmk_module.json @@ -0,0 +1,11 @@ +{ + "module_name": "Layer Dismiss", + "maintainer": "David Scarpetti", + "license": "GPL-2.0-or-later", + "keycodes": [ + { + "key": "KC_LAYER_DISMISS", + "aliases": ["LY_DSMS"] + } + ] +}