Parent directory

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