Compare commits

...

10 Commits

Author SHA1 Message Date
QMK Bot
7faa82869c Merge remote-tracking branch 'origin/develop' into xap 2023-02-11 23:23:46 +00:00
Drashna Jaelre
fe02abc479
[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>
2023-02-12 10:23:07 +11:00
QMK Bot
cdf8ecd2c7 Merge remote-tracking branch 'origin/develop' into xap 2023-02-11 20:38:46 +00:00
QMK Bot
4002843797 Merge remote-tracking branch 'origin/master' into develop 2023-02-11 20:38:10 +00:00
precondition
21f4375393
Update documentation for LM(layer, mod) (#19284)
* Update documentation for LM(layer, mod)

* Move LM table to caveats section
2023-02-11 20:37:30 +00:00
QMK Bot
98b0bcf545 Merge remote-tracking branch 'origin/develop' into xap 2023-02-11 20:36:45 +00:00
Joel Challis
90f3d6201a
Reduce false positives in layout name validation (#19646) 2023-02-11 20:36:11 +00:00
QMK Bot
7a067c6127 Merge remote-tracking branch 'origin/develop' into xap 2023-02-11 19:09:16 +00:00
QMK Bot
0a9d06a505 Merge remote-tracking branch 'origin/master' into develop 2023-02-11 19:08:39 +00:00
Luis Moreno
f667821ed3
[Docs] Resynchronizing Your Branch including submodules (#19268) 2023-02-11 12:07:51 -07:00
22 changed files with 415 additions and 32 deletions

View File

@ -624,6 +624,7 @@ ifeq ($(strip $(VIA_ENABLE)), yes)
DYNAMIC_KEYMAP_ENABLE := yes
RAW_ENABLE := yes
BOOTMAGIC_ENABLE := yes
TRI_LAYER_ENABLE := yes
SRC += $(QUANTUM_DIR)/via.c
OPT_DEFS += -DVIA_ENABLE
endif

View File

@ -39,6 +39,7 @@ GENERIC_FEATURES = \
VELOCIKEY \
WPM \
DYNAMIC_TAPPING_TERM \
TRI_LAYER
define HANDLE_GENERIC_FEATURE
# $$(info "Processing: $1_ENABLE $2.c")

View File

@ -84,7 +84,8 @@ OTHER_OPTION_NAMES = \
PROGRAMMABLE_BUTTON_ENABLE \
SECURE_ENABLE \
CAPS_WORD_ENABLE \
AUTOCORRECT_ENABLE
AUTOCORRECT_ENABLE \
TRI_LAYER_ENABLE
define NAME_ECHO
@printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)"

View File

@ -0,0 +1,18 @@
{
"keycodes": {
"0x7C77": {
"group": "quantum",
"key": "QK_TRI_LAYER_LOWER",
"aliases": [
"TL_LOWR"
]
},
"0x7C78": {
"group": "quantum",
"key": "QK_TRI_LAYER_UPPER",
"aliases": [
"TL_UPPR"
]
}
}
}

View File

@ -93,6 +93,7 @@
* [Swap Hands](feature_swap_hands.md)
* [Tap Dance](feature_tap_dance.md)
* [Tap-Hold Configuration](tap_hold.md)
* [Tri Layer](feature_tri_layer.md)
* [Unicode](feature_unicode.md)
* [Userspace](feature_userspace.md)
* [WPM Calculation](feature_wpm.md)

View File

@ -10,7 +10,7 @@ These functions allow you to activate layers in various ways. Note that layers a
* `DF(layer)` - switches the default layer. The default layer is the always-active base layer that other layers stack on top of. See below for more about the default layer. This might be used to switch from QWERTY to Dvorak layout. (Note that this is a temporary switch that only persists until the keyboard loses power. To modify the default layer in a persistent way requires deeper customization, such as calling the `set_single_persistent_default_layer` function inside of [process_record_user](custom_quantum_functions.md#programming-the-behavior-of-any-keycode).)
* `MO(layer)` - momentarily activates *layer*. As soon as you let go of the key, the layer is deactivated.
* `LM(layer, mod)` - Momentarily activates *layer* (like `MO`), but with modifier(s) *mod* active. Only supports layers 0-15 and the left modifiers: `MOD_LCTL`, `MOD_LSFT`, `MOD_LALT`, `MOD_LGUI` (note the use of `MOD_` constants instead of `KC_`). These modifiers can be combined using bitwise OR, e.g. `LM(_RAISE, MOD_LCTL | MOD_LALT)`.
* `LM(layer, mod)` - Momentarily activates *layer* (like `MO`), but with modifier(s) *mod* active. Only supports layers 0-15. The modifiers this keycode accept are prefixed with `MOD_`, not `KC_`. These modifiers can be combined using bitwise OR, e.g. `LM(_RAISE, MOD_LCTL | MOD_LALT)`.
* `LT(layer, kc)` - momentarily activates *layer* when held, and sends *kc* when tapped. Only supports layers 0-15.
* `OSL(layer)` - momentarily activates *layer* until the next key is pressed. See [One Shot Keys](one_shot_keys.md) for details and additional functionality.
* `TG(layer)` - toggles *layer*, activating it if it's inactive and vice versa
@ -21,6 +21,12 @@ These functions allow you to activate layers in various ways. Note that layers a
Currently, the `layer` argument of `LT()` is limited to layers 0-15, and the `kc` argument to the [Basic Keycode set](keycodes_basic.md), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. This is because QMK uses 16-bit keycodes, of which 4 bits are used for the function identifier and 4 bits for the layer, leaving only 8 bits for the keycode.
For a similar reason, the `layer` argument of `LM()` is also limited to layers 0-15 and the `mod` argument must fit within 5 bits. As a consequence, although left and right modifiers are supported by `LM()`, it is impossible to mix and match left and right modifiers. Specifying at least one right-hand modifier in a combination such as `MOD_RALT|MOD_LSFT` will convert *all* the listed modifiers to their right-hand counterpart. So, using the aforementionned mod-mask will actually send <kbd>Right Alt</kbd>+<kbd>Right Shift</kbd>. Make sure to use the `MOD_xxx` constants over alternative ways of specifying modifiers when defining your layer-mod key.
| `LM(1,KC_LSFT)` | `LM(1,MOD_MASK_SHIFT)` | `LM(1,MOD_BIT(KC_LSFT))` | `LM(1,MOD_LSFT)` |
|:---------------:|:----------------------:|:------------------------:|:----------------:|
| ❌ | ❌ | ❌ | ✅ |
Expanding this would be complicated, at best. Moving to a 32-bit keycode would solve a lot of this, but would double the amount of space that the keymap matrix uses. And it could potentially cause issues, too. If you need to apply modifiers to your tapped keycode, [Tap Dance](feature_tap_dance.md#example-5-using-tap-dance-for-advanced-mod-tap-and-layer-tap-keys) can be used to accomplish this.
## Working with Layers :id=working-with-layers

48
docs/feature_tri_layer.md Normal file
View File

@ -0,0 +1,48 @@
# Tri Layers :id=tri-layers
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`:
```make
TRI_LAYER_ENABLE = yes
```
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.
For a detailed explanation of how the layer stack works, check out [Keymap Overview](keymap.md#keymap-and-layers).
## Keycodes :id=keycodes
| Keycode | Alias | Description |
|----------------------|-----------|---------------------------------------------------------------------------------------------------------|
| `QK_TRI_LAYER_LOWER` | `TL_LOWR` | Momentarily enables the "lower" layer. Enables the "adjust" layer if the "upper" layer is also enabled" |
| `QK_TRI_LAYER_UPPER` | `TL_UPPR` | Momentarily enables the "upper" layer. Enables the "adjust" layer if the "lower" layer is also enabled" |
## Configuration
To change the default values for the layers, you can change these defines, in your `config.h`
| Config name | Default | Description |
|--------------------------|---------|------------------------------------------|
| `TRI_LAYER_LOWER_LAYER` | `1` | Sets the default for the "lower" layer. |
| `TRI_LAYER_UPPER_LAYER` | `2` | Sets the default for the "upper" layer. |
| `TRI_LAYER_ADJUST_LAYER` | `3` | Sets the default for the "adjust" layer. |
Eg, if you wanted to set the "Adjust" layer to be layer 5, you'd add this to your `config.h`:
```c
#define TRI_LAYER_ADJUST_LAYER 5
```
## Functions
| Function name | Description |
|----------------------------------------------|-------------------------------------------------|
| `set_tri_layer_lower_layer(layer)` | Changes the "lower" layer*. |
| `set_tri_layer_upper_layer(layer)` | Changes the "upper" layer*. |
| `set_tri_layer_adjust_layer(layer)` | Changes the "adjust" layer*. |
| `set_tri_layer_layers(lower, upper, adjust)` | Stes the "lower", "upper" and "adjust" layers*. |
| `get_tri_layer_lower_layer()` | Gets the current "lower" layer. |
| `get_tri_layer_upper_layer()` | Gets the current "upper" layer. |
| `get_tri_layer_adjust_layer()` | Gets the current "adjust" layer. |
!> Note: these settings are not persisent, and will be reset to the default on power loss or power cycling of the controller.

View File

@ -51,21 +51,21 @@ git remote set-url origin https://github.com/<your_username>/qmk_firmware.git
Now that you have both remotes configured, you need to update the references for the upstream repository, which is QMK's, by running:
```
git fetch upstream
git fetch --recurse-submodules upstream
```
At this point, resynchronize your branch to QMK's by running:
```
git reset --hard upstream/master
git reset --recurse-submodules --hard upstream/master
```
These steps will update the repository on your computer, but your GitHub fork will still be out of sync. To resynchronize your fork on GitHub, you need to push to your fork, instructing Git to override any remote changes that are not reflected in your local repository. To do this, run:
```
git push --force-with-lease
git push --recurse-submodules=on-demand --force-with-lease
```
!> **DO NOT** run `git push --force-with-lease` on a fork to which other users post commits. This will erase their commits.
!> **DO NOT** run `git push --recurse-submodules=on-demand --force-with-lease` on a fork to which other users post commits. This will erase their commits.
Now your GitHub fork, your local files, and QMK's repository are all the same. From here you can make further needed changes ([use a branch!](newbs_git_using_your_master_branch.md#making-changes)) and post them as normal.

View File

@ -1,9 +1,10 @@
"""Functions that help us generate and use info.json files.
"""
import re
from pathlib import Path
import jsonschema
from dotty_dict import dotty
from milc import cli
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
@ -17,15 +18,30 @@ from qmk.math import compute
true_values = ['1', 'on', 'yes']
false_values = ['0', 'off', 'no']
# TODO: reduce this list down
SAFE_LAYOUT_TOKENS = {
def _keyboard_in_layout_name(keyboard, layout):
"""Validate that a layout macro does not contain name of keyboard
"""
# TODO: reduce this list down
safe_layout_tokens = {
'ansi',
'iso',
'jp',
'jis',
'ortho',
'wkl',
'tkl',
'preonic',
'planck',
}
}
# Ignore tokens like 'split_3x7_4' or just '2x4'
layout = re.sub(r"_split_\d+x\d+_\d+", '', layout)
layout = re.sub(r"_\d+x\d+", '', layout)
name_fragments = set(keyboard.split('/')) - safe_layout_tokens
return any(fragment in layout for fragment in name_fragments)
def _valid_community_layout(layout):
@ -60,10 +76,9 @@ def _validate(keyboard, info_data):
_log_warning(info_data, '"LAYOUT_all" should be "LAYOUT" unless additional layouts are provided.')
# Extended layout name checks - ignoring community_layouts and "safe" values
name_fragments = set(keyboard.split('/')) - SAFE_LAYOUT_TOKENS
potential_layouts = set(layouts.keys()) - set(community_layouts_names)
for layout in potential_layouts:
if any(fragment in layout for fragment in name_fragments):
if _keyboard_in_layout_name(keyboard, layout):
_log_warning(info_data, f'Layout "{layout}" should not contain name of keyboard.')
# Filter out any non-existing community layouts

View File

@ -349,3 +349,13 @@ uint8_t layer_switch_get_layer(keypos_t key) {
action_t layer_switch_get_action(keypos_t key) {
return action_for_key(layer_switch_get_layer(key), key);
}
layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3) {
layer_state_t mask12 = ((layer_state_t)1 << layer1) | ((layer_state_t)1 << layer2);
layer_state_t mask3 = (layer_state_t)1 << layer3;
return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3);
}
void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3));
}

View File

@ -113,6 +113,25 @@ void layer_and(layer_state_t state);
void layer_xor(layer_state_t state);
layer_state_t layer_state_set_user(layer_state_t state);
layer_state_t layer_state_set_kb(layer_state_t state);
/**
* @brief Applies the tri layer to global layer state. Not be used in layer_state_set_(kb|user) functions.
*
* @param layer1 First layer to check for tri layer
* @param layer2 Second layer to check for tri layer
* @param layer3 Layer to activate if both other layers are enabled
*/
void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
/**
* @brief Applies the tri layer behavior to supplied layer bitmask, without using layer functions.
*
* @param state Original layer bitmask to check and modify
* @param layer1 First layer to check for tri layer
* @param layer2 Second layer to check for tri layer
* @param layer3 Layer to activate if both other layers are enabled
* @return layer_state_t returns a modified layer bitmask with tri layer modifications applied
*/
layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3);
#else
# define layer_state 0
@ -131,6 +150,8 @@ layer_state_t layer_state_set_kb(layer_state_t state);
# define layer_xor(state) (void)state
# define layer_state_set_kb(state) (void)state
# define layer_state_set_user(state) (void)state
# define update_tri_layer(layer1, layer2, layer3)
# define update_tri_layer_state(state, layer1, layer2, layer3) (void)state
#endif
/* pressed actions cache */

View File

@ -717,6 +717,8 @@ enum qk_keycode_defines {
QK_AUTOCORRECT_ON = 0x7C74,
QK_AUTOCORRECT_OFF = 0x7C75,
QK_AUTOCORRECT_TOGGLE = 0x7C76,
QK_TRI_LAYER_LOWER = 0x7C77,
QK_TRI_LAYER_UPPER = 0x7C78,
SAFE_RANGE = 0x7E00,
// Alias
@ -1282,6 +1284,8 @@ enum qk_keycode_defines {
AC_ON = QK_AUTOCORRECT_ON,
AC_OFF = QK_AUTOCORRECT_OFF,
AC_TOGG = QK_AUTOCORRECT_TOGGLE,
TL_LOWR = QK_TRI_LAYER_LOWER,
TL_UPPR = QK_TRI_LAYER_UPPER,
};
// Range Helpers
@ -1333,4 +1337,4 @@ enum qk_keycode_defines {
#define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31)
#define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING)
#define IS_RGB_KEYCODE(code) ((code) >= RGB_TOG && (code) <= RGB_MODE_TWINKLE)
#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_AUTOCORRECT_TOGGLE)
#define IS_QUANTUM_KEYCODE(code) ((code) >= QK_BOOTLOADER && (code) <= QK_TRI_LAYER_UPPER)

View File

@ -0,0 +1,30 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include "process_tri_layer.h"
#include "tri_layer.h"
#include "action_layer.h"
bool process_tri_layer(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case QK_TRI_LAYER_LOWER:
if (record->event.pressed) {
layer_on(get_tri_layer_lower_layer());
update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
} else {
layer_off(get_tri_layer_lower_layer());
update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
}
return false;
case QK_TRI_LAYER_UPPER:
if (record->event.pressed) {
layer_on(get_tri_layer_upper_layer());
update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
} else {
layer_off(get_tri_layer_upper_layer());
update_tri_layer(get_tri_layer_lower_layer(), get_tri_layer_upper_layer(), get_tri_layer_adjust_layer());
}
return false;
}
return true;
}

View File

@ -0,0 +1,16 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "action.h"
/**
* @brief Handles tri layer behavior
*
* @param keycode the keycode
* @param record the key record structure
* @return true continue handling keycodes
* @return false stop handling keycodes
*/
bool process_tri_layer(uint16_t keycode, keyrecord_t *record);

View File

@ -342,6 +342,9 @@ bool process_record_quantum(keyrecord_t *record) {
#endif
#ifdef AUTOCORRECT_ENABLE
process_autocorrect(keycode, record) &&
#endif
#ifdef TRI_LAYER_ENABLE
process_tri_layer(keycode, record) &&
#endif
true)) {
return false;
@ -443,16 +446,6 @@ void set_single_persistent_default_layer(uint8_t default_layer) {
default_layer_set((layer_state_t)1 << default_layer);
}
layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3) {
layer_state_t mask12 = ((layer_state_t)1 << layer1) | ((layer_state_t)1 << layer2);
layer_state_t mask3 = (layer_state_t)1 << layer3;
return (state & mask12) == mask12 ? (state | mask3) : (state & ~mask3);
}
void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
layer_state_set(update_tri_layer_state(layer_state, layer1, layer2, layer3));
}
//------------------------------------------------------------------------------
// Override these functions in your keymap file to play different tunes on
// different events such as startup and bootloader jump

View File

@ -244,9 +244,10 @@ extern layer_state_t layer_state;
# include "process_autocorrect.h"
#endif
// For tri-layer
void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3);
layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_t layer2, uint8_t layer3);
#ifdef TRI_LAYER_ENABLE
# include "tri_layer.h"
# include "process_tri_layer.h"
#endif
void set_single_persistent_default_layer(uint8_t default_layer);

39
quantum/tri_layer.c Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include "tri_layer.h"
#include <stdint.h>
static uint8_t tri_layer_lower_layer = TRI_LAYER_LOWER_LAYER;
static uint8_t tri_layer_upper_layer = TRI_LAYER_UPPER_LAYER;
static uint8_t tri_layer_adjust_layer = TRI_LAYER_ADJUST_LAYER;
void set_tri_layer_lower_layer(uint8_t layer) {
tri_layer_lower_layer = layer;
}
void set_tri_layer_upper_layer(uint8_t layer) {
tri_layer_upper_layer = layer;
}
void set_tri_layer_adjust_layer(uint8_t layer) {
tri_layer_adjust_layer = layer;
}
void set_tri_layer_layers(uint8_t lower, uint8_t raise, uint8_t adjust) {
tri_layer_lower_layer = lower;
tri_layer_upper_layer = raise;
tri_layer_adjust_layer = adjust;
}
uint8_t get_tri_layer_lower_layer(void) {
return tri_layer_lower_layer;
}
uint8_t get_tri_layer_upper_layer(void) {
return tri_layer_upper_layer;
}
uint8_t get_tri_layer_adjust_layer(void) {
return tri_layer_adjust_layer;
}

59
quantum/tri_layer.h Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdint.h>
#ifndef TRI_LAYER_LOWER_LAYER
# define TRI_LAYER_LOWER_LAYER 1
#endif
#ifndef TRI_LAYER_UPPER_LAYER
# define TRI_LAYER_UPPER_LAYER 2
#endif
#ifndef TRI_LAYER_ADJUST_LAYER
# define TRI_LAYER_ADJUST_LAYER 3
#endif
/**
* @brief Set the tri layer lower layer index
*
* @param layer
*/
void set_tri_layer_lower_layer(uint8_t layer);
/**
* @brief Set the tri layer upper layer index
*
* @param layer
*/
void set_tri_layer_upper_layer(uint8_t layer);
/**
* @brief Set the tri layer adjust layer index
*
* @param layer
*/
void set_tri_layer_adjust_layer(uint8_t layer);
/**
* @brief Set the tri layer indices
*
* @param lower
* @param upper
* @param adjust
*/
void set_tri_layer_layers(uint8_t lower, uint8_t upper, uint8_t adjust);
/**
* @brief Get the tri layer lower layer index
*
* @return uint8_t
*/
uint8_t get_tri_layer_lower_layer(void);
/**
* @brief Get the tri layer upper layer index
*
* @return uint8_t
*/
uint8_t get_tri_layer_upper_layer(void);
/**
* @brief Get the tri layer adjust layer index
*
* @return uint8_t
*/
uint8_t get_tri_layer_adjust_layer(void);

View File

@ -659,5 +659,7 @@ std::map<uint16_t, std::string> KEYCODE_ID_TABLE = {
{QK_AUTOCORRECT_ON, "QK_AUTOCORRECT_ON"},
{QK_AUTOCORRECT_OFF, "QK_AUTOCORRECT_OFF"},
{QK_AUTOCORRECT_TOGGLE, "QK_AUTOCORRECT_TOGGLE"},
{QK_TRI_LAYER_LOWER, "QK_TRI_LAYER_LOWER"},
{QK_TRI_LAYER_UPPER, "QK_TRI_LAYER_UPPER"},
{SAFE_RANGE, "SAFE_RANGE"},
};

6
tests/tri_layer/config.h Normal file
View File

@ -0,0 +1,6 @@
// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "test_common.h"

8
tests/tri_layer/test.mk Normal file
View File

@ -0,0 +1,8 @@
# Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
# SPDX-License-Identifier: GPL-2.0-or-later
# --------------------------------------------------------------------------------
# Keep this file, even if it is empty, as a marker that this folder contains tests
# --------------------------------------------------------------------------------
TRI_LAYER_ENABLE = yes

View File

@ -0,0 +1,103 @@
// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "test_common.hpp"
using testing::_;
using testing::InSequence;
class TriLayer : public TestFixture {};
TEST_F(TriLayer, TriLayerLowerTest) {
TestDriver driver;
KeymapKey lower_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_LOWER};
set_keymap({lower_layer_key, KeymapKey{1, 0, 0, KC_TRNS}});
/* Press Lower. */
EXPECT_NO_REPORT(driver);
lower_layer_key.press();
run_one_scan_loop();
EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
VERIFY_AND_CLEAR(driver);
/* Release Lower. */
EXPECT_NO_REPORT(driver);
lower_layer_key.release();
run_one_scan_loop();
EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
VERIFY_AND_CLEAR(driver);
}
TEST_F(TriLayer, TriLayerUpperTest) {
TestDriver driver;
KeymapKey upper_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_UPPER};
set_keymap({upper_layer_key, KeymapKey{2, 0, 0, KC_TRNS}});
/* Press Raise. */
EXPECT_NO_REPORT(driver);
upper_layer_key.press();
run_one_scan_loop();
EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
VERIFY_AND_CLEAR(driver);
/* Release Raise. */
EXPECT_NO_REPORT(driver);
upper_layer_key.release();
run_one_scan_loop();
EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
VERIFY_AND_CLEAR(driver);
}
TEST_F(TriLayer, TriLayerAdjustTest) {
TestDriver driver;
KeymapKey lower_layer_key = KeymapKey{0, 0, 0, QK_TRI_LAYER_LOWER};
KeymapKey upper_layer_key = KeymapKey{0, 1, 0, QK_TRI_LAYER_UPPER};
set_keymap({
upper_layer_key,
lower_layer_key,
KeymapKey{1, 0, 0, KC_TRNS},
KeymapKey{1, 1, 0, KC_TRNS},
KeymapKey{2, 0, 0, KC_TRNS},
KeymapKey{2, 1, 0, KC_TRNS},
KeymapKey{3, 0, 0, KC_TRNS},
KeymapKey{3, 1, 0, KC_TRNS},
});
/* Press Lower, then upper, and release upper and then lower. */
EXPECT_NO_REPORT(driver);
lower_layer_key.press();
run_one_scan_loop();
EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
upper_layer_key.press();
run_one_scan_loop();
EXPECT_TRUE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_TRUE(layer_state_is(get_tri_layer_adjust_layer()));
lower_layer_key.release();
run_one_scan_loop();
EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_TRUE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
upper_layer_key.release();
run_one_scan_loop();
EXPECT_FALSE(layer_state_is(get_tri_layer_lower_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_upper_layer()));
EXPECT_FALSE(layer_state_is(get_tri_layer_adjust_layer()));
VERIFY_AND_CLEAR(driver);
}