aboutsummaryrefslogtreecommitdiff
path: root/quantum/action_tapping.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/action_tapping.c')
-rw-r--r--quantum/action_tapping.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c
new file mode 100644
index 000000000..36839f9fa
--- /dev/null
+++ b/quantum/action_tapping.c
@@ -0,0 +1,456 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include "action.h"
4#include "action_layer.h"
5#include "action_tapping.h"
6#include "keycode.h"
7#include "timer.h"
8
9#ifdef DEBUG_ACTION
10# include "debug.h"
11#else
12# include "nodebug.h"
13#endif
14
15#ifndef NO_ACTION_TAPPING
16
17# define IS_TAPPING() !IS_NOEVENT(tapping_key.event)
18# define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed)
19# define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed)
20# define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
21#ifndef COMBO_ENABLE
22# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)))
23#else
24# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
25#endif
26
27__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; }
28
29# ifdef TAPPING_TERM_PER_KEY
30# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_record_keycode(&tapping_key, false), &tapping_key))
31# else
32# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
33# endif
34
35# ifdef TAPPING_FORCE_HOLD_PER_KEY
36__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) { return false; }
37# endif
38
39# ifdef PERMISSIVE_HOLD_PER_KEY
40__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { return false; }
41# endif
42
43# ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY
44__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { return false; }
45# endif
46
47static keyrecord_t tapping_key = {};
48static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
49static uint8_t waiting_buffer_head = 0;
50static uint8_t waiting_buffer_tail = 0;
51
52static bool process_tapping(keyrecord_t *record);
53static bool waiting_buffer_enq(keyrecord_t record);
54static void waiting_buffer_clear(void);
55static bool waiting_buffer_typed(keyevent_t event);
56static bool waiting_buffer_has_anykey_pressed(void);
57static void waiting_buffer_scan_tap(void);
58static void debug_tapping_key(void);
59static void debug_waiting_buffer(void);
60
61/** \brief Action Tapping Process
62 *
63 * FIXME: Needs doc
64 */
65void action_tapping_process(keyrecord_t record) {
66 if (process_tapping(&record)) {
67 if (!IS_NOEVENT(record.event)) {
68 debug("processed: ");
69 debug_record(record);
70 debug("\n");
71 }
72 } else {
73 if (!waiting_buffer_enq(record)) {
74 // clear all in case of overflow.
75 debug("OVERFLOW: CLEAR ALL STATES\n");
76 clear_keyboard();
77 waiting_buffer_clear();
78 tapping_key = (keyrecord_t){};
79 }
80 }
81
82 // process waiting_buffer
83 if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) {
84 debug("---- action_exec: process waiting_buffer -----\n");
85 }
86 for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
87 if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
88 debug("processed: waiting_buffer[");
89 debug_dec(waiting_buffer_tail);
90 debug("] = ");
91 debug_record(waiting_buffer[waiting_buffer_tail]);
92 debug("\n\n");
93 } else {
94 break;
95 }
96 }
97 if (!IS_NOEVENT(record.event)) {
98 debug("\n");
99 }
100}
101
102/** \brief Tapping
103 *
104 * Rule: Tap key is typed(pressed and released) within TAPPING_TERM.
105 * (without interfering by typing other key)
106 */
107/* return true when key event is processed or consumed. */
108bool process_tapping(keyrecord_t *keyp) {
109 keyevent_t event = keyp->event;
110
111 // if tapping
112 if (IS_TAPPING_PRESSED()) {
113 if (WITHIN_TAPPING_TERM(event)) {
114 if (tapping_key.tap.count == 0) {
115 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
116 // first tap!
117 debug("Tapping: First tap(0->1).\n");
118 tapping_key.tap.count = 1;
119 debug_tapping_key();
120 process_record(&tapping_key);
121
122 // copy tapping state
123 keyp->tap = tapping_key.tap;
124 // enqueue
125 return false;
126 }
127 /* Process a key typed within TAPPING_TERM
128 * This can register the key before settlement of tapping,
129 * useful for long TAPPING_TERM but may prevent fast typing.
130 */
131# if defined(TAPPING_TERM_PER_KEY) || (TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD) || defined(PERMISSIVE_HOLD_PER_KEY)
132 else if (((
133# ifdef TAPPING_TERM_PER_KEY
134 get_tapping_term(get_record_keycode(&tapping_key, false), keyp)
135# else
136 TAPPING_TERM
137# endif
138 >= 500)
139
140# ifdef PERMISSIVE_HOLD_PER_KEY
141 || get_permissive_hold(get_record_keycode(&tapping_key, false), keyp)
142# elif defined(PERMISSIVE_HOLD)
143 || true
144# endif
145 ) &&
146 IS_RELEASED(event) && waiting_buffer_typed(event)) {
147 debug("Tapping: End. No tap. Interfered by typing key\n");
148 process_record(&tapping_key);
149 tapping_key = (keyrecord_t){};
150 debug_tapping_key();
151 // enqueue
152 return false;
153 }
154# endif
155 /* Process release event of a key pressed before tapping starts
156 * Without this unexpected repeating will occur with having fast repeating setting
157 * https://github.com/tmk/tmk_keyboard/issues/60
158 */
159 else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) {
160 // Modifier should be retained till end of this tapping.
161 action_t action = layer_switch_get_action(event.key);
162 switch (action.kind.id) {
163 case ACT_LMODS:
164 case ACT_RMODS:
165 if (action.key.mods && !action.key.code) return false;
166 if (IS_MOD(action.key.code)) return false;
167 break;
168 case ACT_LMODS_TAP:
169 case ACT_RMODS_TAP:
170 if (action.key.mods && keyp->tap.count == 0) return false;
171 if (IS_MOD(action.key.code)) return false;
172 break;
173 }
174 // Release of key should be process immediately.
175 debug("Tapping: release event of a key pressed before tapping\n");
176 process_record(keyp);
177 return true;
178 } else {
179 // set interrupted flag when other key preesed during tapping
180 if (event.pressed) {
181 tapping_key.tap.interrupted = true;
182# if defined(HOLD_ON_OTHER_KEY_PRESS) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY)
183# if defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY)
184 if (get_hold_on_other_key_press(get_record_keycode(&tapping_key, false), keyp))
185# endif
186 {
187 debug("Tapping: End. No tap. Interfered by pressed key\n");
188 process_record(&tapping_key);
189 tapping_key = (keyrecord_t){};
190 debug_tapping_key();
191 // enqueue
192 return false;
193 }
194# endif
195 }
196 // enqueue
197 return false;
198 }
199 }
200 // tap_count > 0
201 else {
202 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
203 debug("Tapping: Tap release(");
204 debug_dec(tapping_key.tap.count);
205 debug(")\n");
206 keyp->tap = tapping_key.tap;
207 process_record(keyp);
208 tapping_key = *keyp;
209 debug_tapping_key();
210 return true;
211 } else if (is_tap_record(keyp) && event.pressed) {
212 if (tapping_key.tap.count > 1) {
213 debug("Tapping: Start new tap with releasing last tap(>1).\n");
214 // unregister key
215 process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false,
216#ifdef COMBO_ENABLE
217 .keycode = tapping_key.keycode,
218#endif
219 });
220 } else {
221 debug("Tapping: Start while last tap(1).\n");
222 }
223 tapping_key = *keyp;
224 waiting_buffer_scan_tap();
225 debug_tapping_key();
226 return true;
227 } else {
228 if (!IS_NOEVENT(event)) {
229 debug("Tapping: key event while last tap(>0).\n");
230 }
231 process_record(keyp);
232 return true;
233 }
234 }
235 }
236 // after TAPPING_TERM
237 else {
238 if (tapping_key.tap.count == 0) {
239 debug("Tapping: End. Timeout. Not tap(0): ");
240 debug_event(event);
241 debug("\n");
242 process_record(&tapping_key);
243 tapping_key = (keyrecord_t){};
244 debug_tapping_key();
245 return false;
246 } else {
247 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
248 debug("Tapping: End. last timeout tap release(>0).");
249 keyp->tap = tapping_key.tap;
250 process_record(keyp);
251 tapping_key = (keyrecord_t){};
252 return true;
253 } else if (is_tap_record(keyp) && event.pressed) {
254 if (tapping_key.tap.count > 1) {
255 debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
256 // unregister key
257 process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false,
258#ifdef COMBO_ENABLE
259 .keycode = tapping_key.keycode,
260#endif
261 });
262 } else {
263 debug("Tapping: Start while last timeout tap(1).\n");
264 }
265 tapping_key = *keyp;
266 waiting_buffer_scan_tap();
267 debug_tapping_key();
268 return true;
269 } else {
270 if (!IS_NOEVENT(event)) {
271 debug("Tapping: key event while last timeout tap(>0).\n");
272 }
273 process_record(keyp);
274 return true;
275 }
276 }
277 }
278 } else if (IS_TAPPING_RELEASED()) {
279 if (WITHIN_TAPPING_TERM(event)) {
280 if (event.pressed) {
281 if (IS_TAPPING_RECORD(keyp)) {
282//# ifndef TAPPING_FORCE_HOLD
283# if !defined(TAPPING_FORCE_HOLD) || defined(TAPPING_FORCE_HOLD_PER_KEY)
284 if (
285# ifdef TAPPING_FORCE_HOLD_PER_KEY
286 !get_tapping_force_hold(get_record_keycode(&tapping_key, false), keyp) &&
287# endif
288 !tapping_key.tap.interrupted && tapping_key.tap.count > 0) {
289 // sequential tap.
290 keyp->tap = tapping_key.tap;
291 if (keyp->tap.count < 15) keyp->tap.count += 1;
292 debug("Tapping: Tap press(");
293 debug_dec(keyp->tap.count);
294 debug(")\n");
295 process_record(keyp);
296 tapping_key = *keyp;
297 debug_tapping_key();
298 return true;
299 }
300# endif
301 // FIX: start new tap again
302 tapping_key = *keyp;
303 return true;
304 } else if (is_tap_record(keyp)) {
305 // Sequential tap can be interfered with other tap key.
306 debug("Tapping: Start with interfering other tap.\n");
307 tapping_key = *keyp;
308 waiting_buffer_scan_tap();
309 debug_tapping_key();
310 return true;
311 } else {
312 // should none in buffer
313 // FIX: interrupted when other key is pressed
314 tapping_key.tap.interrupted = true;
315 process_record(keyp);
316 return true;
317 }
318 } else {
319 if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
320 process_record(keyp);
321 return true;
322 }
323 } else {
324 // FIX: process_action here?
325 // timeout. no sequential tap.
326 debug("Tapping: End(Timeout after releasing last tap): ");
327 debug_event(event);
328 debug("\n");
329 tapping_key = (keyrecord_t){};
330 debug_tapping_key();
331 return false;
332 }
333 }
334 // not tapping state
335 else {
336 if (event.pressed && is_tap_record(keyp)) {
337 debug("Tapping: Start(Press tap key).\n");
338 tapping_key = *keyp;
339 process_record_tap_hint(&tapping_key);
340 waiting_buffer_scan_tap();
341 debug_tapping_key();
342 return true;
343 } else {
344 process_record(keyp);
345 return true;
346 }
347 }
348}
349
350/** \brief Waiting buffer enq
351 *
352 * FIXME: Needs docs
353 */
354bool waiting_buffer_enq(keyrecord_t record) {
355 if (IS_NOEVENT(record.event)) {
356 return true;
357 }
358
359 if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
360 debug("waiting_buffer_enq: Over flow.\n");
361 return false;
362 }
363
364 waiting_buffer[waiting_buffer_head] = record;
365 waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;
366
367 debug("waiting_buffer_enq: ");
368 debug_waiting_buffer();
369 return true;
370}
371
372/** \brief Waiting buffer clear
373 *
374 * FIXME: Needs docs
375 */
376void waiting_buffer_clear(void) {
377 waiting_buffer_head = 0;
378 waiting_buffer_tail = 0;
379}
380
381/** \brief Waiting buffer typed
382 *
383 * FIXME: Needs docs
384 */
385bool waiting_buffer_typed(keyevent_t event) {
386 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
387 if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) {
388 return true;
389 }
390 }
391 return false;
392}
393
394/** \brief Waiting buffer has anykey pressed
395 *
396 * FIXME: Needs docs
397 */
398__attribute__((unused)) bool waiting_buffer_has_anykey_pressed(void) {
399 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
400 if (waiting_buffer[i].event.pressed) return true;
401 }
402 return false;
403}
404
405/** \brief Scan buffer for tapping
406 *
407 * FIXME: Needs docs
408 */
409void waiting_buffer_scan_tap(void) {
410 // tapping already is settled
411 if (tapping_key.tap.count > 0) return;
412 // invalid state: tapping_key released && tap.count == 0
413 if (!tapping_key.event.pressed) return;
414
415 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
416 if (IS_TAPPING_KEY(waiting_buffer[i].event.key) && !waiting_buffer[i].event.pressed && WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
417 tapping_key.tap.count = 1;
418 waiting_buffer[i].tap.count = 1;
419 process_record(&tapping_key);
420
421 debug("waiting_buffer_scan_tap: found at [");
422 debug_dec(i);
423 debug("]\n");
424 debug_waiting_buffer();
425 return;
426 }
427 }
428}
429
430/** \brief Tapping key debug print
431 *
432 * FIXME: Needs docs
433 */
434static void debug_tapping_key(void) {
435 debug("TAPPING_KEY=");
436 debug_record(tapping_key);
437 debug("\n");
438}
439
440/** \brief Waiting buffer debug print
441 *
442 * FIXME: Needs docs
443 */
444static void debug_waiting_buffer(void) {
445 debug("{ ");
446 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
447 debug("[");
448 debug_dec(i);
449 debug("]=");
450 debug_record(waiting_buffer[i]);
451 debug(" ");
452 }
453 debug("}\n");
454}
455
456#endif