-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds a new "Layer Lock" feature, a key that locks the current layer to stay on assuming it was activated by a `MO(layer)`, `LT(layer, key)`, `OSL(layer)`, or `TT(layer)` key. Pressing the Layer Lock key again unlocks and turns off the layer.
- Loading branch information
Showing
3 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2022 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// | ||
// For full documentation, see | ||
// https://getreuer.info/posts/keyboards/layer-lock | ||
|
||
#include "layer_lock.h" | ||
|
||
// The current lock state. The kth bit is on if layer k is locked. | ||
static layer_state_t locked_layers = 0; | ||
|
||
bool process_layer_lock(uint16_t keycode, keyrecord_t* record, | ||
uint16_t lock_keycode) { | ||
// The intention is that locked layers remain on. If something outside of | ||
// this feature turned any locked layers off, unlock them. | ||
if ((locked_layers & ~layer_state) != 0) { | ||
layer_lock_set_user(locked_layers &= layer_state); | ||
} | ||
|
||
if (keycode == lock_keycode) { | ||
if (record->event.pressed) { // The layer lock key was pressed. | ||
layer_lock_invert(get_highest_layer(layer_state)); | ||
} | ||
return false; | ||
} | ||
|
||
switch (keycode) { | ||
case QK_MOMENTARY ... QK_MOMENTARY_MAX: // `MO(layer)` keys. | ||
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: { // `TT(layer)`. | ||
const uint8_t layer = keycode & 255; | ||
if (is_layer_locked(layer)) { | ||
// Event on `MO` or `TT` key where layer is locked. | ||
if (record->event.pressed) { // On press, unlock the layer. | ||
layer_lock_invert(layer); | ||
} | ||
return false; // Skip default handling. | ||
} | ||
} break; | ||
|
||
#ifndef NO_ACTION_TAPPING | ||
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys. | ||
if (record->tap.count == 0 && !record->event.pressed && | ||
is_layer_locked((keycode >> 8) & 15)) { | ||
// Release event on a held layer-tap key where the layer is locked. | ||
return false; // Skip default handling so that layer stays on. | ||
} | ||
break; | ||
#endif // NO_ACTION_TAPPING | ||
} | ||
|
||
return true; | ||
} | ||
|
||
bool is_layer_locked(uint8_t layer) { | ||
return locked_layers & ((layer_state_t)1 << layer); | ||
} | ||
|
||
void layer_lock_invert(uint8_t layer) { | ||
const layer_state_t mask = (layer_state_t)1 << layer; | ||
if ((locked_layers & mask) == 0) { // Layer is being locked. | ||
#ifndef NO_ACTION_ONESHOT | ||
if (layer == get_oneshot_layer()) { | ||
reset_oneshot_layer(); // Reset so that OSL doesn't turn layer off. | ||
} | ||
#endif // NO_ACTION_ONESHOT | ||
layer_on(layer); | ||
} else { // Layer is being unlocked. | ||
layer_off(layer); | ||
} | ||
layer_lock_set_user(locked_layers ^= mask); | ||
} | ||
|
||
// Implement layer_lock_on/off by deferring to layer_lock_invert. | ||
void layer_lock_on(uint8_t layer) { | ||
if (!is_layer_locked(layer)) { layer_lock_invert(layer); } | ||
} | ||
|
||
void layer_lock_off(uint8_t layer) { | ||
if (is_layer_locked(layer)) { layer_lock_invert(layer); } | ||
} | ||
|
||
__attribute__((weak)) void layer_lock_set_user(layer_state_t locked_layers) {} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright 2022 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// | ||
// Layer Lock, a key to stay in the current layer. | ||
// | ||
// Layers are often accessed by holding a button, e.g. with a momentary layer | ||
// switch `MO(layer)` or layer tap `LT(layer, key)` key. But you may sometimes | ||
// want to "lock" or "toggle" the layer so that it stays on without having to | ||
// hold down a button. One way to do that is with a tap-toggle `TT` layer key, | ||
// but here is an alternative. | ||
// | ||
// This library implements a "Layer Lock key". When tapped, it "locks" the | ||
// highest layer to stay active, assuming the layer was activated by one of the | ||
// following keys: | ||
// | ||
// * `MO(layer)` momentary layer switch | ||
// * `LT(layer, key)` layer tap | ||
// * `OSL(layer)` one-shot layer | ||
// * `TT(layer)` layer tap toggle | ||
// | ||
// Tapping the Layer Lock key again unlocks and turns off the layer. | ||
// | ||
// NOTE: When a layer is "locked", other layer keys such as `TO(layer)` or | ||
// manually calling `layer_off(layer)` will override and unlock the layer. | ||
// | ||
// For full documentation, see | ||
// https://getreuer.info/posts/keyboards/layer-lock | ||
|
||
#pragma once | ||
|
||
#include QMK_KEYBOARD_H | ||
|
||
// In your keymap, define a custom keycode to use for Layer Lock. Then handle | ||
// Layer Lock from your `process_record_user` function by calling | ||
// `process_layer_lock`, passing your custom keycode for the `lock_keycode` arg: | ||
// | ||
// #include "features/layer_lock.h" | ||
// | ||
// bool process_record_user(uint16_t keycode, keyrecord_t* record) { | ||
// if (!process_layer_lock(keycode, record, LLOCK)) { return false; } | ||
// // Your macros ... | ||
// | ||
// return true; | ||
// } | ||
bool process_layer_lock(uint16_t keycode, keyrecord_t* record, | ||
uint16_t lock_keycode); | ||
|
||
// Returns true if `layer` is currently locked. | ||
bool is_layer_locked(uint8_t layer); | ||
|
||
// Locks and turns on `layer`. | ||
void layer_lock_on(uint8_t layer); | ||
|
||
// Unlocks and turns off `layer`. | ||
void layer_lock_off(uint8_t layer); | ||
|
||
// Toggles whether `layer` is locked. | ||
void layer_lock_invert(uint8_t layer); | ||
|
||
// An optional callback that gets called when a layer is locked or unlocked. | ||
// This is useful to represent the current lock state, e.g. by setting an LED or | ||
// playing a sound. In your keymap, define | ||
// | ||
// void layer_lock_set_user(layer_state_t locked_layers) { | ||
// // Do something like `set_led(is_layer_locked(NAV));` | ||
// } | ||
void layer_lock_set_user(layer_state_t locked_layers); | ||
|