diff options
Diffstat (limited to 'quantum/layer_lock.c')
-rw-r--r-- | quantum/layer_lock.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/quantum/layer_lock.c b/quantum/layer_lock.c new file mode 100644 index 0000000000..9fc84bcfca --- /dev/null +++ b/quantum/layer_lock.c @@ -0,0 +1,100 @@ +// Copyright 2022-2023 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. + +#include "layer_lock.h" +#include "quantum_keycodes.h" + +#ifndef NO_ACTION_LAYER +// The current lock state. The kth bit is on if layer k is locked. +layer_state_t locked_layers = 0; + +// Layer Lock timer to disable layer lock after X seconds inactivity +# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0 +uint32_t layer_lock_timer = 0; + +void layer_lock_timeout_task(void) { + if (locked_layers && timer_elapsed32(layer_lock_timer) > LAYER_LOCK_IDLE_TIMEOUT) { + layer_lock_all_off(); + layer_lock_timer = timer_read32(); + } +} +void layer_lock_activity_trigger(void) { + layer_lock_timer = timer_read32(); +} +# else +void layer_lock_timeout_task(void) {} +void layer_lock_activity_trigger(void) {} +# endif // LAYER_LOCK_IDLE_TIMEOUT > 0 + +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); + layer_lock_activity_trigger(); + } else { // Layer is being unlocked. + layer_off(layer); + } + layer_lock_set_kb(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); + } +} + +void layer_lock_all_off(void) { + layer_and(~locked_layers); + locked_layers = 0; + layer_lock_set_kb(locked_layers); +} + +#else // NO_ACTION_LAYER +bool is_layer_locked(uint8_t layer) { + return false; +} +void layer_lock_on(uint8_t layer) {} +void layer_lock_off(uint8_t layer) {} +void layer_lock_all_off(void) {} +void layer_lock_invert(uint8_t layer) {} +void layer_lock_timeout_task(void) {} +void layer_lock_activity_trigger(void) {} +#endif // NO_ACTION_LAYER + +__attribute__((weak)) bool layer_lock_set_kb(layer_state_t locked_layers) { + return layer_lock_set_user(locked_layers); +} +__attribute__((weak)) bool layer_lock_set_user(layer_state_t locked_layers) { + return true; +} + +void layer_lock_task(void) { + layer_lock_timeout_task(); +} |