summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPascal Getreuer <50221757+getreuer@users.noreply.github.com>2025-04-14 09:46:24 -0700
committerGitHub <noreply@github.com>2025-04-14 09:46:24 -0700
commit8d8dcb089ed36e7e1a61d77e5a4b6b08c8668869 (patch)
treeb5aa66a32a42e5d1288e8a5751e94cba4ce06350 /tests
parenta7bf8e64a584c9a0930f4aa701a09a6e1de7e117 (diff)
[Core] Flow Tap tap-hold option to disable HRMs during fast typing (#25125)
aka Global Quick Tap, Require Prior Idle
Diffstat (limited to 'tests')
-rw-r--r--tests/tap_hold_configurations/flow_tap/config.h22
-rw-r--r--tests/tap_hold_configurations/flow_tap/test.mk18
-rw-r--r--tests/tap_hold_configurations/flow_tap/test_keymap.c23
-rw-r--r--tests/tap_hold_configurations/flow_tap/test_tap_hold.cpp313
4 files changed, 376 insertions, 0 deletions
diff --git a/tests/tap_hold_configurations/flow_tap/config.h b/tests/tap_hold_configurations/flow_tap/config.h
new file mode 100644
index 0000000000..a17d488214
--- /dev/null
+++ b/tests/tap_hold_configurations/flow_tap/config.h
@@ -0,0 +1,22 @@
1/* Copyright 2022 Vladislav Kucheriavykh
2 * Copyright 2025 Google LLC
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19
20#include "test_common.h"
21
22#define FLOW_TAP_TERM 150
diff --git a/tests/tap_hold_configurations/flow_tap/test.mk b/tests/tap_hold_configurations/flow_tap/test.mk
new file mode 100644
index 0000000000..81ba8da66d
--- /dev/null
+++ b/tests/tap_hold_configurations/flow_tap/test.mk
@@ -0,0 +1,18 @@
1# Copyright 2022 Vladislav Kucheriavykh
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
16COMBO_ENABLE = yes
17
18INTROSPECTION_KEYMAP_C = test_keymap.c
diff --git a/tests/tap_hold_configurations/flow_tap/test_keymap.c b/tests/tap_hold_configurations/flow_tap/test_keymap.c
new file mode 100644
index 0000000000..4dfe5e4cb6
--- /dev/null
+++ b/tests/tap_hold_configurations/flow_tap/test_keymap.c
@@ -0,0 +1,23 @@
1// Copyright 2025 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 "quantum.h"
16
17uint16_t const mt_lt_combo[] = {SFT_T(KC_X), LT(1, KC_Y), COMBO_END};
18
19// clang-format off
20combo_t key_combos[] = {
21 COMBO(mt_lt_combo, KC_Z),
22};
23// clang-format on
diff --git a/tests/tap_hold_configurations/flow_tap/test_tap_hold.cpp b/tests/tap_hold_configurations/flow_tap/test_tap_hold.cpp
new file mode 100644
index 0000000000..7816fcb6da
--- /dev/null
+++ b/tests/tap_hold_configurations/flow_tap/test_tap_hold.cpp
@@ -0,0 +1,313 @@
1// Copyright 2025 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
22using testing::_;
23using testing::AnyNumber;
24using testing::InSequence;
25
26class FlowTapTest : public TestFixture {};
27
28TEST_F(FlowTapTest, short_flow_tap_settled_as_tapped) {
29 TestDriver driver;
30 InSequence s;
31 auto regular_key = KeymapKey(0, 0, 0, KC_A);
32 auto mod_tap_key1 = KeymapKey(0, 1, 0, SFT_T(KC_B));
33 auto mod_tap_key2 = KeymapKey(0, 2, 0, CTL_T(KC_C));
34
35 set_keymap({regular_key, mod_tap_key1, mod_tap_key2});
36
37 // Tap regular key.
38 EXPECT_REPORT(driver, (KC_A));
39 EXPECT_EMPTY_REPORT(driver);
40 tap_key(regular_key);
41 VERIFY_AND_CLEAR(driver);
42
43 // Press mod-tap key 1 quickly after regular key. The mod-tap should settle
44 // immediately as tapped, sending `KC_B`.
45 EXPECT_REPORT(driver, (KC_B));
46 mod_tap_key1.press();
47 run_one_scan_loop();
48 VERIFY_AND_CLEAR(driver);
49
50 // Press mod-tap key 2 quickly.
51 EXPECT_REPORT(driver, (KC_B, KC_C));
52 mod_tap_key2.press();
53 run_one_scan_loop();
54 VERIFY_AND_CLEAR(driver);
55
56 // Hold for longer than the tapping term.
57 EXPECT_NO_REPORT(driver);
58 idle_for(TAPPING_TERM + 1);
59 VERIFY_AND_CLEAR(driver);
60
61 // Release mod-tap keys.
62 EXPECT_REPORT(driver, (KC_C));
63 EXPECT_EMPTY_REPORT(driver);
64 mod_tap_key1.release();
65 run_one_scan_loop();
66 mod_tap_key2.release();
67 run_one_scan_loop();
68 VERIFY_AND_CLEAR(driver);
69}
70
71TEST_F(FlowTapTest, long_flow_tap_settled_as_held) {
72 TestDriver driver;
73 InSequence s;
74 auto regular_key = KeymapKey(0, 0, 0, KC_A);
75 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_B));
76
77 set_keymap({regular_key, mod_tap_key});
78
79 // Tap regular key.
80 EXPECT_REPORT(driver, (KC_A));
81 EXPECT_EMPTY_REPORT(driver);
82 tap_key(regular_key);
83 VERIFY_AND_CLEAR(driver);
84
85 EXPECT_NO_REPORT(driver);
86 idle_for(FLOW_TAP_TERM + 1);
87 VERIFY_AND_CLEAR(driver);
88
89 // Press mod-tap key.
90 EXPECT_NO_REPORT(driver);
91 mod_tap_key.press();
92 run_one_scan_loop();
93 VERIFY_AND_CLEAR(driver);
94
95 // Hold for the tapping term.
96 EXPECT_REPORT(driver, (KC_LSFT));
97 idle_for(TAPPING_TERM);
98 VERIFY_AND_CLEAR(driver);
99
100 // Release mod-tap key.
101 EXPECT_EMPTY_REPORT(driver);
102 mod_tap_key.release();
103 run_one_scan_loop();
104 VERIFY_AND_CLEAR(driver);
105}
106
107TEST_F(FlowTapTest, holding_multiple_mod_taps) {
108 TestDriver driver;
109 InSequence s;
110 auto regular_key = KeymapKey(0, 0, 0, KC_A);
111 auto mod_tap_key1 = KeymapKey(0, 1, 0, SFT_T(KC_B));
112 auto mod_tap_key2 = KeymapKey(0, 2, 0, CTL_T(KC_C));
113
114 set_keymap({regular_key, mod_tap_key1, mod_tap_key2});
115
116 // Tap regular key.
117 EXPECT_REPORT(driver, (KC_A));
118 EXPECT_EMPTY_REPORT(driver);
119 tap_key(regular_key);
120 VERIFY_AND_CLEAR(driver);
121
122 EXPECT_NO_REPORT(driver);
123 idle_for(FLOW_TAP_TERM + 1);
124 VERIFY_AND_CLEAR(driver);
125
126 // Press mod-tap keys.
127 EXPECT_NO_REPORT(driver);
128 mod_tap_key1.press();
129 run_one_scan_loop();
130 mod_tap_key2.press();
131 idle_for(TAPPING_TERM - 5); // Hold almost until tapping term.
132 VERIFY_AND_CLEAR(driver);
133
134 // Press regular key.
135 EXPECT_REPORT(driver, (KC_LSFT));
136 EXPECT_REPORT(driver, (KC_LSFT, KC_LCTL));
137 EXPECT_REPORT(driver, (KC_LSFT, KC_LCTL, KC_A));
138 regular_key.press();
139 idle_for(10);
140 VERIFY_AND_CLEAR(driver);
141
142 // Release keys.
143 EXPECT_REPORT(driver, (KC_LSFT, KC_LCTL));
144 EXPECT_REPORT(driver, (KC_LCTL));
145 EXPECT_EMPTY_REPORT(driver);
146 regular_key.release();
147 run_one_scan_loop();
148 mod_tap_key1.release();
149 run_one_scan_loop();
150 mod_tap_key2.release();
151 run_one_scan_loop();
152 VERIFY_AND_CLEAR(driver);
153}
154
155TEST_F(FlowTapTest, layer_tap_key) {
156 TestDriver driver;
157 InSequence s;
158 auto regular_key = KeymapKey(0, 0, 0, KC_A);
159 auto layer_tap_key = KeymapKey(0, 1, 0, LT(1, KC_B));
160 auto regular_key2 = KeymapKey(1, 0, 0, KC_C);
161
162 set_keymap({regular_key, layer_tap_key, regular_key2});
163
164 // Tap regular key.
165 EXPECT_REPORT(driver, (KC_A));
166 EXPECT_EMPTY_REPORT(driver);
167 tap_key(regular_key);
168 VERIFY_AND_CLEAR(driver);
169
170 // Press layer-tap key, quickly after the regular key.
171 EXPECT_REPORT(driver, (KC_B));
172 layer_tap_key.press();
173 run_one_scan_loop();
174 VERIFY_AND_CLEAR(driver);
175
176 EXPECT_NO_REPORT(driver);
177 idle_for(TAPPING_TERM + 1);
178 VERIFY_AND_CLEAR(driver);
179
180 // Release layer-tap key.
181 EXPECT_EMPTY_REPORT(driver);
182 layer_tap_key.release();
183 run_one_scan_loop();
184
185 // Tap regular key.
186 EXPECT_REPORT(driver, (KC_A));
187 EXPECT_EMPTY_REPORT(driver);
188 tap_key(regular_key);
189 VERIFY_AND_CLEAR(driver);
190
191 EXPECT_NO_REPORT(driver);
192 idle_for(FLOW_TAP_TERM + 1);
193 VERIFY_AND_CLEAR(driver);
194
195 // Press layer-tap key, slowly after the regular key.
196 EXPECT_NO_REPORT(driver);
197 layer_tap_key.press();
198 run_one_scan_loop();
199 VERIFY_AND_CLEAR(driver);
200
201 EXPECT_NO_REPORT(driver);
202 idle_for(TAPPING_TERM + 1);
203 EXPECT_EQ(layer_state, 1 << 1);
204 VERIFY_AND_CLEAR(driver);
205
206 // Tap regular key2.
207 EXPECT_REPORT(driver, (KC_C));
208 EXPECT_EMPTY_REPORT(driver);
209 tap_key(regular_key);
210 VERIFY_AND_CLEAR(driver);
211
212 // Release layer-tap key.
213 EXPECT_NO_REPORT(driver);
214 layer_tap_key.release();
215 run_one_scan_loop();
216 VERIFY_AND_CLEAR(driver);
217}
218
219TEST_F(FlowTapTest, combo_key) {
220 TestDriver driver;
221 InSequence s;
222 auto regular_key = KeymapKey(0, 0, 0, KC_A);
223 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_X));
224 auto layer_tap_key = KeymapKey(0, 2, 0, LT(1, KC_Y));
225
226 set_keymap({regular_key, mod_tap_key, layer_tap_key});
227
228 // Tap regular key.
229 EXPECT_REPORT(driver, (KC_A));
230 EXPECT_EMPTY_REPORT(driver);
231 tap_key(regular_key);
232 VERIFY_AND_CLEAR(driver);
233
234 // Press combo keys quickly after regular key.
235 EXPECT_REPORT(driver, (KC_Z));
236 EXPECT_EMPTY_REPORT(driver);
237 tap_combo({mod_tap_key, layer_tap_key});
238 VERIFY_AND_CLEAR(driver);
239
240 // Press mod-tap key quickly.
241 EXPECT_REPORT(driver, (KC_X));
242 mod_tap_key.press();
243 idle_for(TAPPING_TERM + 1);
244 VERIFY_AND_CLEAR(driver);
245
246 // Release mod-tap key.
247 EXPECT_EMPTY_REPORT(driver);
248 mod_tap_key.release();
249 run_one_scan_loop();
250 VERIFY_AND_CLEAR(driver);
251}
252
253TEST_F(FlowTapTest, oneshot_mod_key) {
254 TestDriver driver;
255 InSequence s;
256 auto regular_key = KeymapKey(0, 0, 0, KC_A);
257 auto osm_key = KeymapKey(0, 1, 0, OSM(MOD_LSFT));
258
259 set_keymap({regular_key, osm_key});
260
261 // Tap regular key.
262 EXPECT_REPORT(driver, (KC_A));
263 EXPECT_EMPTY_REPORT(driver);
264 tap_key(regular_key);
265 VERIFY_AND_CLEAR(driver);
266
267 // Tap OSM, tap regular key.
268 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT))).Times(AnyNumber());
269 EXPECT_REPORT(driver, (KC_LSFT, KC_A));
270 EXPECT_EMPTY_REPORT(driver);
271 tap_key(osm_key);
272 tap_key(regular_key);
273 VERIFY_AND_CLEAR(driver);
274
275 // Nested press of OSM and regular keys.
276 EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_LSFT))).Times(AnyNumber());
277 EXPECT_REPORT(driver, (KC_LSFT, KC_A));
278 EXPECT_EMPTY_REPORT(driver);
279 osm_key.press();
280 run_one_scan_loop();
281 tap_key(regular_key);
282 osm_key.release();
283 run_one_scan_loop();
284 VERIFY_AND_CLEAR(driver);
285}
286
287TEST_F(FlowTapTest, quick_tap) {
288 TestDriver driver;
289 InSequence s;
290 auto mod_tap_key = KeymapKey(0, 1, 0, SFT_T(KC_A));
291
292 set_keymap({mod_tap_key});
293
294 EXPECT_REPORT(driver, (KC_A));
295 EXPECT_EMPTY_REPORT(driver);
296 tap_key(mod_tap_key);
297 VERIFY_AND_CLEAR(driver);
298
299 EXPECT_REPORT(driver, (KC_A));
300 mod_tap_key.press();
301 run_one_scan_loop();
302 VERIFY_AND_CLEAR(driver);
303
304 EXPECT_NO_REPORT(driver);
305 idle_for(TAPPING_TERM + 1);
306 VERIFY_AND_CLEAR(driver);
307
308 // Release mod-tap key.
309 EXPECT_EMPTY_REPORT(driver);
310 mod_tap_key.release();
311 run_one_scan_loop();
312 VERIFY_AND_CLEAR(driver);
313}