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