Fix Caps Word capitalization when used with Combos + Auto Shift. (#17549)
This commit is contained in:
		| @@ -123,7 +123,12 @@ bool get_autoshift_shift_state(uint16_t keycode) { | |||||||
| /** \brief Restores the shift key if it was cancelled by Auto Shift */ | /** \brief Restores the shift key if it was cancelled by Auto Shift */ | ||||||
| static void autoshift_flush_shift(void) { | static void autoshift_flush_shift(void) { | ||||||
|     autoshift_flags.holding_shift = false; |     autoshift_flags.holding_shift = false; | ||||||
|     del_weak_mods(MOD_BIT(KC_LSFT)); | #    ifdef CAPS_WORD_ENABLE | ||||||
|  |     if (!is_caps_word_on()) | ||||||
|  | #    endif // CAPS_WORD_ENABLE | ||||||
|  |     { | ||||||
|  |         del_weak_mods(MOD_BIT(KC_LSFT)); | ||||||
|  |     } | ||||||
|     if (autoshift_flags.cancelling_lshift) { |     if (autoshift_flags.cancelling_lshift) { | ||||||
|         autoshift_flags.cancelling_lshift = false; |         autoshift_flags.cancelling_lshift = false; | ||||||
|         add_mods(MOD_BIT(KC_LSFT)); |         add_mods(MOD_BIT(KC_LSFT)); | ||||||
|   | |||||||
| @@ -131,7 +131,11 @@ bool process_caps_word(uint16_t keycode, keyrecord_t* record) { | |||||||
| #endif // SWAP_HANDS_ENABLE | #endif // SWAP_HANDS_ENABLE | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | #ifdef AUTO_SHIFT_ENABLE | ||||||
|  |         del_weak_mods(get_autoshift_state() ? ~MOD_BIT(KC_LSFT) : 0xff); | ||||||
|  | #else | ||||||
|         clear_weak_mods(); |         clear_weak_mods(); | ||||||
|  | #endif // AUTO_SHIFT_ENABLE | ||||||
|         if (caps_word_press_user(keycode)) { |         if (caps_word_press_user(keycode)) { | ||||||
|             send_keyboard_report(); |             send_keyboard_report(); | ||||||
|             return true; |             return true; | ||||||
|   | |||||||
| @@ -227,7 +227,16 @@ static inline void dump_key_buffer(void) { | |||||||
| #endif | #endif | ||||||
|         } |         } | ||||||
|         record->event.time = 0; |         record->event.time = 0; | ||||||
|  |  | ||||||
|  | #if defined(CAPS_WORD_ENABLE) && defined(AUTO_SHIFT_ENABLE) | ||||||
|  |         // Edge case: preserve the weak Left Shift mod if both Caps Word and | ||||||
|  |         // Auto Shift are on. Caps Word capitalizes by setting the weak Left | ||||||
|  |         // Shift mod during the press event, but Auto Shift doesn't send the | ||||||
|  |         // key until it receives the release event. | ||||||
|  |         del_weak_mods((is_caps_word_on() && get_autoshift_state()) ? ~MOD_BIT(KC_LSFT) : 0xff); | ||||||
|  | #else | ||||||
|         clear_weak_mods(); |         clear_weak_mods(); | ||||||
|  | #endif // defined(CAPS_WORD_ENABLE) && defined(AUTO_SHIFT_ENABLE) | ||||||
|  |  | ||||||
| #if TAP_CODE_DELAY > 0 | #if TAP_CODE_DELAY > 0 | ||||||
|         // only delay once and for a non-tapping key |         // only delay once and for a non-tapping key | ||||||
|   | |||||||
| @@ -19,6 +19,14 @@ | |||||||
| #include "test_fixture.hpp" | #include "test_fixture.hpp" | ||||||
| #include "test_keymap_key.hpp" | #include "test_keymap_key.hpp" | ||||||
|  |  | ||||||
|  | // Allow reports with no keys or only KC_LSFT. | ||||||
|  | // clang-format off | ||||||
|  | #define EXPECT_EMPTY_OR_LSFT(driver)              \ | ||||||
|  |     EXPECT_CALL(driver, send_keyboard_mock(AnyOf( \ | ||||||
|  |             KeyboardReport(),                     \ | ||||||
|  |             KeyboardReport(KC_LSFT)))) | ||||||
|  | // clang-format on | ||||||
|  |  | ||||||
| using ::testing::_; | using ::testing::_; | ||||||
| using ::testing::AnyNumber; | using ::testing::AnyNumber; | ||||||
| using ::testing::AnyOf; | using ::testing::AnyOf; | ||||||
| @@ -39,13 +47,7 @@ TEST_F(CapsWord, AutoShiftKeys) { | |||||||
|     KeymapKey  key_spc(0, 1, 0, KC_SPC); |     KeymapKey  key_spc(0, 1, 0, KC_SPC); | ||||||
|     set_keymap({key_a, key_spc}); |     set_keymap({key_a, key_spc}); | ||||||
|  |  | ||||||
|     // Allow any number of reports with no keys or only KC_LSFT. |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|     // clang-format off |  | ||||||
|     EXPECT_CALL(driver, send_keyboard_mock(AnyOf( |  | ||||||
|                 KeyboardReport(), |  | ||||||
|                 KeyboardReport(KC_LSFT)))) |  | ||||||
|         .Times(AnyNumber()); |  | ||||||
|     // clang-format on |  | ||||||
|     { // Expect: "A, A, space, a". |     { // Expect: "A, A, space, a". | ||||||
|         InSequence s; |         InSequence s; | ||||||
|         EXPECT_REPORT(driver, (KC_LSFT, KC_A)); |         EXPECT_REPORT(driver, (KC_LSFT, KC_A)); | ||||||
| @@ -65,6 +67,46 @@ TEST_F(CapsWord, AutoShiftKeys) { | |||||||
|     testing::Mock::VerifyAndClearExpectations(&driver); |     testing::Mock::VerifyAndClearExpectations(&driver); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Test Caps Word + Auto Shift where keys A and B are rolled. | ||||||
|  | TEST_F(CapsWord, AutoShiftRolledShiftedKeys) { | ||||||
|  |     TestDriver driver; | ||||||
|  |     KeymapKey  key_a(0, 0, 0, KC_A); | ||||||
|  |     KeymapKey  key_b(0, 0, 1, KC_B); | ||||||
|  |     set_keymap({key_a, key_b}); | ||||||
|  |  | ||||||
|  |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|  |     { // Expect: "A, B, A, B". | ||||||
|  |         InSequence s; | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_A)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_B)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_A)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_B)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     caps_word_on(); | ||||||
|  |  | ||||||
|  |     key_a.press(); // Overlapping taps: A down, B down, A up, B up. | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |     key_b.press(); | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |     key_a.release(); | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |     key_b.release(); | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |  | ||||||
|  |     key_a.press(); // Nested taps: A down, B down, B up, A up. | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |     key_b.press(); | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |     key_b.release(); | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |     key_a.release(); | ||||||
|  |     run_one_scan_loop(); | ||||||
|  |  | ||||||
|  |     caps_word_off(); | ||||||
|  |     testing::Mock::VerifyAndClearExpectations(&driver); | ||||||
|  | } | ||||||
|  |  | ||||||
| // Tests that with tap-hold keys with Retro Shift, letter keys are shifted by | // Tests that with tap-hold keys with Retro Shift, letter keys are shifted by | ||||||
| // Caps Word regardless of whether they are retroshifted. | // Caps Word regardless of whether they are retroshifted. | ||||||
| TEST_F(CapsWord, RetroShiftKeys) { | TEST_F(CapsWord, RetroShiftKeys) { | ||||||
| @@ -73,13 +115,7 @@ TEST_F(CapsWord, RetroShiftKeys) { | |||||||
|     KeymapKey  key_layertap_b(0, 1, 0, LT(1, KC_B)); |     KeymapKey  key_layertap_b(0, 1, 0, LT(1, KC_B)); | ||||||
|     set_keymap({key_modtap_a, key_layertap_b}); |     set_keymap({key_modtap_a, key_layertap_b}); | ||||||
|  |  | ||||||
|     // Allow any number of reports with no keys or only KC_LSFT. |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|     // clang-format off |  | ||||||
|     EXPECT_CALL(driver, send_keyboard_mock(AnyOf( |  | ||||||
|                 KeyboardReport(), |  | ||||||
|                 KeyboardReport(KC_LSFT)))) |  | ||||||
|         .Times(AnyNumber()); |  | ||||||
|     // clang-format on |  | ||||||
|     { // Expect: "B, A, B, A". |     { // Expect: "B, A, B, A". | ||||||
|         InSequence s; |         InSequence s; | ||||||
|         EXPECT_REPORT(driver, (KC_LSFT, KC_B)); |         EXPECT_REPORT(driver, (KC_LSFT, KC_B)); | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								tests/caps_word/caps_word_combo/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/caps_word/caps_word_combo/config.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | // Copyright 2022 Google LLC | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 2 of the License, or | ||||||
|  | // (at your option) any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "test_common.h" | ||||||
|  |  | ||||||
|  | #define TAPPING_TERM 200 | ||||||
							
								
								
									
										19
									
								
								tests/caps_word/caps_word_combo/test.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/caps_word/caps_word_combo/test.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | # Copyright 2022 Google LLC | ||||||
|  | # | ||||||
|  | # This program is free software: you can redistribute it and/or modify | ||||||
|  | # it under the terms of the GNU General Public License as published by | ||||||
|  | # the Free Software Foundation, either version 2 of the License, or | ||||||
|  | # (at your option) any later version. | ||||||
|  | # | ||||||
|  | # This program is distributed in the hope that it will be useful, | ||||||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | # GNU General Public License for more details. | ||||||
|  | # | ||||||
|  | # You should have received a copy of the GNU General Public License | ||||||
|  | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | CAPS_WORD_ENABLE = yes | ||||||
|  | COMBO_ENABLE = yes | ||||||
|  | AUTO_SHIFT_ENABLE = yes | ||||||
|  |  | ||||||
							
								
								
									
										212
									
								
								tests/caps_word/caps_word_combo/test_caps_word_combo.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								tests/caps_word/caps_word_combo/test_caps_word_combo.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,212 @@ | |||||||
|  | // Copyright 2022 Google LLC | ||||||
|  | // | ||||||
|  | // This program is free software: you can redistribute it and/or modify | ||||||
|  | // it under the terms of the GNU General Public License as published by | ||||||
|  | // the Free Software Foundation, either version 2 of the License, or | ||||||
|  | // (at your option) any later version. | ||||||
|  | // | ||||||
|  | // This program is distributed in the hope that it will be useful, | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  | // GNU General Public License for more details. | ||||||
|  | // | ||||||
|  | // You should have received a copy of the GNU General Public License | ||||||
|  | // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  | ||||||
|  | // Test Caps Word + Combos, with and without Auto Shift. | ||||||
|  |  | ||||||
|  | #include <algorithm> | ||||||
|  | #include <numeric> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include "keyboard_report_util.hpp" | ||||||
|  | #include "keycode.h" | ||||||
|  | #include "test_common.hpp" | ||||||
|  | #include "test_fixture.hpp" | ||||||
|  | #include "test_keymap_key.hpp" | ||||||
|  |  | ||||||
|  | // Allow reports with no keys or only KC_LSFT. | ||||||
|  | // clang-format off | ||||||
|  | #define EXPECT_EMPTY_OR_LSFT(driver)              \ | ||||||
|  |     EXPECT_CALL(driver, send_keyboard_mock(AnyOf( \ | ||||||
|  |             KeyboardReport(),                     \ | ||||||
|  |             KeyboardReport(KC_LSFT)))) | ||||||
|  | // clang-format on | ||||||
|  |  | ||||||
|  | using ::testing::AnyNumber; | ||||||
|  | using ::testing::AnyOf; | ||||||
|  | using ::testing::InSequence; | ||||||
|  | using ::testing::TestParamInfo; | ||||||
|  |  | ||||||
|  | extern "C" { | ||||||
|  | // Define some combos to use for the test, including overlapping combos and | ||||||
|  | // combos that chord tap-hold keys. | ||||||
|  | enum combo_events { AB_COMBO, BC_COMBO, AD_COMBO, DE_COMBO, FGHI_COMBO, COMBO_LENGTH }; | ||||||
|  | uint16_t COMBO_LEN = COMBO_LENGTH; | ||||||
|  |  | ||||||
|  | const uint16_t ab_combo[] PROGMEM   = {KC_A, KC_B, COMBO_END}; | ||||||
|  | const uint16_t bc_combo[] PROGMEM   = {KC_B, KC_C, COMBO_END}; | ||||||
|  | const uint16_t ad_combo[] PROGMEM   = {KC_A, LCTL_T(KC_D), COMBO_END}; | ||||||
|  | const uint16_t de_combo[] PROGMEM   = {LCTL_T(KC_D), LT(1, KC_E), COMBO_END}; | ||||||
|  | const uint16_t fghi_combo[] PROGMEM = {KC_F, KC_G, KC_H, KC_I, COMBO_END}; | ||||||
|  |  | ||||||
|  | // clang-format off | ||||||
|  | combo_t key_combos[] = { | ||||||
|  |     [AB_COMBO] = COMBO(ab_combo, KC_SPC),  // KC_A + KC_B = KC_SPC | ||||||
|  |     [BC_COMBO] = COMBO(bc_combo, KC_X),    // KC_B + KC_C = KC_X | ||||||
|  |     [AD_COMBO] = COMBO(ad_combo, KC_Y),    // KC_A + LCTL_T(KC_D) = KC_Y | ||||||
|  |     [DE_COMBO] = COMBO(de_combo, KC_Z),    // LCTL_T(KC_D) + LT(1, KC_E) = KC_Z | ||||||
|  |     [FGHI_COMBO] = COMBO(fghi_combo, KC_W) // KC_F + KC_G + KC_H + KC_I = KC_W | ||||||
|  | }; | ||||||
|  | // clang-format on | ||||||
|  | } // extern "C" | ||||||
|  |  | ||||||
|  | namespace { | ||||||
|  |  | ||||||
|  | // To test combos thorougly, we test them with pressing the chord keys with | ||||||
|  | // a few different orders and timings. | ||||||
|  | struct TestParams { | ||||||
|  |     std::string name; | ||||||
|  |     bool        autoshift_on; | ||||||
|  |  | ||||||
|  |     static const std::string& GetName(const TestParamInfo<TestParams>& info) { | ||||||
|  |         return info.param.name; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class CapsWord : public ::testing::WithParamInterface<TestParams>, public TestFixture { | ||||||
|  |    public: | ||||||
|  |     void SetUp() override { | ||||||
|  |         caps_word_off(); | ||||||
|  |         if (GetParam().autoshift_on) { | ||||||
|  |             autoshift_enable(); | ||||||
|  |         } else { | ||||||
|  |             autoshift_disable(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // Test pressing the keys in a combo with different orders and timings. | ||||||
|  | TEST_P(CapsWord, SingleCombo) { | ||||||
|  |     TestDriver driver; | ||||||
|  |     KeymapKey  key_b(0, 0, 1, KC_B); | ||||||
|  |     KeymapKey  key_c(0, 0, 2, KC_C); | ||||||
|  |     set_keymap({key_b, key_c}); | ||||||
|  |  | ||||||
|  |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|  |     EXPECT_REPORT(driver, (KC_LSFT, KC_X)); | ||||||
|  |  | ||||||
|  |     caps_word_on(); | ||||||
|  |     tap_combo({key_b, key_c}); | ||||||
|  |  | ||||||
|  |     EXPECT_TRUE(is_caps_word_on()); | ||||||
|  |     caps_word_off(); | ||||||
|  |  | ||||||
|  |     testing::Mock::VerifyAndClearExpectations(&driver); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Test a longer 4-key combo. | ||||||
|  | TEST_P(CapsWord, LongerCombo) { | ||||||
|  |     TestDriver driver; | ||||||
|  |     KeymapKey  key_f(0, 0, 0, KC_F); | ||||||
|  |     KeymapKey  key_g(0, 0, 1, KC_G); | ||||||
|  |     KeymapKey  key_h(0, 0, 2, KC_H); | ||||||
|  |     KeymapKey  key_i(0, 0, 3, KC_I); | ||||||
|  |     set_keymap({key_f, key_g, key_h, key_i}); | ||||||
|  |  | ||||||
|  |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|  |     EXPECT_REPORT(driver, (KC_LSFT, KC_W)); | ||||||
|  |  | ||||||
|  |     caps_word_on(); | ||||||
|  |     tap_combo({key_f, key_g, key_h, key_i}); | ||||||
|  |  | ||||||
|  |     EXPECT_TRUE(is_caps_word_on()); | ||||||
|  |     caps_word_off(); | ||||||
|  |  | ||||||
|  |     testing::Mock::VerifyAndClearExpectations(&driver); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Test with two overlapping combos on regular keys: | ||||||
|  | // KC_A + KC_B = KC_SPC, | ||||||
|  | // KC_B + KC_C = KC_X. | ||||||
|  | TEST_P(CapsWord, ComboRegularKeys) { | ||||||
|  |     TestDriver driver; | ||||||
|  |     KeymapKey  key_a(0, 0, 0, KC_A); | ||||||
|  |     KeymapKey  key_b(0, 0, 1, KC_B); | ||||||
|  |     KeymapKey  key_c(0, 0, 2, KC_C); | ||||||
|  |     KeymapKey  key_1(0, 0, 3, KC_1); | ||||||
|  |     set_keymap({key_a, key_b, key_c, key_1}); | ||||||
|  |  | ||||||
|  |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|  |     { // Expect: "A, B, 1, X, 1, C, space, a". | ||||||
|  |         InSequence s; | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_A)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_B)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_1)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_X)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_1)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_C)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_SPC)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_A)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     caps_word_on(); | ||||||
|  |     tap_key(key_a); | ||||||
|  |     tap_key(key_b); | ||||||
|  |     tap_key(key_1); | ||||||
|  |     tap_combo({key_b, key_c}); // BC combo types "x". | ||||||
|  |     tap_key(key_1); | ||||||
|  |     tap_key(key_c); | ||||||
|  |     tap_combo({key_a, key_b}); // AB combo types space. | ||||||
|  |     tap_key(key_a); | ||||||
|  |  | ||||||
|  |     EXPECT_FALSE(is_caps_word_on()); | ||||||
|  |     testing::Mock::VerifyAndClearExpectations(&driver); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Test where combo chords involve tap-hold keys: | ||||||
|  | // KC_A + LCTL_T(KC_D) = KC_Y, | ||||||
|  | // LCTL_T(KC_D) + LT(1, KC_E) = KC_Z, | ||||||
|  | TEST_P(CapsWord, ComboModTapKey) { | ||||||
|  |     TestDriver driver; | ||||||
|  |     KeymapKey  key_a(0, 0, 0, KC_A); | ||||||
|  |     KeymapKey  key_modtap_d(0, 0, 1, LCTL_T(KC_D)); | ||||||
|  |     KeymapKey  key_layertap_e(0, 0, 2, LT(1, KC_E)); | ||||||
|  |     set_keymap({key_a, key_modtap_d, key_layertap_e}); | ||||||
|  |  | ||||||
|  |     EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber()); | ||||||
|  |     { // Expect: "A, D, E, Y, Z". | ||||||
|  |         InSequence s; | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_A)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_D)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_E)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_Y)); | ||||||
|  |         EXPECT_REPORT(driver, (KC_LSFT, KC_Z)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     caps_word_on(); | ||||||
|  |     tap_key(key_a); | ||||||
|  |     tap_key(key_modtap_d); | ||||||
|  |     tap_key(key_layertap_e); | ||||||
|  |     tap_combo({key_a, key_modtap_d});          // AD combo types "y". | ||||||
|  |     tap_combo({key_modtap_d, key_layertap_e}); // DE combo types "z". | ||||||
|  |  | ||||||
|  |     EXPECT_TRUE(is_caps_word_on()); | ||||||
|  |     caps_word_off(); | ||||||
|  |  | ||||||
|  |     testing::Mock::VerifyAndClearExpectations(&driver); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // clang-format off | ||||||
|  | INSTANTIATE_TEST_CASE_P( | ||||||
|  |     Combos, | ||||||
|  |     CapsWord, | ||||||
|  |     ::testing::Values( | ||||||
|  |         TestParams{"AutoshiftDisabled", false}, | ||||||
|  |         TestParams{"AutoshiftEnabled", true} | ||||||
|  |         ), | ||||||
|  |     TestParams::GetName | ||||||
|  |     ); | ||||||
|  | // clang-format on | ||||||
|  |  | ||||||
|  | } // namespace | ||||||
| @@ -108,6 +108,22 @@ void TestFixture::tap_key(KeymapKey key, unsigned delay_ms) { | |||||||
|     run_one_scan_loop(); |     run_one_scan_loop(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void TestFixture::tap_combo(const std::vector<KeymapKey>& chord_keys, unsigned delay_ms) { | ||||||
|  |     for (KeymapKey key : chord_keys) { // Press each key. | ||||||
|  |         key.press(); | ||||||
|  |         run_one_scan_loop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (delay_ms > 1) { | ||||||
|  |         idle_for(delay_ms - 1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     for (KeymapKey key : chord_keys) { // Release each key. | ||||||
|  |         key.release(); | ||||||
|  |         run_one_scan_loop(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| void TestFixture::set_keymap(std::initializer_list<KeymapKey> keys) { | void TestFixture::set_keymap(std::initializer_list<KeymapKey> keys) { | ||||||
|     this->keymap.clear(); |     this->keymap.clear(); | ||||||
|     for (auto& key : keys) { |     for (auto& key : keys) { | ||||||
|   | |||||||
| @@ -53,6 +53,13 @@ class TestFixture : public testing::Test { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @brief Taps a combo with `delay_ms` delay between press and release. | ||||||
|  |      * | ||||||
|  |      * Example: `tap_combo({key_a, key_b})` to tap the chord A + B. | ||||||
|  |      */ | ||||||
|  |     void tap_combo(const std::vector<KeymapKey>& chord_keys, unsigned delay_ms = 1); | ||||||
|  |  | ||||||
|     void run_one_scan_loop(); |     void run_one_scan_loop(); | ||||||
|     void idle_for(unsigned ms); |     void idle_for(unsigned ms); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user