fe02abc47921428fe6eb59ca817bfd082f0de4bf

Author
Drashna Jaelre <drashna@live.com>
Committer
GitHub <noreply@github.com>
Date

Message

[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>

Diff

This diff is truncated to protect this page.

  1diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
  2index 4e032f9dcfaf0ed16c432823e086656452aa1413..0880934e95790f79e230cc830eb757a3b338bc30 100644
  3--- a/builddefs/common_features.mk
  4+++ b/builddefs/common_features.mk
  5@@ -620,6 +620,7 @@ ifeq ($(strip $(VIA_ENABLE)), yes)
  6     DYNAMIC_KEYMAP_ENABLE := yes
  7     RAW_ENABLE := yes
  8     BOOTMAGIC_ENABLE := yes
  9+    TRI_LAYER_ENABLE := yes
 10     SRC += $(QUANTUM_DIR)/via.c
 11     OPT_DEFS += -DVIA_ENABLE
 12 endif
 13diff --git a/builddefs/generic_features.mk b/builddefs/generic_features.mk
 14index 0d897bc1c8288375903d91d2984078e953361328..5a1ef5c6f0a523ec43e096d9f2b4c58d326f82dc 100644
 15--- a/builddefs/generic_features.mk
 16+++ b/builddefs/generic_features.mk
 17@@ -39,6 +39,7 @@ GENERIC_FEATURES = \
 18     VELOCIKEY \
 19     WPM \
 20     DYNAMIC_TAPPING_TERM \
 21+    TRI_LAYER
 22 
 23 define HANDLE_GENERIC_FEATURE
 24     # $$(info "Processing: $1_ENABLE $2.c")
 25diff --git a/builddefs/show_options.mk b/builddefs/show_options.mk
 26index e9f7e7d0471fd61dc5ee6df06518fe59af007b24..9723b45438a823bd2b28555aeec146b74e114710 100644
 27--- a/builddefs/show_options.mk
 28+++ b/builddefs/show_options.mk
 29@@ -84,7 +84,8 @@ OTHER_OPTION_NAMES = \
 30   PROGRAMMABLE_BUTTON_ENABLE \
 31   SECURE_ENABLE \
 32   CAPS_WORD_ENABLE \
 33-  AUTOCORRECT_ENABLE
 34+  AUTOCORRECT_ENABLE \
 35+  TRI_LAYER_ENABLE
 36 
 37 define NAME_ECHO
 38        @printf "  %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)"
 39diff --git a/data/constants/keycodes/keycodes_0.0.2_quantum.hjson b/data/constants/keycodes/keycodes_0.0.2_quantum.hjson
 40new file mode 100644
 41index 0000000000000000000000000000000000000000..960afa4e5152206839c783ba395b227686ee7c99
 42--- /dev/null
 43+++ b/data/constants/keycodes/keycodes_0.0.2_quantum.hjson
 44@@ -0,0 +1,18 @@
 45+{
 46+    "keycodes": {
 47+        "0x7C77": {
 48+            "group": "quantum",
 49+            "key": "QK_TRI_LAYER_LOWER",
 50+            "aliases": [
 51+                "TL_LOWR"
 52+            ]
 53+        },
 54+        "0x7C78": {
 55+            "group": "quantum",
 56+            "key": "QK_TRI_LAYER_UPPER",
 57+            "aliases": [
 58+                "TL_UPPR"
 59+            ]
 60+        }
 61+    }
 62+}
 63diff --git a/docs/_summary.md b/docs/_summary.md
 64index d2d4bb9b326ab9e39816c535a3bebc5e8aee0151..b038f08a4dcbe6789235ae22648ce3814f0c7f3c 100644
 65--- a/docs/_summary.md
 66+++ b/docs/_summary.md
 67@@ -93,6 +93,7 @@
 68     * [Swap Hands](feature_swap_hands.md)
 69     * [Tap Dance](feature_tap_dance.md)
 70     * [Tap-Hold Configuration](tap_hold.md)
 71+    * [Tri Layer](feature_tri_layer.md)
 72     * [Unicode](feature_unicode.md)
 73     * [Userspace](feature_userspace.md)
 74     * [WPM Calculation](feature_wpm.md)
 75diff --git a/docs/feature_tri_layer.md b/docs/feature_tri_layer.md
 76new file mode 100644
 77index 0000000000000000000000000000000000000000..aa6c87719ca62baf38cc66e35e91ca35d96427d6
 78--- /dev/null
 79+++ b/docs/feature_tri_layer.md
 80@@ -0,0 +1,48 @@
 81+# Tri Layers :id=tri-layers
 82+
 83diff --git a/quantum/action_layer.c b/quantum/action_layer.c
 84index 74e81379207871bca8b29f4084b71462fdf1db31..35f494df8f1698808bc4f6effc72b1b22ad6867f 100644
 85--- a/quantum/action_layer.c
 86+++ b/quantum/action_layer.c
 87@@ -349,3 +349,13 @@ uint8_t layer_switch_get_layer(keypos_t key) {
 88 action_t layer_switch_get_action(keypos_t key) {
 89     return action_for_key(layer_switch_get_layer(key), key);
 90 }
 91+
 92+layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3) {
 93+    layer_state_t mask12 = ((layer_state_t)1 << layer1) | ((layer_state_t)1 << layer2);
 94+    layer_state_t mask3  = (layer_state_t)1 << layer3;
 95+    return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3);
 96+}
 97+
 98+void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
 99+    layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3));
