test_tap_hold.cpp (7803B)
1 // Copyright 2024 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "keyboard_report_util.hpp" 16 #include "keycode.h" 17 #include "test_common.hpp" 18 #include "action_tapping.h" 19 #include "test_fixture.hpp" 20 #include "test_keymap_key.hpp" 21 22 using testing::_; 23 using testing::InSequence; 24 25 class ChordalHoldDefault : public TestFixture {}; 26 27 TEST_F(ChordalHoldDefault, chord_nested_press_settled_as_tap) { 28 TestDriver driver; 29 InSequence s; 30 // Mod-tap key on the left hand. 31 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); 32 // Regular key on the right hand. 33 auto regular_key = KeymapKey(0, MATRIX_COLS - 1, 0, KC_A); 34 35 set_keymap({mod_tap_key, regular_key}); 36 37 // Press mod-tap key. 38 EXPECT_NO_REPORT(driver); 39 mod_tap_key.press(); 40 run_one_scan_loop(); 41 // Tap regular key. 42 tap_key(regular_key); 43 VERIFY_AND_CLEAR(driver); 44 45 // Release mod-tap key. 46 EXPECT_REPORT(driver, (KC_P)); 47 EXPECT_REPORT(driver, (KC_P, KC_A)); 48 EXPECT_REPORT(driver, (KC_P)); 49 EXPECT_EMPTY_REPORT(driver); 50 mod_tap_key.release(); 51 run_one_scan_loop(); 52 VERIFY_AND_CLEAR(driver); 53 } 54 55 TEST_F(ChordalHoldDefault, chord_rolled_press_settled_as_tap) { 56 TestDriver driver; 57 InSequence s; 58 // Mod-tap key on the left hand. 59 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); 60 // Regular key on the right hand. 61 auto regular_key = KeymapKey(0, MATRIX_COLS - 1, 0, KC_A); 62 63 set_keymap({mod_tap_key, regular_key}); 64 65 // Press mod-tap key and regular key. 66 EXPECT_NO_REPORT(driver); 67 mod_tap_key.press(); 68 run_one_scan_loop(); 69 regular_key.press(); 70 run_one_scan_loop(); 71 VERIFY_AND_CLEAR(driver); 72 73 // Release mod-tap key. 74 EXPECT_REPORT(driver, (KC_P)); 75 EXPECT_REPORT(driver, (KC_P, KC_A)); 76 EXPECT_REPORT(driver, (KC_A)); 77 mod_tap_key.release(); 78 run_one_scan_loop(); 79 VERIFY_AND_CLEAR(driver); 80 81 // Release regular key. 82 EXPECT_EMPTY_REPORT(driver); 83 regular_key.release(); 84 run_one_scan_loop(); 85 VERIFY_AND_CLEAR(driver); 86 } 87 88 TEST_F(ChordalHoldDefault, non_chord_with_mod_tap_settled_as_tap) { 89 TestDriver driver; 90 InSequence s; 91 // Mod-tap key and regular key both on the left hand. 92 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); 93 auto regular_key = KeymapKey(0, 2, 0, KC_A); 94 95 set_keymap({mod_tap_key, regular_key}); 96 97 // Press mod-tap-hold key. 98 EXPECT_NO_REPORT(driver); 99 mod_tap_key.press(); 100 run_one_scan_loop(); 101 VERIFY_AND_CLEAR(driver); 102 103 // Press regular key. 104 EXPECT_REPORT(driver, (KC_P)); 105 EXPECT_REPORT(driver, (KC_P, KC_A)); 106 regular_key.press(); 107 run_one_scan_loop(); 108 VERIFY_AND_CLEAR(driver); 109 110 // Release regular key. 111 EXPECT_REPORT(driver, (KC_P)); 112 regular_key.release(); 113 run_one_scan_loop(); 114 VERIFY_AND_CLEAR(driver); 115 116 // Release mod-tap-hold key. 117 EXPECT_EMPTY_REPORT(driver); 118 mod_tap_key.release(); 119 run_one_scan_loop(); 120 VERIFY_AND_CLEAR(driver); 121 } 122 123 TEST_F(ChordalHoldDefault, tap_mod_tap_key) { 124 TestDriver driver; 125 InSequence s; 126 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); 127 128 set_keymap({mod_tap_key}); 129 130 EXPECT_NO_REPORT(driver); 131 mod_tap_key.press(); 132 idle_for(TAPPING_TERM - 1); 133 VERIFY_AND_CLEAR(driver); 134 135 EXPECT_REPORT(driver, (KC_P)); 136 EXPECT_EMPTY_REPORT(driver); 137 mod_tap_key.release(); 138 run_one_scan_loop(); 139 VERIFY_AND_CLEAR(driver); 140 } 141 142 TEST_F(ChordalHoldDefault, hold_mod_tap_key) { 143 TestDriver driver; 144 InSequence s; 145 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_P)); 146 147 set_keymap({mod_tap_key}); 148 149 EXPECT_REPORT(driver, (KC_LEFT_SHIFT)); 150 mod_tap_key.press(); 151 idle_for(TAPPING_TERM + 1); 152 VERIFY_AND_CLEAR(driver); 153 154 EXPECT_EMPTY_REPORT(driver); 155 mod_tap_key.release(); 156 run_one_scan_loop(); 157 VERIFY_AND_CLEAR(driver); 158 } 159 160 TEST_F(ChordalHoldDefault, two_mod_taps_same_hand_hold_til_timeout) { 161 TestDriver driver; 162 InSequence s; 163 auto mod_tap_key1 = KeymapKey(0, MATRIX_COLS - 2, 0, RCTL_T(KC_A)); 164 auto mod_tap_key2 = KeymapKey(0, MATRIX_COLS - 1, 0, RSFT_T(KC_B)); 165 166 set_keymap({mod_tap_key1, mod_tap_key2}); 167 168 // Press mod-tap keys. 169 EXPECT_NO_REPORT(driver); 170 mod_tap_key1.press(); 171 run_one_scan_loop(); 172 mod_tap_key2.press(); 173 run_one_scan_loop(); 174 VERIFY_AND_CLEAR(driver); 175 176 // Continue holding til the tapping term. 177 EXPECT_REPORT(driver, (KC_RIGHT_CTRL)); 178 EXPECT_REPORT(driver, (KC_RIGHT_CTRL, KC_RIGHT_SHIFT)); 179 idle_for(TAPPING_TERM); 180 VERIFY_AND_CLEAR(driver); 181 182 // Release mod-tap keys. 183 EXPECT_REPORT(driver, (KC_RIGHT_SHIFT)); 184 mod_tap_key1.release(); 185 run_one_scan_loop(); 186 VERIFY_AND_CLEAR(driver); 187 188 EXPECT_EMPTY_REPORT(driver); 189 mod_tap_key2.release(); 190 run_one_scan_loop(); 191 VERIFY_AND_CLEAR(driver); 192 } 193 194 TEST_F(ChordalHoldDefault, three_mod_taps_same_hand_streak_roll) { 195 TestDriver driver; 196 InSequence s; 197 auto mod_tap_key1 = KeymapKey(0, 1, 0, SFT_T(KC_A)); 198 auto mod_tap_key2 = KeymapKey(0, 2, 0, CTL_T(KC_B)); 199 auto mod_tap_key3 = KeymapKey(0, 3, 0, RSFT_T(KC_C)); 200 201 set_keymap({mod_tap_key1, mod_tap_key2, mod_tap_key3}); 202 203 // Press mod-tap keys. 204 EXPECT_NO_REPORT(driver); 205 mod_tap_key1.press(); 206 run_one_scan_loop(); 207 mod_tap_key2.press(); 208 run_one_scan_loop(); 209 mod_tap_key3.press(); 210 run_one_scan_loop(); 211 VERIFY_AND_CLEAR(driver); 212 213 // Release keys 1, 2, 3. 214 // 215 // NOTE: The correct order of events should be 216 // EXPECT_REPORT(driver, (KC_A, KC_B, KC_C)); 217 // EXPECT_REPORT(driver, (KC_B, KC_C)); 218 // EXPECT_REPORT(driver, (KC_C)); 219 // EXPECT_EMPTY_REPORT(driver); 220 // 221 // However, due to a workaround for https://github.com/tmk/tmk_keyboard/issues/60, 222 // the events are processed out of order, with the first two keys released 223 // before pressing KC_C. 224 EXPECT_REPORT(driver, (KC_A)); 225 EXPECT_REPORT(driver, (KC_A, KC_B)); 226 EXPECT_REPORT(driver, (KC_B)); 227 EXPECT_EMPTY_REPORT(driver); 228 EXPECT_REPORT(driver, (KC_C)); 229 EXPECT_EMPTY_REPORT(driver); 230 mod_tap_key1.release(); 231 run_one_scan_loop(); 232 mod_tap_key2.release(); 233 run_one_scan_loop(); 234 mod_tap_key3.release(); 235 run_one_scan_loop(); 236 VERIFY_AND_CLEAR(driver); 237 } 238 239 TEST_F(ChordalHoldDefault, tap_regular_key_while_layer_tap_key_is_held) { 240 TestDriver driver; 241 InSequence s; 242 auto layer_tap_hold_key = KeymapKey(0, 1, 0, LT(1, KC_P)); 243 auto regular_key = KeymapKey(0, MATRIX_COLS - 1, 0, KC_A); 244 auto layer_key = KeymapKey(1, MATRIX_COLS - 1, 0, KC_B); 245 246 set_keymap({layer_tap_hold_key, regular_key, layer_key}); 247 248 EXPECT_NO_REPORT(driver); 249 layer_tap_hold_key.press(); // Press layer-tap-hold key. 250 run_one_scan_loop(); 251 regular_key.press(); // Press regular key. 252 run_one_scan_loop(); 253 regular_key.release(); // Release regular key. 254 run_one_scan_loop(); 255 VERIFY_AND_CLEAR(driver); 256 257 EXPECT_REPORT(driver, (KC_P)); 258 EXPECT_REPORT(driver, (KC_P, KC_A)); 259 EXPECT_REPORT(driver, (KC_P)); 260 EXPECT_EMPTY_REPORT(driver); 261 layer_tap_hold_key.release(); // Release layer-tap-hold key. 262 run_one_scan_loop(); 263 VERIFY_AND_CLEAR(driver); 264 }