X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fkeyboard.c;h=9a809ff4a153dbfca52f1a248cb9e001e26cfd06;hb=1f96edaed60def1f513ddd8adcdfa3e12b971006;hp=43abf4236f62d6f693f242d99b31d4c7a7cd974d;hpb=5b00cf3f024a09d834d125374d93cacc269f84ba;p=tmk_firmware.git diff --git a/common/keyboard.c b/common/keyboard.c index 43abf42..9a809ff 100644 --- a/common/keyboard.c +++ b/common/keyboard.c @@ -1,5 +1,5 @@ /* -Copyright 2011 Jun Wako +Copyright 2011,2012,2013 Jun Wako This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,6 +14,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include #include "keyboard.h" #include "matrix.h" #include "keymap.h" @@ -25,580 +26,114 @@ along with this program. If not, see . #include "debug.h" #include "command.h" #include "util.h" +#include "sendchar.h" +#include "bootmagic.h" +#include "eeconfig.h" +#include "backlight.h" #ifdef MOUSEKEY_ENABLE -#include "mousekey.h" +# include "mousekey.h" #endif -#ifdef EXTRAKEY_ENABLE -#include -#endif - - -#define LAYER_DELAY 250 - -typedef enum keykind { - NONE, - FN_DOWN, FN_UP, - FNK_DOWN, FNK_UP, - KEY_DOWN, KEY_UP, - MOD_DOWN, MOD_UP, -} keykind_t; - -typedef enum { IDLE, DELAYING, WAITING, PRESSING } kbdstate_t; - - -uint8_t current_layer = 0; -uint8_t default_layer = 0; - -/* keyboard internal states */ -static kbdstate_t kbdstate = IDLE; -static uint8_t fn_state_bits = 0; -static keyrecord_t delayed_fn; -static keyrecord_t waiting_key; - - -static const char *state_str(kbdstate_t state) -{ - if (state == IDLE) return PSTR("IDLE"); - if (state == DELAYING) return PSTR("DELAYING"); - if (state == WAITING) return PSTR("WAITING"); - if (state == PRESSING) return PSTR("PRESSING"); - return PSTR("UNKNOWN"); -} - -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_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 ? 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 clear_keyboard(void) -{ - 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 clear_keyboard_but_mods(void) -{ - host_clear_keys(); - host_send_keyboard_report(); - - host_system_send(0); - host_consumer_send(0); - -#ifdef MOUSEKEY_ENABLE - mousekey_clear(); - mousekey_send(); +#ifdef PS2_MOUSE_ENABLE +# include "ps2_mouse.h" #endif -} - -static void layer_switch_on(uint8_t code) -{ - if (!IS_FN(code)) return; - fn_state_bits |= FN_BIT(code); - if (current_layer != keymap_fn_layer(FN_INDEX(code))) { - clear_keyboard_but_mods(); - debug("Layer Switch(on): "); debug_hex(current_layer); - current_layer = keymap_fn_layer(FN_INDEX(code)); - debug(" -> "); debug_hex(current_layer); debug("\n"); - } -} -static void layer_switch_off(uint8_t code) +#ifdef MATRIX_HAS_GHOST +static bool has_ghost_in_row(uint8_t row) { - if (!IS_FN(code)) return; - fn_state_bits &= ~FN_BIT(code); - if (current_layer != keymap_fn_layer(biton(fn_state_bits))) { - clear_keyboard_but_mods(); - - debug("Layer Switch(off): "); debug_hex(current_layer); - current_layer = keymap_fn_layer(biton(fn_state_bits)); - debug(" -> "); debug_hex(current_layer); debug("\n"); - } -} + matrix_row_t matrix_row = matrix_get_row(row); + // No ghost exists when less than 2 keys are down on the row + if (((matrix_row - 1) & matrix_row) == 0) + return false; -// whether any key except modifier is down or not -static inline bool is_anykey_down(void) -{ - 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< "); print_P(state_str(kbdstate)); debug("\n"); \ -} while (0) - -static inline void process_key(keyevent_t event) -{ - 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("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"); - switch (kbdstate) { - case IDLE: - switch (kind) { - case FN_DOWN: - layer_switch_on(code); - break; - case FN_UP: - layer_switch_off(code); - break; - case FNK_DOWN: - // 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(keymap_fn_keycode(FN_INDEX(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: - register_code(code); - NEXT(PRESSING); - break; - case MOD_DOWN: - register_code(code); - break; - case KEY_UP: - case MOD_UP: - unregister_code(code); - break; - default: - break; - } - break; - case PRESSING: - switch (kind) { - case FN_DOWN: - // ignored when any key is pressed - break; - case FN_UP: - layer_switch_off(code); - NEXT(IDLE); - break; - case FNK_DOWN: - register_code(keymap_fn_keycode(FN_INDEX(code))); - break; - case FNK_UP: - // can't know whether layer switched or not - layer_switch_off(code); - unregister_code(keymap_fn_keycode(FN_INDEX(code))); - break; - case KEY_DOWN: - case MOD_DOWN: - register_code(code); - break; - case KEY_UP: - case MOD_UP: - unregister_code(code); - // TODO: no key registered? mousekey, mediakey, systemkey - if (!host_has_anykey()) - NEXT(IDLE); - break; - default: - break; - } - break; - case DELAYING: - switch (kind) { - case FN_DOWN: - case FNK_DOWN: - case KEY_DOWN: - 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); - break; - case FNK_UP: - if (code == delayed_fn.code) { - // type Fn with alt keycode - // 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))); - host_set_mods(tmp_mods); - NEXT(IDLE); - } else { - layer_switch_off(code); - NEXT(IDLE); - } - break; - case KEY_UP: - unregister_code(code); - NEXT(IDLE); - break; - case MOD_UP: - unregister_code(code); - break; - default: - break; - } - break; - case WAITING: - switch (kind) { - case FN_DOWN: - case FNK_DOWN: - case KEY_DOWN: - tmp_mods = keyboard_report->mods; - host_set_mods(delayed_fn.mods); - register_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); - host_set_mods(waiting_key.mods); - register_code(waiting_key.code); - host_set_mods(tmp_mods); - register_code(code); - NEXT(IDLE); - break; - case MOD_DOWN: - register_code(code); - break; - case FN_UP: - 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))); - host_set_mods(waiting_key.mods); - register_code(waiting_key.code); - unregister_code(keymap_fn_keycode(FN_INDEX(delayed_fn.code))); - host_set_mods(tmp_mods); - NEXT(IDLE); - } else { - layer_switch_off(code); - NEXT(IDLE); - } - break; - case KEY_UP: - if (code == waiting_key.code) { - layer_switch_on(delayed_fn.code); - NEXT(IDLE); - // process waiting_key - tmp_mods = keyboard_report->mods; - host_set_mods(waiting_key.mods); - process_key(waiting_key.event); - host_set_mods(tmp_mods); - process_key(event); - } else { - unregister_code(code); - } - break; - case MOD_UP: - unregister_code(code); - break; - default: - break; - } - break; - } -} void keyboard_init(void) { - debug_keyboard = true; - timer_init(); matrix_init(); #ifdef PS2_MOUSE_ENABLE ps2_mouse_init(); #endif + +#ifdef BOOTMAGIC_ENABLE + bootmagic(); +#endif + +#ifdef BACKLIGHT_ENABLE + backlight_init(); +#endif } +/* + * Do keyboard routine jobs: scan mantrix, light LEDs, ... + * This is repeatedly called as fast as possible. + */ 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: COMMAND state? - clear_keyboard(); - return; - } - - for (int r = 0; r < MATRIX_ROWS; r++) { + for (uint8_t r = 0; r < MATRIX_ROWS; r++) { matrix_row = matrix_get_row(r); matrix_change = matrix_row ^ matrix_prev[r]; if (matrix_change) { if (debug_matrix) matrix_print(); - - for (int c = 0; c < MATRIX_COLS; c++) { - if (matrix_change & (1< LAYER_DELAY) { - if (kbdstate == DELAYING) { - layer_switch_on(delayed_fn.code); - NEXT(IDLE); - } - if (kbdstate == WAITING) { - layer_switch_on(delayed_fn.code); - NEXT(IDLE); - uint8_t tmp_mods = keyboard_report->mods; - host_set_mods(waiting_key.mods); - process_key(waiting_key.event); - host_set_mods(tmp_mods); - } - } - } +MATRIX_LOOP_END: #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) { - debug("FAIL SAFE: clear all keys.\n"); - clear_keyboard(); - } +#ifdef PS2_MOUSE_ENABLE + ps2_mouse_task(); +#endif + + // update LED + if (led_status != host_keyboard_leds()) { + led_status = host_keyboard_leds(); + keyboard_set_leds(led_status); } - - return; } void keyboard_set_leds(uint8_t leds) { + if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); } led_set(leds); }