summary refs log tree commit diff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
authorJouke Witteveen <j.witteveen@gmail.com>2022-06-13 22:12:55 +0200
committerGitHub <noreply@github.com>2022-06-13 22:12:55 +0200
commit1706da9054f8c4aa77493062a8937a7b64970a9e (patch)
tree1a77464586942c66bdcae99a26bf1558862a7842 /quantum/process_keycode
parentb17324498ee8e7bf1e8ed57cc8c9b505ca0ce85b (diff)
tap-dance: Restructure code and document in more detail (#16394)
Diffstat (limited to 'quantum/process_keycode')
-rw-r--r--quantum/process_keycode/process_tap_dance.c137
-rw-r--r--quantum/process_keycode/process_tap_dance.h33
2 files changed, 70 insertions, 100 deletions
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index db8df5f870..3270a1b000 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -15,12 +15,8 @@
  */
 #include "quantum.h"
 
-#ifndef NO_ACTION_ONESHOT
-uint8_t get_oneshot_mods(void);
-#endif
-
-static uint16_t last_td;
-static int16_t  highest_td = -1;
+static uint16_t active_td;
+static uint16_t last_tap_time;
 
 void qk_tap_dance_pair_on_each_tap(qk_tap_dance_state_t *state, void *user_data) {
     qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
@@ -34,18 +30,14 @@ void qk_tap_dance_pair_on_each_tap(qk_tap_dance_state_t *state, void *user_data)
 void qk_tap_dance_pair_finished(qk_tap_dance_state_t *state, void *user_data) {
     qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
 
-    if (state->count == 1) {
-        register_code16(pair->kc1);
-    } else if (state->count == 2) {
-        register_code16(pair->kc2);
-    }
+    register_code16(pair->kc1);
 }
 
 void qk_tap_dance_pair_reset(qk_tap_dance_state_t *state, void *user_data) {
     qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
 
-    wait_ms(TAP_CODE_DELAY);
     if (state->count == 1) {
+        wait_ms(TAP_CODE_DELAY);
         unregister_code16(pair->kc1);
     } else if (state->count == 2) {
         unregister_code16(pair->kc2);
@@ -87,23 +79,40 @@ static inline void _process_tap_dance_action_fn(qk_tap_dance_state_t *state, voi
 }
 
 static inline void process_tap_dance_action_on_each_tap(qk_tap_dance_action_t *action) {
+    action->state.count++;
+    action->state.weak_mods = get_mods();
+    action->state.weak_mods |= get_weak_mods();
+#ifndef NO_ACTION_ONESHOT
+    action->state.oneshot_mods = get_oneshot_mods();
+#endif
     _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_each_tap);
 }
 
-static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_action_t *action) {
-    if (action->state.finished) return;
-    action->state.finished = true;
-    add_mods(action->state.oneshot_mods);
-    add_weak_mods(action->state.weak_mods);
-    send_keyboard_report();
-    _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_dance_finished);
-}
-
 static inline void process_tap_dance_action_on_reset(qk_tap_dance_action_t *action) {
     _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_reset);
-    del_mods(action->state.oneshot_mods);
     del_weak_mods(action->state.weak_mods);
+#ifndef NO_ACTION_ONESHOT
+    del_mods(action->state.oneshot_mods);
+#endif
     send_keyboard_report();
+    action->state = (const qk_tap_dance_state_t){0};
+}
+
+static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_action_t *action) {
+    if (!action->state.finished) {
+        action->state.finished = true;
+        add_weak_mods(action->state.weak_mods);
+#ifndef NO_ACTION_ONESHOT
+        add_mods(action->state.oneshot_mods);
+#endif
+        send_keyboard_report();
+        _process_tap_dance_action_fn(&action->state, action->user_data, action->fn.on_dance_finished);
+    }
+    active_td = 0;
+    if (!action->state.pressed) {
+        // There will not be a key release event, so reset now.
+        process_tap_dance_action_on_reset(action);
+    }
 }
 
 void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
@@ -111,51 +120,33 @@ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
 
     if (!record->event.pressed) return;
 
