diff options
| author | Drashna Jaelre <drashna@live.com> | 2023-02-11 15:23:07 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-12 10:23:07 +1100 |
| commit | fe02abc47921428fe6eb59ca817bfd082f0de4bf (patch) | |
| tree | 5bc3f68ec782969cfed93660c21704df4b530823 | |
| parent | 40028437971fbca33f49e1d0b683b3b6e2dc9a61 (diff) | |
[Core] Tri Layer Keys (#19795)
Co-authored-by: wilba <wilba@wilba.tech>
Co-authored-by: Pablo MartÃnez <58857054+elpekenin@users.noreply.github.com>
Co-authored-by: Joel Challis <git@zvecr.com>
Co-authored-by: Nick Brassel <nick@tzarc.org>
| -rw-r--r-- | builddefs/common_features.mk | 1 | ||||
| -rw-r--r-- | builddefs/generic_features.mk | 1 | ||||
| -rw-r--r-- | builddefs/show_options.mk | 3 | ||||
| -rw-r--r-- | data/constants/keycodes/keycodes_0.0.2_quantum.hjson | 18 | ||||
| -rw-r--r-- | docs/_summary.md | 1 | ||||
| -rw-r--r-- | docs/feature_tri_layer.md | 48 | ||||
| -rw-r--r-- | quantum/action_layer.c | 10 | ||||
| -rw-r--r-- | quantum/action_layer.h | 21 | ||||
| -rw-r--r-- | quantum/keycodes.h | 6 | ||||
| -rw-r--r-- | quantum/process_keycode/process_tri_layer.c | 30 | ||||
| -rw-r--r-- | quantum/process_keycode/process_tri_layer.h | 16 | ||||
| -rw-r--r-- | quantum/quantum.c | 13 | ||||
| -rw-r--r-- | quantum/quantum.h | 7 | ||||
| -rw-r--r-- | quantum/tri_layer.c | 39 | ||||
| -rw-r--r-- | quantum/tri_layer.h | 59 | ||||
| -rw-r--r-- | tests/test_common/keycode_table.cpp | 2 | ||||
| -rw-r--r-- | tests/tri_layer/config.h | 6 | ||||
| -rw-r--r-- | tests/tri_layer/test.mk | 8 | ||||
| -rw-r--r-- | tests/tri_layer/test_tri_layer.cpp | 103 |
19 files changed, 377 insertions, 15 deletions
diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk index 4e032f9dcf..0880934e95 100644 --- a/builddefs/common_features.mk +++ b/builddefs/common_features.mk | |||
| @@ -620,6 +620,7 @@ ifeq ($(strip $(VIA_ENABLE)), yes) | |||
| 620 | DYNAMIC_KEYMAP_ENABLE := yes | 620 | DYNAMIC_KEYMAP_ENABLE := yes |
| 621 | RAW_ENABLE := yes | 621 | RAW_ENABLE := yes |
| 622 | BOOTMAGIC_ENABLE := yes | 622 | BOOTMAGIC_ENABLE := yes |
| 623 | TRI_LAYER_ENABLE := yes | ||
| 623 | SRC += $(QUANTUM_DIR)/via.c | 624 | SRC += $(QUANTUM_DIR)/via.c |
| 624 | OPT_DEFS += -DVIA_ENABLE | 625 | OPT_DEFS += -DVIA_ENABLE |
| 625 | endif | 626 | endif |
diff --git a/builddefs/generic_features.mk b/builddefs/generic_features.mk index 0d897bc1c8..5a1ef5c6f0 100644 --- a/builddefs/generic_features.mk +++ b/builddefs/generic_features.mk | |||
| @@ -39,6 +39,7 @@ GENERIC_FEATURES = \ | |||
| 39 | VELOCIKEY \ | 39 | VELOCIKEY \ |
| 40 | WPM \ | 40 | WPM \ |
| 41 | DYNAMIC_TAPPING_TERM \ | 41 | DYNAMIC_TAPPING_TERM \ |
| 42 | TRI_LAYER | ||
| 42 | 43 | ||
| 43 | define HANDLE_GENERIC_FEATURE | 44 | define HANDLE_GENERIC_FEATURE |
| 44 | # $$(info "Processing: $1_ENABLE $2.c") | 45 | # $$(info "Processing: $1_ENABLE $2.c") |
diff --git a/builddefs/show_options.mk b/builddefs/show_options.mk index e9f7e7d047..9723b45438 100644 --- a/builddefs/show_options.mk +++ b/builddefs/show_options.mk | |||
| @@ -84,7 +84,8 @@ OTHER_OPTION_NAMES = \ | |||
| 84 | PROGRAMMABLE_BUTTON_ENABLE \ | 84 | PROGRAMMABLE_BUTTON_ENABLE \ |
| 85 | SECURE_ENABLE \ | 85 | SECURE_ENABLE \ |
| 86 | CAPS_WORD_ENABLE \ | 86 | CAPS_WORD_ENABLE \ |
| 87 | AUTOCORRECT_ENABLE | 87 | AUTOCORRECT_ENABLE \ |
| 88 | TRI_LAYER_ENABLE | ||
| 88 | 89 | ||
| 89 | define NAME_ECHO | 90 | define NAME_ECHO |
| 90 | @printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)" | 91 | @printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)" |
diff --git a/data/constants/keycodes/keycodes_0.0.2_quantum.hjson b/data/constants/keycodes/keycodes_0.0.2_quantum.hjson new file mode 100644 index 0000000000..960afa4e51 --- /dev/null +++ b/data/constants/keycodes/keycodes_0.0.2_quantum.hjson | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "keycodes": { | ||
| 3 | "0x7C77": { | ||
| 4 | "group": "quantum", | ||
| 5 | "key": "QK_TRI_LAYER_LOWER", | ||
| 6 | "aliases": [ | ||
| 7 | "TL_LOWR" | ||
| 8 | ] | ||
| 9 | }, | ||
| 10 | "0x7C78": { | ||
| 11 | "group": "quantum", | ||
| 12 | "key": "QK_TRI_LAYER_UPPER", | ||
| 13 | "aliases": [ | ||
| 14 | "TL_UPPR" | ||
| 15 | ] | ||
| 16 | } | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/docs/_summary.md b/docs/_summary.md index d2d4bb9b32..b038f08a4d 100644 --- a/docs/_summary.md +++ b/docs/_summary.md | |||
| @@ -93,6 +93,7 @@ | |||
| 93 | * [Swap Hands](feature_swap_hands.md) | 93 | * [Swap Hands](feature_swap_hands.md) |
| 94 | * [Tap Dance](feature_tap_dance.md) | 94 | * [Tap Dance](feature_tap_dance.md) |
| 95 | * [Tap-Hold Configuration](tap_hold.md) | 95 | * [Tap-Hold Configuration](tap_hold.md) |
| 96 | * [Tri Layer](feature_tri_layer.md) | ||
| 96 | * [Unicode](feature_unicode.md) | 97 | * [Unicode](feature_unicode.md) |
| 97 | * [Userspace](feature_userspace.md) | 98 | * [Userspace](feature_userspace.md) |
| 98 | * [WPM Calculation](feature_wpm.md) | 99 | * [WPM Calculation](feature_wpm.md) |
diff --git a/docs/feature_tri_layer.md b/docs/feature_tri_layer.md new file mode 100644 index 0000000000..aa6c87719c --- /dev/null +++ b/docs/feature_tri_layer.md | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | # Tri Layers :id=tri-layers | ||
| 2 | |||
| 3 | This enables support for the OLKB style "Tri Layer" keycodes. These function similar to the `MO` (momentary) function key, but if both the "Lower" and "Upper" keys are pressed, it activates a third "Adjust" layer. To enable this functionality, add this line to your `rules.mk`: | ||
| 4 | |||
| 5 | ```make | ||
| 6 | TRI_LAYER_ENABLE = yes | ||
| 7 | ``` | ||
| 8 | |||
| 9 | Note that the "upper", "lower" and "adjust" names don't have a particular significance, they are just used to identify and clarify the behavior. Layers are processed from highest numeric value to lowest, however the values are not required to be consecutive. | ||
| 10 | |||
| 11 | For a detailed explanation of how the layer stack works, check out [Keymap Overview](keymap.md#keymap-and-layers). | ||
| 12 | |||
| 13 | ## Keycodes :id=keycodes | ||
| 14 | |||
| 15 | | Keycode | Alias | Description | | ||
| 16 | |----------------------|-----------|---------------------------------------------------------------------------------------------------------| | ||
| 17 | | `QK_TRI_LAYER_LOWER` | `TL_LOWR` | Momentarily enables the "lower" layer. Enables the "adjust" layer if the "upper" layer is also enabled" | | ||
| 18 | | `QK_TRI_LAYER_UPPER` | `TL_UPPR` | Momentarily enables the "upper" layer. Enables the "adjust" layer if the "lower" layer is also enabled" | | ||
| 19 | |||
| 20 | ## Configuration | ||
| 21 | |||
| 22 | To change the default values for the layers, you can change these defines, in your `config.h` | ||
| 23 | |||
| 24 | | Config name | Default | Description | | ||
| 25 | |--------------------------|---------|------------------------------------------| | ||
| 26 | | `TRI_LAYER_LOWER_LAYER` | `1` | Sets the default for the "lower" layer. | | ||
| 27 | | `TRI_LAYER_UPPER_LAYER` | `2` | Sets the default for the "upper" layer. | | ||
| 28 | | `TRI_LAYER_ADJUST_LAYER` | `3` | Sets the default for the "adjust" layer. | | ||
| 29 | |||
| 30 | Eg, if you wanted to set the "Adjust" layer to be layer 5, you'd add this to your `config.h`: | ||
| 31 | |||
| 32 | ```c | ||
| 33 | #define TRI_LAYER_ADJUST_LAYER 5 | ||
| 34 | ``` | ||
| 35 | |||
| 36 | ## Functions | ||
| 37 | |||
| 38 | | Function name | Description | | ||
| 39 | |----------------------------------------------|-------------------------------------------------| | ||
| 40 | | `set_tri_layer_lower_layer(layer)` | Changes the "lower" layer*. | | ||
| 41 | | `set_tri_layer_upper_layer(layer)` | Changes the "upper" layer*. | | ||
| 42 | | `set_tri_layer_adjust_layer(layer)` | Changes the "adjust" layer*. | | ||
| 43 | | `set_tri_layer_layers(lower, upper, adjust)` | Stes the "lower", "upper" and "adjust" layers*. | | ||
| 44 | | `get_tri_layer_lower_layer()` | Gets the current "lower" layer. | | ||
| 45 | | `get_tri_layer_upper_layer()` | Gets the current "upper" layer. | | ||
| 46 | | `get_tri_layer_adjust_layer()` | Gets the current "adjust" layer. | | ||
| 47 | |||
| 48 | !> Note: these settings are not persisent, and will be reset to the default on power loss or power cycling of the controller. | ||
diff --git a/quantum/action_layer.c b/quantum/action_layer.c index 74e8137920..35f494df8f 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c | |||
| @@ -349,3 +349,13 @@ uint8_t layer_switch_get_layer(keypos_t key) { | |||
| 349 | action_t layer_switch_get_action(keypos_t key) { | 349 | action_t layer_switch_get_action(keypos_t key) { |
| 350 | return action_for_key(layer_switch_get_layer(key), key); | 350 | return action_for_key(layer_switch_get_layer(key), key); |
| 351 | } | 351 | } |
| 352 | |||
| 353 | layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3) { | ||
| 354 | layer_state_t mask12 = ((layer_state_t)1 << layer1) | ((layer_state_t)1 << layer2); | ||
| 355 | layer_state_t mask3 = (layer_state_t)1 << layer3; | ||
| 356 | return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3); | ||
| 357 | } | ||
| 358 | |||
| 359 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) { | ||
| 360 | layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3)); | ||
| 361 | } | ||
diff --git a/quantum/action_layer.h b/quantum/action_layer.h index 3fe2726529..ff783bb3e7 100644 --- a/quantum/action_layer.h +++ b/quantum/action_layer.h | |||
| @@ -113,6 +113,25 @@ void layer_and(layer_state_t state); | |||
| 113 | void layer_xor(layer_state_t state); | 113 | void layer_xor(layer_state_t state); |
| 114 | layer_state_t layer_state_set_user(layer_state_t state); | 114 | layer_state_t layer_state_set_user(layer_state_t state); |
| 115 | layer_state_t layer_state_set_kb(layer_state_t state); | 115 | layer_state_t layer_state_set_kb(layer_state_t state); |
| 116 | |||
| 117 | /** | ||
| 118 | * @brief Applies the tri layer to global layer state. Not be used in layer_state_set_(kb|user) functions. | ||
| 119 | * | ||
| 120 | * @param layer1 First layer to check for tri layer | ||
| 121 | * @param layer2 Second layer to check for tri layer | ||
| 122 | * @param layer3 Layer to activate if both other layers are enabled | ||
| 123 | */ | ||
| 124 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); | ||
| 125 | /** | ||
| 126 | * @brief Applies the tri layer behavior to supplied layer bitmask, without using layer functions. | ||
| 127 | * | ||
| 128 | * @param state Original layer bitmask to check and modify | ||
| 129 | * @param layer1 First layer to check for tri layer | ||
| 130 | * @param layer2 Second layer to check for tri layer | ||
| 131 | * @param layer3 Layer to activate if both other layers are enabled | ||
| 132 | * @return layer_state_t returns a modified layer bitmask with tri layer modifications applied | ||
| 133 | */ | ||
| 134 | layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3); | ||
| 116 | #else | 135 | #else |
| 117 | # define layer_state 0 | 136 | # define layer_state 0 |
| 118 | 137 | ||
| @@ -131,6 +150,8 @@ layer_state_t layer_state_set_kb(layer_state_t state); | |||
| 131 | # define layer_xor(state) (void)state | 150 | # define layer_xor(state) (void)state |
| 132 | # define layer_state_set_kb(state) (void)state | 151 | # define layer_state_set_kb(state) (void)state |
| 133 | # define layer_state_set_user(state) (void)state | 152 | # define layer_state_set_user(state) (void)state |
| 153 | # define update_tri_layer(layer1, layer2, layer3) | ||
| 154 | # define update_tri_layer_state(state, layer1, layer2, layer3) (void)state | ||
| 134 | #endif | 155 | #endif |
| 135 | 156 | ||
| 136 | /* pressed actions cache */ | 157 | /* pressed actions cache */ |
diff --git a/quantum/keycodes.h b/quantum/keycodes.h index f24ccf01b8..4fa4306ed6 100644 --- a/quantum/keycodes.h +++ b/quantum/keycodes.h | |||
| @@ -717,6 +717,8 @@ enum qk_keycode_defines { | |||
| 717 | QK_AUTOCORRECT_ON = 0x7C74, | 717 | QK_AUTOCORRECT_ON = 0x7C74, |
| 718 | QK_AUTOCORRECT_OFF = 0x7C75, | 718 | QK_AUTOCORRECT_OFF = 0x7C75, |
| 719 | QK_AUTOCORRECT_TOGGLE = 0x7C76, | 719 | QK_AUTOCORRECT_TOGGLE = 0x7C76, |
| 720 | QK_TRI_LAYER_LOWER = 0x7C77, | ||
| 721 | QK_TRI_LAYER_UPPER = 0x7C78, | ||
| 720 | SAFE_RANGE = 0x7E00, | 722 | SAFE_RANGE = 0x7E00, |
| 721 | 723 | ||
| 722 | // Alias | 724 | // Alias |
| @@ -1282,6 +1284,8 @@ enum qk_keycode_defines { | |||
| 1282 | AC_ON = QK_AUTOCORRECT_ON, | 1284 | AC_ON = QK_AUTOCORRECT_ON, |
| 1283 | AC_OFF = QK_AUTOCORRECT_OFF, | 1285 | AC_OFF = QK_AUTOCORRECT_OFF, |
| 1284 | AC_TOGG = QK_AUTOCORRECT_TOGGLE, | 1286 | AC_TOGG = QK_AUTOCORRECT_TOGGLE, |
| 1287 | TL_LOWR = QK_TRI_LAYER_LOWER, | ||
| 1288 | TL_UPPR = QK_TRI_LAYER_UPPER, | ||
| 1285 | }; | 1289 | }; |
| 1286 | 1290 | ||
| 1287 | // Range Helpers | 1291 | // Range Helpers |
| @@ -1333,4 +1337,4 @@ enum qk_keycode_defines { | |||
| 1333 | #define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31) | 1337 | #define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31) |
| 1334 | #define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING) | 1338 | #define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING) |
| 1335 | #define IS_RGB_KEYCODE(code) ((code) >= RGB_TOG && (code) <= RGB_MODE_TWINKLE) | 1339 | #define IS_RGB_KEYCODE(code) ((code) >= RGB_TOG && (code) <= RGB_MODE_TWINKLE) |
| 1336 | #define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_AUTOCORRECT_TOGGLE) | 1340 | #define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_TRI_LAYER_UPPER) |
diff --git a/quantum/process_keycode/process_tri_layer.c b/quantum/process_keycode/process_tri_layer.c new file mode 100644 index 0000000000..1e681b9a1c --- /dev/null +++ b/quantum/process_keycode/process_tri_layer.c | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2023 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "process_tri_layer.h" | ||
| 5 | #include "tri_layer.h" | ||
| 6 | #include "action_layer.h" | ||
| 7 | |||
| 8 | bool process_tri_layer(uint16_t keycode, keyrecord_t *record) { | ||
| 9 | switch (keycode) { | ||
| 10 | case QK_TRI_LAYER_LOWER: | ||
| 11 | if (record->event.pressed) { | ||
| 12 | layer_on(get_tri_layer_lower_layer()); | ||
| 13 | update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer()); | ||
| 14 | } else { | ||
| 15 | layer_off(get_tri_layer_lower_layer()); | ||
| 16 | update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer()); | ||
| 17 | } | ||
| 18 | return false; | ||
| 19 | case QK_TRI_LAYER_UPPER: | ||
| 20 | if (record->event.pressed) { | ||
| 21 | layer_on(get_tri_layer_upper_layer()); | ||
| 22 | update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer()); | ||
| 23 | } else { | ||
| 24 | layer_off(get_tri_layer_upper_layer()); | ||
| 25 | update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer()); | ||
| 26 | } | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | return true; | ||
| 30 | } | ||
diff --git a/quantum/process_keycode/process_tri_layer.h b/quantum/process_keycode/process_tri_layer.h new file mode 100644 index 0000000000..9c4e3df1c2 --- /dev/null +++ b/quantum/process_keycode/process_tri_layer.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Copyright 2023 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "action.h" | ||
| 7 | |||
| 8 | /** | ||
| 9 | * @brief Handles tri layer behavior | ||
| 10 | * | ||
| 11 | * @param keycode the keycode | ||
| 12 | * @param record the key record structure | ||
| 13 | * @return true continue handling keycodes | ||
| 14 | * @return false stop handling keycodes | ||
| 15 | */ | ||
| 16 | bool process_tri_layer(uint16_t keycode, keyrecord_t *record); | ||
diff --git a/quantum/quantum.c b/quantum/quantum.c index 5554ecab32..0587f215fe 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -343,6 +343,9 @@ bool process_record_quantum(keyrecord_t *record) { | |||
| 343 | #ifdef AUTOCORRECT_ENABLE | 343 | #ifdef AUTOCORRECT_ENABLE |
| 344 | process_autocorrect(keycode, record) && | 344 | process_autocorrect(keycode, record) && |
| 345 | #endif | 345 | #endif |
| 346 | #ifdef TRI_LAYER_ENABLE | ||
| 347 | process_tri_layer(keycode, record) && | ||
| 348 | #endif | ||
| 346 | true)) { | 349 | true)) { |
| 347 | return false; | 350 | return false; |
| 348 | } | 351 | } |
| @@ -443,16 +446,6 @@ void set_single_persistent_default_layer(uint8_t default_layer) { | |||
| 443 | default_layer_set((layer_state_t)1 << default_layer); | 446 | default_layer_set((layer_state_t)1 << default_layer); |
| 444 | } | 447 | } |
| 445 | 448 | ||
| 446 | layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3) { | ||
| 447 | layer_state_t mask12 = ((layer_state_t)1 << layer1) | ((layer_state_t)1 << layer2); | ||
| 448 | layer_state_t mask3 = (layer_state_t)1 << layer3; | ||
| 449 | return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3); | ||
| 450 | } | ||
| 451 | |||
| 452 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) { | ||
| 453 | layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3)); | ||
| 454 | } | ||
| 455 | |||
| 456 | //------------------------------------------------------------------------------ | 449 | //------------------------------------------------------------------------------ |
| 457 | // Override these functions in your keymap file to play different tunes on | 450 | // Override these functions in your keymap file to play different tunes on |
| 458 | // different events such as startup and bootloader jump | 451 | // different events such as startup and bootloader jump |
diff --git a/quantum/quantum.h b/quantum/quantum.h index 615ec2382c..708d325a32 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h | |||
| @@ -240,9 +240,10 @@ extern layer_state_t layer_state; | |||
| 240 | # include "process_autocorrect.h" | 240 | # include "process_autocorrect.h" |
| 241 | #endif | 241 | #endif |
| 242 | 242 | ||
| 243 | // For tri-layer | 243 | #ifdef TRI_LAYER_ENABLE |
| 244 | void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); | 244 | # include "tri_layer.h" |
| 245 | layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3); | 245 | # include "process_tri_layer.h" |
| 246 | #endif | ||
| 246 | 247 | ||
| 247 | void set_single_persistent_default_layer(uint8_t default_layer); | 248 | void set_single_persistent_default_layer(uint8_t default_layer); |
| 248 | 249 | ||
diff --git a/quantum/tri_layer.c b/quantum/tri_layer.c new file mode 100644 index 0000000000..a5e3f8cb47 --- /dev/null +++ b/quantum/tri_layer.c | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // Copyright 2023 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "tri_layer.h" | ||
| 5 | #include <stdint.h> | ||
| 6 | |||
| 7 | static uint8_t tri_layer_lower_layer = TRI_LAYER_LOWER_LAYER; | ||
| 8 | static uint8_t tri_layer_upper_layer = TRI_LAYER_UPPER_LAYER; | ||
| 9 | static uint8_t tri_layer_adjust_layer = TRI_LAYER_ADJUST_LAYER; | ||
| 10 | |||
| 11 | void set_tri_layer_lower_layer(uint8_t layer) { | ||
| 12 | tri_layer_lower_layer = layer; | ||
| 13 | } | ||
| 14 | |||
| 15 | void set_tri_layer_upper_layer(uint8_t layer) { | ||
| 16 | tri_layer_upper_layer = layer; | ||
| 17 | } | ||
| 18 | |||
| 19 | void set_tri_layer_adjust_layer(uint8_t layer) { | ||
| 20 | tri_layer_adjust_layer = layer; | ||
| 21 | } | ||
| 22 | |||
| 23 | void set_tri_layer_layers(uint8_t lower, uint8_t raise, uint8_t adjust) { | ||
| 24 | tri_layer_lower_layer = lower; | ||
| 25 | tri_layer_upper_layer = raise; | ||
| 26 | tri_layer_adjust_layer = adjust; | ||
| 27 | } | ||
| 28 | |||
| 29 | uint8_t get_tri_layer_lower_layer(void) { | ||
| 30 | return tri_layer_lower_layer; | ||
| 31 | } | ||
| 32 | |||
| 33 | uint8_t get_tri_layer_upper_layer(void) { | ||
| 34 | return tri_layer_upper_layer; | ||
| 35 | } | ||
| 36 | |||
| 37 | uint8_t get_tri_layer_adjust_layer(void) { | ||
| 38 | return tri_layer_adjust_layer; | ||
| 39 | } | ||
diff --git a/quantum/tri_layer.h b/quantum/tri_layer.h new file mode 100644 index 0000000000..3341ebffb2 --- /dev/null +++ b/quantum/tri_layer.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // Copyright 2023 QMK | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | |||
| 6 | #ifndef TRI_LAYER_LOWER_LAYER | ||
| 7 | # define TRI_LAYER_LOWER_LAYER 1 | ||
| 8 | #endif | ||
| 9 | #ifndef TRI_LAYER_UPPER_LAYER | ||
| 10 | # define TRI_LAYER_UPPER_LAYER 2 | ||
| 11 | #endif | ||
| 12 | #ifndef TRI_LAYER_ADJUST_LAYER | ||
| 13 | # define TRI_LAYER_ADJUST_LAYER 3 | ||
| 14 | #endif | ||
| 15 | |||
| 16 | /** | ||
| 17 | * @brief Set the tri layer lower layer index | ||
| 18 | * | ||
| 19 | * @param layer | ||
| 20 | */ | ||
| 21 | void set_tri_layer_lower_layer(uint8_t layer); | ||
| 22 | /** | ||
| 23 | * @brief Set the tri layer upper layer index | ||
| 24 | * | ||
| 25 | * @param layer | ||
| 26 | */ | ||
| 27 | void set_tri_layer_upper_layer(uint8_t layer); | ||
| 28 | /** | ||
| 29 | * @brief Set the tri layer adjust layer index | ||
| 30 | * | ||
| 31 | * @param layer | ||
| 32 | */ | ||
| 33 | void set_tri_layer_adjust_layer(uint8_t layer); | ||
| 34 | /** | ||
| 35 | * @brief Set the tri layer indices | ||
| 36 | * | ||
| 37 | * @param lower | ||
| 38 | * @param upper | ||
| 39 | * @param adjust | ||
| 40 | */ | ||
| 41 | void set_tri_layer_layers(uint8_t lower, uint8_t upper, uint8_t adjust); | ||
| 42 | /** | ||
| 43 | * @brief Get the tri layer lower layer index | ||
| 44 | * | ||
| 45 | * @return uint8_t | ||
| 46 | */ | ||
| 47 | uint8_t get_tri_layer_lower_layer(void); | ||
| 48 | /** | ||
| 49 | * @brief Get the tri layer upper layer index | ||
| 50 | * | ||
| 51 | * @return uint8_t | ||
| 52 | */ | ||
| 53 | uint8_t get_tri_layer_upper_layer(void); | ||
| 54 | /** | ||
| 55 | * @brief Get the tri layer adjust layer index | ||
| 56 | * | ||
| 57 | * @return uint8_t | ||
| 58 | */ | ||
| 59 | uint8_t get_tri_layer_adjust_layer(void); | ||
diff --git a/tests/test_common/keycode_table.cpp b/tests/test_common/keycode_table.cpp index ab9c292e95..337bc8fb5f 100644 --- a/tests/test_common/keycode_table.cpp +++ b/tests/test_common/keycode_table.cpp | |||
| @@ -659,5 +659,7 @@ std::map<uint16_t, std::string> KEYCODE_ID_TABLE = { | |||
| 659 | {QK_AUTOCORRECT_ON, "QK_AUTOCORRECT_ON"}, | 659 | {QK_AUTOCORRECT_ON, "QK_AUTOCORRECT_ON"}, |
| 660 | {QK_AUTOCORRECT_OFF, "QK_AUTOCORRECT_OFF"}, | 660 | {QK_AUTOCORRECT_OFF, "QK_AUTOCORRECT_OFF"}, |
| 661 | {QK_AUTOCORRECT_TOGGLE, "QK_AUTOCORRECT_TOGGLE"}, | 661 | {QK_AUTOCORRECT_TOGGLE, "QK_AUTOCORRECT_TOGGLE"}, |
| 662 | {QK_TRI_LAYER_LOWER, "QK_TRI_LAYER_LOWER"}, | ||
| 663 | {QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"}, | ||
| 662 | {SAFE_RANGE, "SAFE_RANGE"}, | 664 | {SAFE_RANGE, "SAFE_RANGE"}, |
| 663 | }; | 665 | }; |
diff --git a/tests/tri_layer/config.h b/tests/tri_layer/config.h new file mode 100644 index 0000000000..b68bf0c2d5 --- /dev/null +++ b/tests/tri_layer/config.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | // Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "test_common.h" | ||
diff --git a/tests/tri_layer/test.mk b/tests/tri_layer/test.mk new file mode 100644 index 0000000000..50548c3e1c --- /dev/null +++ b/tests/tri_layer/test.mk | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | # Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | ||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | # -------------------------------------------------------------------------------- | ||
| 5 | # Keep this file, even if it is empty, as a marker that this folder contains tests | ||
| 6 | # -------------------------------------------------------------------------------- | ||
| 7 | |||
| 8 | TRI_LAYER_ENABLE = yes | ||
diff --git a/tests/tri_layer/test_tri_layer.cpp b/tests/tri_layer/test_tri_layer.cpp new file mode 100644 index 0000000000..fffc124f4c --- /dev/null +++ b/tests/tri_layer/test_tri_layer.cpp | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | // Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "test_common.hpp" | ||
| 5 | |||
| 6 | using testing::_; | ||
| 7 | using testing::InSequence; | ||
| 8 | |||
| 9 | class TriLayer : public TestFixture {}; | ||
| 10 | |||
| 11 | TEST_F(TriLayer, TriLayerLowerTest) { | ||
| 12 | TestDriver driver; | ||
| 13 | KeymapKey lower_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_LOWER}; | ||
| 14 | |||
| 15 | set_keymap({lower_layer_key, KeymapKey{1, 0, 0, KC_TRNS}}); | ||
| 16 | |||
| 17 | /* Press Lower. */ | ||
| 18 | EXPECT_NO_REPORT(driver); | ||
| 19 | lower_layer_key.press(); | ||
| 20 | run_one_scan_loop(); | ||
| 21 | EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 22 | EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 23 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 24 | VERIFY_AND_CLEAR(driver); | ||
| 25 | |||
| 26 | /* Release Lower. */ | ||
| 27 | EXPECT_NO_REPORT(driver); | ||
| 28 | lower_layer_key.release(); | ||
| 29 | run_one_scan_loop(); | ||
| 30 | EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 31 | EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 32 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 33 | VERIFY_AND_CLEAR(driver); | ||
| 34 | } | ||
| 35 | |||
| 36 | TEST_F(TriLayer, TriLayerUpperTest) { | ||
| 37 | TestDriver driver; | ||
| 38 | KeymapKey upper_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_UPPER}; | ||
| 39 | |||
| 40 | set_keymap({upper_layer_key, KeymapKey{2, 0, 0, KC_TRNS}}); | ||
| 41 | |||
| 42 | /* Press Raise. */ | ||
| 43 | EXPECT_NO_REPORT(driver); | ||
| 44 | upper_layer_key.press(); | ||
| 45 | run_one_scan_loop(); | ||
| 46 | EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 47 | EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 48 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 49 | VERIFY_AND_CLEAR(driver); | ||
| 50 | |||
| 51 | /* Release Raise. */ | ||
| 52 | EXPECT_NO_REPORT(driver); | ||
| 53 | upper_layer_key.release(); | ||
| 54 | run_one_scan_loop(); | ||
| 55 | EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 56 | EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 57 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 58 | VERIFY_AND_CLEAR(driver); | ||
| 59 | } | ||
| 60 | |||
| 61 | TEST_F(TriLayer, TriLayerAdjustTest) { | ||
| 62 | TestDriver driver; | ||
| 63 | KeymapKey lower_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_LOWER}; | ||
| 64 | KeymapKey upper_layer_key = KeymapKey{0, 1, 0, QK_TRI_LAYER_UPPER}; | ||
| 65 | |||
| 66 | set_keymap({ | ||
| 67 | upper_layer_key, | ||
| 68 | lower_layer_key, | ||
| 69 | KeymapKey{1, 0, 0, KC_TRNS}, | ||
| 70 | KeymapKey{1, 1, 0, KC_TRNS}, | ||
| 71 | KeymapKey{2, 0, 0, KC_TRNS}, | ||
| 72 | KeymapKey{2, 1, 0, KC_TRNS}, | ||
| 73 | KeymapKey{3, 0, 0, KC_TRNS}, | ||
| 74 | KeymapKey{3, 1, 0, KC_TRNS}, | ||
| 75 | }); | ||
| 76 | |||
| 77 | /* Press Lower, then upper, and release upper and then lower. */ | ||
| 78 | EXPECT_NO_REPORT(driver); | ||
| 79 | lower_layer_key.press(); | ||
| 80 | run_one_scan_loop(); | ||
| 81 | EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 82 | EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 83 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 84 | |||
| 85 | upper_layer_key.press(); | ||
| 86 | run_one_scan_loop(); | ||
| 87 | EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 88 | EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 89 | EXPECT_TRUE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 90 | |||
| 91 | lower_layer_key.release(); | ||
| 92 | run_one_scan_loop(); | ||
| 93 | EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 94 | EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 95 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 96 | |||
| 97 | upper_layer_key.release(); | ||
| 98 | run_one_scan_loop(); | ||
| 99 | EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer())); | ||
| 100 | EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer())); | ||
| 101 | EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer())); | ||
| 102 | VERIFY_AND_CLEAR(driver); | ||
| 103 | } | ||
