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