Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
45 changes: 45 additions & 0 deletions layer_dismiss/layer_dismiss.c
Original file line number Diff line number Diff line change
@@ -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;
}
11 changes: 11 additions & 0 deletions layer_dismiss/qmk_module.json
Original file line number Diff line number Diff line change
@@ -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"]
}
]
}