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