test_alt_repeat_key.cpp (18170B)
1 // Copyright 2023 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 <functional> 17 18 #include "keyboard_report_util.hpp" 19 #include "keycode.h" 20 #include "test_common.hpp" 21 #include "test_fixture.hpp" 22 #include "test_keymap_key.hpp" 23 24 using ::testing::AnyNumber; 25 using ::testing::InSequence; 26 27 namespace { 28 29 bool process_record_user_default(uint16_t keycode, keyrecord_t* record) { 30 return true; 31 } 32 33 bool remember_last_key_user_default(uint16_t keycode, keyrecord_t* record, uint8_t* remembered_mods) { 34 return true; 35 } 36 37 uint16_t get_alt_repeat_key_keycode_user_default(uint16_t keycode, uint8_t mods) { 38 return KC_TRNS; 39 } 40 41 // Indirections so that process_record_user() can be replaced with other 42 // functions in the test cases below. 43 std::function<bool(uint16_t, keyrecord_t*)> process_record_user_fun = process_record_user_default; 44 std::function<bool(uint16_t, keyrecord_t*, uint8_t*)> remember_last_key_user_fun = remember_last_key_user_default; 45 std::function<uint16_t(uint16_t, uint8_t)> get_alt_repeat_key_keycode_user_fun = get_alt_repeat_key_keycode_user_default; 46 47 extern "C" bool process_record_user(uint16_t keycode, keyrecord_t* record) { 48 return process_record_user_fun(keycode, record); 49 } 50 51 extern "C" bool remember_last_key_user(uint16_t keycode, keyrecord_t* record, uint8_t* remembered_mods) { 52 return remember_last_key_user_fun(keycode, record, remembered_mods); 53 } 54 55 extern "C" uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) { 56 return get_alt_repeat_key_keycode_user_fun(keycode, mods); 57 } 58 59 class AltRepeatKey : public TestFixture { 60 public: 61 bool process_record_user_was_called_; 62 63 void SetUp() override { 64 process_record_user_fun = process_record_user_default; 65 remember_last_key_user_fun = remember_last_key_user_default; 66 get_alt_repeat_key_keycode_user_fun = get_alt_repeat_key_keycode_user_default; 67 } 68 69 void ExpectProcessRecordUserCalledWith(bool expected_press, uint16_t expected_keycode, int8_t expected_repeat_key_count) { 70 process_record_user_was_called_ = false; 71 process_record_user_fun = [=](uint16_t keycode, keyrecord_t* record) { 72 EXPECT_EQ(record->event.pressed, expected_press); 73 EXPECT_KEYCODE_EQ(keycode, expected_keycode); 74 EXPECT_EQ(get_repeat_key_count(), expected_repeat_key_count); 75 // Tests below use this to verify process_record_user() was called. 76 process_record_user_was_called_ = true; 77 return true; 78 }; 79 } 80 81 // Expects that the characters of `s` are sent. 82 // NOTE: This implementation is limited to chars a-z, A-Z. 83 void ExpectString(TestDriver& driver, const std::string& s) { 84 InSequence seq; 85 for (int c : s) { 86 switch (c) { 87 case 'a' ... 'z': { // Lowercase letter. 88 uint16_t keycode = c - ('a' - KC_A); 89 EXPECT_REPORT(driver, (keycode)); 90 } break; 91 92 case 'A' ... 'Z': { // Capital letter = KC_LSFT + letter key. 93 uint16_t keycode = c - ('A' - KC_A); 94 EXPECT_REPORT(driver, (KC_LSFT, keycode)); 95 } break; 96 } 97 } 98 } 99 }; 100 101 TEST_F(AltRepeatKey, AlternateBasic) { 102 TestDriver driver; 103 KeymapKey key_bspc(0, 0, 0, KC_BSPC); 104 KeymapKey key_pgdn(0, 1, 0, KC_PGDN); 105 KeymapKey key_pgup(0, 2, 0, KC_PGUP); 106 KeymapKey key_repeat(0, 4, 0, QK_REP); 107 KeymapKey key_alt_repeat(0, 5, 0, QK_AREP); 108 set_keymap({key_bspc, key_pgdn, key_pgup, key_repeat, key_alt_repeat}); 109 110 // Allow any number of empty reports. 111 EXPECT_EMPTY_REPORT(driver).Times(AnyNumber()); 112 { 113 InSequence seq; 114 EXPECT_REPORT(driver, (KC_BSPC)); 115 EXPECT_REPORT(driver, (KC_DEL)); 116 EXPECT_REPORT(driver, (KC_DEL)); 117 EXPECT_REPORT(driver, (KC_BSPC)); 118 EXPECT_REPORT(driver, (KC_DEL)); 119 EXPECT_REPORT(driver, (KC_PGDN)); 120 EXPECT_REPORT(driver, (KC_PGUP)); 121 EXPECT_REPORT(driver, (KC_PGUP)); 122 EXPECT_REPORT(driver, (KC_PGDN)); 123 } 124 125 tap_key(key_bspc); 126 127 for (int n = 1; n <= 2; ++n) { // Tap the Alternate Repeat Key twice. 128 ExpectProcessRecordUserCalledWith(true, KC_DEL, -n); 129 key_alt_repeat.press(); // Press the Alternate Repeat Key. 130 run_one_scan_loop(); 131 EXPECT_TRUE(process_record_user_was_called_); 132 133 // Expect the corresponding release event. 134 ExpectProcessRecordUserCalledWith(false, KC_DEL, -n); 135 key_alt_repeat.release(); // Release the Repeat Key. 136 run_one_scan_loop(); 137 EXPECT_TRUE(process_record_user_was_called_); 138 } 139 140 process_record_user_fun = process_record_user_default; 141 tap_keys(key_repeat, key_alt_repeat); 142 tap_keys(key_pgdn, key_alt_repeat); 143 tap_keys(key_pgup, key_alt_repeat); 144 145 testing::Mock::VerifyAndClearExpectations(&driver); 146 } 147 148 struct TestParamsAlternateKeyCodes { 149 uint16_t keycode; 150 uint8_t mods; 151 uint16_t expected_alt_keycode; 152 }; 153 154 // Tests `get_alt_repeat_key_keycode()` for various keycodes. 155 TEST_F(AltRepeatKey, GetAltRepeatKeyKeycode) { 156 for (const auto& params : std::vector<TestParamsAlternateKeyCodes>({ 157 // clang-format off 158 // Each line tests one call to `get_alt_repeat_key_keycode()`: 159 // {keycode, mods, expected_alt_keycode}. 160 // Arrows. 161 {KC_LEFT, 0, KC_RGHT}, 162 {KC_RGHT, 0, KC_LEFT}, 163 {KC_LEFT, MOD_BIT(KC_LSFT), LSFT(KC_RGHT)}, 164 {KC_LEFT, MOD_BIT(KC_RSFT), RSFT(KC_RGHT)}, 165 {KC_LEFT, MOD_BIT(KC_LCTL) | MOD_BIT(KC_LSFT), C(S(KC_RGHT))}, 166 {KC_LEFT, MOD_BIT(KC_LGUI), LGUI(KC_RGHT)}, 167 {C(KC_LEFT), MOD_BIT(KC_LSFT), C(S(KC_RGHT))}, 168 {KC_UP, 0, KC_DOWN}, 169 // Navigation keys. 170 {KC_PGUP, 0, KC_PGDN}, 171 {KC_HOME, 0, KC_END }, 172 // Media keys. 173 {KC_WBAK, 0, KC_WFWD}, 174 {KC_MNXT, 0, KC_MPRV}, 175 {KC_MRWD, 0, KC_MFFD}, 176 {KC_VOLU, 0, KC_VOLD}, 177 {KC_BRIU, 0, KC_BRID}, 178 // Emacs navigation. 179 {KC_N, MOD_BIT(KC_LCTL), C(KC_P)}, 180 {KC_B, MOD_BIT(KC_LCTL), LCTL(KC_F)}, 181 {KC_B, MOD_BIT(KC_RCTL), RCTL(KC_F)}, 182 {KC_B, MOD_BIT(KC_LALT), LALT(KC_F)}, 183 {KC_F, MOD_BIT(KC_LCTL), C(KC_B)}, 184 {KC_A, MOD_BIT(KC_LCTL), C(KC_E)}, 185 {KC_D, MOD_BIT(KC_LCTL), C(KC_U)}, 186 // Vim navigation. 187 {KC_J, 0, KC_K}, 188 {KC_K, 0, KC_J}, 189 {KC_H, 0, KC_L}, 190 {KC_B, 0, KC_W}, 191 {KC_W, 0, KC_B}, 192 {KC_E, 0, KC_B}, 193 {KC_B, MOD_BIT(KC_LSFT), S(KC_W)}, 194 {KC_W, MOD_BIT(KC_LSFT), S(KC_B)}, 195 {KC_E, MOD_BIT(KC_LSFT), S(KC_B)}, 196 {KC_O, MOD_BIT(KC_LCTL), C(KC_I)}, 197 {KC_I, MOD_BIT(KC_LCTL), C(KC_O)}, 198 // Other. 199 {KC_DEL, 0, KC_BSPC}, 200 {KC_LBRC, 0, KC_RBRC}, 201 {KC_LCBR, 0, KC_RCBR}, 202 // Some keys where the last key is a tap-hold key. 203 {LSFT_T(KC_F), MOD_BIT(KC_RCTL), RCTL(KC_B)}, 204 {LT(1, KC_A), MOD_BIT(KC_RGUI), RGUI(KC_E)}, 205 {RALT_T(KC_J), 0, KC_K}, 206 // Some keys where no alternate is defined. 207 {KC_A, 0, KC_NO}, 208 {KC_F1, 0, KC_NO}, 209 {QK_LEAD, 0, KC_NO}, 210 {MO(1), 0, KC_NO}, 211 // clang-format on 212 })) { 213 SCOPED_TRACE(std::string("Input keycode: ") + get_keycode_string(params.keycode)); 214 set_last_keycode(params.keycode); 215 set_last_mods(params.mods); 216 217 const uint16_t actual = get_alt_repeat_key_keycode(); 218 219 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), params.expected_alt_keycode); 220 } 221 } 222 223 // Test adding to and overriding the above through the 224 // `get_alt_repeat_key_keycode_user()` callback. 225 TEST_F(AltRepeatKey, GetAltRepeatKeyKeycodeUser) { 226 get_alt_repeat_key_keycode_user_fun = [](uint16_t keycode, uint8_t mods) -> uint16_t { 227 bool shifted = (mods & MOD_MASK_SHIFT); 228 switch (keycode) { 229 case KC_LEFT: 230 return KC_ENT; 231 case MO(1): 232 return TG(1); 233 case KC_TAB: // Tab <-> Shift + Tab example. 234 if (shifted) { 235 return KC_TAB; 236 } else { 237 return S(KC_TAB); 238 } 239 } 240 241 // Ctrl + Y <-> Ctrl + Z example. 242 if ((mods & MOD_MASK_CTRL)) { 243 switch (keycode) { 244 case KC_Y: 245 return C(KC_Z); 246 case KC_Z: 247 return C(KC_Y); 248 } 249 } 250 251 return KC_NO; 252 }; 253 254 set_last_keycode(KC_LEFT); 255 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), KC_ENT); 256 257 set_last_keycode(MO(1)); 258 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), TG(1)); 259 260 set_last_keycode(KC_TAB); 261 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), S(KC_TAB)); 262 263 set_last_keycode(KC_TAB); 264 set_last_mods(MOD_BIT(KC_LSFT)); 265 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), KC_TAB); 266 267 set_last_keycode(KC_Z); 268 set_last_mods(MOD_BIT(KC_LCTL)); 269 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), C(KC_Y)); 270 271 set_last_keycode(KC_Y); 272 set_last_mods(MOD_BIT(KC_LCTL)); 273 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), C(KC_Z)); 274 } 275 276 // Tests rolling from a key to Alternate Repeat. 277 TEST_F(AltRepeatKey, RollingToAltRepeat) { 278 TestDriver driver; 279 KeymapKey key_left(0, 0, 0, KC_LEFT); 280 KeymapKey key_alt_repeat(0, 1, 0, QK_AREP); 281 set_keymap({key_left, key_alt_repeat}); 282 283 { 284 InSequence seq; 285 EXPECT_REPORT(driver, (KC_LEFT)); 286 EXPECT_REPORT(driver, (KC_LEFT, KC_RGHT)); 287 EXPECT_REPORT(driver, (KC_RGHT)); 288 EXPECT_EMPTY_REPORT(driver); 289 EXPECT_REPORT(driver, (KC_RGHT)); 290 EXPECT_EMPTY_REPORT(driver); 291 } 292 293 // Perform a rolled press from Left to Alternate Repeat. 294 295 ExpectProcessRecordUserCalledWith(true, KC_LEFT, 0); 296 key_left.press(); 297 run_one_scan_loop(); 298 EXPECT_TRUE(process_record_user_was_called_); 299 300 ExpectProcessRecordUserCalledWith(true, KC_RGHT, -1); 301 key_alt_repeat.press(); // Press the Alternate Repeat Key. 302 run_one_scan_loop(); 303 EXPECT_TRUE(process_record_user_was_called_); 304 305 ExpectProcessRecordUserCalledWith(false, KC_LEFT, 0); 306 key_left.release(); 307 run_one_scan_loop(); 308 EXPECT_TRUE(process_record_user_was_called_); 309 310 ExpectProcessRecordUserCalledWith(false, KC_RGHT, -1); 311 key_alt_repeat.release(); // Release the Alternate Repeat Key. 312 run_one_scan_loop(); 313 EXPECT_TRUE(process_record_user_was_called_); 314 315 process_record_user_fun = process_record_user_default; 316 tap_key(key_alt_repeat); 317 318 testing::Mock::VerifyAndClearExpectations(&driver); 319 } 320 321 // Tests rolling from Alternate Repeat to another key. 322 TEST_F(AltRepeatKey, RollingFromAltRepeat) { 323 TestDriver driver; 324 KeymapKey key_left(0, 0, 0, KC_LEFT); 325 KeymapKey key_up(0, 1, 0, KC_UP); 326 KeymapKey key_alt_repeat(0, 2, 0, QK_AREP); 327 set_keymap({key_left, key_up, key_alt_repeat}); 328 329 { 330 InSequence seq; 331 EXPECT_REPORT(driver, (KC_LEFT)); 332 EXPECT_EMPTY_REPORT(driver); 333 EXPECT_REPORT(driver, (KC_RGHT)); 334 EXPECT_REPORT(driver, (KC_RGHT, KC_UP)); 335 EXPECT_REPORT(driver, (KC_UP)); 336 EXPECT_EMPTY_REPORT(driver); 337 EXPECT_REPORT(driver, (KC_DOWN)); 338 EXPECT_EMPTY_REPORT(driver); 339 } 340 341 tap_key(key_left); 342 343 // Perform a rolled press from Alternate Repeat to Up. 344 345 ExpectProcessRecordUserCalledWith(true, KC_RGHT, -1); 346 key_alt_repeat.press(); // Press the Alternate Repeat Key. 347 run_one_scan_loop(); 348 EXPECT_TRUE(process_record_user_was_called_); 349 350 ExpectProcessRecordUserCalledWith(true, KC_UP, 0); 351 key_up.press(); 352 run_one_scan_loop(); 353 EXPECT_TRUE(process_record_user_was_called_); 354 355 EXPECT_KEYCODE_EQ(get_last_keycode(), KC_UP); 356 357 ExpectProcessRecordUserCalledWith(false, KC_RGHT, -1); 358 key_alt_repeat.release(); // Release the Alternate Repeat Key. 359 run_one_scan_loop(); 360 EXPECT_TRUE(process_record_user_was_called_); 361 362 ExpectProcessRecordUserCalledWith(false, KC_UP, 0); 363 key_up.release(); 364 run_one_scan_loop(); 365 EXPECT_TRUE(process_record_user_was_called_); 366 367 process_record_user_fun = process_record_user_default; 368 tap_key(key_alt_repeat); 369 370 testing::Mock::VerifyAndClearExpectations(&driver); 371 } 372 373 // Tests using the Alternate Repeat Key on a macro that doesn't have an 374 // alternate keycode defined. 375 TEST_F(AltRepeatKey, AlternateUnsupportedMacro) { 376 TestDriver driver; 377 KeymapKey key_foo(0, 0, 0, QK_USER_0); 378 KeymapKey key_alt_repeat(0, 1, 0, QK_AREP); 379 set_keymap({key_foo, key_alt_repeat}); 380 381 process_record_user_fun = [=](uint16_t keycode, keyrecord_t* record) { 382 process_record_user_was_called_ = true; 383 switch (keycode) { 384 case QK_USER_0: 385 if (record->event.pressed) { 386 SEND_STRING("foo"); 387 } 388 break; 389 } 390 return true; 391 }; 392 393 // Allow any number of empty reports. 394 EXPECT_EMPTY_REPORT(driver).Times(AnyNumber()); 395 ExpectString(driver, "foofoo"); 396 397 process_record_user_was_called_ = false; 398 tap_key(key_foo); 399 400 EXPECT_TRUE(process_record_user_was_called_); 401 EXPECT_KEYCODE_EQ(get_last_keycode(), QK_USER_0); 402 EXPECT_KEYCODE_EQ(get_alt_repeat_key_keycode(), KC_NO); 403 404 process_record_user_was_called_ = false; 405 key_alt_repeat.press(); // Press Alternate Repeat. 406 run_one_scan_loop(); 407 408 EXPECT_FALSE(process_record_user_was_called_); 409 410 process_record_user_was_called_ = false; 411 key_alt_repeat.release(); // Release Alternate Repeat. 412 run_one_scan_loop(); 413 414 EXPECT_FALSE(process_record_user_was_called_); 415 416 process_record_user_was_called_ = false; 417 tap_key(key_foo); 418 419 EXPECT_TRUE(process_record_user_was_called_); 420 421 testing::Mock::VerifyAndClearExpectations(&driver); 422 } 423 424 // Tests a macro with custom alternate behavior. 425 TEST_F(AltRepeatKey, MacroCustomAlternate) { 426 TestDriver driver; 427 KeymapKey key_foo(0, 0, 0, QK_USER_0); 428 KeymapKey key_alt_repeat(0, 1, 0, QK_AREP); 429 set_keymap({key_foo, key_alt_repeat}); 430 431 get_alt_repeat_key_keycode_user_fun = [](uint16_t keycode, uint8_t mods) -> uint16_t { 432 switch (keycode) { 433 case QK_USER_0: 434 return QK_USER_0; // QK_USER_0 handles its own alternate. 435 default: 436 return KC_NO; // No key by default. 437 } 438 }; 439 process_record_user_fun = [=](uint16_t keycode, keyrecord_t* record) { 440 process_record_user_was_called_ = true; 441 switch (keycode) { 442 case QK_USER_0: 443 if (record->event.pressed) { 444 if (get_repeat_key_count() >= 0) { 445 SEND_STRING("foo"); 446 } else { // Key is being alternate repeated. 447 SEND_STRING("bar"); 448 } 449 } 450 break; 451 } 452 return true; 453 }; 454 455 // Allow any number of empty reports. 456 EXPECT_EMPTY_REPORT(driver).Times(AnyNumber()); 457 ExpectString(driver, "foobarbar"); 458 459 tap_keys(key_foo, key_alt_repeat, key_alt_repeat); 460 461 testing::Mock::VerifyAndClearExpectations(&driver); 462 } 463 464 // Tests the Additional "Alternate" keys example from the documentation page. 465 TEST_F(AltRepeatKey, AdditionalAlternateKeysExample) { 466 TestDriver driver; 467 KeymapKey key_a(0, 0, 0, KC_A); 468 KeymapKey key_w(0, 1, 0, KC_W); 469 KeymapKey key_altrep2(0, 2, 0, QK_USER_0); 470 KeymapKey key_altrep3(0, 3, 0, QK_USER_1); 471 set_keymap({key_a, key_w, key_altrep2, key_altrep3}); 472 473 remember_last_key_user_fun = [](uint16_t keycode, keyrecord_t* record, uint8_t* remembered_mods) { 474 switch (keycode) { 475 case QK_USER_0: 476 case QK_USER_1: 477 return false; // Ignore ALTREP keys. 478 } 479 return true; // Other keys can be repeated. 480 }; 481 process_record_user_fun = [=](uint16_t keycode, keyrecord_t* record) { 482 switch (keycode) { 483 case QK_USER_0: 484 if (record->event.pressed) { 485 const uint16_t last_key = get_last_keycode(); 486 switch (last_key) { 487 case KC_A: 488 SEND_STRING(/*a*/ "tion"); 489 break; 490 case KC_W: 491 SEND_STRING(/*w*/ "hich"); 492 break; 493 } 494 } 495 return false; 496 case QK_USER_1: 497 if (record->event.pressed) { 498 const uint16_t last_key = get_last_keycode(); 499 switch (last_key) { 500 case KC_A: 501 SEND_STRING(/*a*/ "bout"); 502 break; 503 case KC_W: 504 SEND_STRING(/*w*/ "ould"); 505 break; 506 } 507 } 508 return false; 509 } 510 return true; 511 }; 512 513 // Allow any number of empty reports. 514 EXPECT_EMPTY_REPORT(driver).Times(AnyNumber()); 515 ExpectString(driver, "ationwhichaboutwould"); 516 517 tap_keys(key_a, key_altrep2, key_w, key_altrep2); 518 tap_keys(key_a, key_altrep3, key_w, key_altrep3); 519 520 testing::Mock::VerifyAndClearExpectations(&driver); 521 } 522 523 } // namespace