Fix layer switching from tap dances by redoing the keymap lookup (#17935)
This commit is contained in:
parent
0e6f191436
commit
ca0c12847a
@ -115,12 +115,12 @@ static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_actio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
|
bool preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
|
||||||
qk_tap_dance_action_t *action;
|
qk_tap_dance_action_t *action;
|
||||||
|
|
||||||
if (!record->event.pressed) return;
|
if (!record->event.pressed) return false;
|
||||||
|
|
||||||
if (!active_td || keycode == active_td) return;
|
if (!active_td || keycode == active_td) return false;
|
||||||
|
|
||||||
action = &tap_dance_actions[TD_INDEX(active_td)];
|
action = &tap_dance_actions[TD_INDEX(active_td)];
|
||||||
action->state.interrupted = true;
|
action->state.interrupted = true;
|
||||||
@ -130,6 +130,12 @@ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
|
|||||||
// Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with
|
// Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with
|
||||||
// modifiers), but these weak mods should not affect the keypress which interrupted the tap dance.
|
// modifiers), but these weak mods should not affect the keypress which interrupted the tap dance.
|
||||||
clear_weak_mods();
|
clear_weak_mods();
|
||||||
|
|
||||||
|
// Signal that a tap dance has been finished due to being interrupted,
|
||||||
|
// therefore the keymap lookup for the currently processed event needs to
|
||||||
|
// be repeated with the current layer state that might have been updated by
|
||||||
|
// the finished tap dance.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
|
bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
@ -81,7 +81,7 @@ void reset_tap_dance(qk_tap_dance_state_t *state);
|
|||||||
|
|
||||||
/* To be used internally */
|
/* To be used internally */
|
||||||
|
|
||||||
void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record);
|
bool preprocess_tap_dance(uint16_t keycode, keyrecord_t *record);
|
||||||
bool process_tap_dance(uint16_t keycode, keyrecord_t *record);
|
bool process_tap_dance(uint16_t keycode, keyrecord_t *record);
|
||||||
void tap_dance_task(void);
|
void tap_dance_task(void);
|
||||||
|
|
||||||
|
@ -251,7 +251,11 @@ bool process_record_quantum(keyrecord_t *record) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TAP_DANCE_ENABLE
|
#ifdef TAP_DANCE_ENABLE
|
||||||
preprocess_tap_dance(keycode, record);
|
if (preprocess_tap_dance(keycode, record)) {
|
||||||
|
// The tap dance might have updated the layer state, therefore the
|
||||||
|
// result of the keycode lookup might change.
|
||||||
|
keycode = get_record_keycode(record, true);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!(
|
if (!(
|
||||||
|
6
tests/tap_dance/tap_dance_layers/config.h
Normal file
6
tests/tap_dance/tap_dance_layers/config.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 2022 Sergey Vlasov (@sigprof)
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "test_common.h"
|
97
tests/tap_dance/tap_dance_layers/tap_dance_defs.c
Normal file
97
tests/tap_dance/tap_dance_layers/tap_dance_defs.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
// Copyright 2022 Sergey Vlasov (@sigprof)
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "tap_dance_defs.h"
|
||||||
|
|
||||||
|
// Implement custom keycodes which are used to check that the layer switching
|
||||||
|
// behaves properly.
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch (keycode) {
|
||||||
|
case FAST_AB:
|
||||||
|
case SLOW_AB:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
tap_code(KC_A);
|
||||||
|
} else {
|
||||||
|
tap_code(KC_B);
|
||||||
|
}
|
||||||
|
return keycode == SLOW_AB;
|
||||||
|
case FAST_CD:
|
||||||
|
case SLOW_CD:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
tap_code(KC_C);
|
||||||
|
} else {
|
||||||
|
tap_code(KC_D);
|
||||||
|
}
|
||||||
|
return keycode == SLOW_CD;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement a custom tap dance with the following behavior:
|
||||||
|
// - single tap: KC_APP
|
||||||
|
// - single hold: MO(1)
|
||||||
|
// - double tap/hold: KC_RCTL
|
||||||
|
// (The single tap and hold actions are mostly equivalent to LT(1, KC_APP).)
|
||||||
|
|
||||||
|
enum lt_app_state {
|
||||||
|
LTA_NONE,
|
||||||
|
LTA_SINGLE_TAP,
|
||||||
|
LTA_SINGLE_HOLD,
|
||||||
|
LTA_DOUBLE_HOLD,
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum lt_app_state saved_lt_app_state;
|
||||||
|
|
||||||
|
static enum lt_app_state get_lt_app_state(qk_tap_dance_state_t *state) {
|
||||||
|
if (state->count == 1) {
|
||||||
|
if (!state->pressed) {
|
||||||
|
return LTA_SINGLE_TAP;
|
||||||
|
} else {
|
||||||
|
return LTA_SINGLE_HOLD;
|
||||||
|
}
|
||||||
|
} else if (state->count == 2) {
|
||||||
|
return LTA_DOUBLE_HOLD;
|
||||||
|
} else {
|
||||||
|
return LTA_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lt_app_finished(qk_tap_dance_state_t *state, void *user_data) {
|
||||||
|
saved_lt_app_state = get_lt_app_state(state);
|
||||||
|
switch (saved_lt_app_state) {
|
||||||
|
case LTA_NONE:
|
||||||
|
break;
|
||||||
|
case LTA_SINGLE_TAP:
|
||||||
|
register_code(KC_APP);
|
||||||
|
break;
|
||||||
|
case LTA_SINGLE_HOLD:
|
||||||
|
layer_on(1);
|
||||||
|
break;
|
||||||
|
case LTA_DOUBLE_HOLD:
|
||||||
|
register_code(KC_RCTL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lt_app_reset(qk_tap_dance_state_t *state, void *user_data) {
|
||||||
|
switch (saved_lt_app_state) {
|
||||||
|
case LTA_NONE:
|
||||||
|
break;
|
||||||
|
case LTA_SINGLE_TAP:
|
||||||
|
unregister_code(KC_APP);
|
||||||
|
break;
|
||||||
|
case LTA_SINGLE_HOLD:
|
||||||
|
layer_off(1);
|
||||||
|
break;
|
||||||
|
case LTA_DOUBLE_HOLD:
|
||||||
|
unregister_code(KC_RCTL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qk_tap_dance_action_t tap_dance_actions[] = {
|
||||||
|
[TD_L_MOVE] = ACTION_TAP_DANCE_LAYER_MOVE(KC_APP, 1),
|
||||||
|
[TD_L_TOGG] = ACTION_TAP_DANCE_LAYER_TOGGLE(KC_APP, 1),
|
||||||
|
[TD_LT_APP] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lt_app_finished, lt_app_reset),
|
||||||
|
};
|
29
tests/tap_dance/tap_dance_layers/tap_dance_defs.h
Normal file
29
tests/tap_dance/tap_dance_layers/tap_dance_defs.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright 2022 Sergey Vlasov (@sigprof)
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum custom_keycodes {
|
||||||
|
// (FAST|SLOW)_xy = tap KC_x on press, tap KC_y on release. For FAST_xy
|
||||||
|
// process_record_user() returns false to stop processing early; for
|
||||||
|
// SLOW_xy process_record_user() returns true, therefore all other key
|
||||||
|
// handlers are invoked.
|
||||||
|
FAST_AB = SAFE_RANGE,
|
||||||
|
FAST_CD,
|
||||||
|
SLOW_AB,
|
||||||
|
SLOW_CD,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tap_dance_ids {
|
||||||
|
TD_L_MOVE, // ACTION_TAP_DANCE_LAYER_MOVE(KC_APP, 1)
|
||||||
|
TD_L_TOGG, // ACTION_TAP_DANCE_LAYER_TOGGLE(KC_APP, 1)
|
||||||
|
TD_LT_APP, // similar to LT(1, KC_APP) with KC_RCTL on tap+hold or double tap
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
10
tests/tap_dance/tap_dance_layers/test.mk
Normal file
10
tests/tap_dance/tap_dance_layers/test.mk
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Copyright 2022 Sergey Vlasov (@sigprof)
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------------
|
||||||
|
# Keep this file, even if it is empty, as a marker that this folder contains tests
|
||||||
|
# --------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TAP_DANCE_ENABLE = yes
|
||||||
|
|
||||||
|
SRC += tap_dance_defs.c
|
717
tests/tap_dance/tap_dance_layers/test_tap_dance_layers.cpp
Normal file
717
tests/tap_dance/tap_dance_layers/test_tap_dance_layers.cpp
Normal file
@ -0,0 +1,717 @@
|
|||||||
|
// Copyright 2022 Sergey Vlasov (@sigprof)
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "keyboard_report_util.hpp"
|
||||||
|
#include "keycode.h"
|
||||||
|
#include "test_common.hpp"
|
||||||
|
#include "action_tapping.h"
|
||||||
|
#include "test_keymap_key.hpp"
|
||||||
|
#include "tap_dance_defs.h"
|
||||||
|
|
||||||
|
using testing::_;
|
||||||
|
using testing::InSequence;
|
||||||
|
|
||||||
|
struct TapDanceKeyParams {
|
||||||
|
std::string name; // Tap dance name (part of test name)
|
||||||
|
uint16_t keycode; // Tap dance keycode (TD(n))
|
||||||
|
uint16_t expect_on_tap; // Keycode for single tap
|
||||||
|
uint16_t expect_on_hold; // Keycode for single hold (may be MO(1))
|
||||||
|
uint16_t expect_on_double_tap; // Keycode for double tap (may be MO(1))
|
||||||
|
uint16_t expect_on_double_hold; // Keycode for double hold (may be MO(1))
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OtherKeyLayerParams {
|
||||||
|
uint16_t keycode; // Keycode in the keymap
|
||||||
|
uint16_t expect_on_press; // Keycode to expect on press
|
||||||
|
uint16_t expect_on_release; // Keycode to expect on release (may be KC_NO if none)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OtherKeyParams {
|
||||||
|
std::string name; // Other key name (part of test name)
|
||||||
|
OtherKeyLayerParams l0; // Keycodes for layer 0
|
||||||
|
OtherKeyLayerParams l1; // Keycodes for layer 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::tuple<TapDanceKeyParams, OtherKeyParams> TapDanceLayersParams;
|
||||||
|
|
||||||
|
class TapDanceLayers : public ::testing::WithParamInterface<TapDanceLayersParams>, public TestFixture {
|
||||||
|
protected:
|
||||||
|
TapDanceKeyParams tap_dance;
|
||||||
|
OtherKeyParams other_key;
|
||||||
|
|
||||||
|
std::unique_ptr<KeymapKey> key_td, key_td_l1, key_other, key_other_l1;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
std::tie(tap_dance, other_key) = GetParam();
|
||||||
|
|
||||||
|
key_td = std::make_unique<KeymapKey>(0, 1, 0, tap_dance.keycode);
|
||||||
|
key_td_l1 = std::make_unique<KeymapKey>(1, 1, 0, KC_TRNS);
|
||||||
|
key_other = std::make_unique<KeymapKey>(0, 2, 0, other_key.l0.keycode);
|
||||||
|
key_other_l1 = std::make_unique<KeymapKey>(1, 2, 0, other_key.l1.keycode);
|
||||||
|
|
||||||
|
set_keymap({*key_td, *key_td_l1, *key_other, *key_other_l1});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const TapDanceKeyParams tap_dance_keys[] = {
|
||||||
|
TapDanceKeyParams{
|
||||||
|
"LayerMove",
|
||||||
|
TD(TD_L_MOVE),
|
||||||
|
KC_APP,
|
||||||
|
KC_APP,
|
||||||
|
MO(1),
|
||||||
|
MO(1),
|
||||||
|
},
|
||||||
|
TapDanceKeyParams{
|
||||||
|
"LayerToggle",
|
||||||
|
TD(TD_L_TOGG),
|
||||||
|
KC_APP,
|
||||||
|
KC_APP,
|
||||||
|
MO(1),
|
||||||
|
MO(1),
|
||||||
|
},
|
||||||
|
TapDanceKeyParams{
|
||||||
|
"CustomLT",
|
||||||
|
TD(TD_LT_APP),
|
||||||
|
KC_APP,
|
||||||
|
MO(1),
|
||||||
|
KC_RCTL,
|
||||||
|
KC_RCTL,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const OtherKeyParams other_keys[] = {
|
||||||
|
OtherKeyParams{
|
||||||
|
"Builtin",
|
||||||
|
OtherKeyLayerParams{KC_A, KC_A, KC_NO},
|
||||||
|
OtherKeyLayerParams{KC_B, KC_B, KC_NO},
|
||||||
|
},
|
||||||
|
OtherKeyParams{
|
||||||
|
"CustomFast",
|
||||||
|
OtherKeyLayerParams{FAST_AB, KC_A, KC_B},
|
||||||
|
OtherKeyLayerParams{FAST_CD, KC_C, KC_D},
|
||||||
|
},
|
||||||
|
OtherKeyParams{
|
||||||
|
"CustomSlow",
|
||||||
|
OtherKeyLayerParams{SLOW_AB, KC_A, KC_B},
|
||||||
|
OtherKeyLayerParams{SLOW_CD, KC_C, KC_D},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
INSTANTIATE_TEST_CASE_P(
|
||||||
|
Layers,
|
||||||
|
TapDanceLayers,
|
||||||
|
::testing::Combine(
|
||||||
|
::testing::ValuesIn(tap_dance_keys),
|
||||||
|
::testing::ValuesIn(other_keys)
|
||||||
|
),
|
||||||
|
[](const ::testing::TestParamInfo<TapDanceLayersParams>& info) {
|
||||||
|
return std::get<0>(info.param).name + std::get<1>(info.param).name;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Test single tap of the tap dance key with tapping term delay after the tap.
|
||||||
|
TEST_P(TapDanceLayers, SingleTap) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// The tap of the tap dance key does not result in sending a report
|
||||||
|
// immediately.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
|
||||||
|
// After the tapping term expires, a tap event for the single tap keycode
|
||||||
|
// is generated.
|
||||||
|
idle_for(TAPPING_TERM - 1);
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_tap));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test single tap of the tap dance key without a delay between the tap dance
|
||||||
|
// key and the other key.
|
||||||
|
TEST_P(TapDanceLayers, SingleTapFast) {
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// The tap of the tap dance key does not result in sending a report
|
||||||
|
// immediately.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
|
||||||
|
// A quick press of the other key causes the tap event for the tap dance to
|
||||||
|
// be sent before the press event for the other key, and the layer 0
|
||||||
|
// mapping is used for the other key.
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_tap));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test single hold of the tap dance key with tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which switch the layer on hold).
|
||||||
|
TEST_P(TapDanceLayers, SingleHoldLayer) {
|
||||||
|
if (tap_dance.expect_on_hold != MO(1)) {
|
||||||
|
// Do nothing - the SingleHoldKeycode test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the hold of the tap dance key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// After the tapping term expires, the tap dance finishes and switches the
|
||||||
|
// layer, but does not send a report.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_press));
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key does not produce a report.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test single hold of the tap dance key with tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which send a keycode on single hold).
|
||||||
|
TEST_P(TapDanceLayers, SingleHoldKeycode) {
|
||||||
|
if (tap_dance.expect_on_hold == MO(1)) {
|
||||||
|
// Do nothing - the SingleHoldLayer test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the hold of the tap dance key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// After the tapping term expires, the tap dance sends the report with the
|
||||||
|
// hold keycode.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_hold));
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_hold, other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_hold));
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key sends the release report for the
|
||||||
|
// corresponding hold keycode.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
} else {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
}
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test single hold of the tap dance key without tapping term delay after the
|
||||||
|
// hold (test variant for tap dances which switch the layer on hold).
|
||||||
|
TEST_P(TapDanceLayers, SingleHoldFastLayer) {
|
||||||
|
if (tap_dance.expect_on_hold != MO(1)) {
|
||||||
|
// Do nothing - the SingleHoldFastKeycode test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the hold of the tap dance key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_press));
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key does not produce a report.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test single hold of the tap dance key without tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which send a keycode on single hold).
|
||||||
|
TEST_P(TapDanceLayers, SingleHoldFastKeycode) {
|
||||||
|
if (tap_dance.expect_on_hold == MO(1)) {
|
||||||
|
// Do nothing - the SingleHoldFastLayer test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the hold of the tap dance key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces first the report for the tap dance hold
|
||||||
|
// keycode, and then the reports for the layer 0 mapping of the other key.
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_hold));
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_hold, other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_hold));
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key sends a release report for the corresponding
|
||||||
|
// hold keycode.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
} else {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
}
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double tap of the tap dance key with tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which switch the layer on double tap).
|
||||||
|
TEST_P(TapDanceLayers, DoubleTapLayer) {
|
||||||
|
if (tap_dance.expect_on_double_tap != MO(1)) {
|
||||||
|
// Do nothing - the DoubleTapKeycode test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double tap of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
tap_key(*key_td);
|
||||||
|
|
||||||
|
// After the tapping term this tap dance does not send a report too.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_press));
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double tap of the tap dance key with tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which send a keycode on double tap).
|
||||||
|
TEST_P(TapDanceLayers, DoubleTapKeycode) {
|
||||||
|
if (tap_dance.expect_on_double_tap == MO(1)) {
|
||||||
|
// Do nothing - the DoubleTapLayer test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double tap of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
tap_key(*key_td);
|
||||||
|
|
||||||
|
// After the tapping term this tap dance sends the double tap keycode.
|
||||||
|
idle_for(TAPPING_TERM - 1);
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_tap));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double tap of the tap dance key without tapping term delay after the
|
||||||
|
// hold (test variant for tap dances which switch the layer on double tap).
|
||||||
|
TEST_P(TapDanceLayers, DoubleTapFastLayer) {
|
||||||
|
if (tap_dance.expect_on_double_tap != MO(1)) {
|
||||||
|
// Do nothing - the DoubleTapFastKeycode test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double tap of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
tap_key(*key_td);
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_press));
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double tap of the tap dance key without tapping term delay after the
|
||||||
|
// hold (test variant for tap dances which send a keycode on double tap).
|
||||||
|
TEST_P(TapDanceLayers, DoubleTapFastKeycode) {
|
||||||
|
if (tap_dance.expect_on_double_tap == MO(1)) {
|
||||||
|
// Do nothing - the DoubleTapFastLayer test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double tap of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
tap_key(*key_td);
|
||||||
|
|
||||||
|
// Pressing the other key produces first the report for the tap dance
|
||||||
|
// double tap keycode, and then the reports for the layer 0 mapping of the
|
||||||
|
// other key.
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_tap));
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double hold of the tap dance key with tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which switch the layer on double hold).
|
||||||
|
TEST_P(TapDanceLayers, DoubleHoldLayer) {
|
||||||
|
if (tap_dance.expect_on_double_hold != MO(1)) {
|
||||||
|
// Do nothing - the DoubleHoldKeycode test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double hold of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// After the tapping term expires, the tap dance finishes and switches the
|
||||||
|
// layer, but does not send a report.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_press));
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key does not produce a report.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double hold of the tap dance key with tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which send a keycode on double hold).
|
||||||
|
TEST_P(TapDanceLayers, DoubleHoldKeycode) {
|
||||||
|
if (tap_dance.expect_on_double_hold == MO(1)) {
|
||||||
|
// Do nothing - the DoubleHoldLayer test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double hold of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// After the tapping term expires, the tap dance sends the report with the
|
||||||
|
// double hold keycode.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
idle_for(TAPPING_TERM);
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_hold));
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_hold, other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_hold));
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key sends the release report for the
|
||||||
|
// corresponding double hold keycode.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
} else {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
}
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the reports for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double hold of the tap dance key without tapping term delay after the
|
||||||
|
// hold (test variant for tap dances which switch the layer on double hold).
|
||||||
|
TEST_P(TapDanceLayers, DoubleHoldFastLayer) {
|
||||||
|
if (tap_dance.expect_on_double_hold != MO(1)) {
|
||||||
|
// Do nothing - the DoubleHoldFastKeycode test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double hold of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_press));
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key does not produce a report.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the reports for the layer 1 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l1.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l1.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test double hold of the tap dance key without tapping term delay after the hold
|
||||||
|
// (test variant for tap dances which send a keycode on double hold).
|
||||||
|
TEST_P(TapDanceLayers, DoubleHoldFastKeycode) {
|
||||||
|
if (tap_dance.expect_on_double_hold == MO(1)) {
|
||||||
|
// Do nothing - the DoubleHoldFastLayer test would run instead.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestDriver driver;
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
// No report gets sent immediately after the double hold of the tap dance
|
||||||
|
// key.
|
||||||
|
EXPECT_NO_REPORT(driver);
|
||||||
|
tap_key(*key_td);
|
||||||
|
key_td->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Pressing the other key produces first the report for the tap dance
|
||||||
|
// double hold keycode, and then the reports for the layer 0 mapping of the
|
||||||
|
// other key.
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_hold));
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_hold, other_key.l0.expect_on_press));
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (tap_dance.expect_on_double_hold));
|
||||||
|
}
|
||||||
|
key_other->press();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the tap dance key sends a release report for the corresponding
|
||||||
|
// double hold keycode.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
} else {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_press));
|
||||||
|
}
|
||||||
|
key_td->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
|
||||||
|
// Releasing the other key produces the report for the layer 0 mapping of
|
||||||
|
// that key.
|
||||||
|
if (other_key.l0.expect_on_release != KC_NO) {
|
||||||
|
EXPECT_REPORT(driver, (other_key.l0.expect_on_release));
|
||||||
|
}
|
||||||
|
EXPECT_EMPTY_REPORT(driver);
|
||||||
|
key_other->release();
|
||||||
|
run_one_scan_loop();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user