keyboard stuff
1/*
2Copyright 2011 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 <stdint.h>
18#include <stdbool.h>
19#include "wait.h"
20#include "keycode.h"
21#include "host.h"
22#include "print.h"
23#include "debug.h"
24#include "util.h"
25#include "timer.h"
26#include "keyboard.h"
27#include "bootloader.h"
28#include "action_layer.h"
29#include "action_util.h"
30#include "eeconfig.h"
31#include "led.h"
32#include "command.h"
33#include "quantum.h"
34#include "usb_device_state.h"
35#include "version.h"
36
37#ifdef BACKLIGHT_ENABLE
38# include "backlight.h"
39#endif
40
41#ifdef SLEEP_LED_ENABLE
42# include "sleep_led.h"
43#endif
44
45#if defined(MOUSEKEY_ENABLE)
46# include "mousekey.h"
47#endif
48
49#ifdef AUDIO_ENABLE
50# include "audio.h"
51#endif /* AUDIO_ENABLE */
52
53static bool command_common(uint8_t code);
54static void command_common_help(void);
55static void print_version(void);
56static void print_status(void);
57static bool command_console(uint8_t code);
58static void command_console_help(void);
59#if defined(MOUSEKEY_ENABLE)
60static bool mousekey_console(uint8_t code);
61#endif
62
63static void switch_default_layer(uint8_t layer);
64
65command_state_t command_state = ONESHOT;
66
67bool command_proc(uint8_t code) {
68 switch (command_state) {
69 case ONESHOT:
70 if (!IS_COMMAND()) return false;
71 return (command_extra(code) || command_common(code));
72 break;
73 case CONSOLE:
74 if (IS_COMMAND())
75 return (command_extra(code) || command_common(code));
76 else
77 return (command_console_extra(code) || command_console(code));
78 break;
79#if defined(MOUSEKEY_ENABLE)
80 case MOUSEKEY:
81 mousekey_console(code);
82 break;
83#endif
84 default:
85 command_state = ONESHOT;
86 return false;
87 }
88 return true;
89}
90
91/* TODO: Refactoring is needed. */
92/* This allows to define extra commands. return false when not processed. */
93bool command_extra(uint8_t code) __attribute__((weak));
94bool command_extra(uint8_t code) {
95 (void)code;
96 return false;
97}
98
99bool command_console_extra(uint8_t code) __attribute__((weak));
100bool command_console_extra(uint8_t code) {
101 (void)code;
102 return false;
103}
104
105/***********************************************************
106 * Command common
107 ***********************************************************/
108
109static void command_common_help(void) {
110 print(/* clang-format off */
111 "\n\t- Magic -\n"
112
113 STR(MAGIC_KEY_DEBUG) ": Debug Message Toggle\n"
114 STR(MAGIC_KEY_DEBUG_MATRIX) ": Matrix Debug Mode Toggle"
115 " - Show keypresses in matrix grid\n"
116 STR(MAGIC_KEY_DEBUG_KBD) ": Keyboard Debug Toggle"
117 " - Show keypress report\n"
118 STR(MAGIC_KEY_DEBUG_MOUSE) ": Debug Mouse Toggle\n"
119 STR(MAGIC_KEY_VERSION) ": Version\n"
120 STR(MAGIC_KEY_STATUS) ": Status\n"
121 STR(MAGIC_KEY_CONSOLE) ": Activate Console Mode\n"
122
123#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
124 STR(MAGIC_KEY_LAYER0) ": Switch to Layer 0\n"
125 STR(MAGIC_KEY_LAYER1) ": Switch to Layer 1\n"
126 STR(MAGIC_KEY_LAYER2) ": Switch to Layer 2\n"
127 STR(MAGIC_KEY_LAYER3) ": Switch to Layer 3\n"
128 STR(MAGIC_KEY_LAYER4) ": Switch to Layer 4\n"
129 STR(MAGIC_KEY_LAYER5) ": Switch to Layer 5\n"
130 STR(MAGIC_KEY_LAYER6) ": Switch to Layer 6\n"
131 STR(MAGIC_KEY_LAYER7) ": Switch to Layer 7\n"
132 STR(MAGIC_KEY_LAYER8) ": Switch to Layer 8\n"
133 STR(MAGIC_KEY_LAYER9) ": Switch to Layer 9\n"
134#endif
135
136#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
137 "F1-F10: Switch to Layer 0-9 (F10 = L0)\n"
138#endif
139
140#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
141 "0-9: Switch to Layer 0-9\n"
142#endif
143
144 STR(MAGIC_KEY_LAYER0_ALT) ": Switch to Layer 0 (alternate)\n"
145
146 STR(MAGIC_KEY_BOOTLOADER) ": Jump to Bootloader\n"
147 STR(MAGIC_KEY_BOOTLOADER_ALT) ": Jump to Bootloader (alternate)\n"
148
149#ifdef KEYBOARD_LOCK_ENABLE
150 STR(MAGIC_KEY_LOCK) ": Lock Keyboard\n"
151#endif
152
153 STR(MAGIC_KEY_EEPROM) ": Print EEPROM Settings\n"
154 STR(MAGIC_KEY_EEPROM_CLEAR) ": Clear EEPROM\n"
155
156#ifdef NKRO_ENABLE
157 STR(MAGIC_KEY_NKRO) ": NKRO Toggle\n"
158#endif
159
160#ifdef SLEEP_LED_ENABLE
161 STR(MAGIC_KEY_SLEEP_LED) ": Sleep LED Test\n"
162#endif
163 ); /* clang-format on */
164}
165
166static void print_version(void) {
167 xprintf("%s", /* clang-format off */
168 "\n\t- Version -\n"
169 "VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") "
170 "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") "
171 "VER: " STR(DEVICE_VER) "\n"
172 "BUILD: (" __DATE__ ")\n"
173#ifndef SKIP_VERSION
174# ifdef PROTOCOL_CHIBIOS
175 "CHIBIOS: " STR(CHIBIOS_VERSION)
176 ", CONTRIB: " STR(CHIBIOS_CONTRIB_VERSION) "\n"
177# endif
178#endif
179
180 /* build options */
181 "OPTIONS:"
182
183#ifdef PROTOCOL_LUFA
184 " LUFA"
185#endif
186#ifdef PROTOCOL_VUSB
187 " VUSB"
188#endif
189#ifdef BOOTMAGIC_ENABLE
190 " BOOTMAGIC"
191#endif
192#ifdef MOUSEKEY_ENABLE
193 " MOUSEKEY"
194#endif
195#ifdef EXTRAKEY_ENABLE
196 " EXTRAKEY"
197#endif
198#ifdef CONSOLE_ENABLE
199 " CONSOLE"
200#endif
201#ifdef COMMAND_ENABLE
202 " COMMAND"
203#endif
204#ifdef NKRO_ENABLE
205 " NKRO"
206#endif
207#ifdef LTO_ENABLE
208 " LTO"
209#endif
210
211 " " STR(BOOTLOADER_SIZE) "\n"
212
213 "GCC: " STR(__GNUC__)
214 "." STR(__GNUC_MINOR__)
215 "." STR(__GNUC_PATCHLEVEL__)
216#if defined(__AVR__)
217 " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
218 " AVR_ARCH: avr" STR(__AVR_ARCH__)
219#endif
220 "\n"
221 ); /* clang-format on */
222}
223
224static void print_status(void) {
225 xprintf(/* clang-format off */
226 "\n\t- Status -\n"
227
228 "host_keyboard_leds(): %02X\n"
229 "keyboard_protocol: %02X\n"
230 "keyboard_idle: %02X\n"
231#ifdef NKRO_ENABLE
232 "keymap_config.nkro: %02X\n"
233#endif
234 "timer_read32(): %08lX\n"
235
236 , host_keyboard_leds()
237 , usb_device_state_get_protocol()
238 , usb_device_state_get_idle_rate()
239#ifdef NKRO_ENABLE
240 , keymap_config.nkro
241#endif
242 , timer_read32()
243
244 ); /* clang-format on */
245}
246
247#if !defined(NO_PRINT) && !defined(USER_PRINT)
248static void print_eeconfig(void) {
249 xprintf("eeconfig:\ndefault_layer: %" PRIu32 "\n", (uint32_t)eeconfig_read_default_layer());
250
251 debug_config_t dc;
252 eeconfig_read_debug(&dc);
253 xprintf(/* clang-format off */
254
255 "debug_config.raw: %02X\n"
256 ".enable: %u\n"
257 ".matrix: %u\n"
258 ".keyboard: %u\n"
259 ".mouse: %u\n"
260
261 , dc.raw
262 , dc.enable
263 , dc.matrix
264 , dc.keyboard
265 , dc.mouse
266 ); /* clang-format on */
267
268 keymap_config_t kc;
269 eeconfig_read_keymap(&kc);
270 xprintf(/* clang-format off */
271
272 "keymap_config.raw: %02X\n"
273 ".swap_control_capslock: %u\n"
274 ".capslock_to_control: %u\n"
275 ".swap_lctl_lgui: %u\n"
276 ".swap_rctl_rgui: %u\n"
277 ".swap_lalt_lgui: %u\n"
278 ".swap_ralt_rgui: %u\n"
279 ".no_gui: %u\n"
280 ".swap_grave_esc: %u\n"
281 ".swap_backslash_backspace: %u\n"
282 ".nkro: %u\n"
283 ".swap_escape_capslock: %u\n"
284
285 , kc.raw
286 , kc.swap_control_capslock
287 , kc.capslock_to_control
288 , kc.swap_lctl_lgui
289 , kc.swap_rctl_rgui
290 , kc.swap_lalt_lgui
291 , kc.swap_ralt_rgui
292 , kc.no_gui
293 , kc.swap_grave_esc
294 , kc.swap_backslash_backspace
295 , kc.nkro
296 , kc.swap_escape_capslock
297 ); /* clang-format on */
298
299# ifdef BACKLIGHT_ENABLE
300
301 backlight_config_t bc;
302 eeconfig_read_backlight(&bc);
303 xprintf(/* clang-format off */
304 "backlight_config"
305
306 ".raw: %02X\n"
307 ".enable: %u\n"
308 ".level: %u\n"
309
310 , bc.raw
311 , bc.enable
312 , bc.level
313
314 ); /* clang-format on */
315
316# endif /* BACKLIGHT_ENABLE */
317}
318#endif /* !NO_PRINT && !USER_PRINT */
319
320static bool command_common(uint8_t code) {
321#ifdef KEYBOARD_LOCK_ENABLE
322 static host_driver_t *host_driver = 0;
323#endif
324
325 switch (code) {
326#ifdef SLEEP_LED_ENABLE
327
328 // test breathing sleep LED
329 case MAGIC_KC(MAGIC_KEY_SLEEP_LED):
330 print("Sleep LED Test\n");
331 sleep_led_toggle();
332 led_set(host_keyboard_leds());
333 break;
334#endif
335
336 // print stored eeprom config
337 case MAGIC_KC(MAGIC_KEY_EEPROM):
338#if !defined(NO_PRINT) && !defined(USER_PRINT)
339 print_eeconfig();
340#endif /* !NO_PRINT && !USER_PRINT */
341 break;
342
343 // clear eeprom
344 case MAGIC_KC(MAGIC_KEY_EEPROM_CLEAR):
345 print("Clearing EEPROM\n");
346 eeconfig_init();
347 break;
348
349#ifdef KEYBOARD_LOCK_ENABLE
350
351 // lock/unlock keyboard
352 case MAGIC_KC(MAGIC_KEY_LOCK):
353 if (host_get_driver()) {
354 host_driver = host_get_driver();
355 clear_keyboard();
356 host_set_driver(0);
357 print("Locked.\n");
358 } else {
359 host_set_driver(host_driver);
360 print("Unlocked.\n");
361 }
362 break;
363#endif
364
365 // print help
366 case MAGIC_KC(MAGIC_KEY_HELP):
367 case MAGIC_KC(MAGIC_KEY_HELP_ALT):
368 command_common_help();
369 break;
370
371 // activate console
372 case MAGIC_KC(MAGIC_KEY_CONSOLE):
373 debug_matrix = false;
374 debug_keyboard = false;
375 debug_mouse = false;
376 debug_enable = false;
377 command_console_help();
378 print("C> ");
379 command_state = CONSOLE;
380 break;
381
382 // jump to bootloader
383 case MAGIC_KC(MAGIC_KEY_BOOTLOADER):
384 case MAGIC_KC(MAGIC_KEY_BOOTLOADER_ALT):
385 print("\n\nJumping to bootloader... ");
386 reset_keyboard();
387 break;
388
389 // debug toggle
390 case MAGIC_KC(MAGIC_KEY_DEBUG):
391 debug_enable = !debug_enable;
392 if (debug_enable) {
393 print("\ndebug: on\n");
394 } else {
395 print("\ndebug: off\n");
396 debug_matrix = false;
397 debug_keyboard = false;
398 debug_mouse = false;
399 }
400 break;
401
402 // debug matrix toggle
403 case MAGIC_KC(MAGIC_KEY_DEBUG_MATRIX):
404 debug_matrix = !debug_matrix;
405 if (debug_matrix) {
406 print("\nmatrix: on\n");
407 debug_enable = true;
408 } else {
409 print("\nmatrix: off\n");
410 }
411 break;
412
413 // debug keyboard toggle
414 case MAGIC_KC(MAGIC_KEY_DEBUG_KBD):
415 debug_keyboard = !debug_keyboard;
416 if (debug_keyboard) {
417 print("\nkeyboard: on\n");
418 debug_enable = true;
419 } else {
420 print("\nkeyboard: off\n");
421 }
422 break;
423
424 // debug mouse toggle
425 case MAGIC_KC(MAGIC_KEY_DEBUG_MOUSE):
426 debug_mouse = !debug_mouse;
427 if (debug_mouse) {
428 print("\nmouse: on\n");
429 debug_enable = true;
430 } else {
431 print("\nmouse: off\n");
432 }
433 break;
434
435 // print version
436 case MAGIC_KC(MAGIC_KEY_VERSION):
437 print_version();
438 break;
439
440 // print status
441 case MAGIC_KC(MAGIC_KEY_STATUS):
442 print_status();
443 break;
444
445#ifdef NKRO_ENABLE
446
447 // NKRO toggle
448 case MAGIC_KC(MAGIC_KEY_NKRO):
449 clear_keyboard(); // clear to prevent stuck keys
450 keymap_config.nkro = !keymap_config.nkro;
451 if (keymap_config.nkro) {
452 print("NKRO: on\n");
453 } else {
454 print("NKRO: off\n");
455 }
456 break;
457#endif
458
459 // switch layers
460
461 case MAGIC_KC(MAGIC_KEY_LAYER0_ALT):
462 switch_default_layer(0);
463 break;
464
465#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
466
467 case MAGIC_KC(MAGIC_KEY_LAYER0):
468 switch_default_layer(0);
469 break;
470
471 case MAGIC_KC(MAGIC_KEY_LAYER1):
472 switch_default_layer(1);
473 break;
474
475 case MAGIC_KC(MAGIC_KEY_LAYER2):
476 switch_default_layer(2);
477 break;
478
479 case MAGIC_KC(MAGIC_KEY_LAYER3):
480 switch_default_layer(3);
481 break;
482
483 case MAGIC_KC(MAGIC_KEY_LAYER4):
484 switch_default_layer(4);
485 break;
486
487 case MAGIC_KC(MAGIC_KEY_LAYER5):
488 switch_default_layer(5);
489 break;
490
491 case MAGIC_KC(MAGIC_KEY_LAYER6):
492 switch_default_layer(6);
493 break;
494
495 case MAGIC_KC(MAGIC_KEY_LAYER7):
496 switch_default_layer(7);
497 break;
498
499 case MAGIC_KC(MAGIC_KEY_LAYER8):
500 switch_default_layer(8);
501 break;
502
503 case MAGIC_KC(MAGIC_KEY_LAYER9):
504 switch_default_layer(9);
505 break;
506#endif
507
508#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
509
510 case KC_F1 ... KC_F9:
511 switch_default_layer((code - KC_F1) + 1);
512 break;
513 case KC_F10:
514 switch_default_layer(0);
515 break;
516#endif
517
518#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
519
520 case KC_1 ... KC_9:
521 switch_default_layer((code - KC_1) + 1);
522 break;
523 case KC_0:
524 switch_default_layer(0);
525 break;
526#endif
527
528 default:
529 print("?");
530 return false;
531 }
532 return true;
533}
534
535/***********************************************************
536 * Command console
537 ***********************************************************/
538static void command_console_help(void) {
539 print("\n\t- Console -\n"
540 "ESC/q: quit\n"
541#ifdef MOUSEKEY_ENABLE
542 "m: mousekey\n"
543#endif
544 );
545}
546
547static bool command_console(uint8_t code) {
548 switch (code) {
549 case KC_H:
550 case KC_SLASH: /* ? */
551 command_console_help();
552 print("C> ");
553 return true;
554 case KC_Q:
555 case KC_ESC:
556 command_state = ONESHOT;
557 return false;
558#if defined(MOUSEKEY_ENABLE)
559 case KC_M:
560 command_state = MOUSEKEY;
561 mousekey_console(KC_SLASH /* ? */);
562 return true;
563#endif
564 default:
565 print("?");
566 return false;
567 }
568}
569
570/***********************************************************
571 * Mousekey console
572 ***********************************************************/
573
574#if defined(MOUSEKEY_ENABLE)
575
576# if !defined(NO_PRINT) && !defined(USER_PRINT)
577static void mousekey_param_print(void) {
578 xprintf(/* clang-format off */
579
580#ifndef MK_3_SPEED
581 "1: delay(*10ms): %u\n"
582 "2: interval(ms): %u\n"
583 "3: max_speed: %u\n"
584 "4: time_to_max: %u\n"
585 "5: wheel_max_speed: %u\n"
586 "6: wheel_time_to_max: %u\n"
587
588 , mk_delay
589 , mk_interval
590 , mk_max_speed
591 , mk_time_to_max
592 , mk_wheel_max_speed
593 , mk_wheel_time_to_max
594#else
595 "no knobs sorry\n"
596#endif
597
598 ); /* clang-format on */
599}
600# endif /* !NO_PRINT && !USER_PRINT */
601
602# if !defined(NO_PRINT) && !defined(USER_PRINT)
603static void mousekey_console_help(void) {
604 mousekey_param_print();
605 xprintf(/* clang-format off */
606 "p: print values\n"
607 "d: set defaults\n"
608 "up: +1\n"
609 "dn: -1\n"
610 "lt: +10\n"
611 "rt: -10\n"
612 "ESC/q: quit\n"
613
614#ifndef MK_3_SPEED
615 "\n"
616 "speed = delta * max_speed * (repeat / time_to_max)\n"
617 "where delta: cursor=%d, wheel=%d\n"
618 "See http://en.wikipedia.org/wiki/Mouse_keys\n"
619 , MOUSEKEY_MOVE_DELTA, MOUSEKEY_WHEEL_DELTA
620#endif
621
622 ); /* clang-format on */
623}
624# endif /* !NO_PRINT && !USER_PRINT */
625
626/* Only used by `quantum/command.c` / `command_proc()`. To avoid
627 * any doubt: we return `false` to return to the main console,
628 * which differs from the `bool` that `command_proc()` returns. */
629bool mousekey_console(uint8_t code) {
630 static uint8_t param = 0;
631 static uint8_t *pp = NULL;
632 static char *desc = NULL;
633
634# if defined(NO_PRINT) || defined(USER_PRINT) /* -Wunused-parameter */
635 (void)desc;
636# endif
637
638 int8_t change = 0;
639
640 switch (code) {
641 case KC_H:
642 case KC_SLASH: /* ? */
643# if !defined(NO_PRINT) && !defined(USER_PRINT)
644 print("\n\t- Mousekey -\n");
645 mousekey_console_help();
646# endif
647 break;
648
649 case KC_Q:
650 case KC_ESC:
651 print("q\n");
652 if (!param) return false;
653 param = 0;
654 pp = NULL;
655 desc = NULL;
656 break;
657
658 case KC_P:
659# if !defined(NO_PRINT) && !defined(USER_PRINT)
660 print("\n\t- Values -\n");
661 mousekey_param_print();
662# endif
663 break;
664
665 case KC_1 ... KC_0: /* KC_0 gives param = 10 */
666 param = 1 + code - KC_1;
667 switch (param) { /* clang-format off */
668# define PARAM(n, v) case n: pp = &(v); desc = #v; break
669
670#ifndef MK_3_SPEED
671 PARAM(1, mk_delay);
672 PARAM(2, mk_interval);
673 PARAM(3, mk_max_speed);
674 PARAM(4, mk_time_to_max);
675 PARAM(5, mk_wheel_max_speed);
676 PARAM(6, mk_wheel_time_to_max);
677#endif /* MK_3_SPEED */
678
679# undef PARAM
680 default:
681 param = 0;
682 print("?\n");
683 break;
684 } /* clang-format on */
685 if (param) xprintf("%u\n", param);
686 break;
687
688 /* clang-format off */
689 case KC_UP: change = +1; break;
690 case KC_DOWN: change = -1; break;
691 case KC_LEFT: change = -10; break;
692 case KC_RIGHT: change = +10; break;
693 /* clang-format on */
694
695 case KC_D:
696
697# ifndef MK_3_SPEED
698 mk_delay = MOUSEKEY_DELAY / 10;
699 mk_interval = MOUSEKEY_INTERVAL;
700 mk_max_speed = MOUSEKEY_MAX_SPEED;
701 mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
702 mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
703 mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
704# endif /* MK_3_SPEED */
705
706 print("defaults\n");
707 break;
708
709 default:
710 print("?\n");
711 break;
712 }
713
714 if (change) {
715 if (pp) {
716 int16_t val = *pp + change;
717 if (val > (int16_t)UINT8_MAX)
718 *pp = UINT8_MAX;
719 else if (val < 0)
720 *pp = 0;
721 else
722 *pp = (uint8_t)val;
723 xprintf("= %u\n", *pp);
724 } else {
725 print("?\n");
726 }
727 }
728
729 if (param) {
730 xprintf("M%u:%s> ", param, desc ? desc : "???");
731 } else {
732 print("M> ");
733 }
734 return true;
735}
736
737#endif /* MOUSEKEY_ENABLE */
738
739/***********************************************************
740 * Utilities
741 ***********************************************************/
742
743static void switch_default_layer(uint8_t layer) {
744 xprintf("L%d\n", layer);
745 default_layer_set((layer_state_t)1 << layer);
746 clear_keyboard();
747}