summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrashna Jaelre <drashna@live.com>2023-02-11 15:23:07 -0800
committerGitHub <noreply@github.com>2023-02-12 10:23:07 +1100
commitfe02abc47921428fe6eb59ca817bfd082f0de4bf (patch)
tree5bc3f68ec782969cfed93660c21704df4b530823
parent40028437971fbca33f49e1d0b683b3b6e2dc9a61 (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.mk1
-rw-r--r--builddefs/generic_features.mk1
-rw-r--r--builddefs/show_options.mk3
-rw-r--r--data/constants/keycodes/keycodes_0.0.2_quantum.hjson18
-rw-r--r--docs/_summary.md1
-rw-r--r--docs/feature_tri_layer.md48
-rw-r--r--quantum/action_layer.c10
-rw-r--r--quantum/action_layer.h21
-rw-r--r--quantum/keycodes.h6
-rw-r--r--quantum/process_keycode/process_tri_layer.c30
-rw-r--r--quantum/process_keycode/process_tri_layer.h16
-rw-r--r--quantum/quantum.c13
-rw-r--r--quantum/quantum.h7
-rw-r--r--quantum/tri_layer.c39
-rw-r--r--quantum/tri_layer.h59
-rw-r--r--tests/test_common/keycode_table.cpp2
-rw-r--r--tests/tri_layer/config.h6
-rw-r--r--tests/tri_layer/test.mk8
-rw-r--r--tests/tri_layer/test_tri_layer.cpp103
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
625endif 626endif
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
43define HANDLE_GENERIC_FEATURE 44define 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
89define NAME_ECHO 90define 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
3This 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
6TRI_LAYER_ENABLE = yes
7```
8
9Note 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
11For 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
22To 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
30Eg, 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) {
349action_t layer_switch_get_action(keypos_t key) { 349action_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
353layer_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
359void 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);
113void layer_xor(layer_state_t state); 113void layer_xor(layer_state_t state);
114layer_state_t layer_state_set_user(layer_state_t state); 114layer_state_t layer_state_set_user(layer_state_t state);
115layer_state_t layer_state_set_kb(layer_state_t state); 115layer_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 */
124void 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 */
134layer_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
8bool 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 */
16bool 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
446layer_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
452void 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
244void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3); 244# include "tri_layer.h"
245layer_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
247void set_single_persistent_default_layer(uint8_t default_layer); 248void 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
7static uint8_t tri_layer_lower_layer = TRI_LAYER_LOWER_LAYER;
8static uint8_t tri_layer_upper_layer = TRI_LAYER_UPPER_LAYER;
9static uint8_t tri_layer_adjust_layer = TRI_LAYER_ADJUST_LAYER;
10
11void set_tri_layer_lower_layer(uint8_t layer) {
12 tri_layer_lower_layer = layer;
13}
14
15void set_tri_layer_upper_layer(uint8_t layer) {
16 tri_layer_upper_layer = layer;
17}
18
19void set_tri_layer_adjust_layer(uint8_t layer) {
20 tri_layer_adjust_layer = layer;
21}
22
23void 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
29uint8_t get_tri_layer_lower_layer(void) {
30 return tri_layer_lower_layer;
31}
32
33uint8_t get_tri_layer_upper_layer(void) {
34 return tri_layer_upper_layer;
35}
36
37uint8_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 */
21void set_tri_layer_lower_layer(uint8_t layer);
22/**
23 * @brief Set the tri layer upper layer index
24 *
25 * @param layer
26 */
27void set_tri_layer_upper_layer(uint8_t layer);
28/**
29 * @brief Set the tri layer adjust layer index
30 *
31 * @param layer
32 */
33void 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 */
41void 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 */
47uint8_t get_tri_layer_lower_layer(void);
48/**
49 * @brief Get the tri layer upper layer index
50 *
51 * @return uint8_t
52 */
53uint8_t get_tri_layer_upper_layer(void);
54/**
55 * @brief Get the tri layer adjust layer index
56 *
57 * @return uint8_t
58 */
59uint8_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
8TRI_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
6using testing::_;
7using testing::InSequence;
8
9class TriLayer : public TestFixture {};
10
11TEST_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
36TEST_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
61TEST_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}