X-Git-Url: https://git.friedersdorff.com/?a=blobdiff_plain;f=common%2Fkeyboard.c;h=b0e0ed7935278f5b97f617822bfb2b12944951b6;hb=f291c2279eb9f656ed2a2e3152bab155470c4ef9;hp=9f0c27670efbd1d132e44361df60916e005d828c;hpb=4ae979f6ef8dbf9e1d1f35be15322ad6d02e2958;p=max%2Ftmk_keyboard.git diff --git a/common/keyboard.c b/common/keyboard.c old mode 100755 new mode 100644 index 9f0c2767..b0e0ed79 --- a/common/keyboard.c +++ b/common/keyboard.c @@ -19,7 +19,7 @@ along with this program. If not, see . #include "keymap.h" #include "host.h" #include "led.h" -#include "usb_keycodes.h" +#include "keycode.h" #include "timer.h" #include "print.h" #include "debug.h" @@ -28,11 +28,12 @@ along with this program. If not, see . #ifdef MOUSEKEY_ENABLE #include "mousekey.h" #endif -#ifdef EXTRAKEY_ENABLE -#include -#endif +#define Kdebug(s) do { if (debug_keyboard) debug(s); } while(0) +#define Kdebug_P(s) do { if (debug_keyboard) debug_P(s); } while(0) +#define Kdebug_hex(s) do { if (debug_keyboard) debug_hex(s); } while(0) + #define LAYER_DELAY 250 typedef enum keykind { @@ -41,15 +42,18 @@ typedef enum keykind { FNK_DOWN, FNK_UP, KEY_DOWN, KEY_UP, MOD_DOWN, MOD_UP, - MOUSEKEY_DOWN, MOUSEKEY_UP, - DELAY } keykind_t; typedef enum { IDLE, DELAYING, WAITING, PRESSING } kbdstate_t; -uint8_t current_layer = 0; +#ifdef KEYMAP_DEFAULT_LAYER +uint8_t default_layer = KEYMAP_DEFAULT_LAYER; +uint8_t current_layer = KEYMAP_DEFAULT_LAYER; +#else uint8_t default_layer = 0; +uint8_t current_layer = 0; +#endif /* keyboard internal states */ static kbdstate_t kbdstate = IDLE; @@ -69,59 +73,81 @@ static const char *state_str(kbdstate_t state) static inline keykind_t get_keykind(uint8_t code, bool pressed) { - if IS_KEY(code) return (pressed ? KEY_DOWN : KEY_UP); - if IS_MOD(code) return (pressed ? MOD_DOWN : MOD_UP); + if IS_KEY(code) return (pressed ? KEY_DOWN : KEY_UP); + if IS_MOD(code) return (pressed ? MOD_DOWN : MOD_UP); if IS_FN(code) { if (keymap_fn_keycode(FN_INDEX(code))) return (pressed ? FNK_DOWN : FNK_UP); else return (pressed ? FN_DOWN : FN_UP); } - if IS_MOUSEKEY(code) return (pressed ? MOUSEKEY_DOWN : MOUSEKEY_UP); + if IS_MOUSEKEY(code) return (pressed ? KEY_DOWN : KEY_UP); + if IS_SYSTEM(code) return (pressed ? KEY_DOWN : KEY_UP); + if IS_CONSUMER(code) return (pressed ? KEY_DOWN : KEY_UP); return NONE; } -static void layer_switch_on(uint8_t code) +static void clear_keyboard(void) { - if (!IS_FN(code)) return; - fn_state_bits |= FN_BIT(code); - if (current_layer != keymap_fn_layer(FN_INDEX(code))) { - //TODO: clear all key execpt Mod key - debug("Layer Switch(on): "); debug_hex(current_layer); - current_layer = keymap_fn_layer(FN_INDEX(code)); - debug(" -> "); debug_hex(current_layer); debug("\n"); - } + host_clear_keys(); + host_clear_mods(); + host_send_keyboard_report(); + + host_system_send(0); + host_consumer_send(0); + +#ifdef MOUSEKEY_ENABLE + mousekey_clear(); + mousekey_send(); +#endif } -static void layer_switch_off(uint8_t code) +static void clear_keyboard_but_mods(void) { - if (!IS_FN(code)) return; - fn_state_bits &= ~FN_BIT(code); - if (current_layer != keymap_fn_layer(biton(fn_state_bits))) { - //TODO: clear all key execpt Mod key - debug("Layer Switch(off): "); debug_hex(current_layer); - current_layer = keymap_fn_layer(biton(fn_state_bits)); - debug(" -> "); debug_hex(current_layer); debug("\n"); - } + host_clear_keys(); + host_send_keyboard_report(); + + host_system_send(0); + host_consumer_send(0); + +#ifdef MOUSEKEY_ENABLE + mousekey_clear(); + mousekey_send(); +#endif } -static inline uint8_t get_keycode(key_t key) +static bool anykey_sent_to_host(void) { - return keymap_get_keycode(current_layer, key.row, key.col); + return (host_has_anykey() || host_mouse_in_use() || + host_last_sysytem_report() || host_last_consumer_report()); } -// whether any key except modifier is down or not -static inline bool is_anykey_down(void) +static void layer_switch_on(uint8_t code) { - for (int r = 0; r < MATRIX_ROWS; r++) { - matrix_row_t matrix_row = matrix_get_row(r); - for (int c = 0; c < MATRIX_COLS; c++) { - if (matrix_row && (1< "); Kdebug_hex(new_layer); Kdebug("\n"); + + clear_keyboard_but_mods(); + current_layer = new_layer; + } +} + +static bool layer_switch_off(uint8_t code) +{ + if (!IS_FN(code)) return false; + fn_state_bits &= ~FN_BIT(code); + uint8_t new_layer = (fn_state_bits ? keymap_fn_layer(biton(fn_state_bits)) : default_layer); + if (current_layer != new_layer) { + Kdebug("Layer Switch(off): "); Kdebug_hex(current_layer); + Kdebug(" -> "); Kdebug_hex(new_layer); Kdebug("\n"); + + clear_keyboard_but_mods(); + current_layer = new_layer; + return true; } return false; } @@ -129,17 +155,103 @@ static inline bool is_anykey_down(void) static void register_code(uint8_t code) { if IS_KEY(code) { - host_add_key(code); - host_send_keyboard_report(); + if (!command_proc(code)) { + host_add_key(code); + host_send_keyboard_report(); + } } else if IS_MOD(code) { host_add_mod_bit(MOD_BIT(code)); host_send_keyboard_report(); } + else if IS_FN(code) { + if (!command_proc(keymap_fn_keycode(FN_INDEX(code)))) { + host_add_key(keymap_fn_keycode(FN_INDEX(code))); + host_send_keyboard_report(); + } + } else if IS_MOUSEKEY(code) { +#ifdef MOUSEKEY_ENABLE mousekey_on(code); mousekey_send(); +#endif + } + else if IS_CONSUMER(code) { + uint16_t usage = 0; + switch (code) { + case KC_AUDIO_MUTE: + usage = AUDIO_MUTE; + break; + case KC_AUDIO_VOL_UP: + usage = AUDIO_VOL_UP; + break; + case KC_AUDIO_VOL_DOWN: + usage = AUDIO_VOL_DOWN; + break; + case KC_MEDIA_NEXT_TRACK: + usage = TRANSPORT_NEXT_TRACK; + break; + case KC_MEDIA_PREV_TRACK: + usage = TRANSPORT_PREV_TRACK; + break; + case KC_MEDIA_STOP: + usage = TRANSPORT_STOP; + break; + case KC_MEDIA_PLAY_PAUSE: + usage = TRANSPORT_PLAY_PAUSE; + break; + case KC_MEDIA_SELECT: + usage = AL_CC_CONFIG; + break; + case KC_MAIL: + usage = AL_EMAIL; + break; + case KC_CALCULATOR: + usage = AL_CALCULATOR; + break; + case KC_MY_COMPUTER: + usage = AL_LOCAL_BROWSER; + break; + case KC_WWW_SEARCH: + usage = AC_SEARCH; + break; + case KC_WWW_HOME: + usage = AC_HOME; + break; + case KC_WWW_BACK: + usage = AC_BACK; + break; + case KC_WWW_FORWARD: + usage = AC_FORWARD; + break; + case KC_WWW_STOP: + usage = AC_STOP; + break; + case KC_WWW_REFRESH: + usage = AC_REFRESH; + break; + case KC_WWW_FAVORITES: + usage = AC_BOOKMARKS; + break; + } + host_consumer_send(usage); + } + else if IS_SYSTEM(code) { + uint16_t usage = 0; + switch (code) { + case KC_SYSTEM_POWER: + usage = SYSTEM_POWER_DOWN; + break; + case KC_SYSTEM_SLEEP: + usage = SYSTEM_SLEEP; + break; + case KC_SYSTEM_WAKE: + usage = SYSTEM_WAKE_UP; + break; + } + host_system_send(usage); } + } static void unregister_code(uint8_t code) @@ -152,32 +264,51 @@ static void unregister_code(uint8_t code) host_del_mod_bit(MOD_BIT(code)); host_send_keyboard_report(); } + else if IS_FN(code) { + host_del_key(keymap_fn_keycode(FN_INDEX(code))); + host_send_keyboard_report(); + } else if IS_MOUSEKEY(code) { +#ifdef MOUSEKEY_ENABLE mousekey_off(code); mousekey_send(); +#endif + } + else if IS_CONSUMER(code) { + host_consumer_send(0x0000); + } + else if IS_SYSTEM(code) { + host_system_send(0x0000); } } /* * - * Event/State|IDLE DELAYING[f] WAITING[f,k] PRESSING + * Event/State|IDLE PRESSING DELAYING[f] WAITING[f,k] * -----------+------------------------------------------------------------------ - * Fn Down |IDLE(L+) WAITING(Sk) WAITING(Sk) - - * Up |IDLE(L-) IDLE(L-) IDLE(L-) IDLE(L-) - * Fnk Down |DELAYING(Sf) WAITING(Sk) WAINTING(Sk) PRESSING(Rf) - * Up |IDLE(L-) IDLE(Rf,Uf) IDLE(Rf,Ps,Uf)*3 PRESSING(Uf) - * Key Down |PRESSING(Rk) WAITING(Sk) WAITING(Sk) PRESSING(Rk) - * Up |IDLE(Uk) DELAYING(Uk) IDLE(L+,Ps,Uk) IDLE(Uk)*4 - * Delay |- IDLE(L+) IDLE(L+,Ps) - + * Fn Down |(L+) -*1 WAITING(Sk) IDLE(Rf,Ps)*7 + * Up |(L-) IDLE(L-)*8 IDLE(L-)*8 IDLE(L-)*8 + * Fnk Down |DELAYING(Sf)* (Rf) WAITING(Sk) IDLE(Rf,Ps,Rf) + * Up |(L-) IDLE(L-/Uf)*8 IDLE(Rf,Uf/L-)*3 IDLE(Rf,Ps,Uf/L-)*3 + * Key Down |PRESSING(Rk) (Rk) WAITING(Sk) IDLE(Rf,Ps,Rk) + * Up |(Uk) IDLE(Uk)*4 (Uk) IDLE(L+,Ps,Pk)/(Uk)*a * | - * No key Down|IDLE(Ld) IDLE(Ld) IDLE(Ld) IDLE(Ld) + * Delay |- - IDLE(L+) IDLE(L+,Ps) + * Magic Key |COMMAND*5 * + * *1: ignore Fn if other key is down. * *2: register Fnk if any key is pressing - * *3: when Fnk == Stored Fnk, if not ignore. - * *4: when no registered key any more + * *3: register/unregister delayed Fnk and move to IDLE if code == delayed Fnk, else *8 + * *4: if no keys registered to host + * *5: unregister all keys + * *6: only if no keys down + * *7: ignore Fn because Fnk key and stored key are down. + * *8: move to IDLE if layer switch(off) occurs, else stay at current state + * *9: repeat key if pressing Fnk twice quickly(move to PRESSING) + * *a: layer switch and process waiting key and code if code == wainting key, else unregister key * * States: - * IDLE: + * IDLE: No key is down except modifiers * DELAYING: delay layer switch after pressing Fn with alt keycode * WAITING: key is pressed during DELAYING * @@ -185,47 +316,43 @@ static void unregister_code(uint8_t code) * Fn: Fn key without alternative keycode * Fnk: Fn key with alternative keycode * -: ignore + * Delay: layer switch delay term is elapsed * * Actions: * Rk: register key * Uk: unregister key - * Rf: register stored Fn(alt keycode) - * Uf: unregister stored Fn(alt keycode) + * Rf: register Fn(alt keycode) + * Uf: unregister Fn(alt keycode) * Rs: register stored key * Us: unregister stored key - * Sk: store key - * Sf: store Fn - * Ps: play stored key(Interpret stored key and transit state) - * L+: Switch to new layer(*retain* Modifiers only) - * L-: Switch back to last layer(*clear* stored key/Fn, *unregister* all Modifier/key) - * Ld: Switch back to default layer(*clear* stored key/Fn, *unregister* all Modifier/key) + * Sk: Store key(waiting Key) + * Sf: Store Fn(delayed Fn) + * Ps: Process stored key + * Ps: Process key + * Is: Interpret stored keys in current layer + * L+: Switch to new layer(*unregister* all keys but modifiers) + * L-: Switch back to last layer(*unregister* all keys but modifiers) + * Ld: Switch back to default layer(*unregister* all keys but modifiers) */ #define NEXT(state) do { \ - debug("NEXT: "); print_P(state_str(kbdstate)); \ + Kdebug("NEXT: "); Kdebug_P(state_str(kbdstate)); \ kbdstate = state; \ - debug(" -> "); print_P(state_str(kbdstate)); debug("\n"); \ + Kdebug(" -> "); Kdebug_P(state_str(kbdstate)); Kdebug("\n"); \ } while (0) static inline void process_key(keyevent_t event) { - - /* TODO: ring buffer - static keyrecord_t waiting_keys[5]; - static uint8_t waiting_keys_head = 0; - static uint8_t waiting_keys_tail = 0; - */ - - uint8_t code = get_keycode(event.key); + uint8_t code = keymap_get_keycode(current_layer, event.key.row, event.key.col); keykind_t kind = get_keykind(code, event.pressed); uint8_t tmp_mods; - //debug("kbdstate: "); debug_hex(kbdstate); - debug("state: "); print_P(state_str(kbdstate)); - debug(" kind: "); debug_hex(kind); - debug(" code: "); debug_hex(code); - if (event.pressed) { debug("d"); } else { debug("u"); } - debug("\n"); + Kdebug("state: "); Kdebug_P(state_str(kbdstate)); + Kdebug(" kind: "); Kdebug_hex(kind); + Kdebug(" code: "); Kdebug_hex(code); + if (event.pressed) { Kdebug("d"); } else { Kdebug("u"); } + Kdebug("\n"); + switch (kbdstate) { case IDLE: switch (kind) { @@ -236,15 +363,25 @@ static inline void process_key(keyevent_t event) layer_switch_off(code); break; case FNK_DOWN: - // store event - delayed_fn = (keyrecord_t) { .event = event, .code = code, .mods = keyboard_report->mods, .time = timer_read() }; - NEXT(DELAYING); + // repeat Fn alt key when press Fn key down, up then down again quickly + if (KEYEQ(delayed_fn.event.key, event.key) && + timer_elapsed(delayed_fn.time) < LAYER_DELAY) { + register_code(code); + NEXT(PRESSING); + } else { + delayed_fn = (keyrecord_t) { + .event = event, + .code = code, + .mods = keyboard_report->mods, + .time = timer_read() + }; + NEXT(DELAYING); + } break; case FNK_UP: layer_switch_off(code); break; case KEY_DOWN: - case MOUSEKEY_DOWN: register_code(code); NEXT(PRESSING); break; @@ -252,7 +389,6 @@ static inline void process_key(keyevent_t event) register_code(code); break; case KEY_UP: - case MOUSEKEY_UP: case MOD_UP: unregister_code(code); break; @@ -266,26 +402,29 @@ static inline void process_key(keyevent_t event) // ignored when any key is pressed break; case FN_UP: - layer_switch_off(code); - NEXT(IDLE); + if (layer_switch_off(code)) + NEXT(IDLE); break; case FNK_DOWN: - register_code(keymap_fn_keycode(FN_INDEX(code))); + register_code(code); break; case FNK_UP: - unregister_code(keymap_fn_keycode(FN_INDEX(code))); + if (layer_switch_off(code)) { + NEXT(IDLE); + } else { + unregister_code(code); + if (!anykey_sent_to_host()) + NEXT(IDLE); + } break; case KEY_DOWN: case MOD_DOWN: - case MOUSEKEY_DOWN: register_code(code); break; case KEY_UP: case MOD_UP: - case MOUSEKEY_UP: unregister_code(code); - // no key registered? mousekey, mediakey, systemkey - if (!host_has_anykey()) + if (!anykey_sent_to_host()) NEXT(IDLE); break; default: @@ -297,16 +436,20 @@ static inline void process_key(keyevent_t event) case FN_DOWN: case FNK_DOWN: case KEY_DOWN: - case MOUSEKEY_DOWN: - waiting_key = (keyrecord_t) { .event = event, .code = code, .mods = keyboard_report->mods, .time = timer_read() }; + waiting_key = (keyrecord_t) { + .event = event, + .code = code, + .mods = keyboard_report->mods, + .time = timer_read() + }; NEXT(WAITING); break; case MOD_DOWN: register_code(code); break; case FN_UP: - layer_switch_off(code); - NEXT(IDLE); + if (layer_switch_off(code)) + NEXT(IDLE); break; case FNK_UP: if (code == delayed_fn.code) { @@ -314,20 +457,16 @@ static inline void process_key(keyevent_t event) // restore the mod status at the time of pressing Fn key tmp_mods = keyboard_report->mods; host_set_mods(delayed_fn.mods); - register_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); - unregister_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); + register_code(delayed_fn.code); + unregister_code(delayed_fn.code); host_set_mods(tmp_mods); NEXT(IDLE); } else { - layer_switch_off(code); - NEXT(IDLE); + if (layer_switch_off(code)) + NEXT(IDLE); } break; case KEY_UP: - case MOUSEKEY_UP: - unregister_code(code); - NEXT(IDLE); - break; case MOD_UP: unregister_code(code); break; @@ -340,41 +479,45 @@ static inline void process_key(keyevent_t event) case FN_DOWN: case FNK_DOWN: case KEY_DOWN: - case MOUSEKEY_DOWN: tmp_mods = keyboard_report->mods; host_set_mods(delayed_fn.mods); - register_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); + register_code(delayed_fn.code); host_set_mods(waiting_key.mods); register_code(waiting_key.code); host_set_mods(tmp_mods); - register_code(code); + if (kind == FN_DOWN) { + // ignore Fn + } else if (kind == FNK_DOWN) { + register_code(code); + } else if (kind == KEY_DOWN) { + register_code(code); + } NEXT(IDLE); break; case MOD_DOWN: register_code(code); break; case FN_UP: - layer_switch_off(code); - NEXT(IDLE); + if (layer_switch_off(code)) + NEXT(IDLE); break; case FNK_UP: if (code == delayed_fn.code) { // alt down, key down, alt up tmp_mods = keyboard_report->mods; host_set_mods(delayed_fn.mods); - register_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); + register_code(delayed_fn.code); host_set_mods(waiting_key.mods); register_code(waiting_key.code); - unregister_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); + unregister_code(delayed_fn.code); host_set_mods(tmp_mods); NEXT(IDLE); } else { - layer_switch_off(code); - NEXT(IDLE); + if (layer_switch_off(code)) + NEXT(IDLE); } break; case KEY_UP: - case MOUSEKEY_UP: if (code == waiting_key.code) { layer_switch_on(delayed_fn.code); NEXT(IDLE); @@ -396,8 +539,6 @@ static inline void process_key(keyevent_t event) } break; } - - // TODO: FAIL SAFE: unregister all keys when no key down } void keyboard_init(void) @@ -414,22 +555,15 @@ void keyboard_init(void) void keyboard_task(void) { static matrix_row_t matrix_prev[MATRIX_ROWS]; + static uint8_t led_status = 0; matrix_row_t matrix_row = 0; matrix_row_t matrix_change = 0; matrix_scan(); - if (command_proc()) { - debug("COMMAND\n"); - // TODO: clear all keys - host_clear_keyboard_report(); - host_send_keyboard_report(); - return; - } for (int r = 0; r < MATRIX_ROWS; r++) { matrix_row = matrix_get_row(r); matrix_change = matrix_row ^ matrix_prev[r]; if (matrix_change) { - // TODO: print once per scan if (debug_matrix) matrix_print(); for (int c = 0; c < MATRIX_COLS; c++) { @@ -447,7 +581,6 @@ void keyboard_task(void) } } MATRIX_LOOP_END: - // TODO: FAIL SAFE: clear all key if no key down // layer switch when delay term elapses if (kbdstate == DELAYING || kbdstate == WAITING) { @@ -467,8 +600,29 @@ void keyboard_task(void) } } +#ifdef MOUSEKEY_ENABLE // mousekey repeat & acceleration mousekey_task(); +#endif + + // FAIL SAFE: clear all key if no key down + if (matrix_change) { + matrix_row_t is_matrix_on = 0; + for (int r = 0; r < MATRIX_ROWS; r++) { + is_matrix_on |= matrix_get_row(r); + } + if (!is_matrix_on) { + Kdebug("FAIL SAFE: clear all keys(default layer).\n"); + clear_keyboard(); + current_layer = default_layer; + } + } + + // update LED + if (led_status != host_keyboard_leds()) { + led_status = host_keyboard_leds(); + keyboard_set_leds(led_status); + } return; }