]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/process_keycode/process_tap_dance.c
tap-dance: Add some debugging support
[qmk_firmware.git] / quantum / process_keycode / process_tap_dance.c
1 #include "quantum.h"
2
3 static qk_tap_dance_state_t qk_tap_dance_state;
4 bool td_debug_enable = false;
5
6 #if CONSOLE_ENABLE
7 #define td_debug(s) if (td_debug_enable) \
8     { \
9       xprintf ("D:tap_dance:%s:%s = { keycode = %d, count = %d, active = %d, pressed = %d }\n", __FUNCTION__, s, \
10                qk_tap_dance_state.keycode, qk_tap_dance_state.count, \
11                qk_tap_dance_state.active, qk_tap_dance_state.pressed);  \
12     }
13 #else
14 #define td_debug(s)
15 #endif
16
17 void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data) {
18   qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
19
20   if (state->count == 1) {
21     register_code (pair->kc1);
22   } else if (state->count == 2) {
23     register_code (pair->kc2);
24   }
25 }
26
27 void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) {
28   qk_tap_dance_pair_t *pair = (qk_tap_dance_pair_t *)user_data;
29
30   if (state->count == 1) {
31     unregister_code (pair->kc1);
32   } else if (state->count == 2) {
33     unregister_code (pair->kc2);
34   }
35 }
36
37 static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
38                                           void *user_data,
39                                           qk_tap_dance_user_fn_t fn)
40 {
41   if (fn) {
42     fn(state, user_data);
43   }
44 }
45
46 static inline void process_tap_dance_action_on_each_tap (qk_tap_dance_action_t action)
47 {
48   td_debug("trigger");
49   _process_tap_dance_action_fn (&qk_tap_dance_state, action.user_data, action.fn.on_each_tap);
50 }
51
52 static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_action_t action)
53 {
54   td_debug("trigger");
55   _process_tap_dance_action_fn (&qk_tap_dance_state, action.user_data, action.fn.on_dance_finished);
56 }
57
58 static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t action)
59 {
60   td_debug("trigger")
61   _process_tap_dance_action_fn (&qk_tap_dance_state, action.user_data, action.fn.on_reset);
62 }
63
64 bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
65   bool r = true;
66   uint16_t idx = keycode - QK_TAP_DANCE;
67   qk_tap_dance_action_t action;
68
69   switch(keycode) {
70   case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
71     action = tap_dance_actions[idx];
72
73     process_tap_dance_action_on_each_tap (action);
74     if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) {
75       process_tap_dance_action_on_dance_finished (action);
76     } else if (qk_tap_dance_state.active && qk_tap_dance_state.pressed) {
77       reset_tap_dance (&qk_tap_dance_state);
78     } else {
79       r = false;
80     }
81
82     qk_tap_dance_state.active = true;
83     qk_tap_dance_state.pressed = record->event.pressed;
84     if (record->event.pressed) {
85       qk_tap_dance_state.keycode = keycode;
86       qk_tap_dance_state.timer = timer_read ();
87       qk_tap_dance_state.count++;
88     }
89     break;
90
91   default:
92     if (qk_tap_dance_state.keycode) {
93       // if we are here, the tap dance was interrupted by a different key
94       idx = qk_tap_dance_state.keycode - QK_TAP_DANCE;
95       action = tap_dance_actions[idx];
96
97       process_tap_dance_action_on_each_tap (action);
98       process_tap_dance_action_on_dance_finished (action);
99       reset_tap_dance (&qk_tap_dance_state);
100       qk_tap_dance_state.active = false;
101     }
102     break;
103   }
104
105   return r;
106 }
107
108 void matrix_scan_tap_dance () {
109   if (qk_tap_dance_state.active && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) {
110     // if we are here, the tap dance was timed out
111     uint16_t idx = qk_tap_dance_state.keycode - QK_TAP_DANCE;
112     qk_tap_dance_action_t action = tap_dance_actions[idx];
113
114     process_tap_dance_action_on_dance_finished (action);
115     reset_tap_dance (&qk_tap_dance_state);
116   }
117 }
118
119 void reset_tap_dance (qk_tap_dance_state_t *state) {
120   uint16_t idx = state->keycode - QK_TAP_DANCE;
121   qk_tap_dance_action_t action;
122
123   if (state->pressed)
124     return;
125
126   action = tap_dance_actions[idx];
127   process_tap_dance_action_on_reset (action);
128
129   state->keycode = 0;
130   state->count = 0;
131   state->active = false;
132 }