qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

test_caps_word.cpp (21205B)


      1 // Copyright 2022 Google LLC
      2 //
      3 // This program is free software: you can redistribute it and/or modify
      4 // it under the terms of the GNU General Public License as published by
      5 // the Free Software Foundation, either version 2 of the License, or
      6 // (at your option) any later version.
      7 //
      8 // This program is distributed in the hope that it will be useful,
      9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 // GNU General Public License for more details.
     12 //
     13 // You should have received a copy of the GNU General Public License
     14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15 
     16 #include "keyboard_report_util.hpp"
     17 #include "keycode.h"
     18 #include "test_common.hpp"
     19 #include "test_fixture.hpp"
     20 #include "test_keymap_key.hpp"
     21 
     22 using ::testing::_;
     23 using ::testing::AnyNumber;
     24 using ::testing::AnyOf;
     25 using ::testing::InSequence;
     26 using ::testing::TestParamInfo;
     27 
     28 namespace {
     29 
     30 bool press_user_default(uint16_t keycode) {
     31     switch (keycode) {
     32         // Keycodes that continue Caps Word, with shift applied.
     33         case KC_A ... KC_Z:
     34         case KC_MINS:
     35             add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
     36             return true;
     37 
     38         // Keycodes that continue Caps Word, without shifting.
     39         case KC_1 ... KC_0:
     40         case KC_BSPC:
     41         case KC_DEL:
     42         case KC_UNDS:
     43             return true;
     44 
     45         default:
     46             return false; // Deactivate Caps Word.
     47     }
     48 }
     49 
     50 uint16_t passed_keycode;
     51 bool     press_user_save_passed_keycode(uint16_t keycode) {
     52     passed_keycode = keycode;
     53     return true;
     54 }
     55 
     56 bool (*press_user_fun)(uint16_t) = press_user_default;
     57 
     58 extern "C" {
     59 bool caps_word_press_user(uint16_t keycode) {
     60     return press_user_fun(keycode);
     61 }
     62 } // extern "C"
     63 
     64 class CapsWord : public TestFixture {
     65    public:
     66     void SetUp() override {
     67         caps_word_off();
     68         press_user_fun = press_user_default;
     69     }
     70 };
     71 
     72 // Tests caps_word_on(), _off(), and _toggle() functions.
     73 TEST_F(CapsWord, OnOffToggleFuns) {
     74     TestDriver driver;
     75 
     76     EXPECT_EQ(is_caps_word_on(), false);
     77 
     78     caps_word_on();
     79     EXPECT_EQ(is_caps_word_on(), true);
     80     caps_word_on();
     81     EXPECT_EQ(is_caps_word_on(), true);
     82 
     83     caps_word_off();
     84     EXPECT_EQ(is_caps_word_on(), false);
     85     caps_word_off();
     86     EXPECT_EQ(is_caps_word_on(), false);
     87 
     88     caps_word_toggle();
     89     EXPECT_EQ(is_caps_word_on(), true);
     90     caps_word_toggle();
     91     EXPECT_EQ(is_caps_word_on(), false);
     92 
     93     VERIFY_AND_CLEAR(driver);
     94 }
     95 
     96 // Tests the default `caps_word_press_user()` function.
     97 TEST_F(CapsWord, DefaultCapsWordPressUserFun) {
     98     // Spot check some keycodes that continue Caps Word, with shift applied.
     99     for (uint16_t keycode : {KC_A, KC_B, KC_Z, KC_MINS}) {
    100         SCOPED_TRACE("keycode: " + testing::PrintToString(keycode));
    101         clear_weak_mods();
    102         EXPECT_TRUE(caps_word_press_user(keycode));
    103         EXPECT_EQ(get_weak_mods(), MOD_BIT(KC_LSFT));
    104     }
    105 
    106     // Some keycodes that continue Caps Word, without shifting.
    107     for (uint16_t keycode : {KC_1, KC_9, KC_0, KC_BSPC, KC_DEL}) {
    108         SCOPED_TRACE("keycode: " + testing::PrintToString(keycode));
    109         clear_weak_mods();
    110         EXPECT_TRUE(caps_word_press_user(keycode));
    111         EXPECT_EQ(get_weak_mods(), 0);
    112     }
    113 
    114     // Some keycodes that turn off Caps Word.
    115     for (uint16_t keycode : {KC_SPC, KC_DOT, KC_COMM, KC_TAB, KC_ESC, KC_ENT}) {
    116         SCOPED_TRACE("keycode: " + testing::PrintToString(keycode));
    117         EXPECT_FALSE(caps_word_press_user(keycode));
    118     }
    119 }
    120 
    121 // Tests that `QK_CAPS_WORD_TOGGLE` key toggles Caps Word.
    122 TEST_F(CapsWord, CapswrdKey) {
    123     TestDriver driver;
    124     KeymapKey  key_capswrd(0, 0, 0, QK_CAPS_WORD_TOGGLE);
    125     set_keymap({key_capswrd});
    126 
    127     // No keyboard reports should be sent.
    128     EXPECT_NO_REPORT(driver);
    129 
    130     tap_key(key_capswrd); // Tap the QK_CAPS_WORD_TOGGLE key.
    131     EXPECT_EQ(is_caps_word_on(), true);
    132 
    133     tap_key(key_capswrd); // Tap the QK_CAPS_WORD_TOGGLE key again.
    134     EXPECT_EQ(is_caps_word_on(), false);
    135 
    136     VERIFY_AND_CLEAR(driver);
    137 }
    138 
    139 // Tests that being idle for CAPS_WORD_IDLE_TIMEOUT turns off Caps Word.
    140 TEST_F(CapsWord, IdleTimeout) {
    141     TestDriver driver;
    142     KeymapKey  key_a(0, 0, 0, KC_A);
    143     set_keymap({key_a});
    144 
    145     // Allow any number of reports with no keys or only KC_LSFT.
    146     // clang-format off
    147     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    148                 KeyboardReport(),
    149                 KeyboardReport(KC_LSFT))))
    150         .Times(AnyNumber());
    151     // clang-format on
    152 
    153     // Expect "Shift+A".
    154     EXPECT_REPORT(driver, (KC_LSFT, KC_A));
    155 
    156     // Turn on Caps Word and tap "A".
    157     caps_word_on();
    158     tap_key(key_a);
    159     VERIFY_AND_CLEAR(driver);
    160 
    161     EXPECT_EMPTY_REPORT(driver);
    162     idle_for(CAPS_WORD_IDLE_TIMEOUT);
    163     run_one_scan_loop();
    164     VERIFY_AND_CLEAR(driver);
    165 
    166     // Caps Word should be off and mods should be clear.
    167     EXPECT_EQ(is_caps_word_on(), false);
    168     EXPECT_EQ(get_mods() | get_weak_mods(), 0);
    169 
    170     // Expect unshifted "A".
    171     EXPECT_REPORT(driver, (KC_A));
    172     EXPECT_EMPTY_REPORT(driver);
    173     tap_key(key_a);
    174     run_one_scan_loop();
    175     VERIFY_AND_CLEAR(driver);
    176 }
    177 
    178 // Tests that typing "A, 4, A, 4" produces "Shift+A, 4, Shift+A, 4".
    179 TEST_F(CapsWord, ShiftsLettersButNotDigits) {
    180     TestDriver driver;
    181     KeymapKey  key_a(0, 0, 0, KC_A);
    182     KeymapKey  key_4(0, 1, 0, KC_4);
    183     set_keymap({key_a, key_4});
    184 
    185     // Allow any number of reports with no keys or only KC_LSFT.
    186     // clang-format off
    187     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    188                 KeyboardReport(),
    189                 KeyboardReport(KC_LSFT))))
    190         .Times(AnyNumber());
    191     // clang-format on
    192 
    193     { // Expect: "Shift+A, 4, Shift+A, 4".
    194         InSequence s;
    195         EXPECT_REPORT(driver, (KC_LSFT, KC_A));
    196         EXPECT_REPORT(driver, (KC_4));
    197         EXPECT_REPORT(driver, (KC_LSFT, KC_A));
    198         EXPECT_REPORT(driver, (KC_4));
    199     }
    200 
    201     // Turn on Caps Word and tap "A, 4, A, 4".
    202     caps_word_on();
    203     tap_keys(key_a, key_4, key_a, key_4);
    204 
    205     VERIFY_AND_CLEAR(driver);
    206 }
    207 
    208 // Tests that typing "A, Space, A" produces "Shift+A, Space, A".
    209 TEST_F(CapsWord, SpaceTurnsOffCapsWord) {
    210     TestDriver driver;
    211     KeymapKey  key_a(0, 0, 0, KC_A);
    212     KeymapKey  key_spc(0, 1, 0, KC_SPC);
    213     set_keymap({key_a, key_spc});
    214 
    215     // Allow any number of reports with no keys or only KC_LSFT.
    216     // clang-format off
    217     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    218                 KeyboardReport(),
    219                 KeyboardReport(KC_LSFT))))
    220         .Times(AnyNumber());
    221     // clang-format on
    222 
    223     { // Expect: "Shift+A, Space, A".
    224         InSequence seq;
    225         EXPECT_REPORT(driver, (KC_LSFT, KC_A));
    226         EXPECT_REPORT(driver, (KC_SPC));
    227         EXPECT_REPORT(driver, (KC_A));
    228     }
    229 
    230     // Turn on Caps Word and tap "A, Space, A".
    231     caps_word_on();
    232     tap_keys(key_a, key_spc, key_a);
    233 
    234     VERIFY_AND_CLEAR(driver);
    235 }
    236 
    237 // Tests that typing "AltGr + A" produces "Shift + AltGr + A".
    238 TEST_F(CapsWord, ShiftsAltGrSymbols) {
    239     TestDriver driver;
    240     KeymapKey  key_a(0, 0, 0, KC_A);
    241     KeymapKey  key_altgr(0, 1, 0, KC_RALT);
    242     set_keymap({key_a, key_altgr});
    243 
    244     // Allow any number of reports with no keys or only modifiers.
    245     // clang-format off
    246     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    247                 KeyboardReport(),
    248                 KeyboardReport(KC_LSFT),
    249                 KeyboardReport(KC_RALT),
    250                 KeyboardReport(KC_LSFT, KC_RALT))))
    251         .Times(AnyNumber());
    252     // Expect "Shift + AltGr + A".
    253     EXPECT_REPORT(driver, (KC_LSFT, KC_RALT, KC_A));
    254     // clang-format on
    255 
    256     // Turn on Caps Word and type "AltGr + A".
    257     caps_word_on();
    258 
    259     key_altgr.press();
    260     run_one_scan_loop();
    261     tap_key(key_a);
    262     run_one_scan_loop();
    263     key_altgr.release();
    264     run_one_scan_loop();
    265 
    266     idle_for(CAPS_WORD_IDLE_TIMEOUT);
    267 
    268     VERIFY_AND_CLEAR(driver);
    269 }
    270 
    271 // Tests typing "AltGr + A" using a mod-tap key.
    272 TEST_F(CapsWord, ShiftsModTapAltGrSymbols) {
    273     TestDriver driver;
    274     KeymapKey  key_a(0, 0, 0, KC_A);
    275     KeymapKey  key_altgr_t(0, 1, 0, RALT_T(KC_B));
    276     set_keymap({key_a, key_altgr_t});
    277 
    278     // Allow any number of reports with no keys or only modifiers.
    279     // clang-format off
    280     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    281                 KeyboardReport(),
    282                 KeyboardReport(KC_LSFT),
    283                 KeyboardReport(KC_RALT),
    284                 KeyboardReport(KC_LSFT, KC_RALT))))
    285         .Times(AnyNumber());
    286     // Expect "Shift + AltGr + A".
    287     EXPECT_REPORT(driver, (KC_LSFT, KC_RALT, KC_A));
    288     // clang-format on
    289 
    290     // Turn on Caps Word and type "AltGr + A".
    291     caps_word_on();
    292 
    293     key_altgr_t.press();
    294     idle_for(TAPPING_TERM + 1);
    295     tap_key(key_a);
    296     run_one_scan_loop();
    297     key_altgr_t.release();
    298     run_one_scan_loop();
    299     EXPECT_TRUE(is_caps_word_on());
    300 
    301     idle_for(CAPS_WORD_IDLE_TIMEOUT);
    302 
    303     VERIFY_AND_CLEAR(driver);
    304 }
    305 
    306 struct CapsWordPressUserParams {
    307     std::string name;
    308     uint16_t    keycode;
    309     uint16_t    delay_ms;
    310     uint16_t    expected_passed_keycode;
    311     bool        continues_caps_word;
    312 
    313     static const std::string& GetName(const TestParamInfo<CapsWordPressUserParams>& info) {
    314         return info.param.name;
    315     }
    316 };
    317 
    318 class CapsWordPressUser : public ::testing::WithParamInterface<CapsWordPressUserParams>, public CapsWord {
    319     void SetUp() override {
    320         caps_word_on();
    321         passed_keycode = KC_NO;
    322         press_user_fun = press_user_save_passed_keycode;
    323     }
    324 };
    325 
    326 // Tests keycodes passed to caps_word_press_user() function for various keys.
    327 TEST_P(CapsWordPressUser, KeyCode) {
    328     TestDriver driver;
    329     KeymapKey  key(0, 0, 0, GetParam().keycode);
    330     set_keymap({key});
    331 
    332     EXPECT_ANY_REPORT(driver).Times(AnyNumber());
    333     tap_key(key, GetParam().delay_ms);
    334 
    335     EXPECT_EQ(passed_keycode, GetParam().expected_passed_keycode);
    336     EXPECT_EQ(is_caps_word_on(), GetParam().continues_caps_word);
    337     clear_oneshot_mods();
    338     VERIFY_AND_CLEAR(driver);
    339 }
    340 
    341 const uint16_t LT_1_KC_A = LT(1, KC_A);
    342 // clang-format off
    343 INSTANTIATE_TEST_CASE_P(
    344     PressUser,
    345     CapsWordPressUser,
    346     ::testing::Values(
    347         CapsWordPressUserParams{
    348             "KC_A", KC_A, 1, KC_A, true},
    349         CapsWordPressUserParams{
    350             "KC_HASH", KC_HASH, 1, KC_HASH, true},
    351         CapsWordPressUserParams{
    352             "KC_LSFT", KC_LSFT, 1, KC_LSFT, true},
    353         CapsWordPressUserParams{
    354             "KC_RSFT", KC_RSFT, 1, KC_RSFT, true},
    355         CapsWordPressUserParams{
    356             "LSFT_T_tapped", LSFT_T(KC_A), 1, KC_A, true},
    357         CapsWordPressUserParams{
    358             "LSFT_T_held", LSFT_T(KC_A), TAPPING_TERM + 1, KC_LSFT, true},
    359         CapsWordPressUserParams{
    360             "RSFT_T_held", RSFT_T(KC_A), TAPPING_TERM + 1, KC_RSFT, true},
    361         CapsWordPressUserParams{
    362             "RSA_T_held", RSA_T(KC_A), TAPPING_TERM + 1, RSFT(KC_RALT), true},
    363         // Holding a mod-tap other than Shift or AltGr stops Caps Word.
    364         CapsWordPressUserParams{
    365             "LCTL_T_held", LCTL_T(KC_A), TAPPING_TERM + 1, KC_NO, false},
    366         CapsWordPressUserParams{
    367             "LALT_T_held", LALT_T(KC_A), TAPPING_TERM + 1, KC_NO, false},
    368         CapsWordPressUserParams{
    369             "LGUI_T_held", LGUI_T(KC_A), TAPPING_TERM + 1, KC_NO, false},
    370         // Layer keys are ignored and continue Caps Word.
    371         CapsWordPressUserParams{
    372             "MO", MO(1), 1, KC_NO, true},
    373         CapsWordPressUserParams{
    374             "TO", TO(1), 1, KC_NO, true},
    375         CapsWordPressUserParams{
    376             "TG", TG(1), 1, KC_NO, true},
    377         CapsWordPressUserParams{
    378             "TT", TT(1), 1, KC_NO, true},
    379         CapsWordPressUserParams{
    380             "OSL", OSL(1), 1, KC_NO, true},
    381         CapsWordPressUserParams{
    382             "LT_held", LT_1_KC_A, TAPPING_TERM + 1, KC_NO, true},
    383         // Tri-Layer keys are ignored and continue Caps Word.
    384         CapsWordPressUserParams{
    385             "TL_LOWR", TL_LOWR, 1, KC_NO, true},
    386         CapsWordPressUserParams{
    387             "TL_UPPR", TL_UPPR, 1, KC_NO, true},
    388         // AltGr keys are ignored and continue Caps Word.
    389         CapsWordPressUserParams{
    390             "KC_RALT", KC_RALT, 1, KC_NO, true},
    391         CapsWordPressUserParams{
    392             "OSM_MOD_RALT", OSM(MOD_RALT), 1, KC_NO, true},
    393         CapsWordPressUserParams{
    394             "RALT_T_held", RALT_T(KC_A), TAPPING_TERM + 1, KC_NO, true}
    395         ),
    396     CapsWordPressUserParams::GetName
    397     );
    398 // clang-format on
    399 
    400 struct CapsWordBothShiftsParams {
    401     std::string name;
    402     uint16_t    left_shift_keycode;
    403     uint16_t    right_shift_keycode;
    404 
    405     static const std::string& GetName(const TestParamInfo<CapsWordBothShiftsParams>& info) {
    406         return info.param.name;
    407     }
    408 };
    409 
    410 // Tests the BOTH_SHIFTS_TURNS_ON_CAPS_WORD method to turn on Caps Word.
    411 class CapsWordBothShifts : public ::testing::WithParamInterface<CapsWordBothShiftsParams>, public CapsWord {};
    412 
    413 // Pressing shifts as "Left down, Right down, Left up, Right up".
    414 TEST_P(CapsWordBothShifts, PressLRLR) {
    415     TestDriver driver;
    416     KeymapKey  left_shift(0, 0, 0, GetParam().left_shift_keycode);
    417     KeymapKey  right_shift(0, 1, 0, GetParam().right_shift_keycode);
    418     set_keymap({left_shift, right_shift});
    419 
    420     // clang-format off
    421     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    422                 KeyboardReport(),
    423                 KeyboardReport(KC_LSFT),
    424                 KeyboardReport(KC_RSFT),
    425                 KeyboardReport(KC_LSFT, KC_RSFT))))
    426         .Times(AnyNumber());
    427     // clang-format on
    428 
    429     EXPECT_EQ(is_caps_word_on(), false);
    430 
    431     left_shift.press(); // Press both shifts.
    432     run_one_scan_loop();
    433     right_shift.press();
    434 
    435     // For mod-tap, wait for the tapping term.
    436     if (left_shift.code == LSFT_T(KC_A)) {
    437         idle_for(TAPPING_TERM);
    438     }
    439 
    440     run_one_scan_loop();
    441     left_shift.release(); // Release both.
    442     run_one_scan_loop();
    443     right_shift.release();
    444     run_one_scan_loop();
    445 
    446     EXPECT_EQ(is_caps_word_on(), true);
    447 
    448     VERIFY_AND_CLEAR(driver);
    449 }
    450 
    451 // Pressing shifts as "Left down, Right down, Right up, Left up".
    452 TEST_P(CapsWordBothShifts, PressLRRL) {
    453     TestDriver driver;
    454     KeymapKey  left_shift(0, 0, 0, GetParam().left_shift_keycode);
    455     KeymapKey  right_shift(0, 1, 0, GetParam().right_shift_keycode);
    456     set_keymap({left_shift, right_shift});
    457 
    458     // clang-format off
    459     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    460                 KeyboardReport(),
    461                 KeyboardReport(KC_LSFT),
    462                 KeyboardReport(KC_RSFT),
    463                 KeyboardReport(KC_LSFT, KC_RSFT))))
    464         .Times(AnyNumber());
    465     // clang-format on
    466 
    467     EXPECT_EQ(is_caps_word_on(), false);
    468 
    469     left_shift.press(); // Press both shifts.
    470     run_one_scan_loop();
    471     right_shift.press();
    472 
    473     if (left_shift.code == LSFT_T(KC_A)) {
    474         idle_for(TAPPING_TERM);
    475     }
    476     run_one_scan_loop();
    477 
    478     right_shift.release(); // Release both.
    479     run_one_scan_loop();
    480     left_shift.release();
    481     run_one_scan_loop();
    482 
    483     EXPECT_EQ(is_caps_word_on(), true);
    484 
    485     VERIFY_AND_CLEAR(driver);
    486 }
    487 
    488 // clang-format off
    489 INSTANTIATE_TEST_CASE_P(
    490     ShiftPairs,
    491     CapsWordBothShifts,
    492     ::testing::Values(
    493         CapsWordBothShiftsParams{
    494             "PlainShifts", KC_LSFT, KC_RSFT},
    495         CapsWordBothShiftsParams{
    496             "OneshotShifts", OSM(MOD_LSFT), OSM(MOD_RSFT)},
    497         CapsWordBothShiftsParams{
    498             "SpaceCadetShifts", SC_LSPO, SC_RSPC},
    499         CapsWordBothShiftsParams{
    500             "ModTapShifts", LSFT_T(KC_A), RSFT_T(KC_B)}
    501         ),
    502     CapsWordBothShiftsParams::GetName
    503     );
    504 // clang-format on
    505 
    506 struct CapsWordDoubleTapShiftParams {
    507     std::string name;
    508     uint16_t    left_shift_keycode;
    509 
    510     static const std::string& GetName(const TestParamInfo<CapsWordDoubleTapShiftParams>& info) {
    511         return info.param.name;
    512     }
    513 };
    514 
    515 // Tests the DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD method to turn on Caps Word.
    516 class CapsWordDoubleTapShift : public ::testing::WithParamInterface<CapsWordDoubleTapShiftParams>, public CapsWord {};
    517 
    518 // Tests that double tapping activates Caps Word.
    519 TEST_P(CapsWordDoubleTapShift, Activation) {
    520     TestDriver driver;
    521     KeymapKey  left_shift(0, 0, 0, GetParam().left_shift_keycode);
    522     KeymapKey  esc(0, 0, 1, KC_ESCAPE);
    523     set_keymap({left_shift, esc});
    524 
    525     // clang-format off
    526     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    527                 KeyboardReport(),
    528                 KeyboardReport(KC_LSFT))))
    529         .Times(AnyNumber());
    530     // clang-format on
    531 
    532     EXPECT_EQ(is_caps_word_on(), false);
    533 
    534     // Tapping shift twice within the tapping term turns on Caps Word.
    535     tap_key(left_shift);
    536     idle_for(TAPPING_TERM - 10);
    537     tap_key(left_shift);
    538 
    539     EXPECT_EQ(is_caps_word_on(), true);
    540 
    541     VERIFY_AND_CLEAR(driver);
    542 
    543     // We have to manually reset the internal state of the caps word state
    544     // machine at this point. This due to imperfect test isolation which can't
    545     // reset the caps word double shift timer on test case setup.
    546     idle_for(CAPS_WORD_IDLE_TIMEOUT);
    547 
    548     EXPECT_REPORT(driver, (KC_ESC));
    549     EXPECT_EMPTY_REPORT(driver);
    550     tap_key(esc);
    551     VERIFY_AND_CLEAR(driver);
    552 }
    553 
    554 // Double tap doesn't count if another key is pressed between the taps.
    555 TEST_P(CapsWordDoubleTapShift, Interrupted) {
    556     TestDriver driver;
    557     KeymapKey  left_shift(0, 0, 0, GetParam().left_shift_keycode);
    558     KeymapKey  key_a(0, 1, 0, KC_A);
    559     set_keymap({left_shift, key_a});
    560 
    561     // clang-format off
    562     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    563                 KeyboardReport(),
    564                 KeyboardReport(KC_LSFT),
    565                 KeyboardReport(KC_LSFT, KC_A))))
    566         .Times(AnyNumber());
    567     // clang-format on
    568 
    569     left_shift.press();
    570     run_one_scan_loop();
    571 
    572     tap_key(key_a); // 'A' key interrupts the double tap.
    573 
    574     left_shift.release();
    575     run_one_scan_loop();
    576 
    577     idle_for(TAPPING_TERM - 10);
    578     tap_key(left_shift);
    579 
    580     EXPECT_EQ(is_caps_word_on(), false); // Caps Word is still off.
    581     clear_oneshot_mods();
    582 
    583     VERIFY_AND_CLEAR(driver);
    584 }
    585 
    586 // Double tap doesn't count if taps are more than tapping term apart.
    587 TEST_P(CapsWordDoubleTapShift, SlowTaps) {
    588     TestDriver driver;
    589     KeymapKey  left_shift(0, 0, 0, GetParam().left_shift_keycode);
    590     set_keymap({left_shift});
    591 
    592     // clang-format off
    593     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    594                 KeyboardReport(),
    595                 KeyboardReport(KC_LSFT))))
    596         .Times(AnyNumber());
    597     // clang-format on
    598 
    599     tap_key(left_shift);
    600     idle_for(TAPPING_TERM + 1);
    601     tap_key(left_shift);
    602 
    603     EXPECT_EQ(is_caps_word_on(), false); // Caps Word is still off.
    604     clear_oneshot_mods();
    605     send_keyboard_report();
    606 
    607     VERIFY_AND_CLEAR(driver);
    608 }
    609 
    610 // clang-format off
    611 INSTANTIATE_TEST_CASE_P(
    612     Shifts,
    613     CapsWordDoubleTapShift,
    614     ::testing::Values(
    615         CapsWordDoubleTapShiftParams{"PlainShift", KC_LSFT},
    616         CapsWordDoubleTapShiftParams{"OneshotShift", OSM(MOD_LSFT)}
    617         ),
    618     CapsWordDoubleTapShiftParams::GetName
    619     );
    620 
    621 // Tests that holding a OSL keeps caps word active and shifts keys on the layer that need to be shifted.
    622 TEST_F(CapsWord, IgnoresOSLHold) {
    623     TestDriver driver;
    624     KeymapKey key_a(0, 0, 0, KC_A);
    625     KeymapKey key_osl(0, 1, 0, OSL(1));
    626     KeymapKey key_b(1, 0, 0, KC_B);
    627     set_keymap({key_a, key_osl, key_b});
    628 
    629     // Allow any number of reports with no keys or only modifiers.
    630     // clang-format off
    631     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    632                 KeyboardReport(),
    633                 KeyboardReport(KC_LSFT))))
    634         .Times(AnyNumber());
    635 
    636     EXPECT_REPORT(driver, (KC_LSFT, KC_B));
    637     caps_word_on();
    638 
    639     key_osl.press();
    640     run_one_scan_loop();
    641     tap_key(key_b);
    642     key_osl.release();
    643     idle_for(CAPS_WORD_IDLE_TIMEOUT + 1);
    644 
    645     VERIFY_AND_CLEAR(driver);
    646 }
    647 
    648 // Tests that tapping a OSL keeps caps word active and shifts keys on the layer that need to be shifted.
    649 TEST_F(CapsWord, IgnoresOSLTap) {
    650     TestDriver driver;
    651     KeymapKey key_a(0, 0, 0, KC_A);
    652     KeymapKey key_osl(0, 1, 0, OSL(1));
    653     KeymapKey key_b(1, 0, 0, KC_B);
    654     set_keymap({key_a, key_osl, key_b});
    655 
    656     // Allow any number of reports with no keys or only modifiers.
    657     // clang-format off
    658     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    659                 KeyboardReport(),
    660                 KeyboardReport(KC_LSFT))))
    661         .Times(AnyNumber());
    662     // clang-format on
    663 
    664     EXPECT_REPORT(driver, (KC_LSFT, KC_B));
    665     caps_word_on();
    666 
    667     tap_key(key_osl);
    668     tap_key(key_b);
    669     idle_for(CAPS_WORD_IDLE_TIMEOUT);
    670 
    671     VERIFY_AND_CLEAR(driver);
    672 }
    673 
    674 TEST_F(CapsWord, IgnoresLayerLockKey) {
    675     TestDriver driver;
    676     KeymapKey  key_llock(0, 1, 0, QK_LAYER_LOCK);
    677     KeymapKey  key_b(0, 0, 0, KC_B);
    678     set_keymap({key_llock, key_b});
    679 
    680     // Allow any number of reports with no keys or only modifiers.
    681     // clang-format off
    682     EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
    683                 KeyboardReport(),
    684                 KeyboardReport(KC_LSFT))))
    685         .Times(AnyNumber());
    686     // clang-format on
    687 
    688     EXPECT_REPORT(driver, (KC_LSFT, KC_B));
    689     caps_word_on();
    690 
    691     tap_key(key_llock);
    692     tap_key(key_b);
    693     idle_for(CAPS_WORD_IDLE_TIMEOUT);
    694 
    695     VERIFY_AND_CLEAR(driver);
    696 }
    697 } // namespace