layer_lock.c
3056 bytes
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#include "layer_lock.h"
16#include "quantum_keycodes.h"
17
18#ifndef NO_ACTION_LAYER
19// The current lock state. The kth bit is on if layer k is locked.
20layer_state_t locked_layers = 0;
21
22// Layer Lock timer to disable layer lock after X seconds inactivity
23# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0
24uint32_t layer_lock_timer = 0;
25
26void layer_lock_timeout_task(void) {
27 if (locked_layers && timer_elapsed32(layer_lock_timer) > LAYER_LOCK_IDLE_TIMEOUT) {
28 layer_lock_all_off();
29 layer_lock_timer = timer_read32();
30 }
31}
32void layer_lock_activity_trigger(void) {
33 layer_lock_timer = timer_read32();
34}
35# else
36void layer_lock_timeout_task(void) {}
37void layer_lock_activity_trigger(void) {}
38# endif // LAYER_LOCK_IDLE_TIMEOUT > 0
39
40bool is_layer_locked(uint8_t layer) {
41 return locked_layers & ((layer_state_t)1 << layer);
42}
43
44void layer_lock_invert(uint8_t layer) {
45 const layer_state_t mask = (layer_state_t)1 << layer;
46 if ((locked_layers & mask) == 0) { // Layer is being locked.
47# ifndef NO_ACTION_ONESHOT
48 if (layer == get_oneshot_layer()) {
49 reset_oneshot_layer(); // Reset so that OSL doesn't turn layer off.
50 }
51# endif // NO_ACTION_ONESHOT
52 layer_on(layer);
53 layer_lock_activity_trigger();
54 } else { // Layer is being unlocked.
55 layer_off(layer);
56 }
57 layer_lock_set_kb(locked_layers ^= mask);
58}
59
60// Implement layer_lock_on/off by deferring to layer_lock_invert.
61void layer_lock_on(uint8_t layer) {
62 if (!is_layer_locked(layer)) {
63 layer_lock_invert(layer);
64 }
65}
66
67void layer_lock_off(uint8_t layer) {
68 if (is_layer_locked(layer)) {
69 layer_lock_invert(layer);
70 }
71}
72
73void layer_lock_all_off(void) {
74 layer_and(~locked_layers);
75 locked_layers = 0;
76 layer_lock_set_kb(locked_layers);
77}
78
79#else // NO_ACTION_LAYER
80bool is_layer_locked(uint8_t layer) {
81 return false;
82}
83void layer_lock_on(uint8_t layer) {}
84void layer_lock_off(uint8_t layer) {}
85void layer_lock_all_off(void) {}
86void layer_lock_invert(uint8_t layer) {}
87void layer_lock_timeout_task(void) {}
88void layer_lock_activity_trigger(void) {}
89#endif // NO_ACTION_LAYER
90
91__attribute__((weak)) bool layer_lock_set_kb(layer_state_t locked_layers) {
92 return layer_lock_set_user(locked_layers);
93}
94__attribute__((weak)) bool layer_lock_set_user(layer_state_t locked_layers) {
95 return true;
96}
97
98void layer_lock_task(void) {
99 layer_lock_timeout_task();
100}