100+}
101diff --git a/quantum/action_layer.h b/quantum/action_layer.h
102index 3fe272652999e8869ea7da303c79ecd0938df0cd..ff783bb3e7fc92b6469940c3b2d60560e584e36d 100644
103--- a/quantum/action_layer.h
104+++ b/quantum/action_layer.h
105@@ -113,6 +113,25 @@ void          layer_and(layer_state_t state);
106 void          layer_xor(layer_state_t state);
107 layer_state_t layer_state_set_user(layer_state_t state);
108 layer_state_t layer_state_set_kb(layer_state_t state);
109+
110+/**
111+ * @brief Applies the tri layer to global layer state. Not be used in layer_state_set_(kb|user) functions.
112+ *
113+ * @param layer1 First layer to check for tri layer
114+ * @param layer2 Second layer to check for tri layer
115+ * @param layer3 Layer to activate if both other layers are enabled
116+ */
117+void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
118+/**
119+ * @brief Applies the tri layer behavior to supplied layer bitmask, without using layer functions.
120+ *
121+ * @param state Original layer bitmask to check and modify
122+ * @param layer1 First layer to check for tri layer
123+ * @param layer2 Second layer to check for tri layer
124+ * @param layer3 Layer to activate if both other layers are enabled
125+ * @return layer_state_t returns a modified layer bitmask with tri layer modifications applied
126+ */
127+layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3);
128 #else
129 #    define layer_state 0
130 
131@@ -131,6 +150,8 @@ layer_state_t layer_state_set_kb(layer_state_t state);
132 #    define layer_xor(state) (void)state
133 #    define layer_state_set_kb(state) (void)state
134 #    define layer_state_set_user(state) (void)state
135+#    define update_tri_layer(layer1, layer2, layer3)
136+#    define update_tri_layer_state(state, layer1, layer2, layer3) (void)state
137 #endif
138 
139 /* pressed actions cache */
140diff --git a/quantum/keycodes.h b/quantum/keycodes.h
141index f24ccf01b8fcc9faace757a8dcfc3d24ef19445a..4fa4306ed61736b824e7510dc4bbcb0c83b7ae06 100644
142--- a/quantum/keycodes.h
143+++ b/quantum/keycodes.h
144@@ -717,6 +717,8 @@ enum qk_keycode_defines {
145     QK_AUTOCORRECT_ON = 0x7C74,
146     QK_AUTOCORRECT_OFF = 0x7C75,
147     QK_AUTOCORRECT_TOGGLE = 0x7C76,
148+    QK_TRI_LAYER_LOWER = 0x7C77,
149+    QK_TRI_LAYER_UPPER = 0x7C78,
150     SAFE_RANGE = 0x7E00,
151 
152 // Alias
153@@ -1282,6 +1284,8 @@ enum qk_keycode_defines {
154     AC_ON      = QK_AUTOCORRECT_ON,
155     AC_OFF     = QK_AUTOCORRECT_OFF,
156     AC_TOGG    = QK_AUTOCORRECT_TOGGLE,
157+    TL_LOWR    = QK_TRI_LAYER_LOWER,
158+    TL_UPPR    = QK_TRI_LAYER_UPPER,
159 };
160 
161 // Range Helpers
162@@ -1333,4 +1337,4 @@ enum qk_keycode_defines {
163 #define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31)
164 #define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING)
165 #define IS_RGB_KEYCODE(code) ((code) >= RGB_TOG && (code) <= RGB_MODE_TWINKLE)
166-#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_AUTOCORRECT_TOGGLE)
167+#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_TRI_LAYER_UPPER)
168diff --git a/quantum/process_keycode/process_tri_layer.c b/quantum/process_keycode/process_tri_layer.c
169new file mode 100644
170index 0000000000000000000000000000000000000000..1e681b9a1c2e5663f0a6980833c1c46281664dab
171--- /dev/null
172+++ b/quantum/process_keycode/process_tri_layer.c
173@@ -0,0 +1,30 @@
174+// Copyright 2023 QMK
175+// SPDX-License-Identifier: GPL-2.0-or-later
176+
177+#include "process_tri_layer.h"
178+#include "tri_layer.h"
179+#include "action_layer.h"
180+
181+bool process_tri_layer(uint16_t keycode, keyrecord_t *record) {
182+    switch (keycode) {
183+        case QK_TRI_LAYER_LOWER:
184+            if (record->event.pressed) {
185+                layer_on(get_tri_layer_lower_layer());
186+                update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
187+            } else {
188+                layer_off(get_tri_layer_lower_layer());
189+                update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
190+            }
191+            return false;
192+        case QK_TRI_LAYER_UPPER:
193+            if (record->event.pressed) {
194+                layer_on(get_tri_layer_upper_layer());
195+                update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
196+            } else {
197+                layer_off(get_tri_layer_upper_layer());
198+                update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
199+            }
200+            return false;
201+    }
202+    return true;
203+}
204diff --git a/quantum/process_keycode/process_tri_layer.h b/quantum/process_keycode/process_tri_layer.h
205new file mode 100644
206index 0000000000000000000000000000000000000000..9c4e3df1c2f4bc47215a51d9110e9e5c1217dff4
207--- /dev/null
208+++ b/quantum/process_keycode/process_tri_layer.h
209@@ -0,0 +1,16 @@
210+// Copyright 2023 QMK
211+// SPDX-License-Identifier: GPL-2.0-or-later
212+
213+#pragma once
214+
215+#include "action.h"
216+
217+/**
218+ * @brief Handles tri layer behavior
219+ *
220+ * @param keycode the keycode
221+ * @param record the key record structure
222+ * @return true continue handling keycodes
223+ * @return false stop handling keycodes
224+ */
225+bool process_tri_layer(uint16_t keycode, keyrecord_t *record);
226diff --git a/quantum/quantum.c b/quantum/quantum.c
227index 5554ecab327b07d67ff927172276d65fd0327b2a..0587f215fe3a8933b789ad5b956fdd56e9d9942a 100644
228--- a/quantum/quantum.c
229+++ b/quantum/quantum.c
230@@ -342,6 +342,9 @@ bool process_record_quantum(keyrecord_t *record) {
231 #endif
232 #ifdef AUTOCORRECT_ENABLE
233             process_autocorrect(keycode, record) &&
234+#endif
235+#ifdef TRI_LAYER_ENABLE
236+            process_tri_layer(keycode, record) &&
237 #endif
238             true)) {
239         return false;
240@@ -443,16 +446,6 @@ void set_single_persistent_default_layer(uint8_t default_layer) {
241     default_layer_set((layer_state_t)1 << default_layer);
242 }
243 
244-layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3) {
245-    layer_state_t mask12 = ((layer_state_t)1 << layer1) | ((layer_state_t)1 << layer2);
246-    layer_state_t mask3  = (layer_state_t)1 << layer3;
247-    return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3);
248-}
249-
250-void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
251-    layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3));
252-}
253-
254 //------------------------------------------------------------------------------
255 // Override these functions in your keymap file to play different tunes on
256 // different events such as startup and bootloader jump
257diff --git a/quantum/quantum.h b/quantum/quantum.h
258index 615ec2382c5075cb4f3bef804ab83de30672b03f..708d325a3219b7be439b5bb16d2210c70f92753e 100644
259--- a/quantum/quantum.h
260+++ b/quantum/quantum.h
261@@ -240,9 +240,10 @@ extern layer_state_t layer_state;
262 #    include "process_autocorrect.h"
263 #endif
264 
265-// For tri-layer
266-void          update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
267-layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3);
268+#ifdef TRI_LAYER_ENABLE
269+#    include "tri_layer.h"
270+#    include "process_tri_layer.h"
271+#endif
272 
273 void set_single_persistent_default_layer(uint8_t default_layer);
274 
275diff --git a/quantum/tri_layer.c b/quantum/tri_layer.c
276new file mode 100644
277index 0000000000000000000000000000000000000000..a5e3f8cb477f7681c6917a03d0ba74550ea8baec
278--- /dev/null
279+++ b/quantum/tri_layer.c
280@@ -0,0 +1,39 @@
281+// Copyright 2023 QMK
282+// SPDX-License-Identifier: GPL-2.0-or-later
283+
284+#include "tri_layer.h"
285+#include <stdint.h>
286+
287+static uint8_t tri_layer_lower_layer  = TRI_LAYER_LOWER_LAYER;
288+static uint8_t tri_layer_upper_layer  = TRI_LAYER_UPPER_LAYER;
289+static uint8_t tri_layer_adjust_layer = TRI_LAYER_ADJUST_LAYER;
290+
291+void set_tri_layer_lower_layer(uint8_t layer) {
292+    tri_layer_lower_layer = layer;
293+}
294+
295+void set_tri_layer_upper_layer(uint8_t layer) {
296+    tri_layer_upper_layer = layer;
297+}
298+
299+void set_tri_layer_adjust_layer(uint8_t layer) {
300+    tri_layer_adjust_layer = layer;
301+}
302+
303+void set_tri_layer_layers(uint8_t lower, uint8_t raise, uint8_t adjust) {
304+    tri_layer_lower_layer  = lower;
305+    tri_layer_upper_layer  = raise;
306+    tri_layer_adjust_layer = adjust;
307+}
308+
309+uint8_t get_tri_layer_lower_layer(void) {
310+    return tri_layer_lower_layer;
311+}
312+
313+uint8_t get_tri_layer_upper_layer(void) {
314+    return tri_layer_upper_layer;
315+}
316+
317+uint8_t get_tri_layer_adjust_layer(void) {
318+    return tri_layer_adjust_layer;
319+}
320diff --git a/quantum/tri_layer.h b/quantum/tri_layer.h
321new file mode 100644
322index 0000000000000000000000000000000000000000..3341ebffb288cf355f909e1a0d5d68c5316282b5
323--- /dev/null
324+++ b/quantum/tri_layer.h
325@@ -0,0 +1,59 @@
326+// Copyright 2023 QMK
327+// SPDX-License-Identifier: GPL-2.0-or-later
328+
329+#include <stdint.h>
330+
331+#ifndef TRI_LAYER_LOWER_LAYER
332+#    define TRI_LAYER_LOWER_LAYER 1
333+#endif
334+#ifndef TRI_LAYER_UPPER_LAYER
335+#    define TRI_LAYER_UPPER_LAYER 2
336+#endif
337+#ifndef TRI_LAYER_ADJUST_LAYER
338+#    define TRI_LAYER_ADJUST_LAYER 3
339+#endif
340+
341+/**
342+ * @brief Set the tri layer lower layer index
343+ *
344+ * @param layer
345+ */
346+void set_tri_layer_lower_layer(uint8_t layer);
347+/**
348+ * @brief Set the tri layer upper layer index
349+ *
350+ * @param layer
351+ */
352+void set_tri_layer_upper_layer(uint8_t layer);
353+/**
354+ * @brief Set the tri layer adjust layer index
355+ *
356+ * @param layer
357+ */
358+void set_tri_layer_adjust_layer(uint8_t layer);
359+/**
360+ * @brief Set the tri layer indices
361+ *
362+ * @param lower
363+ * @param upper
364+ * @param adjust
365+ */
366+void set_tri_layer_layers(uint8_t lower, uint8_t upper, uint8_t adjust);
367+/**
368+ * @brief Get the tri layer lower layer index
369+ *
370+ * @return uint8_t
371+ */
372+uint8_t get_tri_layer_lower_layer(void);
373+/**
374+ * @brief Get the tri layer upper layer index
375+ *
376+ * @return uint8_t
377+ */
378+uint8_t get_tri_layer_upper_layer(void);
379+/**
380+ * @brief Get the tri layer adjust layer index
381+ *
382+ * @return uint8_t
383+ */
384+uint8_t get_tri_layer_adjust_layer(void);
385diff --git a/tests/test_common/keycode_table.cpp b/tests/test_common/keycode_table.cpp
386index ab9c292e95dbae28195f064a40ee5d5f4a73703f..337bc8fb5f5c5e5726f22acf2e8609d52838346b 100644
387--- a/tests/test_common/keycode_table.cpp
388+++ b/tests/test_common/keycode_table.cpp
389@@ -659,5 +659,7 @@ std::map<uint16_t, std::string> KEYCODE_ID_TABLE = {
390     {QK_AUTOCORRECT_ON, "QK_AUTOCORRECT_ON"},
391     {QK_AUTOCORRECT_OFF, "QK_AUTOCORRECT_OFF"},
392     {QK_AUTOCORRECT_TOGGLE, "QK_AUTOCORRECT_TOGGLE"},
393+    {QK_TRI_LAYER_LOWER, "QK_TRI_LAYER_LOWER"},
394+    {QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"},
395     {SAFE_RANGE, "SAFE_RANGE"},
396 };
397diff --git a/tests/tri_layer/config.h b/tests/tri_layer/config.h
398new file mode 100644
399index 0000000000000000000000000000000000000000..b68bf0c2d5aa19e7439bf7f3ecd2d224ba78e74c
400--- /dev/null
401+++ b/tests/tri_layer/config.h
402@@ -0,0 +1,6 @@
403+// Copyright 2021 Christopher Courtney, aka Drashna Jael're  (@drashna) <drashna@live.com>
404+// SPDX-License-Identifier: GPL-2.0-or-later
405+
406+#pragma once
407+
408+#include "test_common.h"
409diff --git a/tests/tri_layer/test.mk b/tests/tri_layer/test.mk
410new file mode 100644
411index 0000000000000000000000000000000000000000..50548c3e1c0e0d9698d14c7c08743acd33af73df
412--- /dev/null
413+++ b/tests/tri_layer/test.mk
414@@ -0,0 +1,8 @@
415+# Copyright 2021 Christopher Courtney, aka Drashna Jael're  (@drashna) <drashna@live.com>
416+# SPDX-License-Identifier: GPL-2.0-or-later
417+
418+# --------------------------------------------------------------------------------
419+# Keep this file, even if it is empty, as a marker that this folder contains tests
420+# --------------------------------------------------------------------------------
421+
422+TRI_LAYER_ENABLE = yes
423diff --git a/tests/tri_layer/test_tri_layer.cpp b/tests/tri_layer/test_tri_layer.cpp
424new file mode 100644
425index 0000000000000000000000000000000000000000..fffc124f4c6aa2390d5531dc7794ac6b5f6d2e61
426--- /dev/null
427+++ b/tests/tri_layer/test_tri_layer.cpp
428@@ -0,0 +1,103 @@
429+// Copyright 2021 Christopher Courtney, aka Drashna Jael're  (@drashna) <drashna@live.com>
430+// SPDX-License-Identifier: GPL-2.0-or-later
431+
432+#include "test_common.hpp"
433+
434+using testing::_;
435+using testing::InSequence;
436+
437+class TriLayer : public TestFixture {};
438+
439+TEST_F(TriLayer, TriLayerLowerTest) {
440+    TestDriver driver;
441+    KeymapKey  lower_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_LOWER};
442+
443+    set_keymap({lower_layer_key, KeymapKey{1, 0, 0, KC_TRNS}});
444+
445+    /* Press Lower. */
446+    EXPECT_NO_REPORT(driver);
447+    lower_layer_key.press();
448+    run_one_scan_loop();
449+    EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer()));
450+    EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
451+    EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
452+    VERIFY_AND_CLEAR(driver);
453+
454+    /* Release Lower. */
455+    EXPECT_NO_REPORT(driver);
456+    lower_layer_key.release();
457+    run_one_scan_loop();
458+    EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
459+    EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
460+    EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
461+    VERIFY_AND_CLEAR(driver);
462+}
463+
464+TEST_F(TriLayer, TriLayerUpperTest) {
465+    TestDriver driver;
466+    KeymapKey  upper_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_UPPER};
467+
468+    set_keymap({upper_layer_key, KeymapKey{2, 0, 0, KC_TRNS}});
469+
470+    /* Press Raise. */
471+    EXPECT_NO_REPORT(driver);
472+    upper_layer_key.press();
473+    run_one_scan_loop();
474+    EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
475+    EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer()));
476+    EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
477+    VERIFY_AND_CLEAR(driver);
478+
479+    /* Release Raise. */
480+    EXPECT_NO_REPORT(driver);
481+    upper_layer_key.release();
482+    run_one_scan_loop();
483+    EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
484+    EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
485+    EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
486+    VERIFY_AND_CLEAR(driver);
487+}
488+
489+TEST_F(TriLayer, TriLayerAdjustTest) {
490+    TestDriver driver;
491+    KeymapKey  lower_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_LOWER};
492+    KeymapKey  upper_layer_key = KeymapKey{0, 1, 0, QK_TRI_LAYER_UPPER};
493+
494+    set_keymap({
495+        upper_layer_key,
496+        lower_layer_key,
497+        KeymapKey{1, 0, 0, KC_TRNS},
498+        KeymapKey{1, 1, 0, KC_TRNS},
499+        KeymapKey{2, 0, 0, KC_TRNS},
500+        KeymapKey{2, 1, 0, KC_TRNS},
501+        KeymapKey{3, 0, 0, KC_TRNS},
502+        KeymapKey{3, 1, 0, KC_TRNS},
503+    });
504+
505+    /* Press Lower, then upper, and release upper and then lower. */
506+    EXPECT_NO_REPORT(driver);
507+    lower_layer_key.press();
508+    run_one_scan_loop();
509+    EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer()));
510+    EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
511+    EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
512+
513+    upper_layer_key.press();
514+    run_one_scan_loop();
515+    EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer()));
516+    EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer()));
517+    EXPECT_TRUE(layer_state_is(get_tri_layer_adjust_layer()));
518+
519+    lower_layer_key.release();
520+    run_one_scan_loop();
521+    EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
522+    EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer()));
523+    EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
524+
525+    upper_layer_key.release();
526+    run_one_scan_loop();
527+    EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));