summaryrefslogtreecommitdiff
path: root/tests/caps_word
diff options
context:
space:
mode:
Diffstat (limited to 'tests/caps_word')
-rw-r--r--tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp64
-rw-r--r--tests/caps_word/caps_word_combo/config.h20
-rw-r--r--tests/caps_word/caps_word_combo/test.mk19
-rw-r--r--tests/caps_word/caps_word_combo/test_caps_word_combo.cpp212
-rw-r--r--tests/caps_word/test_caps_word.cpp159
5 files changed, 460 insertions, 14 deletions
diff --git a/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp b/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp
index deb4d95766..ba21c527a6 100644
--- a/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp
+++ b/tests/caps_word/caps_word_autoshift/test_caps_word_autoshift.cpp
@@ -19,6 +19,14 @@
#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::_;
using ::testing::AnyNumber;
using ::testing::AnyOf;
@@ -39,13 +47,7 @@ TEST_F(CapsWord, AutoShiftKeys) {
KeymapKey key_spc(0, 1, 0, KC_SPC);
set_keymap({key_a, key_spc});
- // Allow any number of reports with no keys or only KC_LSFT.
- // clang-format off
- EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
- KeyboardReport(),
- KeyboardReport(KC_LSFT))))
- .Times(AnyNumber());
- // clang-format on
+ EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber());
{ // Expect: "A, A, space, a".
InSequence s;
EXPECT_REPORT(driver, (KC_LSFT, KC_A));
@@ -65,6 +67,46 @@ TEST_F(CapsWord, AutoShiftKeys) {
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
// Caps Word regardless of whether they are retroshifted.
TEST_F(CapsWord, RetroShiftKeys) {
@@ -73,13 +115,7 @@ TEST_F(CapsWord, RetroShiftKeys) {
KeymapKey key_layertap_b(0, 1, 0, LT(1, KC_B));
set_keymap({key_modtap_a, key_layertap_b});
- // Allow any number of reports with no keys or only KC_LSFT.
- // clang-format off
- EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
- KeyboardReport(),
- KeyboardReport(KC_LSFT))))
- .Times(AnyNumber());
- // clang-format on
+ EXPECT_EMPTY_OR_LSFT(driver).Times(AnyNumber());
{ // Expect: "B, A, B, A".
InSequence s;
EXPECT_REPORT(driver, (KC_LSFT, KC_B));
diff --git a/tests/caps_word/caps_word_combo/config.h b/tests/caps_word/caps_word_combo/config.h
new file mode 100644
index 0000000000..92dbe045b2
--- /dev/null
+++ b/tests/caps_word/caps_word_combo/config.h
@@ -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
diff --git a/tests/caps_word/caps_word_combo/test.mk b/tests/caps_word/caps_word_combo/test.mk
new file mode 100644
index 0000000000..9f2e157189
--- /dev/null
+++ b/tests/caps_word/caps_word_combo/test.mk
@@ -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
+
diff --git a/tests/caps_word/caps_word_combo/test_caps_word_combo.cpp b/tests/caps_word/caps_word_combo/test_caps_word_combo.cpp
new file mode 100644
index 0000000000..3a0530b854
--- /dev/null
+++ b/tests/caps_word/caps_word_combo/test_caps_word_combo.cpp
@@ -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
diff --git a/tests/caps_word/test_caps_word.cpp b/tests/caps_word/test_caps_word.cpp
index 0af4b0175d..3f59ed3744 100644
--- a/tests/caps_word/test_caps_word.cpp
+++ b/tests/caps_word/test_caps_word.cpp
@@ -25,10 +25,47 @@ using ::testing::AnyOf;
using ::testing::InSequence;
using ::testing::TestParamInfo;
+namespace {
+
+bool press_user_default(uint16_t keycode) {
+ switch (keycode) {
+ // Keycodes that continue Caps Word, with shift applied.
+ case KC_A ... KC_Z:
+ case KC_MINS:
+ add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
+ return true;
+
+ // Keycodes that continue Caps Word, without shifting.
+ case KC_1 ... KC_0:
+ case KC_BSPC:
+ case KC_DEL:
+ case KC_UNDS:
+ return true;
+
+ default:
+ return false; // Deactivate Caps Word.
+ }
+}
+
+uint16_t passed_keycode;
+bool press_user_save_passed_keycode(uint16_t keycode) {
+ passed_keycode = keycode;
+ return true;
+}
+
+bool (*press_user_fun)(uint16_t) = press_user_default;
+
+extern "C" {
+bool caps_word_press_user(uint16_t keycode) {
+ return press_user_fun(keycode);
+}
+} // extern "C"
+
class CapsWord : public TestFixture {
public:
void SetUp() override {
caps_word_off();
+ press_user_fun = press_user_default;
}
};
@@ -226,6 +263,126 @@ TEST_F(CapsWord, ShiftsAltGrSymbols) {
testing::Mock::VerifyAndClearExpectations(&driver);
}
+// Tests typing "AltGr + A" using a mod-tap key.
+TEST_F(CapsWord, ShiftsModTapAltGrSymbols) {
+ TestDriver driver;
+ KeymapKey key_a(0, 0, 0, KC_A);
+ KeymapKey key_altgr_t(0, 1, 0, RALT_T(KC_B));
+ set_keymap({key_a, key_altgr_t});
+
+ // Allow any number of reports with no keys or only modifiers.
+ // clang-format off
+ EXPECT_CALL(driver, send_keyboard_mock(AnyOf(
+ KeyboardReport(),
+ KeyboardReport(KC_RALT),
+ KeyboardReport(KC_LSFT, KC_RALT))))
+ .Times(AnyNumber());
+ // Expect "Shift + AltGr + A".
+ EXPECT_REPORT(driver, (KC_LSFT, KC_RALT, KC_A));
+ // clang-format on
+
+ // Turn on Caps Word and type "AltGr + A".
+ caps_word_on();
+
+ key_altgr_t.press();
+ idle_for(TAPPING_TERM + 1);
+ tap_key(key_a);
+ run_one_scan_loop();
+ key_altgr_t.release();
+
+ EXPECT_TRUE(is_caps_word_on());
+ testing::Mock::VerifyAndClearExpectations(&driver);
+}
+
+struct CapsWordPressUserParams {
+ std::string name;
+ uint16_t keycode;
+ uint16_t delay_ms;
+ uint16_t expected_passed_keycode;
+ bool continues_caps_word;
+
+ static const std::string& GetName(const TestParamInfo<CapsWordPressUserParams>& info) {
+ return info.param.name;
+ }
+};
+
+class CapsWordPressUser : public ::testing::WithParamInterface<CapsWordPressUserParams>, public CapsWord {
+ void SetUp() override {
+ caps_word_on();
+ passed_keycode = KC_NO;
+ press_user_fun = press_user_save_passed_keycode;
+ }
+};
+
+// Tests keycodes passed to caps_word_press_user() function for various keys.
+TEST_P(CapsWordPressUser, KeyCode) {
+ TestDriver driver;
+ KeymapKey key(0, 0, 0, GetParam().keycode);
+ set_keymap({key});
+
+ EXPECT_ANY_REPORT(driver).Times(AnyNumber());
+ tap_key(key, GetParam().delay_ms);
+
+ EXPECT_EQ(passed_keycode, GetParam().expected_passed_keycode);
+ EXPECT_EQ(is_caps_word_on(), GetParam().continues_caps_word);
+ clear_oneshot_mods();
+ testing::Mock::VerifyAndClearExpectations(&driver);
+}
+
+const uint16_t LT_1_KC_A = LT(1, KC_A);
+// clang-format off
+INSTANTIATE_TEST_CASE_P(
+ PressUser,
+ CapsWordPressUser,
+ ::testing::Values(
+ CapsWordPressUserParams{
+ "KC_A", KC_A, 1, KC_A, true},
+ CapsWordPressUserParams{
+ "KC_HASH", KC_HASH, 1, KC_HASH, true},
+ CapsWordPressUserParams{
+ "KC_LSFT", KC_LSFT, 1, KC_LSFT, true},
+ CapsWordPressUserParams{
+ "KC_RSFT", KC_RSFT, 1, KC_RSFT, true},
+ CapsWordPressUserParams{
+ "LSFT_T_tapped", LSFT_T(KC_A), 1, KC_A, true},
+ CapsWordPressUserParams{
+ "LSFT_T_held", LSFT_T(KC_A), TAPPING_TERM + 1, KC_LSFT, true},
+ CapsWordPressUserParams{
+ "RSFT_T_held", RSFT_T(KC_A), TAPPING_TERM + 1, KC_RSFT, true},
+ CapsWordPressUserParams{
+ "RSA_T_held", RSA_T(KC_A), TAPPING_TERM + 1, RSFT(KC_RALT), true},
+ // Holding a mod-tap other than Shift or AltGr stops Caps Word.
+ CapsWordPressUserParams{
+ "LCTL_T_held", LCTL_T(KC_A), TAPPING_TERM + 1, KC_NO, false},
+ CapsWordPressUserParams{
+ "LALT_T_held", LALT_T(KC_A), TAPPING_TERM + 1, KC_NO, false},
+ CapsWordPressUserParams{
+ "LGUI_T_held", LGUI_T(KC_A), TAPPING_TERM + 1, KC_NO, false},
+ // Layer keys are ignored and continue Caps Word.
+ CapsWordPressUserParams{
+ "MO", MO(1), 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "TO", TO(1), 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "TG", TG(1), 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "TT", TT(1), 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "OSL", OSL(1), 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "LT_held", LT_1_KC_A, TAPPING_TERM + 1, KC_NO, true},
+ // AltGr keys are ignored and continue Caps Word.
+ CapsWordPressUserParams{
+ "KC_RALT", KC_RALT, 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "OSM_MOD_RALT", OSM(MOD_RALT), 1, KC_NO, true},
+ CapsWordPressUserParams{
+ "RALT_T_held", RALT_T(KC_A), TAPPING_TERM + 1, KC_NO, true}
+ ),
+ CapsWordPressUserParams::GetName
+ );
+// clang-format on
+
struct CapsWordBothShiftsParams {
std::string name;
uint16_t left_shift_keycode;
@@ -435,3 +592,5 @@ INSTANTIATE_TEST_CASE_P(
CapsWordDoubleTapShiftParams::GetName
);
// clang-format on
+
+} // namespace