]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/common/action.c
core: Update comments in keycode.h
[max/tmk_keyboard.git] / tmk_core / common / action.c
1 /*
2 Copyright 2012,2013,2020 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 "hook.h"
30 #include "wait.h"
31 #include "bootloader.h"
32
33 #ifdef DEBUG_ACTION
34 #include "debug.h"
35 #else
36 #include "nodebug.h"
37 #endif
38
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         hook_matrix_change(event);
46     }
47
48     keyrecord_t record = { .event = event };
49
50 #ifndef NO_ACTION_TAPPING
51     action_tapping_process(record);
52 #else
53     process_action(&record);
54     if (!IS_NOEVENT(record.event)) {
55         dprint("processed: "); debug_record(record); dprintln();
56     }
57 #endif
58 }
59
60 void process_action(keyrecord_t *record)
61 {
62     if (hook_process_action(record)) return;
63
64     keyevent_t event = record->event;
65 #ifndef NO_ACTION_TAPPING
66     uint8_t tap_count = record->tap.count;
67 #endif
68
69     if (IS_NOEVENT(event)) { return; }
70
71     action_t action = layer_switch_get_action(event);
72     dprint("ACTION: "); debug_action(action);
73 #ifndef NO_ACTION_LAYER
74     dprint(" layer_state: "); layer_debug();
75     dprint(" default_layer_state: "); default_layer_debug();
76 #endif
77     dprintln();
78
79     switch (action.kind.id) {
80         /* Key and Mods */
81         case ACT_LMODS:
82         case ACT_RMODS:
83             {
84                 uint8_t mods = (action.kind.id == ACT_LMODS) ?  action.key.mods :
85                                                                 action.key.mods<<4;
86                 if (event.pressed) {
87                     if (mods) {
88                         add_weak_mods(mods);
89                         send_keyboard_report();
90                     }
91                     register_code(action.key.code);
92                 } else {
93                     unregister_code(action.key.code);
94                     if (mods) {
95                         del_weak_mods(mods);
96                         send_keyboard_report();
97                     }
98                 }
99             }
100             break;
101 #ifndef NO_ACTION_TAPPING
102         case ACT_LMODS_TAP:
103         case ACT_RMODS_TAP:
104             {
105                 uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ?  action.key.mods :
106                                                                     action.key.mods<<4;
107                 switch (action.key.code) {
108     #ifndef NO_ACTION_ONESHOT
109                     case MODS_ONESHOT:
110                         // Oneshot modifier
111                         if (event.pressed) {
112                             if (tap_count == 0) {
113                                 register_mods(mods);
114                             }
115                             else if (tap_count == 1) {
116                                 dprint("MODS_TAP: Oneshot: start\n");
117                                 set_oneshot_mods(mods);
118                             }
119                             else {
120                                 register_mods(mods);
121                             }
122                         } else {
123                             if (tap_count == 0) {
124                                 clear_oneshot_mods();
125                                 unregister_mods(mods);
126                             }
127                             else if (tap_count == 1) {
128                                 // Retain Oneshot mods
129                             }
130                             else {
131                                 clear_oneshot_mods();
132                                 unregister_mods(mods);
133                             }
134                         }
135                         break;
136     #endif
137                     case MODS_TAP_TOGGLE:
138                         if (event.pressed) {
139                             if (tap_count <= TAPPING_TOGGLE) {
140                                 if (mods & get_mods()) {
141                                     dprint("MODS_TAP_TOGGLE: toggle mods off\n");
142                                     unregister_mods(mods);
143                                 } else {
144                                     dprint("MODS_TAP_TOGGLE: toggle mods on\n");
145                                     register_mods(mods);
146                                 }
147                             }
148                         } else {
149                             if (tap_count < TAPPING_TOGGLE) {
150                                 dprint("MODS_TAP_TOGGLE: release : unregister_mods\n");
151                                 unregister_mods(mods);
152                             }
153                         }
154                         break;
155                     default:
156                         if (event.pressed) {
157                             if (tap_count > 0) {
158                                 if (record->tap.interrupted) {
159                                     dprint("MODS_TAP: Tap: Cancel: add_mods\n");
160                                     // ad hoc: set 0 to cancel tap
161                                     record->tap.count = 0;
162                                     register_mods(mods);
163                                 } else {
164                                     dprint("MODS_TAP: Tap: register_code\n");
165                                     register_code(action.key.code);
166
167                                     // Delay for MacOS #659
168                                     if (action.key.code == KC_CAPSLOCK ||
169                                             action.key.code == KC_NUMLOCK ||
170                                             action.key.code == KC_SCROLLLOCK) {
171                                         wait_ms(100);
172                                     }
173                                 }
174                             } else {
175                                 dprint("MODS_TAP: No tap: add_mods\n");
176                                 register_mods(mods);
177                             }
178                         } else {
179                             if (tap_count > 0) {
180                                 dprint("MODS_TAP: Tap: unregister_code\n");
181                                 unregister_code(action.key.code);
182                             } else {
183                                 dprint("MODS_TAP: No tap: add_mods\n");
184                                 unregister_mods(mods);
185                             }
186                         }
187                         break;
188                 }
189             }
190             break;
191 #endif
192 #ifdef EXTRAKEY_ENABLE
193         /* other HID usage */
194         case ACT_USAGE:
195             switch (action.usage.page) {
196                 case PAGE_SYSTEM:
197                     if (event.pressed) {
198                         host_system_send(action.usage.code);
199                     } else {
200                         host_system_send(0);
201                     }
202                     break;
203                 case PAGE_CONSUMER:
204                     if (event.pressed) {
205                         host_consumer_send(action.usage.code);
206                     } else {
207                         host_consumer_send(0);
208                     }
209                     break;
210             }
211             break;
212 #endif
213 #ifdef MOUSEKEY_ENABLE
214         /* Mouse key */
215         case ACT_MOUSEKEY:
216             if (event.pressed) {
217                 mousekey_on(action.key.code);
218                 mousekey_send();
219             } else {
220                 mousekey_off(action.key.code);
221                 mousekey_send();
222             }
223             break;
224 #endif
225 #ifndef NO_ACTION_LAYER
226         case ACT_LAYER:
227             if (action.layer_bitop.on == 0) {
228                 /* Default Layer Bitwise Operation */
229                 if (!event.pressed) {
230                     uint8_t shift = action.layer_bitop.part*4;
231                     uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
232                     uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
233                     switch (action.layer_bitop.op) {
234                         case OP_BIT_AND: default_layer_and(bits | mask); break;
235                         case OP_BIT_OR:  default_layer_or(bits | mask);  break;
236                         case OP_BIT_XOR: default_layer_xor(bits | mask); break;
237                         case OP_BIT_SET: default_layer_and(mask); default_layer_or(bits); break;
238                     }
239                 }
240             } else {
241                 /* Layer Bitwise Operation */
242                 if (event.pressed ? (action.layer_bitop.on & ON_PRESS) :
243                                     (action.layer_bitop.on & ON_RELEASE)) {
244                     uint8_t shift = action.layer_bitop.part*4;
245                     uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
246                     uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
247                     switch (action.layer_bitop.op) {
248                         case OP_BIT_AND: layer_and(bits | mask); break;
249                         case OP_BIT_OR:  layer_or(bits | mask);  break;
250                         case OP_BIT_XOR: layer_xor(bits | mask); break;
251                         case OP_BIT_SET: layer_and(mask); layer_or(bits); break;
252                     }
253                 }
254             }
255             break;
256     #ifndef NO_ACTION_TAPPING
257         case ACT_LAYER_TAP:
258         case ACT_LAYER_TAP_EXT:
259             switch (action.layer_tap.code) {
260                 case 0xc0 ... 0xdf:
261                     /* layer On/Off with modifiers */
262                     if (event.pressed) {
263                         layer_on(action.layer_tap.val);
264                         register_mods((action.layer_tap.code & 0x10) ?
265                                 (action.layer_tap.code & 0x0f) << 4 :
266                                 (action.layer_tap.code & 0x0f));
267                     } else {
268                         layer_off(action.layer_tap.val);
269                         unregister_mods((action.layer_tap.code & 0x10) ?
270                                 (action.layer_tap.code & 0x0f) << 4 :
271                                 (action.layer_tap.code & 0x0f));
272                     }
273                     break;
274                 case OP_TAP_TOGGLE:
275                     /* tap toggle */
276                     if (event.pressed) {
277                         if (tap_count < TAPPING_TOGGLE) {
278                             layer_invert(action.layer_tap.val);
279                         }
280                     } else {
281                         if (tap_count <= TAPPING_TOGGLE) {
282                             layer_invert(action.layer_tap.val);
283                         }
284                     }
285                     break;
286                 case OP_ON_OFF:
287                     event.pressed ? layer_on(action.layer_tap.val) :
288                                     layer_off(action.layer_tap.val);
289                     break;
290                 case OP_OFF_ON:
291                     event.pressed ? layer_off(action.layer_tap.val) :
292                                     layer_on(action.layer_tap.val);
293                     break;
294                 case OP_SET_CLEAR:
295                     event.pressed ? layer_move(action.layer_tap.val) :
296                                     layer_clear();
297                     break;
298                 default:
299                     /* tap key */
300                     if (event.pressed) {
301                         if (tap_count > 0) {
302                             dprint("KEYMAP_TAP_KEY: Tap: register_code\n");
303                             register_code(action.layer_tap.code);
304
305                             // Delay for MacOS #659
306                             if (action.layer_tap.code == KC_CAPSLOCK ||
307                                     action.layer_tap.code == KC_NUMLOCK ||
308                                     action.layer_tap.code == KC_SCROLLLOCK) {
309                                 wait_ms(100);
310                             }
311                         } else {
312                             dprint("KEYMAP_TAP_KEY: No tap: On on press\n");
313                             layer_on(action.layer_tap.val);
314                         }
315                     } else {
316                         if (tap_count > 0) {
317                             dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n");
318                             unregister_code(action.layer_tap.code);
319                         } else {
320                             dprint("KEYMAP_TAP_KEY: No tap: Off on release\n");
321                             layer_off(action.layer_tap.val);
322                         }
323                     }
324                     break;
325             }
326             break;
327     #endif
328 #endif
329         /* Extentions */
330 #ifndef NO_ACTION_MACRO
331         case ACT_MACRO:
332             action_macro_play(action_get_macro(record, action.func.id, action.func.opt));
333             break;
334 #endif
335 #ifdef BACKLIGHT_ENABLE
336         case ACT_BACKLIGHT:
337             if (!event.pressed) {
338                 switch (action.backlight.opt) {
339                     case BACKLIGHT_INCREASE:
340                         backlight_increase();
341                         break;
342                     case BACKLIGHT_DECREASE:
343                         backlight_decrease();
344                         break;
345                     case BACKLIGHT_TOGGLE:
346                         backlight_toggle();
347                         break;
348                     case BACKLIGHT_STEP:
349                         backlight_step();
350                         break;
351                     case BACKLIGHT_LEVEL:
352                         backlight_level(action.backlight.level);
353                         break;
354                 }
355             }
356             break;
357 #endif
358         case ACT_COMMAND:
359             switch (action.command.id) {
360                 case COMMAND_BOOTLOADER:
361                     if (event.pressed) {
362                         clear_keyboard();
363                         wait_ms(50);
364                         bootloader_jump();
365                     }
366                     break;
367             }
368             break;
369 #ifndef NO_ACTION_FUNCTION
370         case ACT_FUNCTION:
371             action_function(record, action.func.id, action.func.opt);
372             break;
373 #endif
374         default:
375             break;
376     }
377 }
378
379
380
381
382 /*
383  * Utilities for actions.
384  */
385 void register_code(uint8_t code)
386 {
387     if (code == KC_NO) {
388         return;
389     }
390
391 #ifdef LOCKING_SUPPORT_ENABLE
392     else if (code == KC_LOCKING_CAPS ||
393                 code == KC_LOCKING_NUM ||
394                 code == KC_LOCKING_SCROLL) {
395         uint8_t c, l;
396         if (code == KC_LOCKING_CAPS) {
397             c = KC_CAPSLOCK;
398             l = 1<<USB_LED_CAPS_LOCK;
399         } else if (code == KC_LOCKING_NUM) {
400             c = KC_NUMLOCK;
401             l = 1<<USB_LED_NUM_LOCK;
402         } else if (code == KC_LOCKING_SCROLL) {
403             c = KC_SCROLLLOCK;
404             l = 1<<USB_LED_SCROLL_LOCK;
405         }
406 #ifdef LOCKING_RESYNC_ENABLE
407         // Resync: ignore if lock indicator is already on
408         if (host_keyboard_leds() & l) return;
409 #endif
410         add_key(c);
411         send_keyboard_report();
412         wait_ms(100); // Delay for MacOS #390
413         del_key(c);
414         send_keyboard_report();
415     }
416 #endif
417
418     else if IS_KEY(code) {
419         // TODO: should push command_proc out of this block?
420         if (command_proc(code)) return;
421
422 #ifndef NO_ACTION_ONESHOT
423 /* TODO: remove
424         if (oneshot_state.mods && !oneshot_state.disabled) {
425             uint8_t tmp_mods = get_mods();
426             add_mods(oneshot_state.mods);
427
428             add_key(code);
429             send_keyboard_report();
430
431             set_mods(tmp_mods);
432             send_keyboard_report();
433             oneshot_cancel();
434         } else 
435 */
436 #endif
437         {
438             add_key(code);
439             send_keyboard_report();
440         }
441     }
442     else if IS_MOD(code) {
443         add_mods(MOD_BIT(code));
444         send_keyboard_report();
445     }
446     else if IS_SYSTEM(code) {
447         host_system_send(KEYCODE2SYSTEM(code));
448     }
449     else if IS_CONSUMER(code) {
450         host_consumer_send(KEYCODE2CONSUMER(code));
451     }
452 }
453
454 void unregister_code(uint8_t code)
455 {
456     if (code == KC_NO) {
457         return;
458     }
459
460 #ifdef LOCKING_SUPPORT_ENABLE
461     else if (code == KC_LOCKING_CAPS ||
462                 code == KC_LOCKING_NUM ||
463                 code == KC_LOCKING_SCROLL) {
464         uint8_t c, l;
465         if (code == KC_LOCKING_CAPS) {
466             c = KC_CAPSLOCK;
467             l = 1<<USB_LED_CAPS_LOCK;
468         } else if (code == KC_LOCKING_NUM) {
469             c = KC_NUMLOCK;
470             l = 1<<USB_LED_NUM_LOCK;
471         } else if (code == KC_LOCKING_SCROLL) {
472             c = KC_SCROLLLOCK;
473             l = 1<<USB_LED_SCROLL_LOCK;
474         }
475 #ifdef LOCKING_RESYNC_ENABLE
476         // Resync: ignore if lock indicator is already off
477         if (!(host_keyboard_leds() & l)) return;
478 #endif
479         add_key(c);
480         send_keyboard_report();
481         wait_ms(100); // Delay for MacOS #390
482         del_key(c);
483         send_keyboard_report();
484     }
485 #endif
486
487     else if IS_KEY(code) {
488         del_key(code);
489         send_keyboard_report();
490     }
491     else if IS_MOD(code) {
492         del_mods(MOD_BIT(code));
493         send_keyboard_report();
494     }
495     else if IS_SYSTEM(code) {
496         host_system_send(0);
497     }
498     else if IS_CONSUMER(code) {
499         host_consumer_send(0);
500     }
501 }
502
503 void type_code(uint8_t code)
504 {
505     register_code(code);
506     unregister_code(code);
507 }
508
509 void register_mods(uint8_t mods)
510 {
511     if (mods) {
512         add_mods(mods);
513         send_keyboard_report();
514     }
515 }
516
517 void unregister_mods(uint8_t mods)
518 {
519     if (mods) {
520         del_mods(mods);
521         send_keyboard_report();
522     }
523 }
524
525 void clear_keyboard(void)
526 {
527     clear_mods();
528     clear_keyboard_but_mods();
529 }
530
531 void clear_keyboard_but_mods(void)
532 {
533     clear_weak_mods();
534     clear_keys();
535     send_keyboard_report();
536 #ifdef MOUSEKEY_ENABLE
537     mousekey_clear();
538     mousekey_send();
539 #endif
540 #ifdef EXTRAKEY_ENABLE
541     host_system_send(0);
542     host_consumer_send(0);
543 #endif
544 }
545
546 bool is_tap_key(keyevent_t event)
547 {
548     if (IS_NOEVENT(event)) { return false; }
549
550     action_t action = layer_switch_get_action(event);
551
552     switch (action.kind.id) {
553         case ACT_LMODS_TAP:
554         case ACT_RMODS_TAP:
555             switch (action.key.code) {
556                 case MODS_ONESHOT:
557                 case MODS_TAP_TOGGLE:
558                 case KC_A ... KC_EXSEL:                 // tap key
559                 case KC_LCTRL ... KC_RGUI:              // tap key
560                     return true;
561             }
562         case ACT_LAYER_TAP:
563         case ACT_LAYER_TAP_EXT:
564             switch (action.layer_tap.code) {
565                 case 0xc0 ... 0xdf:         // with modifiers
566                     return false;
567                 case KC_A ... KC_EXSEL:     // tap key
568                 case KC_LCTRL ... KC_RGUI:  // tap key
569                 case OP_TAP_TOGGLE:
570                     return true;
571             }
572             return false;
573         case ACT_MACRO:
574         case ACT_FUNCTION:
575             if (action.func.opt & FUNC_TAP) { return true; }
576             return false;
577     }
578     return false;
579 }
580
581
582 /*
583  * debug print
584  */
585 void debug_event(keyevent_t event)
586 {
587     dprintf("%04X%c(%u)", (event.key.row<<8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time);
588 }
589
590 void debug_record(keyrecord_t record)
591 {
592     debug_event(record.event);
593 #ifndef NO_ACTION_TAPPING
594     dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' '));
595 #endif
596 }
597
598 void debug_action(action_t action)
599 {
600     switch (action.kind.id) {
601         case ACT_LMODS:             dprint("ACT_LMODS");             break;
602         case ACT_RMODS:             dprint("ACT_RMODS");             break;
603         case ACT_LMODS_TAP:         dprint("ACT_LMODS_TAP");         break;
604         case ACT_RMODS_TAP:         dprint("ACT_RMODS_TAP");         break;
605         case ACT_USAGE:             dprint("ACT_USAGE");             break;
606         case ACT_MOUSEKEY:          dprint("ACT_MOUSEKEY");          break;
607         case ACT_LAYER:             dprint("ACT_LAYER");             break;
608         case ACT_LAYER_TAP:         dprint("ACT_LAYER_TAP");         break;
609         case ACT_LAYER_TAP_EXT:     dprint("ACT_LAYER_TAP_EXT");     break;
610         case ACT_MACRO:             dprint("ACT_MACRO");             break;
611         case ACT_COMMAND:           dprint("ACT_COMMAND");           break;
612         case ACT_FUNCTION:          dprint("ACT_FUNCTION");          break;
613         default:                    dprint("UNKNOWN");               break;
614     }
615     dprintf("[%X:%02X]", action.kind.param>>8, action.kind.param&0xff);
616 }