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