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