diff options
| author | Drashna Jaelre <drashna@live.com> | 2024-11-20 22:31:54 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-21 17:31:54 +1100 |
| commit | 36b5559b997cedd14a352aa70891558936b8b3a3 (patch) | |
| tree | bf4d30ba2d31b69d659c53a225e4a5b9a7299f7a /quantum/process_keycode/process_layer_lock.c | |
| parent | 39161b9ee793f4c62836b209ec877acda457b88d (diff) | |
[Core] Add Layer Lock feature (#23430)
Co-authored-by: Daniel <1767914+iamdanielv@users.noreply.github.com>
Co-authored-by: Pascal Getreuer <getreuer@google.com>
Co-authored-by: Pascal Getreuer <50221757+getreuer@users.noreply.github.com>
Diffstat (limited to 'quantum/process_keycode/process_layer_lock.c')
| -rw-r--r-- | quantum/process_keycode/process_layer_lock.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/quantum/process_keycode/process_layer_lock.c b/quantum/process_keycode/process_layer_lock.c new file mode 100644 index 0000000000..1e36d8844e --- /dev/null +++ b/quantum/process_keycode/process_layer_lock.c | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | // Copyright 2022-2023 Google LLC | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | /** | ||
| 16 | * @file layer_lock.c | ||
| 17 | * @brief Layer Lock implementation | ||
| 18 | * | ||
| 19 | * For full documentation, see | ||
| 20 | * <https://getreuer.info/posts/keyboards/layer-lock> | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include "layer_lock.h" | ||
| 24 | #include "process_layer_lock.h" | ||
| 25 | #include "quantum_keycodes.h" | ||
| 26 | #include "action_util.h" | ||
| 27 | |||
| 28 | // The current lock state. The kth bit is on if layer k is locked. | ||
| 29 | extern layer_state_t locked_layers; | ||
| 30 | #if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0 | ||
| 31 | extern uint32_t layer_lock_timer; | ||
| 32 | #endif | ||
| 33 | |||
| 34 | // Handles an event on an `MO` or `TT` layer switch key. | ||
| 35 | static bool handle_mo_or_tt(uint8_t layer, keyrecord_t* record) { | ||
| 36 | if (is_layer_locked(layer)) { | ||
| 37 | if (record->event.pressed) { // On press, unlock the layer. | ||
| 38 | layer_lock_invert(layer); | ||
| 39 | } | ||
| 40 | return false; // Skip default handling. | ||
| 41 | } | ||
| 42 | return true; | ||
| 43 | } | ||
| 44 | |||
| 45 | bool process_layer_lock(uint16_t keycode, keyrecord_t* record) { | ||
| 46 | #ifndef NO_ACTION_LAYER | ||
| 47 | # if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0 | ||
| 48 | layer_lock_timer = timer_read32(); | ||
| 49 | # endif // LAYER_LOCK_IDLE_TIMEOUT > 0 | ||
| 50 | |||
| 51 | // The intention is that locked layers remain on. If something outside of | ||
| 52 | // this feature turned any locked layers off, unlock them. | ||
| 53 | if ((locked_layers & ~layer_state) != 0) { | ||
| 54 | layer_lock_set_kb(locked_layers &= layer_state); | ||
| 55 | } | ||
| 56 | |||
| 57 | if (keycode == QK_LAYER_LOCK) { | ||
| 58 | if (record->event.pressed) { // The layer lock key was pressed. | ||
| 59 | layer_lock_invert(get_highest_layer(layer_state)); | ||
| 60 | } | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | |||
| 64 | switch (keycode) { | ||
| 65 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: // `MO(layer)` keys. | ||
| 66 | return handle_mo_or_tt(QK_MOMENTARY_GET_LAYER(keycode), record); | ||
| 67 | |||
| 68 | case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: // `TT(layer)`. | ||
| 69 | return handle_mo_or_tt(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode), record); | ||
| 70 | |||
| 71 | case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: { // `LM(layer, mod)`. | ||
| 72 | uint8_t layer = QK_LAYER_MOD_GET_LAYER(keycode); | ||
| 73 | if (is_layer_locked(layer)) { | ||
| 74 | if (record->event.pressed) { // On press, unlock the layer. | ||
| 75 | layer_lock_invert(layer); | ||
| 76 | } else { // On release, clear the mods. | ||
| 77 | clear_mods(); | ||
| 78 | send_keyboard_report(); | ||
| 79 | } | ||
| 80 | return false; // Skip default handling. | ||
| 81 | } | ||
| 82 | } break; | ||
| 83 | |||
| 84 | # ifndef NO_ACTION_TAPPING | ||
| 85 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys. | ||
| 86 | if (record->tap.count == 0 && !record->event.pressed && is_layer_locked(QK_LAYER_TAP_GET_LAYER(keycode))) { | ||
| 87 | // Release event on a held layer-tap key where the layer is locked. | ||
| 88 | return false; // Skip default handling so that layer stays on. | ||
| 89 | } | ||
| 90 | break; | ||
| 91 | # endif // NO_ACTION_TAPPING | ||
| 92 | } | ||
| 93 | #endif // NO_ACTION_LAYER | ||
| 94 | return true; | ||
| 95 | } | ||
