test_caps_word.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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. class CapsWord : public TestFixture {
  26. public:
  27. void SetUp() override {
  28. caps_word_off();
  29. }
  30. };
  31. // Tests caps_word_on(), _off(), and _toggle() functions.
  32. TEST_F(CapsWord, OnOffToggleFuns) {
  33. TestDriver driver;
  34. EXPECT_EQ(is_caps_word_on(), false);
  35. caps_word_on();
  36. EXPECT_EQ(is_caps_word_on(), true);
  37. caps_word_on();
  38. EXPECT_EQ(is_caps_word_on(), true);
  39. caps_word_off();
  40. EXPECT_EQ(is_caps_word_on(), false);
  41. caps_word_off();
  42. EXPECT_EQ(is_caps_word_on(), false);
  43. caps_word_toggle();
  44. EXPECT_EQ(is_caps_word_on(), true);
  45. caps_word_toggle();
  46. EXPECT_EQ(is_caps_word_on(), false);
  47. testing::Mock::VerifyAndClearExpectations(&driver);
  48. }
  49. // Tests the default `caps_word_press_user()` function.
  50. TEST_F(CapsWord, DefaultCapsWordPressUserFun) {
  51. // Spot check some keycodes that continue Caps Word, with shift applied.
  52. for (uint16_t keycode : {KC_A, KC_B, KC_Z, KC_MINS}) {
  53. SCOPED_TRACE("keycode: " + testing::PrintToString(keycode));
  54. clear_weak_mods();
  55. EXPECT_TRUE(caps_word_press_user(keycode));
  56. EXPECT_EQ(get_weak_mods(), MOD_BIT(KC_LSFT));
  57. }
  58. // Some keycodes that continue Caps Word, without shifting.
  59. for (uint16_t keycode : {KC_1, KC_9, KC_0, KC_BSPC, KC_DEL}) {
  60. SCOPED_TRACE("keycode: " + testing::PrintToString(keycode));
  61. clear_weak_mods();
  62. EXPECT_TRUE(caps_word_press_user(keycode));
  63. EXPECT_EQ(get_weak_mods(), 0);
  64. }
  65. // Some keycodes that turn off Caps Word.
  66. for (uint16_t keycode : {KC_SPC, KC_DOT, KC_COMM, KC_TAB, KC_ESC, KC_ENT}) {
  67. SCOPED_TRACE("keycode: " + testing::PrintToString(keycode));
  68. EXPECT_FALSE(caps_word_press_user(keycode));
  69. }
  70. }
  71. // Tests that `CAPSWRD` key toggles Caps Word.
  72. TEST_F(CapsWord, CapswrdKey) {
  73. TestDriver driver;
  74. KeymapKey key_capswrd(0, 0, 0, CAPSWRD);
  75. set_keymap({key_capswrd});
  76. // No keyboard reports should be sent.
  77. EXPECT_NO_REPORT(driver);
  78. tap_key(key_capswrd); // Tap the CAPSWRD key.
  79. EXPECT_EQ(is_caps_word_on(), true);
  80. tap_key(key_capswrd); // Tap the CAPSWRD key again.
  81. EXPECT_EQ(is_caps_word_on(), false);
  82. testing::Mock::VerifyAndClearExpectations(&driver);
  83. }
  84. // Tests that being idle for CAPS_WORD_IDLE_TIMEOUT turns off Caps Word.
  85. TEST_F(CapsWord, IdleTimeout) {
  86. TestDriver driver;
  87. KeymapKey key_a(0, 0, 0, KC_A);
  88. set_keymap({key_a});
  89. // Allow any number of reports with no keys or only KC_LSFT.
  90. // clang-format off
  91. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  92. KeyboardReport(),
  93. KeyboardReport(KC_LSFT))))
  94. .Times(AnyNumber());
  95. // clang-format on
  96. // Expect "Shift+A".
  97. EXPECT_REPORT(driver, (KC_LSFT, KC_A));
  98. // Turn on Caps Word and tap "A".
  99. caps_word_on();
  100. tap_key(key_a);
  101. testing::Mock::VerifyAndClearExpectations(&driver);
  102. idle_for(CAPS_WORD_IDLE_TIMEOUT);
  103. run_one_scan_loop();
  104. // Caps Word should be off and mods should be clear.
  105. EXPECT_EQ(is_caps_word_on(), false);
  106. EXPECT_EQ(get_mods() | get_weak_mods(), 0);
  107. EXPECT_EMPTY_REPORT(driver).Times(AnyNumber());
  108. // Expect unshifted "A".
  109. EXPECT_REPORT(driver, (KC_A));
  110. tap_key(key_a);
  111. testing::Mock::VerifyAndClearExpectations(&driver);
  112. }
  113. // Tests that typing "A, 4, A, 4" produces "Shift+A, 4, Shift+A, 4".
  114. TEST_F(CapsWord, ShiftsLettersButNotDigits) {
  115. TestDriver driver;
  116. KeymapKey key_a(0, 0, 0, KC_A);
  117. KeymapKey key_4(0, 1, 0, KC_4);
  118. set_keymap({key_a, key_4});
  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, 4, Shift+A, 4".
  127. InSequence s;
  128. EXPECT_REPORT(driver, (KC_LSFT, KC_A));
  129. EXPECT_REPORT(driver, (KC_4));
  130. EXPECT_REPORT(driver, (KC_LSFT, KC_A));
  131. EXPECT_REPORT(driver, (KC_4));
  132. }
  133. // Turn on Caps Word and tap "A, 4, A, 4".
  134. caps_word_on();
  135. tap_keys(key_a, key_4, key_a, key_4);
  136. testing::Mock::VerifyAndClearExpectations(&driver);
  137. }
  138. // Tests that typing "A, Space, A" produces "Shift+A, Space, A".
  139. TEST_F(CapsWord, SpaceTurnsOffCapsWord) {
  140. TestDriver driver;
  141. KeymapKey key_a(0, 0, 0, KC_A);
  142. KeymapKey key_spc(0, 1, 0, KC_SPC);
  143. set_keymap({key_a, key_spc});
  144. // Allow any number of reports with no keys or only KC_LSFT.
  145. // clang-format off
  146. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  147. KeyboardReport(),
  148. KeyboardReport(KC_LSFT))))
  149. .Times(AnyNumber());
  150. // clang-format on
  151. { // Expect: "Shift+A, Space, A".
  152. InSequence seq;
  153. EXPECT_REPORT(driver, (KC_LSFT, KC_A));
  154. EXPECT_REPORT(driver, (KC_SPC));
  155. EXPECT_REPORT(driver, (KC_A));
  156. }
  157. // Turn on Caps Word and tap "A, Space, A".
  158. caps_word_on();
  159. tap_keys(key_a, key_spc, key_a);
  160. testing::Mock::VerifyAndClearExpectations(&driver);
  161. }
  162. // Tests that typing "AltGr + A" produces "Shift + AltGr + A".
  163. TEST_F(CapsWord, ShiftsAltGrSymbols) {
  164. TestDriver driver;
  165. KeymapKey key_a(0, 0, 0, KC_A);
  166. KeymapKey key_altgr(0, 1, 0, KC_RALT);
  167. set_keymap({key_a, key_altgr});
  168. // Allow any number of reports with no keys or only modifiers.
  169. // clang-format off
  170. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  171. KeyboardReport(),
  172. KeyboardReport(KC_RALT),
  173. KeyboardReport(KC_LSFT, KC_RALT))))
  174. .Times(AnyNumber());
  175. // Expect "Shift + AltGr + A".
  176. EXPECT_REPORT(driver, (KC_LSFT, KC_RALT, KC_A));
  177. // clang-format on
  178. // Turn on Caps Word and type "AltGr + A".
  179. caps_word_on();
  180. key_altgr.press();
  181. run_one_scan_loop();
  182. tap_key(key_a);
  183. run_one_scan_loop();
  184. key_altgr.release();
  185. testing::Mock::VerifyAndClearExpectations(&driver);
  186. }
  187. struct CapsWordBothShiftsParams {
  188. std::string name;
  189. uint16_t left_shift_keycode;
  190. uint16_t right_shift_keycode;
  191. static const std::string& GetName(const TestParamInfo<CapsWordBothShiftsParams>& info) {
  192. return info.param.name;
  193. }
  194. };
  195. // Tests the BOTH_SHIFTS_TURNS_ON_CAPS_WORD method to turn on Caps Word.
  196. class CapsWordBothShifts : public ::testing::WithParamInterface<CapsWordBothShiftsParams>, public CapsWord {};
  197. // Pressing shifts as "Left down, Right down, Left up, Right up".
  198. TEST_P(CapsWordBothShifts, PressLRLR) {
  199. TestDriver driver;
  200. KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode);
  201. KeymapKey right_shift(0, 1, 0, GetParam().right_shift_keycode);
  202. set_keymap({left_shift, right_shift});
  203. // clang-format off
  204. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  205. KeyboardReport(),
  206. KeyboardReport(KC_LSFT),
  207. KeyboardReport(KC_RSFT),
  208. KeyboardReport(KC_LSFT, KC_RSFT))))
  209. .Times(AnyNumber());
  210. // clang-format on
  211. EXPECT_EQ(is_caps_word_on(), false);
  212. left_shift.press(); // Press both shifts.
  213. run_one_scan_loop();
  214. right_shift.press();
  215. // For mod-tap and Space Cadet keys, wait for the tapping term.
  216. if (left_shift.code == LSFT_T(KC_A) || left_shift.code == KC_LSPO) {
  217. idle_for(TAPPING_TERM);
  218. }
  219. run_one_scan_loop();
  220. left_shift.release(); // Release both.
  221. run_one_scan_loop();
  222. right_shift.release();
  223. run_one_scan_loop();
  224. EXPECT_EQ(is_caps_word_on(), true);
  225. testing::Mock::VerifyAndClearExpectations(&driver);
  226. }
  227. // Pressing shifts as "Left down, Right down, Right up, Left up".
  228. TEST_P(CapsWordBothShifts, PressLRRL) {
  229. TestDriver driver;
  230. KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode);
  231. KeymapKey right_shift(0, 1, 0, GetParam().right_shift_keycode);
  232. set_keymap({left_shift, right_shift});
  233. // clang-format off
  234. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  235. KeyboardReport(),
  236. KeyboardReport(KC_LSFT),
  237. KeyboardReport(KC_RSFT),
  238. KeyboardReport(KC_LSFT, KC_RSFT))))
  239. .Times(AnyNumber());
  240. // clang-format on
  241. EXPECT_EQ(is_caps_word_on(), false);
  242. left_shift.press(); // Press both shifts.
  243. run_one_scan_loop();
  244. right_shift.press();
  245. if (left_shift.code == LSFT_T(KC_A) || left_shift.code == KC_LSPO) {
  246. idle_for(TAPPING_TERM);
  247. }
  248. run_one_scan_loop();
  249. right_shift.release(); // Release both.
  250. run_one_scan_loop();
  251. left_shift.release();
  252. run_one_scan_loop();
  253. EXPECT_EQ(is_caps_word_on(), true);
  254. testing::Mock::VerifyAndClearExpectations(&driver);
  255. }
  256. // clang-format off
  257. INSTANTIATE_TEST_CASE_P(
  258. ShiftPairs,
  259. CapsWordBothShifts,
  260. ::testing::Values(
  261. CapsWordBothShiftsParams{
  262. "PlainShifts", KC_LSFT, KC_RSFT},
  263. CapsWordBothShiftsParams{
  264. "OneshotShifts", OSM(MOD_LSFT), OSM(MOD_RSFT)},
  265. CapsWordBothShiftsParams{
  266. "SpaceCadetShifts", KC_LSPO, KC_RSPC},
  267. CapsWordBothShiftsParams{
  268. "ModTapShifts", LSFT_T(KC_A), RSFT_T(KC_B)}
  269. ),
  270. CapsWordBothShiftsParams::GetName
  271. );
  272. // clang-format on
  273. struct CapsWordDoubleTapShiftParams {
  274. std::string name;
  275. uint16_t left_shift_keycode;
  276. static const std::string& GetName(const TestParamInfo<CapsWordDoubleTapShiftParams>& info) {
  277. return info.param.name;
  278. }
  279. };
  280. // Tests the DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD method to turn on Caps Word.
  281. class CapsWordDoubleTapShift : public ::testing::WithParamInterface<CapsWordDoubleTapShiftParams>, public CapsWord {};
  282. // Tests that double tapping activates Caps Word.
  283. TEST_P(CapsWordDoubleTapShift, Activation) {
  284. TestDriver driver;
  285. KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode);
  286. set_keymap({left_shift});
  287. // clang-format off
  288. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  289. KeyboardReport(),
  290. KeyboardReport(KC_LSFT))))
  291. .Times(AnyNumber());
  292. // clang-format on
  293. EXPECT_EQ(is_caps_word_on(), false);
  294. // Tapping shift twice within the tapping term turns on Caps Word.
  295. tap_key(left_shift);
  296. idle_for(TAPPING_TERM - 10);
  297. tap_key(left_shift);
  298. EXPECT_EQ(is_caps_word_on(), true);
  299. testing::Mock::VerifyAndClearExpectations(&driver);
  300. }
  301. // Double tap doesn't count if another key is pressed between the taps.
  302. TEST_P(CapsWordDoubleTapShift, Interrupted) {
  303. TestDriver driver;
  304. KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode);
  305. KeymapKey key_a(0, 1, 0, KC_A);
  306. set_keymap({left_shift, key_a});
  307. // clang-format off
  308. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  309. KeyboardReport(),
  310. KeyboardReport(KC_LSFT),
  311. KeyboardReport(KC_LSFT, KC_A))))
  312. .Times(AnyNumber());
  313. // clang-format on
  314. left_shift.press();
  315. run_one_scan_loop();
  316. tap_key(key_a); // 'A' key interrupts the double tap.
  317. left_shift.release();
  318. run_one_scan_loop();
  319. idle_for(TAPPING_TERM - 10);
  320. tap_key(left_shift);
  321. EXPECT_EQ(is_caps_word_on(), false); // Caps Word is still off.
  322. clear_oneshot_mods();
  323. testing::Mock::VerifyAndClearExpectations(&driver);
  324. }
  325. // Double tap doesn't count if taps are more than tapping term apart.
  326. TEST_P(CapsWordDoubleTapShift, SlowTaps) {
  327. TestDriver driver;
  328. KeymapKey left_shift(0, 0, 0, GetParam().left_shift_keycode);
  329. set_keymap({left_shift});
  330. // clang-format off
  331. EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
  332. KeyboardReport(),
  333. KeyboardReport(KC_LSFT))))
  334. .Times(AnyNumber());
  335. // clang-format on
  336. tap_key(left_shift);
  337. idle_for(TAPPING_TERM + 1);
  338. tap_key(left_shift);
  339. EXPECT_EQ(is_caps_word_on(), false); // Caps Word is still off.
  340. clear_oneshot_mods();
  341. testing::Mock::VerifyAndClearExpectations(&driver);
  342. }
  343. // clang-format off
  344. INSTANTIATE_TEST_CASE_P(
  345. Shifts,
  346. CapsWordDoubleTapShift,
  347. ::testing::Values(
  348. CapsWordDoubleTapShiftParams{"PlainShift", KC_LSFT},
  349. CapsWordDoubleTapShiftParams{"OneshotShift", OSM(MOD_LSFT)}
  350. ),
  351. CapsWordDoubleTapShiftParams::GetName
  352. );
  353. // clang-format on