forked from mirrors/qmk_firmware
Allow mod-tap hold action on one shot layer (#19214)
This commit is contained in:
parent
24adecd922
commit
0f5500182c
2 changed files with 254 additions and 1 deletions
|
@ -350,7 +350,12 @@ void process_action(keyrecord_t *record, action_t action) {
|
||||||
#ifndef NO_ACTION_ONESHOT
|
#ifndef NO_ACTION_ONESHOT
|
||||||
bool do_release_oneshot = false;
|
bool do_release_oneshot = false;
|
||||||
// notice we only clear the one shot layer if the pressed key is not a modifier.
|
// notice we only clear the one shot layer if the pressed key is not a modifier.
|
||||||
if (is_oneshot_layer_active() && event.pressed && (action.kind.id == ACT_USAGE || !IS_MOD(action.key.code))
|
if (is_oneshot_layer_active() && event.pressed &&
|
||||||
|
(action.kind.id == ACT_USAGE || !(IS_MOD(action.key.code)
|
||||||
|
# ifndef NO_ACTION_TAPPING
|
||||||
|
|| (tap_count == 0 && (action.kind.id == ACT_LMODS_TAP || action.kind.id == ACT_RMODS_TAP))
|
||||||
|
# endif
|
||||||
|
))
|
||||||
# ifdef SWAP_HANDS_ENABLE
|
# ifdef SWAP_HANDS_ENABLE
|
||||||
&& !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)
|
&& !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)
|
||||||
# endif
|
# endif
|
||||||
|
|
|
@ -0,0 +1,248 @@
|
||||||
|
#include "keyboard_report_util.hpp"
|
||||||
|
#include "keycode.h"
|
||||||
|
#include "test_common.hpp"
|
||||||
|
#include "action_tapping.h"
|
||||||
|
#include "test_fixture.hpp"
|
||||||
|
#include "test_keymap_key.hpp"
|
||||||
|
|
||||||
|
using testing::_;
|
||||||
|
using testing::InSequence;
|
||||||
|
|
||||||
|
class OneShotLayerModTap : public TestFixture {};
|
||||||
|
|
||||||
|
TEST_F(OneShotLayerModTap, tap_mod_tap_hold_key) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
auto osl_key = KeymapKey{0, 0, 0, OSL(1)};
|
||||||
|
auto mod_tap_hold_key = KeymapKey(1, 1, 0, SFT_T(KC_A));
|
||||||
|
|
||||||
|
set_keymap({osl_key, mod_tap_hold_key});
|
||||||
|
|
||||||
|
/* Set one shot layer */
|
||||||
|
tap_key(osl_key);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press mod-tap-hold key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
mod_tap_hold_key.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release mod-tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_A));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(0);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OneShotLayerModTap, tap_and_hold_mod_tap_hold_key_tapping_term) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
auto osl_key = KeymapKey{0, 0, 0, OSL(1)};
|
||||||
|
auto mod_tap_hold_key = KeymapKey(1, 1, 0, SFT_T(KC_A));
|
||||||
|
|
||||||
|
set_keymap({osl_key, mod_tap_hold_key});
|
||||||
|
|
||||||
|
/* Set one shot layer */
|
||||||
|
tap_key(osl_key);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press mod-tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT));
|
||||||
|
mod_tap_hold_key.press();
|
||||||
|
idle_for(TAPPING_TERM + 1);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release mod-tap-hold key */
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OneShotLayerModTap, tap_regular_key_while_mod_tap_key_is_held_tapping_term) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
auto osl_key = KeymapKey{0, 0, 0, OSL(1)};
|
||||||
|
auto mod_tap_hold_key = KeymapKey(1, 1, 0, SFT_T(KC_A));
|
||||||
|
auto regular_key1 = KeymapKey(1, 2, 0, KC_1);
|
||||||
|
|
||||||
|
set_keymap({osl_key, mod_tap_hold_key, regular_key1});
|
||||||
|
|
||||||
|
/* Set one shot layer */
|
||||||
|
tap_key(osl_key);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press mod-tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT));
|
||||||
|
mod_tap_hold_key.press();
|
||||||
|
idle_for(TAPPING_TERM + 1);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press regular key */
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT, KC_1));
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT));
|
||||||
|
regular_key1.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(0);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release regular key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
regular_key1.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release mod-tap-hold key */
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OneShotLayerModTap, tap_a_mod_tap_key_while_another_mod_tap_key_is_held_tapping_term) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
auto osl_key = KeymapKey{0, 0, 0, OSL(1)};
|
||||||
|
auto regular_key0 = KeymapKey(0, 2, 0, KC_0);
|
||||||
|
auto first_mod_tap_hold_key = KeymapKey(1, 1, 0, SFT_T(KC_A));
|
||||||
|
auto second_mod_tap_hold_key = KeymapKey(1, 2, 0, CTL_T(KC_B));
|
||||||
|
|
||||||
|
set_keymap({osl_key, regular_key0, first_mod_tap_hold_key, second_mod_tap_hold_key});
|
||||||
|
|
||||||
|
/* Set one shot layer */
|
||||||
|
tap_key(osl_key);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press first mod-tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT));
|
||||||
|
first_mod_tap_hold_key.press();
|
||||||
|
idle_for(TAPPING_TERM + 1);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press second tap-hold key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
second_mod_tap_hold_key.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release second tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT, KC_B));
|
||||||
|
EXPECT_REPORT(driver, (KC_LEFT_SHIFT));
|
||||||
|
second_mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(0);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release first mod-tap-hold key */
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
first_mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OneShotLayerModTap, tap_regular_key_while_mod_tap_key_is_held) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
auto osl_key = KeymapKey{0, 0, 0, OSL(1)};
|
||||||
|
auto mod_tap_hold_key = KeymapKey(1, 1, 0, SFT_T(KC_A));
|
||||||
|
auto regular_key0 = KeymapKey(0, 2, 0, KC_0);
|
||||||
|
auto regular_key1 = KeymapKey(1, 2, 0, KC_1);
|
||||||
|
|
||||||
|
set_keymap({osl_key, mod_tap_hold_key, regular_key0, regular_key1});
|
||||||
|
|
||||||
|
/* Set one shot layer */
|
||||||
|
tap_key(osl_key);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press mod-tap-hold key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
mod_tap_hold_key.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press regular key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
regular_key1.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release regular key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
regular_key1.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release mod-tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_A));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
EXPECT_REPORT(driver, (KC_0));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(0);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(OneShotLayerModTap, tap_a_mod_tap_key_while_another_mod_tap_key_is_held) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
auto osl_key = KeymapKey{0, 0, 0, OSL(1)};
|
||||||
|
auto regular_key0 = KeymapKey(0, 2, 0, KC_0);
|
||||||
|
auto first_mod_tap_hold_key = KeymapKey(1, 1, 0, SFT_T(KC_A));
|
||||||
|
auto second_mod_tap_hold_key = KeymapKey(1, 2, 0, CTL_T(KC_B));
|
||||||
|
|
||||||
|
set_keymap({osl_key, regular_key0, first_mod_tap_hold_key, second_mod_tap_hold_key});
|
||||||
|
|
||||||
|
/* Set one shot layer */
|
||||||
|
tap_key(osl_key);
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press first mod-tap-hold key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
first_mod_tap_hold_key.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Press second tap-hold key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
second_mod_tap_hold_key.press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release second tap-hold key */
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
second_mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(1);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
|
||||||
|
/* Release first mod-tap-hold key */
|
||||||
|
EXPECT_REPORT(driver, (KC_A));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
EXPECT_REPORT(driver, (KC_0));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
first_mod_tap_hold_key.release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
expect_layer_state(0);
|
||||||
|
testing::Mock::VerifyAndClearExpectations(&driver);
|
||||||
|
}
|
Loading…
Reference in a new issue