2020 February 29 Breaking Changes Update (#8064)
[jackhill/qmk/firmware.git] / tmk_core / common / action.c
CommitLineData
a074364c 1/*
2Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "host.h"
18#include "keycode.h"
19#include "keyboard.h"
20#include "mousekey.h"
21#include "command.h"
22#include "led.h"
a074364c 23#include "action_layer.h"
24#include "action_tapping.h"
25#include "action_macro.h"
26#include "action_util.h"
27#include "action.h"
9c284786 28#include "wait.h"
a074364c 29
abfd6ed9
JC
30#ifdef BACKLIGHT_ENABLE
31# include "backlight.h"
32#endif
33
2bbf3d58 34#ifdef DEBUG_ACTION
b624f32f 35# include "debug.h"
2bbf3d58 36#else
b624f32f 37# include "nodebug.h"
2bbf3d58 38#endif
a074364c 39
81e85a1a 40int tp_buttons;
41
04b9b62b 42#ifdef RETRO_TAPPING
43int retro_tapping_counter = 0;
44#endif
45
c68e596f 46#ifdef FAUXCLICKY_ENABLE
b624f32f 47# include <fauxclicky.h>
c68e596f 48#endif
a074364c 49
7f388b65 50#ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY
667045b4 51__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode) { return false; }
7f388b65 52#endif
53
3261c408 54#ifndef TAP_CODE_DELAY
b624f32f 55# define TAP_CODE_DELAY 0
3261c408 56#endif
48b01446 57#ifndef TAP_HOLD_CAPS_DELAY
b624f32f 58# define TAP_HOLD_CAPS_DELAY 80
48b01446 59#endif
7c9d5ace 60/** \brief Called to execute an action.
61 *
62 * FIXME: Needs documentation.
63 */
b624f32f 64void action_exec(keyevent_t event) {
a074364c 65 if (!IS_NOEVENT(event)) {
66 dprint("\n---- action_exec: start -----\n");
b624f32f 67 dprint("EVENT: ");
68 debug_event(event);
69 dprintln();
04b9b62b 70#ifdef RETRO_TAPPING
71 retro_tapping_counter++;
72#endif
a074364c 73 }
74
c68e596f
PIN
75#ifdef FAUXCLICKY_ENABLE
76 if (IS_PRESSED(event)) {
77 FAUXCLICKY_ACTION_PRESS;
78 }
79 if (IS_RELEASED(event)) {
80 FAUXCLICKY_ACTION_RELEASE;
81 }
82 fauxclicky_check();
83#endif
84
7230923b 85#ifdef SWAP_HANDS_ENABLE
dd378601
JW
86 if (!IS_NOEVENT(event)) {
87 process_hand_swap(&event);
88 }
89#endif
90
b624f32f 91 keyrecord_t record = {.event = event};
a074364c 92
c3200aa8
TL
93#ifndef NO_ACTION_ONESHOT
94# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
45e0d094 95 if (has_oneshot_layer_timed_out()) {
45e0d094
S
96 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
97 }
3ab0f4d9
CQ
98 if (has_oneshot_mods_timed_out()) {
99 clear_oneshot_mods();
100 }
c3200aa8 101# endif
45e0d094
S
102#endif
103
a074364c 104#ifndef NO_ACTION_TAPPING
105 action_tapping_process(record);
106#else
bf5c2cce 107 process_record(&record);
a074364c 108 if (!IS_NOEVENT(record.event)) {
b624f32f 109 dprint("processed: ");
110 debug_record(record);
111 dprintln();
a074364c 112 }
113#endif
114}
115
7230923b 116#ifdef SWAP_HANDS_ENABLE
dd378601 117bool swap_hands = false;
b624f32f 118bool swap_held = false;
dd378601 119
7c9d5ace 120/** \brief Process Hand Swap
121 *
122 * FIXME: Needs documentation.
123 */
dd378601
JW
124void process_hand_swap(keyevent_t *event) {
125 static swap_state_row_t swap_state[MATRIX_ROWS];
126
b624f32f 127 keypos_t pos = event->key;
128 swap_state_row_t col_bit = (swap_state_row_t)1 << pos.col;
129 bool do_swap = event->pressed ? swap_hands : swap_state[pos.row] & (col_bit);
dd378601
JW
130
131 if (do_swap) {
132 event->key = hand_swap_config[pos.row][pos.col];
133 swap_state[pos.row] |= col_bit;
134 } else {
135 swap_state[pos.row] &= ~(col_bit);
136 }
137}
138#endif
139
74344947 140#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
20dd9c03
WS
141bool disable_action_cache = false;
142
b624f32f 143void process_record_nocache(keyrecord_t *record) {
20dd9c03 144 disable_action_cache = true;
bf5c2cce 145 process_record(record);
20dd9c03
WS
146 disable_action_cache = false;
147}
73cb8774 148#else
b624f32f 149void process_record_nocache(keyrecord_t *record) { process_record(record); }
20dd9c03
WS
150#endif
151
b624f32f 152__attribute__((weak)) bool process_record_quantum(keyrecord_t *record) { return true; }
ef21a855 153
5d771039 154#ifndef NO_ACTION_TAPPING
7c9d5ace 155/** \brief Allows for handling tap-hold actions immediately instead of waiting for TAPPING_TERM or another keypress.
156 *
157 * FIXME: Needs documentation.
158 */
b624f32f 159void process_record_tap_hint(keyrecord_t *record) {
5d771039
JW
160 action_t action = layer_switch_get_action(record->event.key);
161
162 switch (action.kind.id) {
b624f32f 163# ifdef SWAP_HANDS_ENABLE
5d771039
JW
164 case ACT_SWAP_HANDS:
165 switch (action.swap.code) {
166 case OP_SH_TAP_TOGGLE:
167 default:
168 swap_hands = !swap_hands;
b624f32f 169 swap_held = true;
5d771039
JW
170 }
171 break;
b624f32f 172# endif
5d771039
JW
173 }
174}
175#endif
176
7c9d5ace 177/** \brief Take a key event (key press or key release) and processes it.
178 *
179 * FIXME: Needs documentation.
180 */
b624f32f 181void process_record(keyrecord_t *record) {
182 if (IS_NOEVENT(record->event)) {
bf5c2cce 183 return;
b624f32f 184 }
185
186 if (!process_record_quantum(record)) return;
bf5c2cce
JH
187
188 action_t action = store_or_get_action(record->event.pressed, record->event.key);
b624f32f 189 dprint("ACTION: ");
190 debug_action(action);
bf5c2cce 191#ifndef NO_ACTION_LAYER
b624f32f 192 dprint(" layer_state: ");
193 layer_debug();
194 dprint(" default_layer_state: ");
195 default_layer_debug();
bf5c2cce
JH
196#endif
197 dprintln();
198
199 process_action(record, action);
200}
201
7c9d5ace 202/** \brief Take an action and processes it.
203 *
204 * FIXME: Needs documentation.
205 */
b624f32f 206void process_action(keyrecord_t *record, action_t action) {
a074364c 207 keyevent_t event = record->event;
208#ifndef NO_ACTION_TAPPING
209 uint8_t tap_count = record->tap.count;
210#endif
211
b7a81f04
DL
212 if (event.pressed) {
213 // clear the potential weak mods left by previously pressed keys
214 clear_weak_mods();
215 }
74e97eef
TA
216
217#ifndef NO_ACTION_ONESHOT
07fc34e9 218 bool do_release_oneshot = false;
74e97eef
TA
219 // notice we only clear the one shot layer if the pressed key is not a modifier.
220 if (is_oneshot_layer_active() && event.pressed && !IS_MOD(action.key.code)) {
221 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
222 do_release_oneshot = !is_oneshot_layer_active();
223 }
224#endif
225
a074364c 226 switch (action.kind.id) {
227 /* Key and Mods */
228 case ACT_LMODS:
b624f32f 229 case ACT_RMODS: {
230 uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods : action.key.mods << 4;
231 if (event.pressed) {
232 if (mods) {
233 if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
234 // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless.
235 // This also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT).
236 // Same applies for some keys like KC_MEH which are declared as MEH(KC_NO).
237 add_mods(mods);
238 } else {
239 add_weak_mods(mods);
a074364c 240 }
b624f32f 241 send_keyboard_report();
242 }
243 register_code(action.key.code);
244 } else {
245 unregister_code(action.key.code);
246 if (mods) {
247 if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
248 del_mods(mods);
249 } else {
250 del_weak_mods(mods);
a074364c 251 }
b624f32f 252 send_keyboard_report();
a074364c 253 }
254 }
b624f32f 255 } break;
a074364c 256#ifndef NO_ACTION_TAPPING
257 case ACT_LMODS_TAP:
b624f32f 258 case ACT_RMODS_TAP: {
259 uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods : action.key.mods << 4;
260 switch (action.layer_tap.code) {
261# ifndef NO_ACTION_ONESHOT
262 case MODS_ONESHOT:
263 // Oneshot modifier
264 if (event.pressed) {
265 if (tap_count == 0) {
266 dprint("MODS_TAP: Oneshot: 0\n");
267 register_mods(mods | get_oneshot_mods());
268 } else if (tap_count == 1) {
269 dprint("MODS_TAP: Oneshot: start\n");
270 set_oneshot_mods(mods | get_oneshot_mods());
271# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
272 } else if (tap_count == ONESHOT_TAP_TOGGLE) {
273 dprint("MODS_TAP: Toggling oneshot");
274 clear_oneshot_mods();
275 set_oneshot_locked_mods(mods);
276 register_mods(mods);
277# endif
a074364c 278 } else {
b624f32f 279 register_mods(mods | get_oneshot_mods());
280 }
281 } else {
282 if (tap_count == 0) {
283 clear_oneshot_mods();
284 unregister_mods(mods);
285 } else if (tap_count == 1) {
286 // Retain Oneshot mods
287# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
288 if (mods & get_mods()) {
289 clear_oneshot_locked_mods();
a074364c 290 clear_oneshot_mods();
291 unregister_mods(mods);
292 }
b624f32f 293 } else if (tap_count == ONESHOT_TAP_TOGGLE) {
294 // Toggle Oneshot Layer
295# endif
296 } else {
297 clear_oneshot_mods();
298 unregister_mods(mods);
a074364c 299 }
b624f32f 300 }
301 break;
302# endif
303 case MODS_TAP_TOGGLE:
304 if (event.pressed) {
305 if (tap_count <= TAPPING_TOGGLE) {
306 register_mods(mods);
307 }
308 } else {
309 if (tap_count < TAPPING_TOGGLE) {
310 unregister_mods(mods);
311 }
312 }
313 break;
314 default:
315 if (event.pressed) {
316 if (tap_count > 0) {
7f388b65 317# if !defined(IGNORE_MOD_TAP_INTERRUPT) || defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY)
318 if (
319# ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY
320 !get_ignore_mod_tap_interrupt(get_event_keycode(record->event)) &&
321# endif
322 record->tap.interrupted) {
b624f32f 323 dprint("mods_tap: tap: cancel: add_mods\n");
324 // ad hoc: set 0 to cancel tap
325 record->tap.count = 0;
a074364c 326 register_mods(mods);
b624f32f 327 } else
328# endif
329 {
330 dprint("MODS_TAP: Tap: register_code\n");
331 register_code(action.key.code);
a074364c 332 }
333 } else {
b624f32f 334 dprint("MODS_TAP: No tap: add_mods\n");
335 register_mods(mods);
a074364c 336 }
b624f32f 337 } else {
338 if (tap_count > 0) {
339 dprint("MODS_TAP: Tap: unregister_code\n");
340 if (action.layer_tap.code == KC_CAPS) {
341 wait_ms(TAP_HOLD_CAPS_DELAY);
a074364c 342 }
b624f32f 343 unregister_code(action.key.code);
a074364c 344 } else {
b624f32f 345 dprint("MODS_TAP: No tap: add_mods\n");
346 unregister_mods(mods);
a074364c 347 }
b624f32f 348 }
349 break;
a074364c 350 }
b624f32f 351 } break;
a074364c 352#endif
353#ifdef EXTRAKEY_ENABLE
354 /* other HID usage */
355 case ACT_USAGE:
356 switch (action.usage.page) {
357 case PAGE_SYSTEM:
358 if (event.pressed) {
359 host_system_send(action.usage.code);
360 } else {
361 host_system_send(0);
362 }
363 break;
364 case PAGE_CONSUMER:
365 if (event.pressed) {
366 host_consumer_send(action.usage.code);
367 } else {
368 host_consumer_send(0);
369 }
370 break;
371 }
372 break;
373#endif
374#ifdef MOUSEKEY_ENABLE
375 /* Mouse key */
376 case ACT_MOUSEKEY:
377 if (event.pressed) {
81e85a1a 378 switch (action.key.code) {
379 case KC_MS_BTN1:
b624f32f 380 tp_buttons |= (1 << 0);
81e85a1a 381 break;
382 case KC_MS_BTN2:
b624f32f 383 tp_buttons |= (1 << 1);
81e85a1a 384 break;
385 case KC_MS_BTN3:
b624f32f 386 tp_buttons |= (1 << 2);
81e85a1a 387 break;
388 default:
b6c60333 389 break;
81e85a1a 390 }
b6c60333
JH
391 mousekey_on(action.key.code);
392 mousekey_send();
a074364c 393 } else {
81e85a1a 394 switch (action.key.code) {
395 case KC_MS_BTN1:
b624f32f 396 tp_buttons &= ~(1 << 0);
81e85a1a 397 break;
398 case KC_MS_BTN2:
b624f32f 399 tp_buttons &= ~(1 << 1);
81e85a1a 400 break;
401 case KC_MS_BTN3:
b624f32f 402 tp_buttons &= ~(1 << 2);
81e85a1a 403 break;
404 default:
b6c60333 405 break;
81e85a1a 406 }
b6c60333
JH
407 mousekey_off(action.key.code);
408 mousekey_send();
a074364c 409 }
410 break;
411#endif
412#ifndef NO_ACTION_LAYER
413 case ACT_LAYER:
414 if (action.layer_bitop.on == 0) {
415 /* Default Layer Bitwise Operation */
416 if (!event.pressed) {
b624f32f 417 uint8_t shift = action.layer_bitop.part * 4;
418 layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift;
419 layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0;
a074364c 420 switch (action.layer_bitop.op) {
b624f32f 421 case OP_BIT_AND:
422 default_layer_and(bits | mask);
423 break;
424 case OP_BIT_OR:
425 default_layer_or(bits | mask);
426 break;
427 case OP_BIT_XOR:
428 default_layer_xor(bits | mask);
429 break;
430 case OP_BIT_SET:
431 default_layer_set(bits | mask);
432 break;
a074364c 433 }
434 }
435 } else {
436 /* Layer Bitwise Operation */
b624f32f 437 if (event.pressed ? (action.layer_bitop.on & ON_PRESS) : (action.layer_bitop.on & ON_RELEASE)) {
438 uint8_t shift = action.layer_bitop.part * 4;
439 layer_state_t bits = ((layer_state_t)action.layer_bitop.bits) << shift;
440 layer_state_t mask = (action.layer_bitop.xbit) ? ~(((layer_state_t)0xf) << shift) : 0;
a074364c 441 switch (action.layer_bitop.op) {
b624f32f 442 case OP_BIT_AND:
443 layer_and(bits | mask);
444 break;
445 case OP_BIT_OR:
446 layer_or(bits | mask);
447 break;
448 case OP_BIT_XOR:
449 layer_xor(bits | mask);
450 break;
451 case OP_BIT_SET:
452 layer_state_set(bits | mask);
453 break;
a074364c 454 }
455 }
456 }
457 break;
2f6c068e 458 case ACT_LAYER_MODS:
459 if (event.pressed) {
460 layer_on(action.layer_mods.layer);
461 register_mods(action.layer_mods.mods);
462 } else {
463 unregister_mods(action.layer_mods.mods);
464 layer_off(action.layer_mods.layer);
465 }
466 break;
b624f32f 467# ifndef NO_ACTION_TAPPING
a074364c 468 case ACT_LAYER_TAP:
469 case ACT_LAYER_TAP_EXT:
470 switch (action.layer_tap.code) {
a074364c 471 case OP_TAP_TOGGLE:
472 /* tap toggle */
473 if (event.pressed) {
474 if (tap_count < TAPPING_TOGGLE) {
475 layer_invert(action.layer_tap.val);
476 }
477 } else {
478 if (tap_count <= TAPPING_TOGGLE) {
479 layer_invert(action.layer_tap.val);
480 }
481 }
482 break;
483 case OP_ON_OFF:
b624f32f 484 event.pressed ? layer_on(action.layer_tap.val) : layer_off(action.layer_tap.val);
a074364c 485 break;
486 case OP_OFF_ON:
b624f32f 487 event.pressed ? layer_off(action.layer_tap.val) : layer_on(action.layer_tap.val);
a074364c 488 break;
489 case OP_SET_CLEAR:
b624f32f 490 event.pressed ? layer_move(action.layer_tap.val) : layer_clear();
a074364c 491 break;
b624f32f 492# ifndef NO_ACTION_ONESHOT
74e97eef
TA
493 case OP_ONESHOT:
494 // Oneshot modifier
b624f32f 495# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
74e97eef
TA
496 do_release_oneshot = false;
497 if (event.pressed) {
498 del_mods(get_oneshot_locked_mods());
499 if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
500 reset_oneshot_layer();
501 layer_off(action.layer_tap.val);
502 break;
503 } else if (tap_count < ONESHOT_TAP_TOGGLE) {
504 layer_on(action.layer_tap.val);
505 set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
506 }
507 } else {
508 add_mods(get_oneshot_locked_mods());
509 if (tap_count >= ONESHOT_TAP_TOGGLE) {
510 reset_oneshot_layer();
511 clear_oneshot_locked_mods();
512 set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED);
513 } else {
514 clear_oneshot_layer_state(ONESHOT_PRESSED);
515 }
516 }
b624f32f 517# else
74e97eef
TA
518 if (event.pressed) {
519 layer_on(action.layer_tap.val);
520 set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
521 } else {
522 clear_oneshot_layer_state(ONESHOT_PRESSED);
523 if (tap_count > 1) {
524 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
525 }
526 }
b624f32f 527# endif
74e97eef 528 break;
b624f32f 529# endif
a074364c 530 default:
531 /* tap key */
532 if (event.pressed) {
533 if (tap_count > 0) {
534 dprint("KEYMAP_TAP_KEY: Tap: register_code\n");
535 register_code(action.layer_tap.code);
536 } else {
537 dprint("KEYMAP_TAP_KEY: No tap: On on press\n");
538 layer_on(action.layer_tap.val);
539 }
540 } else {
541 if (tap_count > 0) {
542 dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n");
9c284786 543 if (action.layer_tap.code == KC_CAPS) {
48b01446 544 wait_ms(TAP_HOLD_CAPS_DELAY);
3261c408
DJ
545 } else {
546 wait_ms(TAP_CODE_DELAY);
b624f32f 547 }
a074364c 548 unregister_code(action.layer_tap.code);
549 } else {
550 dprint("KEYMAP_TAP_KEY: No tap: Off on release\n");
551 layer_off(action.layer_tap.val);
552 }
553 }
554 break;
555 }
556 break;
b624f32f 557# endif
a074364c 558#endif
b624f32f 559 /* Extentions */
a074364c 560#ifndef NO_ACTION_MACRO
561 case ACT_MACRO:
562 action_macro_play(action_get_macro(record, action.func.id, action.func.opt));
563 break;
a074364c 564#endif
565 case ACT_COMMAND:
8090f6b4 566 break;
7230923b 567#ifdef SWAP_HANDS_ENABLE
8090f6b4
JW
568 case ACT_SWAP_HANDS:
569 switch (action.swap.code) {
570 case OP_SH_TOGGLE:
571 if (event.pressed) {
572 swap_hands = !swap_hands;
573 }
574 break;
575 case OP_SH_ON_OFF:
dd378601
JW
576 swap_hands = event.pressed;
577 break;
8090f6b4
JW
578 case OP_SH_OFF_ON:
579 swap_hands = !event.pressed;
580 break;
581 case OP_SH_ON:
582 if (!event.pressed) {
583 swap_hands = true;
584 }
585 break;
586 case OP_SH_OFF:
587 if (!event.pressed) {
588 swap_hands = false;
589 }
590 break;
b624f32f 591# ifndef NO_ACTION_TAPPING
8090f6b4
JW
592 case OP_SH_TAP_TOGGLE:
593 /* tap toggle */
5d771039
JW
594
595 if (event.pressed) {
596 if (swap_held) {
597 swap_held = false;
598 } else {
8090f6b4
JW
599 swap_hands = !swap_hands;
600 }
601 } else {
5d771039
JW
602 if (tap_count < TAPPING_TOGGLE) {
603 swap_hands = !swap_hands;
604 }
8090f6b4
JW
605 }
606 break;
607 default:
5d771039 608 /* tap key */
8090f6b4 609 if (tap_count > 0) {
5d771039 610 if (swap_held) {
b624f32f 611 swap_hands = !swap_hands; // undo hold set up in _tap_hint
612 swap_held = false;
5d771039 613 }
8090f6b4
JW
614 if (event.pressed) {
615 register_code(action.swap.code);
616 } else {
3261c408 617 wait_ms(TAP_CODE_DELAY);
8090f6b4 618 unregister_code(action.swap.code);
b624f32f 619 *record = (keyrecord_t){}; // hack: reset tap mode
8090f6b4
JW
620 }
621 } else {
5d771039 622 if (swap_held && !event.pressed) {
b624f32f 623 swap_hands = !swap_hands; // undo hold set up in _tap_hint
624 swap_held = false;
5d771039 625 }
8090f6b4 626 }
b624f32f 627# endif
dd378601 628 }
8090f6b4 629#endif
a074364c 630#ifndef NO_ACTION_FUNCTION
631 case ACT_FUNCTION:
632 action_function(record, action.func.id, action.func.opt);
633 break;
634#endif
635 default:
636 break;
637 }
74e97eef 638
bd2c0b96
N
639#ifndef NO_ACTION_LAYER
640 // if this event is a layer action, update the leds
641 switch (action.kind.id) {
642 case ACT_LAYER:
2f6c068e 643 case ACT_LAYER_MODS:
b624f32f 644# ifndef NO_ACTION_TAPPING
bd2c0b96
N
645 case ACT_LAYER_TAP:
646 case ACT_LAYER_TAP_EXT:
b624f32f 647# endif
bd2c0b96
N
648 led_set(host_keyboard_leds());
649 break;
650 default:
651 break;
652 }
653#endif
654
04b9b62b 655#ifndef NO_ACTION_TAPPING
b624f32f 656# ifdef RETRO_TAPPING
657 if (!is_tap_action(action)) {
04b9b62b 658 retro_tapping_counter = 0;
b624f32f 659 } else {
660 if (event.pressed) {
661 if (tap_count > 0) {
662 retro_tapping_counter = 0;
663 } else {
664 }
665 } else {
666 if (tap_count > 0) {
667 retro_tapping_counter = 0;
668 } else {
669 if (retro_tapping_counter == 2) {
670 tap_code(action.layer_tap.code);
671 }
672 retro_tapping_counter = 0;
673 }
04b9b62b 674 }
04b9b62b 675 }
b624f32f 676# endif
04b9b62b 677#endif
678
74e97eef
TA
679#ifndef NO_ACTION_ONESHOT
680 /* Because we switch layers after a oneshot event, we need to release the
681 * key before we leave the layer or no key up event will be generated.
682 */
b624f32f 683 if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED)) {
74e97eef
TA
684 record->event.pressed = false;
685 layer_on(get_oneshot_layer());
bf5c2cce 686 process_record(record);
74e97eef
TA
687 layer_off(get_oneshot_layer());
688 }
689#endif
a074364c 690}
691
7c9d5ace 692/** \brief Utilities for actions. (FIXME: Needs better description)
693 *
694 * FIXME: Needs documentation.
a074364c 695 */
b624f32f 696void register_code(uint8_t code) {
a074364c 697 if (code == KC_NO) {
698 return;
699 }
a074364c 700#ifdef LOCKING_SUPPORT_ENABLE
701 else if (KC_LOCKING_CAPS == code) {
b624f32f 702# ifdef LOCKING_RESYNC_ENABLE
a074364c 703 // Resync: ignore if caps lock already is on
b624f32f 704 if (host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK)) return;
705# endif
a074364c 706 add_key(KC_CAPSLOCK);
707 send_keyboard_report();
04b9b62b 708 wait_ms(100);
a074364c 709 del_key(KC_CAPSLOCK);
710 send_keyboard_report();
711 }
712
713 else if (KC_LOCKING_NUM == code) {
b624f32f 714# ifdef LOCKING_RESYNC_ENABLE
715 if (host_keyboard_leds() & (1 << USB_LED_NUM_LOCK)) return;
716# endif
a074364c 717 add_key(KC_NUMLOCK);
718 send_keyboard_report();
04b9b62b 719 wait_ms(100);
a074364c 720 del_key(KC_NUMLOCK);
721 send_keyboard_report();
722 }
723
724 else if (KC_LOCKING_SCROLL == code) {
b624f32f 725# ifdef LOCKING_RESYNC_ENABLE
726 if (host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK)) return;
727# endif
a074364c 728 add_key(KC_SCROLLLOCK);
729 send_keyboard_report();
04b9b62b 730 wait_ms(100);
a074364c 731 del_key(KC_SCROLLLOCK);
732 send_keyboard_report();
733 }
734#endif
735
b624f32f 736 else if
737 IS_KEY(code) {
738 // TODO: should push command_proc out of this block?
739 if (command_proc(code)) return;
a074364c 740
741#ifndef NO_ACTION_ONESHOT
742/* TODO: remove
743 if (oneshot_state.mods && !oneshot_state.disabled) {
744 uint8_t tmp_mods = get_mods();
745 add_mods(oneshot_state.mods);
746
747 add_key(code);
748 send_keyboard_report();
749
750 set_mods(tmp_mods);
751 send_keyboard_report();
752 oneshot_cancel();
f024a462 753 } else
a074364c 754*/
755#endif
b624f32f 756 {
757 add_key(code);
758 send_keyboard_report();
759 }
760 }
761 else if
762 IS_MOD(code) {
763 add_mods(MOD_BIT(code));
a074364c 764 send_keyboard_report();
765 }
b624f32f 766 else if
767 IS_SYSTEM(code) { host_system_send(KEYCODE2SYSTEM(code)); }
768 else if
769 IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); }
a14eb018 770
b624f32f 771#ifdef MOUSEKEY_ENABLE
772 else if
773 IS_MOUSEKEY(code) {
774 mousekey_on(code);
775 mousekey_send();
776 }
777#endif
a074364c 778}
779
7c9d5ace 780/** \brief Utilities for actions. (FIXME: Needs better description)
781 *
782 * FIXME: Needs documentation.
783 */
b624f32f 784void unregister_code(uint8_t code) {
a074364c 785 if (code == KC_NO) {
786 return;
787 }
a074364c 788#ifdef LOCKING_SUPPORT_ENABLE
789 else if (KC_LOCKING_CAPS == code) {
b624f32f 790# ifdef LOCKING_RESYNC_ENABLE
a074364c 791 // Resync: ignore if caps lock already is off
b624f32f 792 if (!(host_keyboard_leds() & (1 << USB_LED_CAPS_LOCK))) return;
793# endif
a074364c 794 add_key(KC_CAPSLOCK);
795 send_keyboard_report();
796 del_key(KC_CAPSLOCK);
797 send_keyboard_report();
798 }
799
800 else if (KC_LOCKING_NUM == code) {
b624f32f 801# ifdef LOCKING_RESYNC_ENABLE
802 if (!(host_keyboard_leds() & (1 << USB_LED_NUM_LOCK))) return;
803# endif
a074364c 804 add_key(KC_NUMLOCK);
805 send_keyboard_report();
806 del_key(KC_NUMLOCK);
807 send_keyboard_report();
808 }
809
810 else if (KC_LOCKING_SCROLL == code) {
b624f32f 811# ifdef LOCKING_RESYNC_ENABLE
812 if (!(host_keyboard_leds() & (1 << USB_LED_SCROLL_LOCK))) return;
813# endif
a074364c 814 add_key(KC_SCROLLLOCK);
815 send_keyboard_report();
816 del_key(KC_SCROLLLOCK);
817 send_keyboard_report();
818 }
819#endif
820
b624f32f 821 else if
822 IS_KEY(code) {
823 del_key(code);
824 send_keyboard_report();
825 }
826 else if
827 IS_MOD(code) {
828 del_mods(MOD_BIT(code));
829 send_keyboard_report();
830 }
831 else if
832 IS_SYSTEM(code) { host_system_send(0); }
833 else if
834 IS_CONSUMER(code) { host_consumer_send(0); }
835#ifdef MOUSEKEY_ENABLE
836 else if
837 IS_MOUSEKEY(code) {
838 mousekey_off(code);
839 mousekey_send();
840 }
841#endif
a074364c 842}
843
02d44beb
DJ
844/** \brief Utilities for actions. (FIXME: Needs better description)
845 *
846 * FIXME: Needs documentation.
847 */
848void tap_code(uint8_t code) {
b624f32f 849 register_code(code);
850 if (code == KC_CAPS) {
851 wait_ms(TAP_HOLD_CAPS_DELAY);
852 } else {
853 wait_ms(TAP_CODE_DELAY);
854 }
855 unregister_code(code);
02d44beb
DJ
856}
857
63f4806d 858/** \brief Adds the given physically pressed modifiers and sends a keyboard report immediately.
7c9d5ace 859 *
63f4806d 860 * \param mods A bitfield of modifiers to unregister.
7c9d5ace 861 */
b624f32f 862void register_mods(uint8_t mods) {
a074364c 863 if (mods) {
864 add_mods(mods);
865 send_keyboard_report();
866 }
867}
868
63f4806d 869/** \brief Removes the given physically pressed modifiers and sends a keyboard report immediately.
7c9d5ace 870 *
63f4806d 871 * \param mods A bitfield of modifiers to unregister.
7c9d5ace 872 */
b624f32f 873void unregister_mods(uint8_t mods) {
a074364c 874 if (mods) {
875 del_mods(mods);
876 send_keyboard_report();
877 }
878}
879
63f4806d 880/** \brief Adds the given weak modifiers and sends a keyboard report immediately.
881 *
882 * \param mods A bitfield of modifiers to register.
883 */
884void register_weak_mods(uint8_t mods) {
885 if (mods) {
886 add_weak_mods(mods);
887 send_keyboard_report();
888 }
889}
890
891/** \brief Removes the given weak modifiers and sends a keyboard report immediately.
892 *
893 * \param mods A bitfield of modifiers to unregister.
894 */
895void unregister_weak_mods(uint8_t mods) {
896 if (mods) {
897 del_weak_mods(mods);
898 send_keyboard_report();
899 }
900}
901
7c9d5ace 902/** \brief Utilities for actions. (FIXME: Needs better description)
903 *
904 * FIXME: Needs documentation.
905 */
b624f32f 906void clear_keyboard(void) {
a074364c 907 clear_mods();
908 clear_keyboard_but_mods();
909}
910
7c9d5ace 911/** \brief Utilities for actions. (FIXME: Needs better description)
912 *
913 * FIXME: Needs documentation.
914 */
b624f32f 915void clear_keyboard_but_mods(void) {
93b004c9
916 clear_keys();
917 clear_keyboard_but_mods_and_keys();
918}
919
920/** \brief Utilities for actions. (FIXME: Needs better description)
921 *
922 * FIXME: Needs documentation.
923 */
b624f32f 924void clear_keyboard_but_mods_and_keys() {
a074364c 925 clear_weak_mods();
b7a81f04 926 clear_macro_mods();
a074364c 927 send_keyboard_report();
928#ifdef MOUSEKEY_ENABLE
929 mousekey_clear();
930 mousekey_send();
931#endif
932#ifdef EXTRAKEY_ENABLE
933 host_system_send(0);
934 host_consumer_send(0);
935#endif
936}
937
7c9d5ace 938/** \brief Utilities for actions. (FIXME: Needs better description)
939 *
940 * FIXME: Needs documentation.
941 */
b624f32f 942bool is_tap_key(keypos_t key) {
a074364c 943 action_t action = layer_switch_get_action(key);
8e47f648 944 return is_tap_action(action);
945}
a074364c 946
8e47f648 947/** \brief Utilities for actions. (FIXME: Needs better description)
948 *
949 * FIXME: Needs documentation.
950 */
b624f32f 951bool is_tap_action(action_t action) {
a074364c 952 switch (action.kind.id) {
953 case ACT_LMODS_TAP:
954 case ACT_RMODS_TAP:
955 case ACT_LAYER_TAP:
956 case ACT_LAYER_TAP_EXT:
1f4a22ee 957 switch (action.layer_tap.code) {
2f6c068e 958 case KC_NO ... KC_RGUI:
1f4a22ee 959 case OP_TAP_TOGGLE:
74e97eef 960 case OP_ONESHOT:
1f4a22ee
JW
961 return true;
962 }
963 return false;
8090f6b4
JW
964 case ACT_SWAP_HANDS:
965 switch (action.swap.code) {
2f6c068e 966 case KC_NO ... KC_RGUI:
8090f6b4
JW
967 case OP_SH_TAP_TOGGLE:
968 return true;
969 }
970 return false;
a074364c 971 case ACT_MACRO:
972 case ACT_FUNCTION:
b624f32f 973 if (action.func.opt & FUNC_TAP) {
974 return true;
975 }
a074364c 976 return false;
977 }
978 return false;
979}
980
7c9d5ace 981/** \brief Debug print (FIXME: Needs better description)
982 *
983 * FIXME: Needs documentation.
a074364c 984 */
b624f32f 985void debug_event(keyevent_t event) { dprintf("%04X%c(%u)", (event.key.row << 8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); }
a074364c 986
7c9d5ace 987/** \brief Debug print (FIXME: Needs better description)
988 *
989 * FIXME: Needs documentation.
990 */
b624f32f 991void debug_record(keyrecord_t record) {
a074364c 992 debug_event(record.event);
993#ifndef NO_ACTION_TAPPING
994 dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' '));
995#endif
996}
997
7c9d5ace 998/** \brief Debug print (FIXME: Needs better description)
999 *
1000 * FIXME: Needs documentation.
1001 */
b624f32f 1002void debug_action(action_t action) {
a074364c 1003 switch (action.kind.id) {
b624f32f 1004 case ACT_LMODS:
1005 dprint("ACT_LMODS");
1006 break;
1007 case ACT_RMODS:
1008 dprint("ACT_RMODS");
1009 break;
1010 case ACT_LMODS_TAP:
1011 dprint("ACT_LMODS_TAP");
1012 break;
1013 case ACT_RMODS_TAP:
1014 dprint("ACT_RMODS_TAP");
1015 break;
1016 case ACT_USAGE:
1017 dprint("ACT_USAGE");
1018 break;
1019 case ACT_MOUSEKEY:
1020 dprint("ACT_MOUSEKEY");
1021 break;
1022 case ACT_LAYER:
1023 dprint("ACT_LAYER");
1024 break;
1025 case ACT_LAYER_MODS:
1026 dprint("ACT_LAYER_MODS");
1027 break;
1028 case ACT_LAYER_TAP:
1029 dprint("ACT_LAYER_TAP");
1030 break;
1031 case ACT_LAYER_TAP_EXT:
1032 dprint("ACT_LAYER_TAP_EXT");
1033 break;
1034 case ACT_MACRO:
1035 dprint("ACT_MACRO");
1036 break;
1037 case ACT_COMMAND:
1038 dprint("ACT_COMMAND");
1039 break;
1040 case ACT_FUNCTION:
1041 dprint("ACT_FUNCTION");
1042 break;
1043 case ACT_SWAP_HANDS:
1044 dprint("ACT_SWAP_HANDS");
1045 break;
1046 default:
1047 dprint("UNKNOWN");
1048 break;
a074364c 1049 }
b624f32f 1050 dprintf("[%X:%02X]", action.kind.param >> 8, action.kind.param & 0xff);
a074364c 1051}