action_tapping.c
21408 bytes
1#include <stdint.h>
2#include <stdbool.h>
3
4#include "action.h"
5#include "action_layer.h"
6#include "action_tapping.h"
7#include "keycode.h"
8#include "timer.h"
9
10#ifndef NO_ACTION_TAPPING
11
12# if defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY)
13# error "IGNORE_MOD_TAP_INTERRUPT_PER_KEY has been removed; the code needs to be ported to use HOLD_ON_OTHER_KEY_PRESS_PER_KEY instead."
14# elif defined(IGNORE_MOD_TAP_INTERRUPT)
15# error "IGNORE_MOD_TAP_INTERRUPT is no longer necessary as it is now the default behavior of mod-tap keys. Please remove it from your config."
16# endif
17
18# ifndef COMBO_ENABLE
19# define IS_TAPPING_RECORD(r) (KEYEQ(tapping_key.event.key, (r->event.key)))
20# else
21# define IS_TAPPING_RECORD(r) (KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
22# endif
23# 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))
24# define WITHIN_QUICK_TAP_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < GET_QUICK_TAP_TERM(get_record_keycode(&tapping_key, false), &tapping_key))
25
26# ifdef DYNAMIC_TAPPING_TERM_ENABLE
27uint16_t g_tapping_term = TAPPING_TERM;
28# endif
29
30# ifdef TAPPING_TERM_PER_KEY
31__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
32# ifdef DYNAMIC_TAPPING_TERM_ENABLE
33 return g_tapping_term;
34# else
35 return TAPPING_TERM;
36# endif
37}
38# endif
39
40# ifdef QUICK_TAP_TERM_PER_KEY
41__attribute__((weak)) uint16_t get_quick_tap_term(uint16_t keycode, keyrecord_t *record) {
42 return QUICK_TAP_TERM;
43}
44# endif
45
46# ifdef PERMISSIVE_HOLD_PER_KEY
47__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
48 return false;
49}
50# endif
51
52# ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY
53__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
54 return false;
55}
56# endif
57
58# if defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)
59# include "process_auto_shift.h"
60# endif
61
62static keyrecord_t tapping_key = {};
63static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
64static uint8_t waiting_buffer_head = 0;
65static uint8_t waiting_buffer_tail = 0;
66
67static bool process_tapping(keyrecord_t *record);
68static bool waiting_buffer_enq(keyrecord_t record);
69static void waiting_buffer_clear(void);
70static bool waiting_buffer_typed(keyevent_t event);
71static bool waiting_buffer_has_anykey_pressed(void);
72static void waiting_buffer_scan_tap(void);
73static void debug_tapping_key(void);
74static void debug_waiting_buffer(void);
75
76/** \brief Action Tapping Process
77 *
78 * FIXME: Needs doc
79 */
80void action_tapping_process(keyrecord_t record) {
81 if (process_tapping(&record)) {
82 if (IS_EVENT(record.event)) {
83 ac_dprintf("processed: ");
84 debug_record(record);
85 ac_dprintf("\n");
86 }
87 } else {
88 if (!waiting_buffer_enq(record)) {
89 // clear all in case of overflow.
90 ac_dprintf("OVERFLOW: CLEAR ALL STATES\n");
91 clear_keyboard();
92 waiting_buffer_clear();
93 tapping_key = (keyrecord_t){0};
94 }
95 }
96
97 // process waiting_buffer
98 if (IS_EVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) {
99 ac_dprintf("---- action_exec: process waiting_buffer -----\n");
100 }
101 for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
102 if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
103 ac_dprintf("processed: waiting_buffer[%u] =", waiting_buffer_tail);
104 debug_record(waiting_buffer[waiting_buffer_tail]);
105 ac_dprintf("\n\n");
106 } else {
107 break;
108 }
109 }
110 if (IS_EVENT(record.event)) {
111 ac_dprintf("\n");
112 }
113}
114
115/* Some conditionally defined helper macros to keep process_tapping more
116 * readable. The conditional definition of tapping_keycode and all the
117 * conditional uses of it are hidden inside macros named TAP_...
118 */
119# define TAP_DEFINE_KEYCODE const uint16_t tapping_keycode = get_record_keycode(&tapping_key, false)
120
121# if defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)
122# ifdef RETRO_TAPPING_PER_KEY
123# define TAP_GET_RETRO_TAPPING(keyp) get_auto_shifted_key(tapping_keycode, keyp) && get_retro_tapping(tapping_keycode, &tapping_key)
124# else
125# define TAP_GET_RETRO_TAPPING(keyp) get_auto_shifted_key(tapping_keycode, keyp)
126# endif
127/* Used to extend TAPPING_TERM:
128 * indefinitely if RETRO_SHIFT does not have a value
129 * to RETRO_SHIFT if RETRO_SHIFT is set
130 * for possibly retro shifted keys.
131 */
132# define MAYBE_RETRO_SHIFTING(ev, keyp) (get_auto_shifted_key(tapping_keycode, keyp) && TAP_GET_RETRO_TAPPING(keyp) && ((RETRO_SHIFT + 0) == 0 || TIMER_DIFF_16((ev).time, tapping_key.event.time) < (RETRO_SHIFT + 0)))
133# define TAP_IS_LT IS_QK_LAYER_TAP(tapping_keycode)
134# define TAP_IS_MT IS_QK_MOD_TAP(tapping_keycode)
135# define TAP_IS_RETRO IS_RETRO(tapping_keycode)
136# else
137# define TAP_GET_RETRO_TAPPING(keyp) false
138# define MAYBE_RETRO_SHIFTING(ev, kp) false
139# define TAP_IS_LT false
140# define TAP_IS_MT false
141# define TAP_IS_RETRO false
142# endif
143
144# ifdef PERMISSIVE_HOLD_PER_KEY
145# define TAP_GET_PERMISSIVE_HOLD get_permissive_hold(tapping_keycode, &tapping_key)
146# elif defined(PERMISSIVE_HOLD)
147# define TAP_GET_PERMISSIVE_HOLD true
148# else
149# define TAP_GET_PERMISSIVE_HOLD false
150# endif
151
152# ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY
153# define TAP_GET_HOLD_ON_OTHER_KEY_PRESS get_hold_on_other_key_press(tapping_keycode, &tapping_key)
154# elif defined(HOLD_ON_OTHER_KEY_PRESS)
155# define TAP_GET_HOLD_ON_OTHER_KEY_PRESS true
156# else
157# define TAP_GET_HOLD_ON_OTHER_KEY_PRESS false
158# endif
159
160/** \brief Tapping
161 *
162 * Rule: Tap key is typed(pressed and released) within TAPPING_TERM.
163 * (without interfering by typing other key)
164 */
165/* return true when key event is processed or consumed. */
166bool process_tapping(keyrecord_t *keyp) {
167 const keyevent_t event = keyp->event;
168
169 // state machine is in the "reset" state, no tapping key is to be
170 // processed
171 if (IS_NOEVENT(tapping_key.event)) {
172 if (!IS_EVENT(event)) {
173 // early return for tick events
174 } else if (event.pressed && is_tap_record(keyp)) {
175 // the currently pressed key is a tapping key, therefore transition
176 // into the "pressed" tapping key state
177 ac_dprintf("Tapping: Start(Press tap key).\n");
178 tapping_key = *keyp;
179 process_record_tap_hint(&tapping_key);
180 waiting_buffer_scan_tap();
181 debug_tapping_key();
182 } else {
183 // the current key is just a regular key, pass it on for regular
184 // processing
185 process_record(keyp);
186 }
187
188 return true;
189 }
190
191# if (defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)) || defined(PERMISSIVE_HOLD_PER_KEY) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY)
192 TAP_DEFINE_KEYCODE;
193# endif
194
195 // process "pressed" tapping key state
196 if (tapping_key.event.pressed) {
197 if (WITHIN_TAPPING_TERM(event) || MAYBE_RETRO_SHIFTING(event, keyp)) {
198 if (IS_NOEVENT(event)) {
199 // early return for tick events
200 return true;
201 }
202 if (tapping_key.tap.count == 0) {
203 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
204 // first tap!
205 ac_dprintf("Tapping: First tap(0->1).\n");
206 tapping_key.tap.count = 1;
207 debug_tapping_key();
208 process_record(&tapping_key);
209
210 // copy tapping state
211 keyp->tap = tapping_key.tap;
212 // enqueue
213 return false;
214 }
215 /* Process a key typed within TAPPING_TERM
216 * This can register the key before settlement of tapping,
217 * useful for long TAPPING_TERM but may prevent fast typing.
218 */
219 // clang-format off
220 else if (
221 !event.pressed && waiting_buffer_typed(event) &&
222 (
223 TAP_GET_PERMISSIVE_HOLD ||
224 // Causes nested taps to not wait past TAPPING_TERM/RETRO_SHIFT
225 // unnecessarily and fixes them for Layer Taps.
226 TAP_GET_RETRO_TAPPING(keyp)
227 )
228 ) {
229 // clang-format on
230 ac_dprintf("Tapping: End. No tap. Interfered by typing key\n");
231 process_record(&tapping_key);
232 tapping_key = (keyrecord_t){0};
233 debug_tapping_key();
234 // enqueue
235 return false;
236 }
237 /* Process release event of a key pressed before tapping starts
238 * Without this unexpected repeating will occur with having fast repeating setting
239 * https://github.com/tmk/tmk_keyboard/issues/60
240 */
241 else if (!event.pressed && !waiting_buffer_typed(event)) {
242 // Modifier/Layer should be retained till end of this tapping.
243 action_t action = layer_switch_get_action(event.key);
244 switch (action.kind.id) {
245 case ACT_LMODS:
246 case ACT_RMODS:
247 if (action.key.mods && !action.key.code) return false;
248 if (IS_MODIFIER_KEYCODE(action.key.code)) return false;
249 break;
250 case ACT_LMODS_TAP:
251 case ACT_RMODS_TAP:
252 if (action.key.mods && keyp->tap.count == 0) return false;
253 if (IS_MODIFIER_KEYCODE(action.key.code)) return false;
254 break;
255 case ACT_LAYER_TAP:
256 case ACT_LAYER_TAP_EXT:
257 switch (action.layer_tap.code) {
258 case 0 ...(OP_TAP_TOGGLE - 1):
259 case OP_ON_OFF:
260 case OP_OFF_ON:
261 case OP_SET_CLEAR:
262 return false;
263 }
264 break;
265 }
266 // Release of key should be process immediately.
267 ac_dprintf("Tapping: release event of a key pressed before tapping\n");
268 process_record(keyp);
269 return true;
270 } else {
271 // set interrupted flag when other key pressed during tapping
272 if (event.pressed) {
273 tapping_key.tap.interrupted = true;
274 if (TAP_GET_HOLD_ON_OTHER_KEY_PRESS
275# if defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)
276 // Auto Shift cannot evaluate this early
277 // Retro Shift uses the hold action for all nested taps even without HOLD_ON_OTHER_KEY_PRESS, so this is fine to skip
278 && !(MAYBE_RETRO_SHIFTING(event, keyp) && get_auto_shifted_key(get_record_keycode(keyp, false), keyp))
279# endif
280 ) {
281 ac_dprintf("Tapping: End. No tap. Interfered by pressed key\n");
282 process_record(&tapping_key);
283 tapping_key = (keyrecord_t){0};
284 debug_tapping_key();
285 // enqueue
286 return false;
287 }
288 }
289 // enqueue
290 return false;
291 }
292 }
293 // tap_count > 0
294 else {
295 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
296 ac_dprintf("Tapping: Tap release(%u)\n", tapping_key.tap.count);
297 keyp->tap = tapping_key.tap;
298 process_record(keyp);
299 tapping_key = *keyp;
300 debug_tapping_key();
301 return true;
302 } else if (is_tap_record(keyp) && event.pressed) {
303 if (tapping_key.tap.count > 1) {
304 ac_dprintf("Tapping: Start new tap with releasing last tap(>1).\n");
305 // unregister key
306 process_record(&(keyrecord_t){
307 .tap = tapping_key.tap,
308 .event.key = tapping_key.event.key,
309 .event.time = event.time,
310 .event.pressed = false,
311 .event.type = tapping_key.event.type,
312# ifdef COMBO_ENABLE
313 .keycode = tapping_key.keycode,
314# endif
315 });
316 } else {
317 ac_dprintf("Tapping: Start while last tap(1).\n");
318 }
319 tapping_key = *keyp;
320 waiting_buffer_scan_tap();
321 debug_tapping_key();
322 return true;
323 } else {
324 ac_dprintf("Tapping: key event while last tap(>0).\n");
325# if defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT)
326 retroshift_swap_times();
327# endif
328 process_record(keyp);
329 return true;
330 }
331 }
332 }
333 // after TAPPING_TERM
334 else {
335 if (tapping_key.tap.count == 0) {
336 ac_dprintf("Tapping: End. Timeout. Not tap(0): ");
337 debug_event(event);
338 ac_dprintf("\n");
339 process_record(&tapping_key);
340 tapping_key = (keyrecord_t){0};
341 debug_tapping_key();
342 return false;
343 } else {
344 if (IS_NOEVENT(event)) {
345 return true;
346 }
347 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
348 ac_dprintf("Tapping: End. last timeout tap release(>0).");
349 keyp->tap = tapping_key.tap;
350 process_record(keyp);
351 tapping_key = (keyrecord_t){0};
352 return true;
353 } else if (is_tap_record(keyp) && event.pressed) {
354 if (tapping_key.tap.count > 1) {
355 ac_dprintf("Tapping: Start new tap with releasing last timeout tap(>1).\n");
356 // unregister key
357 process_record(&(keyrecord_t){
358 .tap = tapping_key.tap,
359 .event.key = tapping_key.event.key,
360 .event.time = event.time,
361 .event.pressed = false,
362 .event.type = tapping_key.event.type,
363# ifdef COMBO_ENABLE
364 .keycode = tapping_key.keycode,
365# endif
366 });
367 } else {
368 ac_dprintf("Tapping: Start while last timeout tap(1).\n");
369 }
370 tapping_key = *keyp;
371 waiting_buffer_scan_tap();
372 debug_tapping_key();
373 return true;
374 } else {
375 ac_dprintf("Tapping: key event while last timeout tap(>0).\n");
376 process_record(keyp);
377 return true;
378 }
379 }
380 }
381 }
382 // process "released" tapping key state
383 else {
384 if (WITHIN_TAPPING_TERM(event) || MAYBE_RETRO_SHIFTING(event, keyp)) {
385 if (IS_NOEVENT(event)) {
386 // early return for tick events
387 return true;
388 }
389 if (event.pressed) {
390 if (IS_TAPPING_RECORD(keyp)) {
391 if (WITHIN_QUICK_TAP_TERM(event) && !tapping_key.tap.interrupted && tapping_key.tap.count > 0) {
392 // sequential tap.
393 keyp->tap = tapping_key.tap;
394 if (keyp->tap.count < 15) keyp->tap.count += 1;
395 ac_dprintf("Tapping: Tap press(%u)\n", keyp->tap.count);
396 process_record(keyp);
397 tapping_key = *keyp;
398 debug_tapping_key();
399 return true;
400 }
401 // FIX: start new tap again
402 tapping_key = *keyp;
403 return true;
404 } else if (is_tap_record(keyp)) {
405 // Sequential tap can be interfered with other tap key.
406 ac_dprintf("Tapping: Start with interfering other tap.\n");
407 tapping_key = *keyp;
408 waiting_buffer_scan_tap();
409 debug_tapping_key();
410 return true;
411 } else {
412 // should none in buffer
413 // FIX: interrupted when other key is pressed
414 tapping_key.tap.interrupted = true;
415 process_record(keyp);
416 return true;
417 }
418 } else {
419 ac_dprintf("Tapping: other key just after tap.\n");
420 process_record(keyp);
421 return true;
422 }
423 } else {
424 // Timeout - reset state machine.
425 ac_dprintf("Tapping: End(Timeout after releasing last tap): ");
426 debug_event(event);
427 ac_dprintf("\n");
428 tapping_key = (keyrecord_t){0};
429 debug_tapping_key();
430 return false;
431 }
432 }
433}
434
435/** \brief Waiting buffer enq
436 *
437 * FIXME: Needs docs
438 */
439bool waiting_buffer_enq(keyrecord_t record) {
440 if (IS_NOEVENT(record.event)) {
441 return true;
442 }
443
444 if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
445 ac_dprintf("waiting_buffer_enq: Over flow.\n");
446 return false;
447 }
448
449 waiting_buffer[waiting_buffer_head] = record;
450 waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;
451
452 ac_dprintf("waiting_buffer_enq: ");
453 debug_waiting_buffer();
454 return true;
455}
456
457/** \brief Waiting buffer clear
458 *
459 * FIXME: Needs docs
460 */
461void waiting_buffer_clear(void) {
462 waiting_buffer_head = 0;
463 waiting_buffer_tail = 0;
464}
465
466/** \brief Waiting buffer typed
467 *
468 * FIXME: Needs docs
469 */
470bool waiting_buffer_typed(keyevent_t event) {
471 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
472 if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) {
473 return true;
474 }
475 }
476 return false;
477}
478
479/** \brief Waiting buffer has anykey pressed
480 *
481 * FIXME: Needs docs
482 */
483__attribute__((unused)) bool waiting_buffer_has_anykey_pressed(void) {
484 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
485 if (waiting_buffer[i].event.pressed) return true;
486 }
487 return false;
488}
489
490/** \brief Scan buffer for tapping
491 *
492 * FIXME: Needs docs
493 */
494void waiting_buffer_scan_tap(void) {
495 // early return if:
496 // - tapping already is settled
497 // - invalid state: tapping_key released && tap.count == 0
498 if ((tapping_key.tap.count > 0) || !tapping_key.event.pressed) {
499 return;
500 }
501
502# if (defined(AUTO_SHIFT_ENABLE) && defined(RETRO_SHIFT))
503 TAP_DEFINE_KEYCODE;
504# endif
505 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
506 keyrecord_t *candidate = &waiting_buffer[i];
507 // clang-format off
508 if (IS_EVENT(candidate->event) && KEYEQ(candidate->event.key, tapping_key.event.key) && !candidate->event.pressed && (
509 WITHIN_TAPPING_TERM(waiting_buffer[i].event) || MAYBE_RETRO_SHIFTING(waiting_buffer[i].event, &tapping_key)
510 )) {
511 // clang-format on
512 tapping_key.tap.count = 1;
513 candidate->tap.count = 1;
514 process_record(&tapping_key);
515
516 ac_dprintf("waiting_buffer_scan_tap: found at [%u]\n", i);
517 debug_waiting_buffer();
518 return;
519 }
520 }
521}
522
523/** \brief Tapping key debug print
524 *
525 * FIXME: Needs docs
526 */
527static void debug_tapping_key(void) {
528 ac_dprintf("TAPPING_KEY=");
529 debug_record(tapping_key);
530 ac_dprintf("\n");
531}
532
533/** \brief Waiting buffer debug print
534 *
535 * FIXME: Needs docs
536 */
537static void debug_waiting_buffer(void) {
538 ac_dprintf("{ ");
539 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
540 ac_dprintf("[%u]=", i);
541 debug_record(waiting_buffer[i]);
542 ac_dprintf(" ");
543 }
544 ac_dprintf("}\n");
545}
546
547#endif