From ad72e9051967fa6d91fcd4c6d0b61ae4633baf62 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sun, 4 Feb 2024 19:49:31 -0800 Subject: [PATCH 1/2] fix: restores layer lock functionality --- builddefs/generic_features.mk | 1 + data/constants/keycodes/keycodes_0.0.4.hjson | 11 ++ .../keycodes/keycodes_0.0.4_quantum.hjson | 0 data/mappings/info_config.hjson | 3 + data/schemas/keyboard.jsonschema | 6 + quantum/keyboard.c | 7 + quantum/keycodes.h | 6 +- quantum/layer_lock.c | 81 +++++++++++ quantum/layer_lock.h | 129 ++++++++++++++++++ quantum/process_keycode/process_layer_lock.c | 95 +++++++++++++ quantum/process_keycode/process_layer_lock.h | 69 ++++++++++ quantum/quantum.c | 11 ++ quantum/quantum.h | 3 + tests/test_common/keycode_table.cpp | 1 + 14 files changed, 421 insertions(+), 2 deletions(-) create mode 100644 data/constants/keycodes/keycodes_0.0.4_quantum.hjson create mode 100644 quantum/layer_lock.c create mode 100644 quantum/layer_lock.h create mode 100644 quantum/process_keycode/process_layer_lock.c create mode 100644 quantum/process_keycode/process_layer_lock.h diff --git a/builddefs/generic_features.mk b/builddefs/generic_features.mk index dc34a642307d..83d9ad11378f 100644 --- a/builddefs/generic_features.mk +++ b/builddefs/generic_features.mk @@ -36,6 +36,7 @@ GENERIC_FEATURES = \ HAPTIC \ KEY_LOCK \ KEY_OVERRIDE \ + LAYER_LOCK \ LEADER \ MAGIC \ MOUSEKEY \ diff --git a/data/constants/keycodes/keycodes_0.0.4.hjson b/data/constants/keycodes/keycodes_0.0.4.hjson index e69de29bb2d1..63153daa73c8 100644 --- a/data/constants/keycodes/keycodes_0.0.4.hjson +++ b/data/constants/keycodes/keycodes_0.0.4.hjson @@ -0,0 +1,11 @@ +{ + "keycodes": { + "0x7C7B": { + "group": "quantum", + "key": "QK_LAYER_LOCK", + "aliases": [ + "QK_LLCK" + ] + } + } +} diff --git a/data/constants/keycodes/keycodes_0.0.4_quantum.hjson b/data/constants/keycodes/keycodes_0.0.4_quantum.hjson new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/data/mappings/info_config.hjson b/data/mappings/info_config.hjson index b61ca0407145..f1f0deb8b25e 100644 --- a/data/mappings/info_config.hjson +++ b/data/mappings/info_config.hjson @@ -64,6 +64,9 @@ "WEAR_LEVELING_BACKING_SIZE": {"info_key": "eeprom.wear_leveling.backing_size", "value_type": "int", "to_json": false}, "WEAR_LEVELING_LOGICAL_SIZE": {"info_key": "eeprom.wear_leveling.logical_size", "value_type": "int", "to_json": false}, + // Layer locking + "LAYER_LOCK_IDLE_TIMEOUT": {"info_key": "layer_lock.timeout", "value_type": "int"}, + // Indicators "LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"}, "LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"}, diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema index e5802fe07dd9..a9bf46372994 100644 --- a/data/schemas/keyboard.jsonschema +++ b/data/schemas/keyboard.jsonschema @@ -343,6 +343,12 @@ } }, "keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"}, + "layer_lock": { + "type": "object", + "properties": { + "timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"} + } + }, "layout_aliases": { "type": "object", "additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"} diff --git a/quantum/keyboard.c b/quantum/keyboard.c index bdb3217f5c27..d0e1ad8f2fc5 100644 --- a/quantum/keyboard.c +++ b/quantum/keyboard.c @@ -143,6 +143,9 @@ along with this program. If not, see . #ifdef ACHORDION_ENABLE # include "process_achordion.h" #endif +#if defined(LAYER_LOCK_ENABLE) && LAYER_LOCK_IDLE_TIMEOUT > 0 +# include "layer_lock.h" +#endif static uint32_t last_input_modification_time = 0; uint32_t last_input_activity_time(void) { @@ -662,6 +665,10 @@ void quantum_task(void) { #ifdef ACHORDION_ENABLE achordion_task(); #endif + +#if defined(LAYER_LOCK_ENABLE) && LAYER_LOCK_IDLE_TIMEOUT > 0 + layer_lock_task(); +#endif } /** \brief Main task that is repeatedly called as fast as possible. */ diff --git a/quantum/keycodes.h b/quantum/keycodes.h index c92028ab4399..415ac614880f 100644 --- a/quantum/keycodes.h +++ b/quantum/keycodes.h @@ -745,6 +745,7 @@ enum qk_keycode_defines { QK_TRI_LAYER_UPPER = 0x7C78, QK_REPEAT_KEY = 0x7C79, QK_ALT_REPEAT_KEY = 0x7C7A, + QK_LAYER_LOCK = 0x7C7B, QK_KB_0 = 0x7E00, QK_KB_1 = 0x7E01, QK_KB_2 = 0x7E02, @@ -1419,6 +1420,7 @@ enum qk_keycode_defines { TL_UPPR = QK_TRI_LAYER_UPPER, QK_REP = QK_REPEAT_KEY, QK_AREP = QK_ALT_REPEAT_KEY, + QK_LLCK = QK_LAYER_LOCK, }; // Range Helpers @@ -1473,7 +1475,7 @@ enum qk_keycode_defines { #define IS_UNDERGLOW_KEYCODE(code) ((code) >= QK_UNDERGLOW_TOGGLE && (code) <= QK_UNDERGLOW_SPEED_DOWN) #define IS_RGB_KEYCODE(code) ((code) >= RGB_MODE_PLAIN && (code) <= RGB_MODE_TWINKLE) #define IS_RGB_MATRIX_KEYCODE(code) ((code) >= QK_RGB_MATRIX_ON && (code) <= QK_RGB_MATRIX_SPEED_DOWN) -#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_ALT_REPEAT_KEY) +#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_LAYER_LOCK) #define IS_KB_KEYCODE(code) ((code) >= QK_KB_0 && (code) <= QK_KB_31) #define IS_USER_KEYCODE(code) ((code) >= QK_USER_0 && (code) <= QK_USER_31) @@ -1498,6 +1500,6 @@ enum qk_keycode_defines { #define UNDERGLOW_KEYCODE_RANGE QK_UNDERGLOW_TOGGLE ... QK_UNDERGLOW_SPEED_DOWN #define RGB_KEYCODE_RANGE RGB_MODE_PLAIN ... RGB_MODE_TWINKLE #define RGB_MATRIX_KEYCODE_RANGE QK_RGB_MATRIX_ON ... QK_RGB_MATRIX_SPEED_DOWN -#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_ALT_REPEAT_KEY +#define QUANTUM_KEYCODE_RANGE QK_BOOTLOADER ... QK_LAYER_LOCK #define KB_KEYCODE_RANGE QK_KB_0 ... QK_KB_31 #define USER_KEYCODE_RANGE QK_USER_0 ... QK_USER_31 diff --git a/quantum/layer_lock.c b/quantum/layer_lock.c new file mode 100644 index 000000000000..3eaf0305b404 --- /dev/null +++ b/quantum/layer_lock.c @@ -0,0 +1,81 @@ +// 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_task(void) { + if (locked_layers && timer_elapsed32(layer_lock_timer) > LAYER_LOCK_IDLE_TIMEOUT) { + layer_lock_all_off(); + layer_lock_timer = timer_read32(); + } +} +# 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); +# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0 + layer_lock_timer = timer_read32(); +# endif // LAYER_LOCK_IDLE_TIMEOUT > 0 + } 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); + } +} + +void layer_lock_all_off(void) { + layer_and(~locked_layers); + locked_layers = 0; + layer_lock_set_user(locked_layers); +} + +__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; +} +#endif // NO_ACTION_LAYER diff --git a/quantum/layer_lock.h b/quantum/layer_lock.h new file mode 100644 index 000000000000..40abfa1ffd44 --- /dev/null +++ b/quantum/layer_lock.h @@ -0,0 +1,129 @@ +// 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. + +/** + * @file layer_lock.h + * @brief Layer Lock, a key to stay in the current layer. + * + * Overview + * -------- + * + * 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 + * * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods) + * + * 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. + * + * Configuration + * ------------- + * + * Optionally, a timeout may be defined so that Layer Lock disables + * automatically if not keys are pressed for `LAYER_LOCK_IDLE_TIMEOUT` + * milliseconds. Define `LAYER_LOCK_IDLE_TIMEOUT` in your config.h, for instance + * + * #define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds. + * + * and call `layer_lock_task()` from your `matrix_scan_user()` in keymap.c: + * + * void matrix_scan_user(void) { + * layer_lock_task(); + * // Other tasks... + * } + * + * For full documentation, see + * + */ + +#pragma once + +#include +#include +#include "action_layer.h" +#include "action_util.h" + +/** + * Handler function for Layer Lock. + * + * 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; + * } + */ + +#ifndef NO_ACTION_LAYER +/** 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); + +/** Unlocks and turns off all locked layers. */ +void layer_lock_all_off(void); + +/** Toggles whether `layer` is locked. */ +void layer_lock_invert(uint8_t layer); + +/** + * 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));` + * } + * + * @param locked_layers Bitfield in which the kth bit represents whether the + * kth layer is on. + */ +bool layer_lock_set_kb(layer_state_t locked_layers); +bool layer_lock_set_user(layer_state_t locked_layers); + +void layer_lock_task(void); +#else // NO_ACTION_LAYER +static inline bool is_layer_locked(uint8_t layer) { return false; } +static inline void layer_lock_on(uint8_t layer) {} +static inline void layer_lock_off(uint8_t layer) {} +static inline void layer_lock_all_off(void) {} +static inline void layer_lock_invert(uint8_t layer) {} +static inline bool layer_lock_set_kb(layer_state_t locked_layers) { return true; } +static inline bool layer_lock_set_user(layer_state_t locked_layers) { return true; } +static inline void layer_lock_task(void) {} +#endif // NO_ACTION_LAYER diff --git a/quantum/process_keycode/process_layer_lock.c b/quantum/process_keycode/process_layer_lock.c new file mode 100644 index 000000000000..1e36d8844e83 --- /dev/null +++ b/quantum/process_keycode/process_layer_lock.c @@ -0,0 +1,95 @@ +// 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. + +/** + * @file layer_lock.c + * @brief Layer Lock implementation + * + * For full documentation, see + * + */ + +#include "layer_lock.h" +#include "process_layer_lock.h" +#include "quantum_keycodes.h" +#include "action_util.h" + +// The current lock state. The kth bit is on if layer k is locked. +extern layer_state_t locked_layers; +#if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0 +extern uint32_t layer_lock_timer; +#endif + +// Handles an event on an `MO` or `TT` layer switch key. +static bool handle_mo_or_tt(uint8_t layer, keyrecord_t* record) { + if (is_layer_locked(layer)) { + if (record->event.pressed) { // On press, unlock the layer. + layer_lock_invert(layer); + } + return false; // Skip default handling. + } + return true; +} + +bool process_layer_lock(uint16_t keycode, keyrecord_t* record) { +#ifndef NO_ACTION_LAYER +# if defined(LAYER_LOCK_IDLE_TIMEOUT) && LAYER_LOCK_IDLE_TIMEOUT > 0 + layer_lock_timer = timer_read32(); +# endif // LAYER_LOCK_IDLE_TIMEOUT > 0 + + // 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_kb(locked_layers &= layer_state); + } + + if (keycode == QK_LAYER_LOCK) { + 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. + return handle_mo_or_tt(QK_MOMENTARY_GET_LAYER(keycode), record); + + case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: // `TT(layer)`. + return handle_mo_or_tt(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode), record); + + case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: { // `LM(layer, mod)`. + uint8_t layer = QK_LAYER_MOD_GET_LAYER(keycode); + if (is_layer_locked(layer)) { + if (record->event.pressed) { // On press, unlock the layer. + layer_lock_invert(layer); + } else { // On release, clear the mods. + clear_mods(); + send_keyboard_report(); + } + 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(QK_LAYER_TAP_GET_LAYER(keycode))) { + // 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 + } +#endif // NO_ACTION_LAYER + return true; +} diff --git a/quantum/process_keycode/process_layer_lock.h b/quantum/process_keycode/process_layer_lock.h new file mode 100644 index 000000000000..b54c0f6f1062 --- /dev/null +++ b/quantum/process_keycode/process_layer_lock.h @@ -0,0 +1,69 @@ +// 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. + +/** + * @file layer_lock.h + * @brief Layer Lock, a key to stay in the current layer. + * + * Overview + * -------- + * + * 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 + * * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods) + * + * 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. + * + * Configuration + * ------------- + * + * Optionally, a timeout may be defined so that Layer Lock disables + * automatically if not keys are pressed for `LAYER_LOCK_IDLE_TIMEOUT` + * milliseconds. Define `LAYER_LOCK_IDLE_TIMEOUT` in your config.h, for instance + * + * #define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds. + * + * and call `layer_lock_task()` from your `matrix_scan_user()` in keymap.c: + * + * void matrix_scan_user(void) { + * layer_lock_task(); + * // Other tasks... + * } + * + * For full documentation, see + * + */ + +#pragma once + +#include +#include +#include "action.h" + +bool process_layer_lock(uint16_t keycode, keyrecord_t* record); diff --git a/quantum/quantum.c b/quantum/quantum.c index 7c267f4a17b9..fab35fa12840 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -72,6 +72,14 @@ # include "process_unicode_common.h" #endif +#ifdef VELOCIKEY_ENABLE +# include "velocikey.h" +#endif + +#ifdef LAYER_LOCK_ENABLE +# include "process_layer_lock.h" +#endif + #ifdef AUDIO_ENABLE # ifndef GOODBYE_SONG # define GOODBYE_SONG SONG(GOODBYE_SOUND) @@ -396,6 +404,9 @@ bool process_record_quantum(keyrecord_t *record) { #endif #ifdef TRI_LAYER_ENABLE process_tri_layer(keycode, record) && +#endif +#ifdef LAYER_LOCK_ENABLE + process_layer_lock(keycode, record) && #endif true)) { return false; diff --git a/quantum/quantum.h b/quantum/quantum.h index 9c978f3c1934..ebda92cdba3a 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -243,6 +243,9 @@ extern layer_state_t layer_state; # include "os_detection.h" #endif +#ifdef LAYER_LOCK_ENABLE +# include "layer_lock.h" +#endif void set_single_persistent_default_layer(uint8_t default_layer); #define IS_LAYER_ON(layer) layer_state_is(layer) diff --git a/tests/test_common/keycode_table.cpp b/tests/test_common/keycode_table.cpp index 18dd5360277b..477ccf840014 100644 --- a/tests/test_common/keycode_table.cpp +++ b/tests/test_common/keycode_table.cpp @@ -687,6 +687,7 @@ std::map KEYCODE_ID_TABLE = { {QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"}, {QK_REPEAT_KEY, "QK_REPEAT_KEY"}, {QK_ALT_REPEAT_KEY, "QK_ALT_REPEAT_KEY"}, + {QK_LAYER_LOCK, "QK_LAYER_LOCK"}, {QK_KB_0, "QK_KB_0"}, {QK_KB_1, "QK_KB_1"}, {QK_KB_2, "QK_KB_2"}, From 81a7f4c6eac80b03465b650525582b24ace4c042 Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 4 Jul 2024 16:51:36 +0700 Subject: [PATCH 2/2] fix: ignore oryx build pipeline keymaps --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 22c07bdc04a2..9470808c326b 100644 --- a/.gitignore +++ b/.gitignore @@ -125,3 +125,5 @@ via*.json /keyboards/** !/keyboards/zsa/ !/keyboards/zsa/** +/keyboards/zsa/**/keymaps/** +!/keyboards/zsa/**/keymaps/default