logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

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