-    if (highest_td == -1) return;
-
-    for (int i = 0; i <= highest_td; i++) {
-        action = &tap_dance_actions[i];
-        if (action->state.count) {
-            if (keycode == action->state.keycode && keycode == last_td) continue;
-            action->state.interrupted          = true;
-            action->state.interrupting_keycode = keycode;
-            process_tap_dance_action_on_dance_finished(action);
-            reset_tap_dance(&action->state);
-
-            // Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with
-            // modifiers), but these weak mods should not affect the keypress which interrupted the tap dance.
-            clear_weak_mods();
-        }
-    }
+    if (!active_td || keycode == active_td) return;
+
+    action                             = &tap_dance_actions[TD_INDEX(active_td)];
+    action->state.interrupted          = true;
+    action->state.interrupting_keycode = keycode;
+    process_tap_dance_action_on_dance_finished(action);
+
+    // Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with
+    // modifiers), but these weak mods should not affect the keypress which interrupted the tap dance.
+    clear_weak_mods();
 }
 
 bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
-    uint16_t               idx = keycode - QK_TAP_DANCE;
     qk_tap_dance_action_t *action;
 
     switch (keycode) {
         case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
-            if ((int16_t)idx > highest_td) highest_td = idx;
-            action = &tap_dance_actions[idx];
+            action = &tap_dance_actions[TD_INDEX(keycode)];
 
             action->state.pressed = record->event.pressed;
             if (record->event.pressed) {
-                action->state.keycode = keycode;
-                action->state.count++;
-                action->state.timer = timer_read();
-#ifndef NO_ACTION_ONESHOT
-                action->state.oneshot_mods = get_oneshot_mods();
-#else
-                action->state.oneshot_mods = 0;
-#endif
-                action->state.weak_mods = get_mods();
-                action->state.weak_mods |= get_weak_mods();
+                last_tap_time = timer_read();
                 process_tap_dance_action_on_each_tap(action);
-
-                last_td = keycode;
+                active_td = action->state.finished ? 0 : keycode;
             } else {
-                if (action->state.count && action->state.finished) {
-                    reset_tap_dance(&action->state);
+                if (action->state.finished) {
+                    process_tap_dance_action_on_reset(action);
                 }
             }
 
@@ -166,35 +157,17 @@ bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
 }
 
 void tap_dance_task() {
-    if (highest_td == -1) return;
-    uint16_t tap_user_defined;
-
-    for (uint8_t i = 0; i <= highest_td; i++) {
-        qk_tap_dance_action_t *action = &tap_dance_actions[i];
-        if (action->custom_tapping_term > 0) {
-            tap_user_defined = action->custom_tapping_term;
-        } else {
-            tap_user_defined = GET_TAPPING_TERM(action->state.keycode, &(keyrecord_t){});
-        }
-        if (action->state.count && timer_elapsed(action->state.timer) > tap_user_defined) {
-            process_tap_dance_action_on_dance_finished(action);
-            reset_tap_dance(&action->state);
-        }
-    }
-}
-
-void reset_tap_dance(qk_tap_dance_state_t *state) {
     qk_tap_dance_action_t *action;
 
-    if (state->pressed) return;
+    if (!active_td || timer_elapsed(last_tap_time) <= GET_TAPPING_TERM(active_td, &(keyrecord_t){})) return;
 
-    action = &tap_dance_actions[state->keycode - QK_TAP_DANCE];
-
-    process_tap_dance_action_on_reset(action);
+    action = &tap_dance_actions[TD_INDEX(active_td)];
+    if (!action->state.interrupted) {
+        process_tap_dance_action_on_dance_finished(action);
+    }
+}
 
-    state->count                = 0;
-    state->interrupted          = false;
-    state->finished             = false;
-    state->interrupting_keycode = 0;
-    last_td                     = 0;
+void reset_tap_dance(qk_tap_dance_state_t *state) {
+    active_td = 0;
+    process_tap_dance_action_on_reset((qk_tap_dance_action_t *)state);
 }
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index d9ffb1e73d..d97900d96b 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -22,30 +22,27 @@
 #    include <inttypes.h>
 
 typedef struct {
+    uint16_t interrupting_keycode;
     uint8_t  count;
-    uint8_t  oneshot_mods;
     uint8_t  weak_mods;
-    uint16_t keycode;
-    uint16_t interrupting_keycode;
-    uint16_t timer;
-    bool     interrupted;
-    bool     pressed;
-    bool     finished;
+#    ifndef NO_ACTION_ONESHOT
+    uint8_t oneshot_mods;
+#    endif
+    bool pressed : 1;
+    bool finished : 1;
+    bool interrupted : 1;
 } qk_tap_dance_state_t;
 
-#    define TD(n) (QK_TAP_DANCE | ((n)&0xFF))
-
 typedef void (*qk_tap_dance_user_fn_t)(qk_tap_dance_state_t *state, void *user_data);
 
 typedef struct {
+    qk_tap_dance_state_t state;
     struct {
         qk_tap_dance_user_fn_t on_each_tap;
         qk_tap_dance_user_fn_t on_dance_finished;
         qk_tap_dance_user_fn_t on_reset;
     } fn;
-    qk_tap_dance_state_t state;
-    uint16_t             custom_tapping_term;
-    void *               user_data;
+    void *user_data;
 } qk_tap_dance_action_t;
 
 typedef struct {
@@ -62,31 +59,31 @@ typedef struct {
 #    define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) \
         { .fn = {qk_tap_dance_pair_on_each_tap, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset}, .user_data = (void *)&((qk_tap_dance_pair_t){kc1, kc2}), }
 
-#    define ACTION_TAP_DANCE_DUAL_ROLE(kc, layer) \
+#    define ACTION_TAP_DANCE_LAYER_MOVE(kc, layer) \
         { .fn = {qk_tap_dance_dual_role_on_each_tap, qk_tap_dance_dual_role_finished, qk_tap_dance_dual_role_reset}, .user_data = (void *)&((qk_tap_dance_dual_role_t){kc, layer, layer_move}), }
 
 #    define ACTION_TAP_DANCE_LAYER_TOGGLE(kc, layer) \
         { .fn = {NULL, qk_tap_dance_dual_role_finished, qk_tap_dance_dual_role_reset}, .user_data = (void *)&((qk_tap_dance_dual_role_t){kc, layer, layer_invert}), }
 
-#    define ACTION_TAP_DANCE_LAYER_MOVE(kc, layer) ACTION_TAP_DANCE_DUAL_ROLE(kc, layer)
-
 #    define ACTION_TAP_DANCE_FN(user_fn) \
         { .fn = {NULL, user_fn, NULL}, .user_data = NULL, }
 
 #    define ACTION_TAP_DANCE_FN_ADVANCED(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset) \
         { .fn = {user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset}, .user_data = NULL, }
 
-#    define ACTION_TAP_DANCE_FN_ADVANCED_TIME(user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset, tap_specific_tapping_term) \
-        { .fn = {user_fn_on_each_tap, user_fn_on_dance_finished, user_fn_on_dance_reset}, .user_data = NULL, .custom_tapping_term = tap_specific_tapping_term, }
+#    define TD(n) (QK_TAP_DANCE | TD_INDEX(n))
+#    define TD_INDEX(code) ((code)&0xFF)
+#    define TAP_DANCE_KEYCODE(state) TD(((qk_tap_dance_action_t *)state) - tap_dance_actions)
 
 extern qk_tap_dance_action_t tap_dance_actions[];
 
+void reset_tap_dance(qk_tap_dance_state_t *state);
+
 /* To be used internally */
 
 void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record);
 bool process_tap_dance(uint16_t keycode, keyrecord_t *record);
 void tap_dance_task(void);
-void reset_tap_dance(qk_tap_dance_state_t *state);
 
 void qk_tap_dance_pair_on_each_tap(qk_tap_dance_state_t *state, void *user_data);
 void qk_tap_dance_pair_finished(qk_tap_dance_state_t *state, void *user_data);