]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/action.c
Merge pull request #2 from qmk/master
[qmk_firmware.git] / tmk_core / common / action.c
1 /*
2 Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along 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"
23 #include "backlight.h"
24 #include "action_layer.h"
25 #include "action_tapping.h"
26 #include "action_macro.h"
27 #include "action_util.h"
28 #include "action.h"
29 #include "wait.h"
30
31 #ifdef DEBUG_ACTION
32 #include "debug.h"
33 #else
34 #include "nodebug.h"
35 #endif
36
37 int tp_buttons;
38
39 #ifdef FAUXCLICKY_ENABLE
40 #include <fauxclicky.h>
41 #endif
42
43 void action_exec(keyevent_t event)
44 {
45     if (!IS_NOEVENT(event)) {
46         dprint("\n---- action_exec: start -----\n");
47         dprint("EVENT: "); debug_event(event); dprintln();
48     }
49
50 #ifdef FAUXCLICKY_ENABLE
51     if (IS_PRESSED(event)) {
52         FAUXCLICKY_ACTION_PRESS;
53     }
54     if (IS_RELEASED(event)) {
55         FAUXCLICKY_ACTION_RELEASE;
56     }
57     fauxclicky_check();
58 #endif
59
60 #ifdef ONEHAND_ENABLE
61     if (!IS_NOEVENT(event)) {
62         process_hand_swap(&event);
63     }
64 #endif
65
66     keyrecord_t record = { .event = event };
67
68 #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
69     if (has_oneshot_layer_timed_out()) {
70         dprintf("Oneshot layer: timeout\n");
71         clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
72     }
73 #endif
74
75 #ifndef NO_ACTION_TAPPING
76     action_tapping_process(record);
77 #else
78     process_record(&record);
79     if (!IS_NOEVENT(record.event)) {
80         dprint("processed: "); debug_record(record); dprintln();
81     }
82 #endif
83 }
84
85 #ifdef ONEHAND_ENABLE
86 bool swap_hands = false;
87
88 void process_hand_swap(keyevent_t *event) {
89     static swap_state_row_t swap_state[MATRIX_ROWS];
90
91     keypos_t pos = event->key;
92     swap_state_row_t col_bit = (swap_state_row_t)1<<pos.col;
93     bool do_swap = event->pressed ? swap_hands :
94                                     swap_state[pos.row] & (col_bit);
95
96     if (do_swap) {
97         event->key = hand_swap_config[pos.row][pos.col];
98         swap_state[pos.row] |= col_bit;
99     } else {
100         swap_state[pos.row] &= ~(col_bit);
101     }
102 }
103 #endif
104
105 #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
106 bool disable_action_cache = false;
107
108 void process_record_nocache(keyrecord_t *record)
109 {
110     disable_action_cache = true;
111     process_record(record);
112     disable_action_cache = false;
113 }
114 #else
115 void process_record_nocache(keyrecord_t *record)
116 {
117     process_record(record);
118 }
119 #endif
120
121 __attribute__ ((weak))
122 bool process_record_quantum(keyrecord_t *record) {
123     return true;
124 }
125
126 void process_record(keyrecord_t *record)
127 {
128     if (IS_NOEVENT(record->event)) { return; }
129
130     if(!process_record_quantum(record))
131         return;
132
133     action_t action = store_or_get_action(record->event.pressed, record->event.key);
134     dprint("ACTION: "); debug_action(action);
135 #ifndef NO_ACTION_LAYER
136     dprint(" layer_state: "); layer_debug();
137     dprint(" default_layer_state: "); default_layer_debug();
138 #endif
139     dprintln();
140
141     process_action(record, action);
142 }
143
144 void process_action(keyrecord_t *record, action_t action)
145 {
146     keyevent_t event = record->event;
147 #ifndef NO_ACTION_TAPPING
148     uint8_t tap_count = record->tap.count;
149 #endif
150
151     if (event.pressed) {
152         // clear the potential weak mods left by previously pressed keys
153         clear_weak_mods();
154     }
155
156 #ifndef NO_ACTION_ONESHOT
157     bool do_release_oneshot = false;
158     // notice we only clear the one shot layer if the pressed key is not a modifier.
159     if (is_oneshot_layer_active() && event.pressed && !IS_MOD(action.key.code)) {
160         clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
161         do_release_oneshot = !is_oneshot_layer_active();
162     }
163 #endif
164
165     switch (action.kind.id) {
166         /* Key and Mods */
167         case ACT_LMODS:
168         case ACT_RMODS:
169             {
170                 uint8_t mods = (action.kind.id == ACT_LMODS) ?  action.key.mods :
171                                                                 action.key.mods<<4;
172                 if (event.pressed) {
173                     if (mods) {
174                         if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
175                             // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless.
176                             // This also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT).
177                             // Same applies for some keys like KC_MEH which are declared as MEH(KC_NO).
178                             add_mods(mods);
179                         } else {
180                             add_weak_mods(mods);
181                         }
182                         send_keyboard_report();
183                     }
184                     register_code(action.key.code);
185                 } else {
186                     unregister_code(action.key.code);
187                     if (mods) {
188                         if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
189                             del_mods(mods);
190                         } else {
191                             del_weak_mods(mods);
192                         }
193                         send_keyboard_report();
194                     }
195                 }
196             }
197             break;
198 #ifndef NO_ACTION_TAPPING
199         case ACT_LMODS_TAP:
200         case ACT_RMODS_TAP:
201             {
202                 uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ?  action.key.mods :
203                                                                     action.key.mods<<4;
204                 switch (action.layer_tap.code) {
205     #ifndef NO_ACTION_ONESHOT
206                     case MODS_ONESHOT:
207                         // Oneshot modifier
208                         if (event.pressed) {
209                             if (tap_count == 0) {
210                                 dprint("MODS_TAP: Oneshot: 0\n");
211                                 register_mods(mods);
212                             } else if (tap_count == 1) {
213                                 dprint("MODS_TAP: Oneshot: start\n");
214                                 set_oneshot_mods(mods);
215                     #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
216                             } else if (tap_count == ONESHOT_TAP_TOGGLE) {
217                                 dprint("MODS_TAP: Toggling oneshot");
218                                 clear_oneshot_mods();
219                                 set_oneshot_locked_mods(mods);
220                                 register_mods(mods);
221                     #endif
222                             } else {
223                                 register_mods(mods);
224                             }
225                         } else {
226                             if (tap_count == 0) {
227                                 clear_oneshot_mods();
228                                 unregister_mods(mods);
229                             } else if (tap_count == 1) {
230                                 // Retain Oneshot mods
231                     #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
232                                 if (mods & get_mods()) {
233                                     clear_oneshot_locked_mods();
234                                     clear_oneshot_mods();
235                                     unregister_mods(mods);
236                                 }
237                             } else if (tap_count == ONESHOT_TAP_TOGGLE) {
238                                 // Toggle Oneshot Layer
239                     #endif
240                             } else {
241                                 clear_oneshot_mods();
242                                 unregister_mods(mods);
243                             }
244                         }
245                         break;
246     #endif
247                     case MODS_TAP_TOGGLE:
248                         if (event.pressed) {
249                             if (tap_count <= TAPPING_TOGGLE) {
250                                 register_mods(mods);
251                             }
252                         } else {
253                             if (tap_count < TAPPING_TOGGLE) {
254                                 unregister_mods(mods);
255                             }
256                         }
257                         break;
258                     default:
259                         if (event.pressed) {
260                             if (tap_count > 0) {
261 #ifndef IGNORE_MOD_TAP_INTERRUPT
262                                 if (record->tap.interrupted) {
263                                     dprint("mods_tap: tap: cancel: add_mods\n");
264                                     // ad hoc: set 0 to cancel tap
265                                     record->tap.count = 0;
266                                     register_mods(mods);
267                                 } else
268 #endif
269                                 {
270                                     dprint("MODS_TAP: Tap: register_code\n");
271                                     register_code(action.key.code);
272                                 }
273                             } else {
274                                 dprint("MODS_TAP: No tap: add_mods\n");
275                                 register_mods(mods);
276                             }
277                         } else {
278                             if (tap_count > 0) {
279                                 dprint("MODS_TAP: Tap: unregister_code\n");
280                                 unregister_code(action.key.code);
281                             } else {
282                                 dprint("MODS_TAP: No tap: add_mods\n");
283                                 unregister_mods(mods);
284                             }
285                         }
286                         break;
287                 }
288             }
289             break;
290 #endif
291 #ifdef EXTRAKEY_ENABLE
292         /* other HID usage */
293         case ACT_USAGE:
294             switch (action.usage.page) {
295                 case PAGE_SYSTEM:
296                     if (event.pressed) {
297                         host_system_send(action.usage.code);
298                     } else {
299                         host_system_send(0);
300                     }
301                     break;
302                 case PAGE_CONSUMER:
303                     if (event.pressed) {
304                         host_consumer_send(action.usage.code);
305                     } else {
306                         host_consumer_send(0);
307                     }
308                     break;
309             }
310             break;
311 #endif
312 #ifdef MOUSEKEY_ENABLE
313         /* Mouse key */
314         case ACT_MOUSEKEY:
315             if (event.pressed) {
316                 switch (action.key.code) {
317                     case KC_MS_BTN1:
318                         tp_buttons |= (1<<0);
319                         break;
320                     case KC_MS_BTN2:
321                         tp_buttons |= (1<<1);
322                         break;
323                     case KC_MS_BTN3:
324                         tp_buttons |= (1<<2);
325                         break;
326                     default:
327                         break;
328                 }
329                 mousekey_on(action.key.code);
330                 mousekey_send();
331             } else {
332                 switch (action.key.code) {
333                     case KC_MS_BTN1:
334                         tp_buttons &= ~(1<<0);
335                         break;
336                     case KC_MS_BTN2:
337                         tp_buttons &= ~(1<<1);
338                         break;
339                     case KC_MS_BTN3:
340                         tp_buttons &= ~(1<<2);
341                         break;
342                     default:
343                         break;
344                 }
345                 mousekey_off(action.key.code);
346                 mousekey_send();
347             }
348             break;
349 #endif
350 #ifndef NO_ACTION_LAYER
351         case ACT_LAYER:
352             if (action.layer_bitop.on == 0) {
353                 /* Default Layer Bitwise Operation */
354                 if (!event.pressed) {
355                     uint8_t shift = action.layer_bitop.part*4;
356                     uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
357                     uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
358                     switch (action.layer_bitop.op) {
359                         case OP_BIT_AND: default_layer_and(bits | mask); break;
360                         case OP_BIT_OR:  default_layer_or(bits | mask);  break;
361                         case OP_BIT_XOR: default_layer_xor(bits | mask); break;
362                         case OP_BIT_SET: default_layer_and(mask); default_layer_or(bits); break;
363                     }
364                 }
365             } else {
366                 /* Layer Bitwise Operation */
367                 if (event.pressed ? (action.layer_bitop.on & ON_PRESS) :
368                                     (action.layer_bitop.on & ON_RELEASE)) {
369                     uint8_t shift = action.layer_bitop.part*4;
370                     uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
371                     uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
372                     switch (action.layer_bitop.op) {
373                         case OP_BIT_AND: layer_and(bits | mask); break;
374                         case OP_BIT_OR:  layer_or(bits | mask);  break;
375                         case OP_BIT_XOR: layer_xor(bits | mask); break;
376                         case OP_BIT_SET: layer_and(mask); layer_or(bits); break;
377                     }
378                 }
379             }
380             break;
381     #ifndef NO_ACTION_TAPPING
382         case ACT_LAYER_TAP:
383         case ACT_LAYER_TAP_EXT:
384             switch (action.layer_tap.code) {
385                 case 0xe0 ... 0xef:
386                     /* layer On/Off with modifiers(left only) */
387                     if (event.pressed) {
388                         layer_on(action.layer_tap.val);
389                         register_mods(action.layer_tap.code & 0x0f);
390                     } else {
391                         layer_off(action.layer_tap.val);
392                         unregister_mods(action.layer_tap.code & 0x0f);
393                     }
394                     break;
395                 case OP_TAP_TOGGLE:
396                     /* tap toggle */
397                     if (event.pressed) {
398                         if (tap_count < TAPPING_TOGGLE) {
399                             layer_invert(action.layer_tap.val);
400                         }
401                     } else {
402                         if (tap_count <= TAPPING_TOGGLE) {
403                             layer_invert(action.layer_tap.val);
404                         }
405                     }
406                     break;
407                 case OP_ON_OFF:
408                     event.pressed ? layer_on(action.layer_tap.val) :
409                                     layer_off(action.layer_tap.val);
410                     break;
411                 case OP_OFF_ON:
412                     event.pressed ? layer_off(action.layer_tap.val) :
413                                     layer_on(action.layer_tap.val);
414                     break;
415                 case OP_SET_CLEAR:
416                     event.pressed ? layer_move(action.layer_tap.val) :
417                                     layer_clear();
418                     break;
419             #ifndef NO_ACTION_ONESHOT
420                 case OP_ONESHOT:
421                     // Oneshot modifier
422                 #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
423                     do_release_oneshot = false;
424                     if (event.pressed) {
425                         del_mods(get_oneshot_locked_mods());
426                         if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
427                             reset_oneshot_layer();
428                             layer_off(action.layer_tap.val);
429                             break;
430                         } else if (tap_count < ONESHOT_TAP_TOGGLE) {
431                             layer_on(action.layer_tap.val);
432                             set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
433                         }
434                     } else {
435                         add_mods(get_oneshot_locked_mods());
436                         if (tap_count >= ONESHOT_TAP_TOGGLE) {
437                             reset_oneshot_layer();
438                             clear_oneshot_locked_mods();
439                             set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED);
440                         } else {
441                             clear_oneshot_layer_state(ONESHOT_PRESSED);
442                         }
443                     }
444                 #else
445                     if (event.pressed) {
446                         layer_on(action.layer_tap.val);
447                         set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
448                     } else {
449                         clear_oneshot_layer_state(ONESHOT_PRESSED);
450                         if (tap_count > 1) {
451                             clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
452                         }
453                     }
454                 #endif
455                     break;
456             #endif
457                 default:
458                     /* tap key */
459                     if (event.pressed) {
460                         if (tap_count > 0) {
461                             dprint("KEYMAP_TAP_KEY: Tap: register_code\n");
462                             register_code(action.layer_tap.code);
463                         } else {
464                             dprint("KEYMAP_TAP_KEY: No tap: On on press\n");
465                             layer_on(action.layer_tap.val);
466                         }
467                     } else {
468                         if (tap_count > 0) {
469                             dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n");
470                             if (action.layer_tap.code == KC_CAPS) {
471                                 wait_ms(80);
472                             }
473                             unregister_code(action.layer_tap.code);
474                         } else {
475                             dprint("KEYMAP_TAP_KEY: No tap: Off on release\n");
476                             layer_off(action.layer_tap.val);
477                         }
478                     }
479                     break;
480             }
481             break;
482     #endif
483 #endif
484         /* Extentions */
485 #ifndef NO_ACTION_MACRO
486         case ACT_MACRO:
487             action_macro_play(action_get_macro(record, action.func.id, action.func.opt));
488             break;
489 #endif
490 #ifdef BACKLIGHT_ENABLE
491         case ACT_BACKLIGHT:
492             if (!event.pressed) {
493                 switch (action.backlight.opt) {
494                     case BACKLIGHT_INCREASE:
495                         backlight_increase();
496                         break;
497                     case BACKLIGHT_DECREASE:
498                         backlight_decrease();
499                         break;
500                     case BACKLIGHT_TOGGLE:
501                         backlight_toggle();
502                         break;
503                     case BACKLIGHT_STEP:
504                         backlight_step();
505                         break;
506                     case BACKLIGHT_LEVEL:
507                         backlight_level(action.backlight.level);
508                         break;
509                 }
510             }
511             break;
512 #endif
513         case ACT_COMMAND:
514             break;
515 #ifdef ONEHAND_ENABLE
516         case ACT_SWAP_HANDS:
517             switch (action.swap.code) {
518                 case OP_SH_TOGGLE:
519                     if (event.pressed) {
520                         swap_hands = !swap_hands;
521                     }
522                     break;
523                 case OP_SH_ON_OFF:
524                     swap_hands = event.pressed;
525                     break;
526                 case OP_SH_OFF_ON:
527                     swap_hands = !event.pressed;
528                     break;
529                 case OP_SH_ON:
530                     if (!event.pressed) {
531                         swap_hands = true;
532                     }
533                     break;
534                 case OP_SH_OFF:
535                     if (!event.pressed) {
536                         swap_hands = false;
537                     }
538                     break;
539     #ifndef NO_ACTION_TAPPING
540                 case OP_SH_TAP_TOGGLE:
541                     /* tap toggle */
542                     if (tap_count > 0) {
543                         if (!event.pressed) {
544                             swap_hands = !swap_hands;
545                         }
546                     } else {
547                         swap_hands = event.pressed;
548                     }
549                     break;
550                 default:
551                     if (tap_count > 0) {
552                         if (event.pressed) {
553                             register_code(action.swap.code);
554                         } else {
555                             unregister_code(action.swap.code);
556                         }
557                     } else {
558                         swap_hands = event.pressed;
559                     }
560     #endif
561             }
562 #endif
563 #ifndef NO_ACTION_FUNCTION
564         case ACT_FUNCTION:
565             action_function(record, action.func.id, action.func.opt);
566             break;
567 #endif
568         default:
569             break;
570     }
571
572 #ifndef NO_ACTION_LAYER
573     // if this event is a layer action, update the leds
574     switch (action.kind.id) {
575         case ACT_LAYER:
576         #ifndef NO_ACTION_TAPPING
577         case ACT_LAYER_TAP:
578         case ACT_LAYER_TAP_EXT:
579         #endif
580             led_set(host_keyboard_leds());
581             break;
582         default:
583             break;
584     }
585 #endif
586
587 #ifndef NO_ACTION_ONESHOT
588     /* Because we switch layers after a oneshot event, we need to release the
589      * key before we leave the layer or no key up event will be generated.
590      */
591     if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED )   ) {
592         record->event.pressed = false;
593         layer_on(get_oneshot_layer());
594         process_record(record);
595         layer_off(get_oneshot_layer());
596     }
597 #endif
598 }
599
600
601
602
603 /*
604  * Utilities for actions.
605  */
606 void register_code(uint8_t code)
607 {
608     if (code == KC_NO) {
609         return;
610     }
611
612 #ifdef LOCKING_SUPPORT_ENABLE
613     else if (KC_LOCKING_CAPS == code) {
614 #ifdef LOCKING_RESYNC_ENABLE
615         // Resync: ignore if caps lock already is on
616         if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) return;
617 #endif
618         add_key(KC_CAPSLOCK);
619         send_keyboard_report();
620         del_key(KC_CAPSLOCK);
621         send_keyboard_report();
622     }
623
624     else if (KC_LOCKING_NUM == code) {
625 #ifdef LOCKING_RESYNC_ENABLE
626         if (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) return;
627 #endif
628         add_key(KC_NUMLOCK);
629         send_keyboard_report();
630         del_key(KC_NUMLOCK);
631         send_keyboard_report();
632     }
633
634     else if (KC_LOCKING_SCROLL == code) {
635 #ifdef LOCKING_RESYNC_ENABLE
636         if (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) return;
637 #endif
638         add_key(KC_SCROLLLOCK);
639         send_keyboard_report();
640         del_key(KC_SCROLLLOCK);
641         send_keyboard_report();
642     }
643 #endif
644
645     else if IS_KEY(code) {
646         // TODO: should push command_proc out of this block?
647         if (command_proc(code)) return;
648
649 #ifndef NO_ACTION_ONESHOT
650 /* TODO: remove
651         if (oneshot_state.mods && !oneshot_state.disabled) {
652             uint8_t tmp_mods = get_mods();
653             add_mods(oneshot_state.mods);
654
655             add_key(code);
656             send_keyboard_report();
657
658             set_mods(tmp_mods);
659             send_keyboard_report();
660             oneshot_cancel();
661         } else
662 */
663 #endif
664         {
665             add_key(code);
666             send_keyboard_report();
667         }
668     }
669     else if IS_MOD(code) {
670         add_mods(MOD_BIT(code));
671         send_keyboard_report();
672     }
673     else if IS_SYSTEM(code) {
674         host_system_send(KEYCODE2SYSTEM(code));
675     }
676     else if IS_CONSUMER(code) {
677         host_consumer_send(KEYCODE2CONSUMER(code));
678     }
679 }
680
681 void unregister_code(uint8_t code)
682 {
683     if (code == KC_NO) {
684         return;
685     }
686
687 #ifdef LOCKING_SUPPORT_ENABLE
688     else if (KC_LOCKING_CAPS == code) {
689 #ifdef LOCKING_RESYNC_ENABLE
690         // Resync: ignore if caps lock already is off
691         if (!(host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK))) return;
692 #endif
693         add_key(KC_CAPSLOCK);
694         send_keyboard_report();
695         del_key(KC_CAPSLOCK);
696         send_keyboard_report();
697     }
698
699     else if (KC_LOCKING_NUM == code) {
700 #ifdef LOCKING_RESYNC_ENABLE
701         if (!(host_keyboard_leds() & (1<<USB_LED_NUM_LOCK))) return;
702 #endif
703         add_key(KC_NUMLOCK);
704         send_keyboard_report();
705         del_key(KC_NUMLOCK);
706         send_keyboard_report();
707     }
708
709     else if (KC_LOCKING_SCROLL == code) {
710 #ifdef LOCKING_RESYNC_ENABLE
711         if (!(host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK))) return;
712 #endif
713         add_key(KC_SCROLLLOCK);
714         send_keyboard_report();
715         del_key(KC_SCROLLLOCK);
716         send_keyboard_report();
717     }
718 #endif
719
720     else if IS_KEY(code) {
721         del_key(code);
722         send_keyboard_report();
723     }
724     else if IS_MOD(code) {
725         del_mods(MOD_BIT(code));
726         send_keyboard_report();
727     }
728     else if IS_SYSTEM(code) {
729         host_system_send(0);
730     }
731     else if IS_CONSUMER(code) {
732         host_consumer_send(0);
733     }
734 }
735
736 void register_mods(uint8_t mods)
737 {
738     if (mods) {
739         add_mods(mods);
740         send_keyboard_report();
741     }
742 }
743
744 void unregister_mods(uint8_t mods)
745 {
746     if (mods) {
747         del_mods(mods);
748         send_keyboard_report();
749     }
750 }
751
752 void clear_keyboard(void)
753 {
754     clear_mods();
755     clear_keyboard_but_mods();
756 }
757
758 void clear_keyboard_but_mods(void)
759 {
760     clear_weak_mods();
761     clear_macro_mods();
762     clear_keys();
763     send_keyboard_report();
764 #ifdef MOUSEKEY_ENABLE
765     mousekey_clear();
766     mousekey_send();
767 #endif
768 #ifdef EXTRAKEY_ENABLE
769     host_system_send(0);
770     host_consumer_send(0);
771 #endif
772 }
773
774 bool is_tap_key(keypos_t key)
775 {
776     action_t action = layer_switch_get_action(key);
777
778     switch (action.kind.id) {
779         case ACT_LMODS_TAP:
780         case ACT_RMODS_TAP:
781         case ACT_LAYER_TAP:
782         case ACT_LAYER_TAP_EXT:
783             switch (action.layer_tap.code) {
784                 case 0x00 ... 0xdf:
785                 case OP_TAP_TOGGLE:
786                 case OP_ONESHOT:
787                     return true;
788             }
789             return false;
790         case ACT_SWAP_HANDS:
791             switch (action.swap.code) {
792                 case 0x00 ... 0xdf:
793                 case OP_SH_TAP_TOGGLE:
794                     return true;
795             }
796             return false;
797         case ACT_MACRO:
798         case ACT_FUNCTION:
799             if (action.func.opt & FUNC_TAP) { return true; }
800             return false;
801     }
802     return false;
803 }
804
805
806 /*
807  * debug print
808  */
809 void debug_event(keyevent_t event)
810 {
811     dprintf("%04X%c(%u)", (event.key.row<<8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time);
812 }
813
814 void debug_record(keyrecord_t record)
815 {
816     debug_event(record.event);
817 #ifndef NO_ACTION_TAPPING
818     dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' '));
819 #endif
820 }
821
822 void debug_action(action_t action)
823 {
824     switch (action.kind.id) {
825         case ACT_LMODS:             dprint("ACT_LMODS");             break;
826         case ACT_RMODS:             dprint("ACT_RMODS");             break;
827         case ACT_LMODS_TAP:         dprint("ACT_LMODS_TAP");         break;
828         case ACT_RMODS_TAP:         dprint("ACT_RMODS_TAP");         break;
829         case ACT_USAGE:             dprint("ACT_USAGE");             break;
830         case ACT_MOUSEKEY:          dprint("ACT_MOUSEKEY");          break;
831         case ACT_LAYER:             dprint("ACT_LAYER");             break;
832         case ACT_LAYER_TAP:         dprint("ACT_LAYER_TAP");         break;
833         case ACT_LAYER_TAP_EXT:     dprint("ACT_LAYER_TAP_EXT");     break;
834         case ACT_MACRO:             dprint("ACT_MACRO");             break;
835         case ACT_COMMAND:           dprint("ACT_COMMAND");           break;
836         case ACT_FUNCTION:          dprint("ACT_FUNCTION");          break;
837         case ACT_SWAP_HANDS:        dprint("ACT_SWAP_HANDS");        break;
838         default:                    dprint("UNKNOWN");               break;
839     }
840     dprintf("[%X:%02X]", action.kind.param>>8, action.kind.param&0xff);
841 }