]> git.donarmstrong.com Git - tmk_firmware.git/blob - common/action_tapping.c
Fix Tapping: release of a key pressed before tap
[tmk_firmware.git] / common / action_tapping.c
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include "action.h"
4 #include "action_tapping.h"
5 #include "timer.h"
6
7 #ifdef DEBUG_ACTION
8 #include "debug.h"
9 #else
10 #include "nodebug.h"
11 #endif
12
13 #ifndef NO_ACTION_TAPPING
14
15 #define IS_TAPPING()            !IS_NOEVENT(tapping_key.event)
16 #define IS_TAPPING_PRESSED()    (IS_TAPPING() && tapping_key.event.pressed)
17 #define IS_TAPPING_RELEASED()   (IS_TAPPING() && !tapping_key.event.pressed)
18 #define IS_TAPPING_KEY(k)       (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
19 #define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
20
21
22 static keyrecord_t tapping_key = {};
23 static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
24 static uint8_t waiting_buffer_head = 0;
25 static uint8_t waiting_buffer_tail = 0;
26
27 static bool process_tapping(keyrecord_t *record);
28 static bool waiting_buffer_enq(keyrecord_t record);
29 static void waiting_buffer_clear(void);
30 static bool waiting_buffer_typed(keyevent_t event);
31 static bool waiting_buffer_has_anykey_pressed(void);
32 static void waiting_buffer_scan_tap(void);
33 static void debug_tapping_key(void);
34 static void debug_waiting_buffer(void);
35
36
37 void action_tapping_process(keyrecord_t record)
38 {
39     if (process_tapping(&record)) {
40         if (!IS_NOEVENT(record.event)) {
41             debug("processed: "); debug_record(record); debug("\n");
42         }
43     } else {
44         if (!waiting_buffer_enq(record)) {
45             // clear all in case of overflow.
46             debug("OVERFLOW: CLEAR ALL STATES\n");
47             clear_keyboard();
48             waiting_buffer_clear();
49             tapping_key = (keyrecord_t){};
50         }
51     }
52
53     // process waiting_buffer
54     if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) {
55         debug("---- action_exec: process waiting_buffer -----\n");
56     }
57     for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
58         if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
59             debug("processed: waiting_buffer["); debug_dec(waiting_buffer_tail); debug("] = ");
60             debug_record(waiting_buffer[waiting_buffer_tail]); debug("\n\n");
61         } else {
62             break;
63         }
64     }
65     if (!IS_NOEVENT(record.event)) {
66         debug("\n");
67     }
68 }
69
70
71 /* Tapping
72  *
73  * Rule: Tap key is typed(pressed and released) within TAPPING_TERM.
74  *       (without interfering by typing other key)
75  */
76 /* return true when key event is processed or consumed. */
77 bool process_tapping(keyrecord_t *keyp)
78 {
79     keyevent_t event = keyp->event;
80
81     // if tapping
82     if (IS_TAPPING_PRESSED()) {
83         if (WITHIN_TAPPING_TERM(event)) {
84             if (tapping_key.tap.count == 0) {
85                 if (IS_TAPPING_KEY(event.key) && !event.pressed) {
86                     // first tap!
87                     debug("Tapping: First tap(0->1).\n");
88                     tapping_key.tap.count = 1;
89                     debug_tapping_key();
90                     process_action(&tapping_key);
91
92                     // copy tapping state
93                     keyp->tap = tapping_key.tap;
94                     // enqueue
95                     return false;
96                 }
97 #if TAPPING_TERM >= 500
98                 /* This can settle mod/fn state fast but may prevent from typing fast. */
99                 else if (!event.pressed && waiting_buffer_typed(event)) {
100                     // other key typed. not tap.
101                     debug("Tapping: End. No tap. Interfered by typing key\n");
102                     process_action(&tapping_key);
103                     tapping_key = (keyrecord_t){};
104                     debug_tapping_key();
105
106                     // enqueue
107                     return false;
108                 }
109 #endif
110                 /* release a key pressed before tapping */
111                 else if (!event.pressed && !waiting_buffer_typed(event)) {
112                     /* Unexpected repeating occurs unless this event is processed immedately. */
113                     debug("Tapping: release a key pressed before tapping\n");
114                     process_action(keyp);
115                     return true;
116                 }
117                 else {
118                     // set interrupted flag when other key preesed during tapping
119                     if (event.pressed) {
120                         tapping_key.tap.interrupted = true;
121                     }
122                     // enqueue 
123                     return false;
124                 }
125             }
126             // tap_count > 0
127             else {
128                 if (IS_TAPPING_KEY(event.key) && !event.pressed) {
129                     debug("Tapping: Tap release("); debug_dec(tapping_key.tap.count); debug(")\n");
130                     keyp->tap = tapping_key.tap;
131                     process_action(keyp);
132                     tapping_key = *keyp;
133                     debug_tapping_key();
134                     return true;
135                 }
136                 else if (is_tap_key(event.key) && event.pressed) {
137                     if (tapping_key.tap.count > 1) {
138                         debug("Tapping: Start new tap with releasing last tap(>1).\n");
139                         // unregister key
140                         process_action(&(keyrecord_t){
141                                 .tap = tapping_key.tap,
142                                 .event.key = tapping_key.event.key,
143                                 .event.time = event.time,
144                                 .event.pressed = false
145                         });
146                     } else {
147                         debug("Tapping: Start while last tap(1).\n");
148                     }
149                     tapping_key = *keyp;
150                     waiting_buffer_scan_tap();
151                     debug_tapping_key();
152                     return true;
153                 }
154                 else {
155                     if (!IS_NOEVENT(event)) {
156                         debug("Tapping: key event while last tap(>0).\n");
157                     }
158                     process_action(keyp);
159                     return true;
160                 }
161             }
162         }
163         // after TAPPING_TERM
164         else {
165             if (tapping_key.tap.count == 0) {
166                 debug("Tapping: End. Timeout. Not tap(0): ");
167                 debug_event(event); debug("\n");
168                 process_action(&tapping_key);
169                 tapping_key = (keyrecord_t){};
170                 debug_tapping_key();
171                 return false;
172             }  else {
173                 if (IS_TAPPING_KEY(event.key) && !event.pressed) {
174                     debug("Tapping: End. last timeout tap release(>0).");
175                     keyp->tap = tapping_key.tap;
176                     process_action(keyp);
177                     tapping_key = (keyrecord_t){};
178                     return true;
179                 }
180                 else if (is_tap_key(event.key) && event.pressed) {
181                     if (tapping_key.tap.count > 1) {
182                         debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
183                         // unregister key
184                         process_action(&(keyrecord_t){
185                                 .tap = tapping_key.tap,
186                                 .event.key = tapping_key.event.key,
187                                 .event.time = event.time,
188                                 .event.pressed = false
189                         });
190                     } else {
191                         debug("Tapping: Start while last timeout tap(1).\n");
192                     }
193                     tapping_key = *keyp;
194                     waiting_buffer_scan_tap();
195                     debug_tapping_key();
196                     return true;
197                 }
198                 else {
199                     if (!IS_NOEVENT(event)) {
200                         debug("Tapping: key event while last timeout tap(>0).\n");
201                     }
202                     process_action(keyp);
203                     return true;
204                 }
205             }
206         }
207     } else if (IS_TAPPING_RELEASED()) {
208         if (WITHIN_TAPPING_TERM(event)) {
209             if (event.pressed) {
210                 if (IS_TAPPING_KEY(event.key)) {
211                     if (!tapping_key.tap.interrupted && tapping_key.tap.count > 0) {
212                         // sequential tap.
213                         keyp->tap = tapping_key.tap;
214                         if (keyp->tap.count < 15) keyp->tap.count += 1;
215                         debug("Tapping: Tap press("); debug_dec(keyp->tap.count); debug(")\n");
216                         process_action(keyp);
217                         tapping_key = *keyp;
218                         debug_tapping_key();
219                         return true;
220                     } else {
221                         // FIX: start new tap again
222                         tapping_key = *keyp;
223                         return true;
224                     }
225                 } else if (is_tap_key(event.key)) {
226                     // Sequential tap can be interfered with other tap key.
227                     debug("Tapping: Start with interfering other tap.\n");
228                     tapping_key = *keyp;
229                     waiting_buffer_scan_tap();
230                     debug_tapping_key();
231                     return true;
232                 } else {
233                     // should none in buffer
234                     // FIX: interrupted when other key is pressed
235                     tapping_key.tap.interrupted = true;
236                     process_action(keyp);
237                     return true;
238                 }
239             } else {
240                 if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
241                 process_action(keyp);
242                 return true;
243             }
244         } else {
245             // FIX: process_aciton here?
246             // timeout. no sequential tap.
247             debug("Tapping: End(Timeout after releasing last tap): ");
248             debug_event(event); debug("\n");
249             tapping_key = (keyrecord_t){};
250             debug_tapping_key();
251             return false;
252         }
253     }
254     // not tapping state
255     else {
256         if (event.pressed && is_tap_key(event.key)) {
257             debug("Tapping: Start(Press tap key).\n");
258             tapping_key = *keyp;
259             waiting_buffer_scan_tap();
260             debug_tapping_key();
261             return true;
262         } else {
263             process_action(keyp);
264             return true;
265         }
266     }
267 }
268
269
270 /*
271  * Waiting buffer
272  */
273 bool waiting_buffer_enq(keyrecord_t record)
274 {
275     if (IS_NOEVENT(record.event)) {
276         return true;
277     }
278
279     if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
280         debug("waiting_buffer_enq: Over flow.\n");
281         return false;
282     }
283
284     waiting_buffer[waiting_buffer_head] = record;
285     waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;
286
287     debug("waiting_buffer_enq: "); debug_waiting_buffer();
288     return true;
289 }
290
291 void waiting_buffer_clear(void)
292 {
293     waiting_buffer_head = 0;
294     waiting_buffer_tail = 0;
295 }
296
297 bool waiting_buffer_typed(keyevent_t event)
298 {
299     for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
300         if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed !=  waiting_buffer[i].event.pressed) {
301             return true;
302         }
303     }
304     return false;
305 }
306
307 bool waiting_buffer_has_anykey_pressed(void)
308 {
309     for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
310         if (waiting_buffer[i].event.pressed) return true;
311     }
312     return false;
313 }
314
315 /* scan buffer for tapping */
316 void waiting_buffer_scan_tap(void)
317 {
318     // tapping already is settled
319     if (tapping_key.tap.count > 0) return;
320     // invalid state: tapping_key released && tap.count == 0
321     if (!tapping_key.event.pressed) return;
322
323     for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
324         if (IS_TAPPING_KEY(waiting_buffer[i].event.key) &&
325                 !waiting_buffer[i].event.pressed &&
326                 WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
327             tapping_key.tap.count = 1;
328             waiting_buffer[i].tap.count = 1;
329             process_action(&tapping_key);
330
331             debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n");
332             debug_waiting_buffer();
333             return;
334         }
335     }
336 }
337
338
339 /*
340  * debug print
341  */
342 static void debug_tapping_key(void)
343 {
344     debug("TAPPING_KEY="); debug_record(tapping_key); debug("\n");
345 }
346
347 static void debug_waiting_buffer(void)
348 {
349     debug("{ ");
350     for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
351         debug("["); debug_dec(i); debug("]="); debug_record(waiting_buffer[i]); debug(" ");
352     }
353     debug("}\n");
354 }
355
356 #endif