aboutsummaryrefslogtreecommitdiff
path: root/quantum/action_tapping.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/action_tapping.c')
-rw-r--r--quantum/action_tapping.c491
1 files changed, 491 insertions, 0 deletions
diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c
new file mode 100644
index 000000000..eef6ed1b7
--- /dev/null
+++ b/quantum/action_tapping.c
@@ -0,0 +1,491 @@
1#include <stdint.h>
2#include <stdbool.h>
3#include "action.h"
4#include "action_layer.h"
5#include "action_tapping.h"
6#include "keycode.h"
7#include "timer.h"
8#include "keymap.h"
9
10#ifdef DEBUG_ACTION
11# include "debug.h"
12#else
13# include "nodebug.h"
14#endif
15
16#ifndef NO_ACTION_TAPPING
17
18# define IS_TAPPING() !IS_NOEVENT(tapping_key.event)
19# define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed)
20# define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed)
21# define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
22#ifndef COMBO_ENABLE
23# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)))
24#else
25# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
26#endif
27
28__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; }
29
30# ifdef TAPPING_TERM_PER_KEY
31# 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))
32# else
33# define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
34# endif
35
36# ifdef TAPPING_FORCE_HOLD_PER_KEY
37__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) { return false; }
38# endif
39
40# ifdef PERMISSIVE_HOLD_PER_KEY
41__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { return false; }
42# endif
43
44# ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY
45__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { return false; }
46# endif
47
48static keyrecord_t tapping_key = {};
49static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
50static uint8_t waiting_buffer_head = 0;
51static uint8_t waiting_buffer_tail = 0;
52
53static bool process_tapping(keyrecord_t *record);
54static bool waiting_buffer_enq(keyrecord_t record);
55static void waiting_buffer_clear(void);
56static bool waiting_buffer_typed(keyevent_t event);
57static bool waiting_buffer_has_anykey_pressed(void);
58static void waiting_buffer_scan_tap(void);
59static void debug_tapping_key(void);
60static void debug_waiting_buffer(void);
61
62/* Convert record into usable keycode via the contained event. */
63uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) {
64#ifdef COMBO_ENABLE
65 if (record->keycode) { return record->keycode; }
66#endif
67 return get_event_keycode(record->event, update_layer_cache);
68}
69
70/* Convert event into usable keycode. Checks the layer cache to ensure that it
71 * retains the correct keycode after a layer change, if the key is still pressed.
72 * "update_layer_cache" is to ensure that it only updates the layer cache when
73 * appropriate, otherwise, it will update it and cause layer tap (and other keys)
74 * from triggering properly.
75 */
76uint16_t get_event_keycode(keyevent_t event, bool update_layer_cache) {
77 const keypos_t key = event.key;
78
79#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
80 /* TODO: Use store_or_get_action() or a similar function. */
81 if (!disable_action_cache) {
82 uint8_t layer;
83
84 if (event.pressed && update_layer_cache) {
85 layer = layer_switch_get_layer(key);
86 update_source_layers_cache(key, layer);
87 } else {
88 layer = read_source_layers_cache(key);
89 }
90 return keymap_key_to_keycode(layer, key);
91 }
92#endif
93 return keymap_key_to_keycode(layer_switch_get_layer(key), key);
94}
95
96/** \brief Action Tapping Process
97 *
98 * FIXME: Needs doc
99 */
100void action_tapping_process(keyrecord_t record) {
101 if (process_tapping(&record)) {
102 if (!IS_NOEVENT(record.event)) {
103 debug("processed: ");
104 debug_record(record);
105 debug("\n");
106 }
107 } else {
108 if (!waiting_buffer_enq(record)) {
109 // clear all in case of overflow.
110 debug("OVERFLOW: CLEAR ALL STATES\n");
111 clear_keyboard();
112 waiting_buffer_clear();
113 tapping_key = (keyrecord_t){};
114 }
115 }
116
117 // process waiting_buffer
118 if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) {
119 debug("---- action_exec: process waiting_buffer -----\n");
120 }
121 for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
122 if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
123 debug("processed: waiting_buffer[");
124 debug_dec(waiting_buffer_tail);
125 debug("] = ");
126 debug_record(waiting_buffer[waiting_buffer_tail]);
127 debug("\n\n");
128 } else {
129 break;
130 }
131 }
132 if (!IS_NOEVENT(record.event)) {
133 debug("\n");
134 }
135}
136
137/** \brief Tapping
138 *
139 * Rule: Tap key is typed(pressed and released) within TAPPING_TERM.
140 * (without interfering by typing other key)
141 */
142/* return true when key event is processed or consumed. */
143bool process_tapping(keyrecord_t *keyp) {
144 keyevent_t event = keyp->event;
145
146 // if tapping
147 if (IS_TAPPING_PRESSED()) {
148 if (WITHIN_TAPPING_TERM(event)) {
149 if (tapping_key.tap.count == 0) {
150 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
151 // first tap!
152 debug("Tapping: First tap(0->1).\n");
153 tapping_key.tap.count = 1;
154 debug_tapping_key();
155 process_record(&tapping_key);
156
157 // copy tapping state
158 keyp->tap = tapping_key.tap;
159 // enqueue
160 return false;
161 }
162 /* Process a key typed within TAPPING_TERM
163 * This can register the key before settlement of tapping,
164 * useful for long TAPPING_TERM but may prevent fast typing.
165 */
166# if defined(TAPPING_TERM_PER_KEY) || (TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD) || defined(PERMISSIVE_HOLD_PER_KEY)
167 else if (((
168# ifdef TAPPING_TERM_PER_KEY
169 get_tapping_term(get_record_keycode(&tapping_key, false), keyp)
170# else
171 TAPPING_TERM
172# endif
173 >= 500)
174
175# ifdef PERMISSIVE_HOLD_PER_KEY
176 || get_permissive_hold(get_record_keycode(&tapping_key, false), keyp)
177# elif defined(PERMISSIVE_HOLD)
178 || true
179# endif
180 ) &&
181 IS_RELEASED(event) && waiting_buffer_typed(event)) {
182 debug("Tapping: End. No tap. Interfered by typing key\n");
183 process_record(&tapping_key);
184 tapping_key = (keyrecord_t){};
185 debug_tapping_key();
186 // enqueue
187 return false;
188 }
189# endif
190 /* Process release event of a key pressed before tapping starts
191 * Without this unexpected repeating will occur with having fast repeating setting
192 * https://github.com/tmk/tmk_keyboard/issues/60
193 */
194 else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) {
195 // Modifier should be retained till end of this tapping.
196 action_t action = layer_switch_get_action(event.key);
197 switch (action.kind.id) {
198 case ACT_LMODS:
199 case ACT_RMODS:
200 if (action.key.mods && !action.key.code) return false;
201 if (IS_MOD(action.key.code)) return false;
202 break;
203 case ACT_LMODS_TAP:
204 case ACT_RMODS_TAP:
205 if (action.key.mods && keyp->tap.count == 0) return false;
206 if (IS_MOD(action.key.code)) return false;
207 break;
208 }
209 // Release of key should be process immediately.
210 debug("Tapping: release event of a key pressed before tapping\n");
211 process_record(keyp);
212 return true;
213 } else {
214 // set interrupted flag when other key preesed during tapping
215 if (event.pressed) {
216 tapping_key.tap.interrupted = true;
217# if defined(HOLD_ON_OTHER_KEY_PRESS) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY)
218# if defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY)
219 if (get_hold_on_other_key_press(get_record_keycode(&tapping_key, false), keyp))
220# endif
221 {
222 debug("Tapping: End. No tap. Interfered by pressed key\n");
223 process_record(&tapping_key);
224 tapping_key = (keyrecord_t){};
225 debug_tapping_key();
226 // enqueue
227 return false;
228 }
229# endif
230 }
231 // enqueue
232 return false;
233 }
234 }
235 // tap_count > 0
236 else {
237 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
238 debug("Tapping: Tap release(");
239 debug_dec(tapping_key.tap.count);
240 debug(")\n");
241 keyp->tap = tapping_key.tap;
242 process_record(keyp);
243 tapping_key = *keyp;
244 debug_tapping_key();
245 return true;
246 } else if (is_tap_record(keyp) && event.pressed) {
247 if (tapping_key.tap.count > 1) {
248 debug("Tapping: Start new tap with releasing last tap(>1).\n");
249 // unregister key
250 process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false,
251#ifdef COMBO_ENABLE
252 .keycode = tapping_key.keycode,
253#endif
254 });
255 } else {
256 debug("Tapping: Start while last tap(1).\n");
257 }
258 tapping_key = *keyp;
259 waiting_buffer_scan_tap();
260 debug_tapping_key();
261 return true;
262 } else {
263 if (!IS_NOEVENT(event)) {
264 debug("Tapping: key event while last tap(>0).\n");
265 }
266 process_record(keyp);
267 return true;
268 }
269 }
270 }
271 // after TAPPING_TERM
272 else {
273 if (tapping_key.tap.count == 0) {
274 debug("Tapping: End. Timeout. Not tap(0): ");
275 debug_event(event);
276 debug("\n");
277 process_record(&tapping_key);
278 tapping_key = (keyrecord_t){};
279 debug_tapping_key();
280 return false;
281 } else {
282 if (IS_TAPPING_RECORD(keyp) && !event.pressed) {
283 debug("Tapping: End. last timeout tap release(>0).");
284 keyp->tap = tapping_key.tap;
285 process_record(keyp);
286 tapping_key = (keyrecord_t){};
287 return true;
288 } else if (is_tap_record(keyp) && event.pressed) {
289 if (tapping_key.tap.count > 1) {
290 debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
291 // unregister key
292 process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false,
293#ifdef COMBO_ENABLE
294 .keycode = tapping_key.keycode,
295#endif
296 });
297 } else {
298 debug("Tapping: Start while last timeout tap(1).\n");
299 }
300 tapping_key = *keyp;
301 waiting_buffer_scan_tap();
302 debug_tapping_key();
303 return true;
304 } else {
305 if (!IS_NOEVENT(event)) {
306 debug("Tapping: key event while last timeout tap(>0).\n");
307 }
308 process_record(keyp);
309 return true;
310 }
311 }
312 }
313 } else if (IS_TAPPING_RELEASED()) {
314 if (WITHIN_TAPPING_TERM(event)) {
315 if (event.pressed) {
316 if (IS_TAPPING_RECORD(keyp)) {
317//# ifndef TAPPING_FORCE_HOLD
318# if !defined(TAPPING_FORCE_HOLD) || defined(TAPPING_FORCE_HOLD_PER_KEY)
319 if (
320# ifdef TAPPING_FORCE_HOLD_PER_KEY
321 !get_tapping_force_hold(get_record_keycode(&tapping_key, false), keyp) &&
322# endif
323 !tapping_key.tap.interrupted && tapping_key.tap.count > 0) {
324 // sequential tap.
325 keyp->tap = tapping_key.tap;
326 if (keyp->tap.count < 15) keyp->tap.count += 1;
327 debug("Tapping: Tap press(");
328 debug_dec(keyp->tap.count);
329 debug(")\n");
330 process_record(keyp);
331 tapping_key = *keyp;
332 debug_tapping_key();
333 return true;
334 }
335# endif
336 // FIX: start new tap again
337 tapping_key = *keyp;
338 return true;
339 } else if (is_tap_record(keyp)) {
340 // Sequential tap can be interfered with other tap key.
341 debug("Tapping: Start with interfering other tap.\n");
342 tapping_key = *keyp;
343 waiting_buffer_scan_tap();
344 debug_tapping_key();
345 return true;
346 } else {
347 // should none in buffer
348 // FIX: interrupted when other key is pressed
349 tapping_key.tap.interrupted = true;
350 process_record(keyp);
351 return true;
352 }
353 } else {
354 if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
355 process_record(keyp);
356 return true;
357 }
358 } else {
359 // FIX: process_action here?
360 // timeout. no sequential tap.
361 debug("Tapping: End(Timeout after releasing last tap): ");
362 debug_event(event);
363 debug("\n");
364 tapping_key = (keyrecord_t){};
365 debug_tapping_key();
366 return false;
367 }
368 }
369 // not tapping state
370 else {
371 if (event.pressed && is_tap_record(keyp)) {
372 debug("Tapping: Start(Press tap key).\n");
373 tapping_key = *keyp;
374 process_record_tap_hint(&tapping_key);
375 waiting_buffer_scan_tap();
376 debug_tapping_key();
377 return true;
378 } else {
379 process_record(keyp);
380 return true;
381 }
382 }
383}
384
385/** \brief Waiting buffer enq
386 *
387 * FIXME: Needs docs
388 */
389bool waiting_buffer_enq(keyrecord_t record) {
390 if (IS_NOEVENT(record.event)) {
391 return true;
392 }
393
394 if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
395 debug("waiting_buffer_enq: Over flow.\n");
396 return false;
397 }
398
399 waiting_buffer[waiting_buffer_head] = record;
400 waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;
401
402 debug("waiting_buffer_enq: ");
403 debug_waiting_buffer();
404 return true;
405}
406
407/** \brief Waiting buffer clear
408 *
409 * FIXME: Needs docs
410 */
411void waiting_buffer_clear(void) {
412 waiting_buffer_head = 0;
413 waiting_buffer_tail = 0;
414}
415
416/** \brief Waiting buffer typed
417 *
418 * FIXME: Needs docs
419 */
420bool waiting_buffer_typed(keyevent_t event) {
421 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
422 if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) {
423 return true;
424 }
425 }
426 return false;
427}
428
429/** \brief Waiting buffer has anykey pressed
430 *
431 * FIXME: Needs docs
432 */
433__attribute__((unused)) bool waiting_buffer_has_anykey_pressed(void) {
434 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
435 if (waiting_buffer[i].event.pressed) return true;
436 }
437 return false;
438}
439
440/** \brief Scan buffer for tapping
441 *
442 * FIXME: Needs docs
443 */
444void waiting_buffer_scan_tap(void) {
445 // tapping already is settled
446 if (tapping_key.tap.count > 0) return;
447 // invalid state: tapping_key released && tap.count == 0
448 if (!tapping_key.event.pressed) return;
449
450 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
451 if (IS_TAPPING_KEY(waiting_buffer[i].event.key) && !waiting_buffer[i].event.pressed && WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
452 tapping_key.tap.count = 1;
453 waiting_buffer[i].tap.count = 1;
454 process_record(&tapping_key);
455
456 debug("waiting_buffer_scan_tap: found at [");
457 debug_dec(i);
458 debug("]\n");
459 debug_waiting_buffer();
460 return;
461 }
462 }
463}
464
465/** \brief Tapping key debug print
466 *
467 * FIXME: Needs docs
468 */
469static void debug_tapping_key(void) {
470 debug("TAPPING_KEY=");
471 debug_record(tapping_key);
472 debug("\n");
473}
474
475/** \brief Waiting buffer debug print
476 *
477 * FIXME: Needs docs
478 */
479static void debug_waiting_buffer(void) {
480 debug("{ ");
481 for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
482 debug("[");
483 debug_dec(i);
484 debug("]=");
485 debug_record(waiting_buffer[i]);
486 debug(" ");
487 }
488 debug("}\n");
489}
490
491#endif