SRC += $(COMMON_DIR)/host.c \ | SRC += $(COMMON_DIR)/host.c \ | ||||
$(COMMON_DIR)/keyboard.c \ | $(COMMON_DIR)/keyboard.c \ | ||||
$(COMMON_DIR)/command.c \ | $(COMMON_DIR)/command.c \ | ||||
$(COMMON_DIR)/layer.c \ | |||||
$(COMMON_DIR)/timer.c \ | $(COMMON_DIR)/timer.c \ | ||||
$(COMMON_DIR)/print.c \ | $(COMMON_DIR)/print.c \ | ||||
$(COMMON_DIR)/debug.c \ | $(COMMON_DIR)/debug.c \ |
#include "debug.h" | #include "debug.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "timer.h" | #include "timer.h" | ||||
#include "layer.h" | |||||
#include "keyboard.h" | |||||
#include "matrix.h" | #include "matrix.h" | ||||
#include "bootloader.h" | #include "bootloader.h" | ||||
#include "command.h" | #include "command.h" |
return (*driver->keyboard_leds)(); | return (*driver->keyboard_leds)(); | ||||
} | } | ||||
/* new interface */ | |||||
void host_register_key(uint8_t key) | |||||
{ | |||||
host_add_key(key); | |||||
host_send_keyboard_report(); | |||||
} | |||||
void host_unregister_key(uint8_t key) | |||||
{ | |||||
host_del_key(key); | |||||
host_send_keyboard_report(); | |||||
} | |||||
/* keyboard report operations */ | /* keyboard report operations */ | ||||
void host_add_key(uint8_t key) | void host_add_key(uint8_t key) | ||||
{ | { | ||||
{ | { | ||||
if (!driver) return; | if (!driver) return; | ||||
(*driver->send_keyboard)(keyboard_report); | (*driver->send_keyboard)(keyboard_report); | ||||
if (debug_keyboard) { | |||||
print("keys: "); | |||||
for (int i = 0; i < REPORT_KEYS; i++) { | |||||
phex(keyboard_report->keys[i]); print(" "); | |||||
} | |||||
print(" mods: "); phex(keyboard_report->mods); print("\n"); | |||||
} | |||||
} | } | ||||
void host_mouse_send(report_mouse_t *report) | void host_mouse_send(report_mouse_t *report) | ||||
for (; i < REPORT_KEYS; i++) { | for (; i < REPORT_KEYS; i++) { | ||||
if (keyboard_report->keys[i] == code) { | if (keyboard_report->keys[i] == code) { | ||||
keyboard_report->keys[i] = 0; | keyboard_report->keys[i] = 0; | ||||
break; | |||||
} | } | ||||
} | } | ||||
} | } |
host_driver_t *host_get_driver(void); | host_driver_t *host_get_driver(void); | ||||
uint8_t host_keyboard_leds(void); | uint8_t host_keyboard_leds(void); | ||||
/* new interface */ | |||||
void host_register_key(uint8_t key); | |||||
void host_unregister_key(uint8_t key); | |||||
/* keyboard report operations */ | /* keyboard report operations */ | ||||
void host_add_key(uint8_t key); | void host_add_key(uint8_t key); | ||||
void host_del_key(uint8_t key); | void host_del_key(uint8_t key); |
along with this program. If not, see <http://www.gnu.org/licenses/>. | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "keyboard.h" | #include "keyboard.h" | ||||
#include "host.h" | |||||
#include "layer.h" | |||||
#include "matrix.h" | #include "matrix.h" | ||||
#include "keymap.h" | |||||
#include "host.h" | |||||
#include "led.h" | #include "led.h" | ||||
#include "usb_keycodes.h" | #include "usb_keycodes.h" | ||||
#include "timer.h" | #include "timer.h" | ||||
#include "print.h" | #include "print.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "command.h" | #include "command.h" | ||||
#include "util.h" | |||||
#ifdef MOUSEKEY_ENABLE | #ifdef MOUSEKEY_ENABLE | ||||
#include "mousekey.h" | #include "mousekey.h" | ||||
#endif | #endif | ||||
#endif | #endif | ||||
static uint8_t last_leds = 0; | |||||
#define LAYER_DELAY 250 | |||||
typedef enum keykind { | |||||
NONE, | |||||
FN_DOWN, FN_UP, | |||||
FNK_DOWN, FNK_UP, | |||||
KEY_DOWN, KEY_UP, | |||||
MOD_DOWN, MOD_UP, | |||||
MOUSEKEY_DOWN, MOUSEKEY_UP, | |||||
DELAY | |||||
} keykind_t; | |||||
void keyboard_init(void) | |||||
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) | |||||
{ | { | ||||
timer_init(); | |||||
matrix_init(); | |||||
#ifdef PS2_MOUSE_ENABLE | |||||
ps2_mouse_init(); | |||||
#endif | |||||
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"); | |||||
} | } | ||||
void keyboard_proc(void) | |||||
static inline keykind_t get_keykind(uint8_t code, bool pressed) | |||||
{ | { | ||||
uint8_t fn_bits = 0; | |||||
#ifdef EXTRAKEY_ENABLE | |||||
uint16_t consumer_code = 0; | |||||
uint16_t system_code = 0; | |||||
#endif | |||||
matrix_scan(); | |||||
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); | |||||
return NONE; | |||||
} | |||||
if (matrix_is_modified()) { | |||||
if (debug_matrix) matrix_print(); | |||||
#ifdef DEBUG_LED | |||||
// LED flash for debug | |||||
DEBUG_LED_CONFIG; | |||||
DEBUG_LED_ON; | |||||
#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))) { | |||||
//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"); | |||||
} | } | ||||
} | |||||
if (matrix_has_ghost()) { | |||||
// should send error? | |||||
debug("matrix has ghost!!\n"); | |||||
return; | |||||
static void layer_switch_off(uint8_t code) | |||||
{ | |||||
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_swap_keyboard_report(); | |||||
host_clear_keyboard_report(); | |||||
for (int row = 0; row < matrix_rows(); row++) { | |||||
for (int col = 0; col < matrix_cols(); col++) { | |||||
if (!matrix_is_on(row, col)) continue; | |||||
uint8_t code = layer_get_keycode(row, col); | |||||
if (code == KB_NO) { | |||||
// do nothing | |||||
} else if (IS_MOD(code)) { | |||||
host_add_mod_bit(MOD_BIT(code)); | |||||
} else if (IS_FN(code)) { | |||||
fn_bits |= FN_BIT(code); | |||||
} | |||||
// TODO: use table or something | |||||
#ifdef EXTRAKEY_ENABLE | |||||
// System Control | |||||
else if (code == KB_SYSTEM_POWER) { | |||||
#ifdef HOST_PJRC | |||||
if (suspend && remote_wakeup) { | |||||
usb_remote_wakeup(); | |||||
static inline uint8_t get_keycode(key_t key) | |||||
{ | |||||
return keymap_get_keycode(current_layer, key.row, key.col); | |||||
} | |||||
// 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<<c)) { | |||||
if (IS_KEY(get_keycode((key_t){ .row = r, .col = c }))) { | |||||
return true; | |||||
} | } | ||||
#endif | |||||
system_code = SYSTEM_POWER_DOWN; | |||||
} else if (code == KB_SYSTEM_SLEEP) { | |||||
system_code = SYSTEM_SLEEP; | |||||
} else if (code == KB_SYSTEM_WAKE) { | |||||
system_code = SYSTEM_WAKE_UP; | |||||
} | |||||
// Consumer Page | |||||
else if (code == KB_AUDIO_MUTE) { | |||||
consumer_code = AUDIO_MUTE; | |||||
} else if (code == KB_AUDIO_VOL_UP) { | |||||
consumer_code = AUDIO_VOL_UP; | |||||
} else if (code == KB_AUDIO_VOL_DOWN) { | |||||
consumer_code = AUDIO_VOL_DOWN; | |||||
} | } | ||||
else if (code == KB_MEDIA_NEXT_TRACK) { | |||||
consumer_code = TRANSPORT_NEXT_TRACK; | |||||
} else if (code == KB_MEDIA_PREV_TRACK) { | |||||
consumer_code = TRANSPORT_PREV_TRACK; | |||||
} else if (code == KB_MEDIA_STOP) { | |||||
consumer_code = TRANSPORT_STOP; | |||||
} else if (code == KB_MEDIA_PLAY_PAUSE) { | |||||
consumer_code = TRANSPORT_PLAY_PAUSE; | |||||
} else if (code == KB_MEDIA_SELECT) { | |||||
consumer_code = AL_CC_CONFIG; | |||||
} | |||||
else if (code == KB_MAIL) { | |||||
consumer_code = AL_EMAIL; | |||||
} else if (code == KB_CALCULATOR) { | |||||
consumer_code = AL_CALCULATOR; | |||||
} else if (code == KB_MY_COMPUTER) { | |||||
consumer_code = AL_LOCAL_BROWSER; | |||||
} | |||||
else if (code == KB_WWW_SEARCH) { | |||||
consumer_code = AC_SEARCH; | |||||
} else if (code == KB_WWW_HOME) { | |||||
consumer_code = AC_HOME; | |||||
} else if (code == KB_WWW_BACK) { | |||||
consumer_code = AC_BACK; | |||||
} else if (code == KB_WWW_FORWARD) { | |||||
consumer_code = AC_FORWARD; | |||||
} else if (code == KB_WWW_STOP) { | |||||
consumer_code = AC_STOP; | |||||
} else if (code == KB_WWW_REFRESH) { | |||||
consumer_code = AC_REFRESH; | |||||
} else if (code == KB_WWW_FAVORITES) { | |||||
consumer_code = AC_BOOKMARKS; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
static void register_code(uint8_t code) | |||||
{ | |||||
if IS_KEY(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_MOUSEKEY(code) { | |||||
mousekey_on(code); | |||||
mousekey_send(); | |||||
} | |||||
} | |||||
static void unregister_code(uint8_t code) | |||||
{ | |||||
if IS_KEY(code) { | |||||
host_del_key(code); | |||||
host_send_keyboard_report(); | |||||
} | |||||
else if IS_MOD(code) { | |||||
host_del_mod_bit(MOD_BIT(code)); | |||||
host_send_keyboard_report(); | |||||
} | |||||
else if IS_MOUSEKEY(code) { | |||||
mousekey_off(code); | |||||
mousekey_send(); | |||||
} | |||||
} | |||||
/* | |||||
* | |||||
* Event/State|IDLE DELAYING[f] WAITING[f,k] PRESSING | |||||
* -----------+------------------------------------------------------------------ | |||||
* 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) - | |||||
* | | |||||
* No key Down|IDLE(Ld) IDLE(Ld) IDLE(Ld) IDLE(Ld) | |||||
* | |||||
* *2: register Fnk if any key is pressing | |||||
* *3: when Fnk == Stored Fnk, if not ignore. | |||||
* *4: when no registered key any more | |||||
* | |||||
* States: | |||||
* IDLE: | |||||
* DELAYING: delay layer switch after pressing Fn with alt keycode | |||||
* WAITING: key is pressed during DELAYING | |||||
* | |||||
* Events: | |||||
* Fn: Fn key without alternative keycode | |||||
* Fnk: Fn key with alternative keycode | |||||
* -: ignore | |||||
* | |||||
* Actions: | |||||
* Rk: register key | |||||
* Uk: unregister key | |||||
* Rf: register stored Fn(alt keycode) | |||||
* Uf: unregister stored 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) | |||||
*/ | |||||
#define NEXT(state) do { \ | |||||
debug("NEXT: "); print_P(state_str(kbdstate)); \ | |||||
kbdstate = state; \ | |||||
debug(" -> "); print_P(state_str(kbdstate)); debug("\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); | |||||
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"); | |||||
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: | |||||
// store event | |||||
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; | |||||
case MOD_DOWN: | |||||
register_code(code); | |||||
break; | |||||
case KEY_UP: | |||||
case MOUSEKEY_UP: | |||||
case MOD_UP: | |||||
unregister_code(code); | |||||
break; | |||||
default: | |||||
break; | |||||
} | } | ||||
#endif | |||||
else if (IS_KEY(code)) { | |||||
host_add_key(code); | |||||
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: | |||||
unregister_code(keymap_fn_keycode(FN_INDEX(code))); | |||||
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()) | |||||
NEXT(IDLE); | |||||
break; | |||||
default: | |||||
break; | |||||
} | } | ||||
#ifdef MOUSEKEY_ENABLE | |||||
else if (IS_MOUSEKEY(code)) { | |||||
mousekey_decode(code); | |||||
break; | |||||
case DELAYING: | |||||
switch (kind) { | |||||
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() }; | |||||
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: | |||||
case MOUSEKEY_UP: | |||||
unregister_code(code); | |||||
NEXT(IDLE); | |||||
break; | |||||
case MOD_UP: | |||||
unregister_code(code); | |||||
break; | |||||
default: | |||||
break; | |||||
} | } | ||||
#endif | |||||
else { | |||||
debug("ignore keycode: "); debug_hex(code); debug("\n"); | |||||
break; | |||||
case WAITING: | |||||
switch (kind) { | |||||
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))); | |||||
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: | |||||
case MOUSEKEY_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; | |||||
} | } | ||||
layer_switching(fn_bits); | |||||
// TODO: FAIL SAFE: unregister all keys when no key down | |||||
} | |||||
void keyboard_init(void) | |||||
{ | |||||
debug_keyboard = true; | |||||
timer_init(); | |||||
matrix_init(); | |||||
#ifdef PS2_MOUSE_ENABLE | |||||
ps2_mouse_init(); | |||||
#endif | |||||
} | |||||
void keyboard_task(void) | |||||
{ | |||||
static matrix_row_t matrix_prev[MATRIX_ROWS]; | |||||
matrix_row_t matrix_row = 0; | |||||
matrix_row_t matrix_change = 0; | |||||
matrix_scan(); | |||||
if (command_proc()) { | if (command_proc()) { | ||||
debug("COMMAND\n"); | |||||
// TODO: clear all keys | |||||
host_clear_keyboard_report(); | |||||
host_send_keyboard_report(); | |||||
return; | 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(); | |||||
// TODO: should send only when changed from last report | |||||
if (matrix_is_modified()) { | |||||
host_send_keyboard_report(); | |||||
#ifdef EXTRAKEY_ENABLE | |||||
host_consumer_send(consumer_code); | |||||
host_system_send(system_code); | |||||
#endif | |||||
#ifdef DEBUG_LED | |||||
// LED flash for debug | |||||
DEBUG_LED_CONFIG; | |||||
DEBUG_LED_OFF; | |||||
#endif | |||||
for (int c = 0; c < MATRIX_COLS; c++) { | |||||
if (matrix_change & (1<<c)) { | |||||
process_key((keyevent_t){ | |||||
.key = (key_t){ .row = r, .col = c }, | |||||
.pressed = (matrix_row & (1<<c)) | |||||
}); | |||||
// record a processed key | |||||
matrix_prev[r] ^= (1<<c); | |||||
// process a key per task call | |||||
goto MATRIX_LOOP_END; | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
MATRIX_LOOP_END: | |||||
// TODO: FAIL SAFE: clear all key if no key down | |||||
#ifdef MOUSEKEY_ENABLE | |||||
mousekey_send(); | |||||
#endif | |||||
// layer switch when delay term elapses | |||||
if (kbdstate == DELAYING || kbdstate == WAITING) { | |||||
if (timer_elapsed(delayed_fn.time) > 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); | |||||
} | |||||
} | |||||
} | |||||
#ifdef PS2_MOUSE_ENABLE | |||||
// TODO: should comform new API | |||||
if (ps2_mouse_read() == 0) | |||||
ps2_mouse_usb_send(); | |||||
#endif | |||||
// mousekey repeat & acceleration | |||||
mousekey_task(); | |||||
if (last_leds != host_keyboard_leds()) { | |||||
keyboard_set_leds(host_keyboard_leds()); | |||||
last_leds = host_keyboard_leds(); | |||||
} | |||||
return; | |||||
} | } | ||||
void keyboard_set_leds(uint8_t leds) | void keyboard_set_leds(uint8_t leds) |
#ifndef KEYBOARD_H | #ifndef KEYBOARD_H | ||||
#define KEYBOARD_H | #define KEYBOARD_H | ||||
#include <stdbool.h> | |||||
#include <stdint.h> | #include <stdint.h> | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
extern "C" { | extern "C" { | ||||
#endif | #endif | ||||
typedef struct { | |||||
uint8_t row; | |||||
uint8_t col; | |||||
} key_t; | |||||
typedef struct { | |||||
key_t key; | |||||
bool pressed; | |||||
} keyevent_t; | |||||
typedef struct { | |||||
keyevent_t event; | |||||
uint8_t code; | |||||
uint8_t mods; | |||||
uint16_t time; | |||||
} keyrecord_t; | |||||
#define KEYEQ(keya, keyb) (keya.row == keyb.row && keya.col == keyb.col) | |||||
extern uint8_t current_layer; | |||||
extern uint8_t default_layer; | |||||
void keyboard_init(void); | void keyboard_init(void); | ||||
void keyboard_proc(void); | |||||
void keyboard_task(void); | |||||
void keyboard_set_leds(uint8_t leds); | void keyboard_set_leds(uint8_t leds); | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
#endif | #endif |
/* | |||||
Copyright 2011 Jun Wako <[email protected]> | |||||
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 | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "keymap.h" | |||||
#include "host.h" | |||||
#include "debug.h" | |||||
#include "timer.h" | |||||
#include "usb_keycodes.h" | |||||
#include "layer.h" | |||||
/* | |||||
* Parameters: | |||||
* SWITCH_DELAY |=======| | |||||
* SEND_FN_TERM |================| | |||||
* | |||||
* Fn key processing cases: | |||||
* 1. release Fn after SEND_FN_TERM. | |||||
* Layer sw ___________|~~~~~~~~~~~|___ | |||||
* Fn press ___|~~~~~~~~~~~~~~~~~~~|___ | |||||
* Fn send ___________________________ | |||||
* | |||||
* 2. release Fn during SEND_FN_TERM.(not layer used) | |||||
* Layer sw ___________|~~~~~~|________ | |||||
* Fn press ___|~~~~~~~~~~~~~~|________ | |||||
* Fn key send __________________|~|______ | |||||
* other key press ___________________________ | |||||
* other key send ___________________________ | |||||
* | |||||
* 3. release Fn during SEND_FN_TERM.(layer used) | |||||
* Layer sw ___________|~~~~~~|________ | |||||
* Fn press ___|~~~~~~~~~~~~~~|________ | |||||
* Fn key send ___________________________ | |||||
* Fn send ___________________________ | |||||
* other key press _____________|~~|__________ | |||||
* other key send _____________|~~|__________ | |||||
* | |||||
* 4. press other key during SWITCH_DELAY. | |||||
* Layer sw ___________________________ | |||||
* Fn key press ___|~~~~~~~~~|_____________ | |||||
* Fn key send ______|~~~~~~|_____________ | |||||
* other key press ______|~~~|________________ | |||||
* other key send _______|~~|________________ | |||||
* | |||||
* 5. press Fn while press other key. | |||||
* Layer sw ___________________________ | |||||
* Fn key press ___|~~~~~~~~~|_____________ | |||||
* Fn key send ___|~~~~~~~~~|_____________ | |||||
* other key press ~~~~~~~|___________________ | |||||
* other key send ~~~~~~~|___________________ | |||||
* | |||||
* 6. press Fn twice quickly and keep holding down.(repeat) | |||||
* Layer sw ___________________________ | |||||
* Fn key press ___|~|____|~~~~~~~~~~~~~~~~ | |||||
* Fn key send _____|~|__|~~~~~~~~~~~~~~~~ | |||||
*/ | |||||
// LAYER_SWITCH_DELAY: prevent from moving to new layer | |||||
#ifndef LAYER_SWITCH_DELAY | |||||
# define LAYER_SWITCH_DELAY 150 | |||||
#endif | |||||
// LAYER_SEND_FN_TERM: send keycode if release key in this term | |||||
#ifndef LAYER_SEND_FN_TERM | |||||
# define LAYER_SEND_FN_TERM 500 | |||||
#endif | |||||
uint8_t default_layer = 0; | |||||
uint8_t current_layer = 0; | |||||
static bool layer_used = false; | |||||
static uint8_t new_layer(uint8_t fn_bits); | |||||
uint8_t layer_get_keycode(uint8_t row, uint8_t col) | |||||
{ | |||||
uint8_t code = keymap_get_keycode(current_layer, row, col); | |||||
// normal key or mouse key | |||||
if ((IS_KEY(code) || IS_MOUSEKEY(code))) { | |||||
layer_used = true; | |||||
} | |||||
return code; | |||||
} | |||||
// bit substract b from a | |||||
#define BIT_SUBST(a, b) (a&(a^b)) | |||||
void layer_switching(uint8_t fn_bits) | |||||
{ | |||||
// layer switching | |||||
static uint8_t last_fn = 0; | |||||
static uint8_t last_mods = 0; | |||||
static uint16_t last_timer = 0; | |||||
static uint8_t sent_fn = 0; | |||||
if (fn_bits == last_fn) { // Fn state is not changed | |||||
if (fn_bits == 0) { | |||||
// do nothing | |||||
} else { | |||||
if (!keymap_fn_keycode(BIT_SUBST(fn_bits, sent_fn)) || | |||||
timer_elapsed(last_timer) > LAYER_SWITCH_DELAY) { | |||||
uint8_t _layer_to_switch = new_layer(BIT_SUBST(fn_bits, sent_fn)); | |||||
if (current_layer != _layer_to_switch) { // not switch layer yet | |||||
debug("Fn case: 1,2,3(LAYER_SWITCH_DELAY passed)\n"); | |||||
debug("Switch Layer: "); debug_hex(current_layer); | |||||
current_layer = _layer_to_switch; | |||||
layer_used = false; | |||||
debug(" -> "); debug_hex(current_layer); debug("\n"); | |||||
} | |||||
} else { | |||||
if (host_has_anykey()) { // other keys is pressed | |||||
uint8_t _fn_to_send = BIT_SUBST(fn_bits, sent_fn); | |||||
if (_fn_to_send) { | |||||
debug("Fn case: 4(press other key during SWITCH_DELAY.)\n"); | |||||
// send only Fn key first | |||||
uint8_t tmp_mods = keyboard_report->mods; | |||||
host_add_code(keymap_fn_keycode(_fn_to_send)); | |||||
host_set_mods(last_mods); | |||||
host_send_keyboard_report(); | |||||
host_set_mods(tmp_mods); | |||||
host_del_code(keymap_fn_keycode(_fn_to_send)); | |||||
sent_fn |= _fn_to_send; | |||||
} | |||||
} | |||||
} | |||||
// add Fn keys to send | |||||
//host_add_code(keymap_fn_keycode(fn_bits&sent_fn)); // TODO: do all Fn keys | |||||
} | |||||
} else { // Fn state is changed(edge) | |||||
uint8_t fn_changed = 0; | |||||
debug("fn_bits: "); debug_bin(fn_bits); debug("\n"); | |||||
debug("sent_fn: "); debug_bin(sent_fn); debug("\n"); | |||||
debug("last_fn: "); debug_bin(last_fn); debug("\n"); | |||||
debug("last_mods: "); debug_hex(last_mods); debug("\n"); | |||||
debug("last_timer: "); debug_hex16(last_timer); debug("\n"); | |||||
debug("timer_count: "); debug_hex16(timer_count); debug("\n"); | |||||
// pressed Fn | |||||
if ((fn_changed = BIT_SUBST(fn_bits, last_fn))) { | |||||
debug("fn_changed: "); debug_bin(fn_changed); debug("\n"); | |||||
if (host_has_anykey()) { | |||||
debug("Fn case: 5(pressed Fn with other key)\n"); | |||||
sent_fn |= fn_changed; | |||||
} else if (fn_changed & sent_fn) { // pressed same Fn in a row | |||||
if (timer_elapsed(last_timer) > LAYER_SEND_FN_TERM) { | |||||
debug("Fn case: 6(not repeat)\n"); | |||||
// time passed: not repeate | |||||
sent_fn &= ~fn_changed; | |||||
} else { | |||||
debug("Fn case: 6(repeat)\n"); | |||||
} | |||||
} | |||||
} | |||||
// released Fn | |||||
if ((fn_changed = BIT_SUBST(last_fn, fn_bits))) { | |||||
debug("fn_changed: "); debug_bin(fn_changed); debug("\n"); | |||||
if (timer_elapsed(last_timer) < LAYER_SEND_FN_TERM) { | |||||
if (!layer_used && BIT_SUBST(fn_changed, sent_fn)) { | |||||
debug("Fn case: 2(send Fn one shot: released Fn during LAYER_SEND_FN_TERM)\n"); | |||||
// send only Fn key first | |||||
uint8_t tmp_mods = keyboard_report->mods; | |||||
host_add_code(keymap_fn_keycode(fn_changed)); | |||||
host_set_mods(last_mods); | |||||
host_send_keyboard_report(); | |||||
host_set_mods(tmp_mods); | |||||
host_del_code(keymap_fn_keycode(fn_changed)); | |||||
sent_fn |= fn_changed; | |||||
} | |||||
} | |||||
debug("Switch Layer(released Fn): "); debug_hex(current_layer); | |||||
current_layer = new_layer(BIT_SUBST(fn_bits, sent_fn)); | |||||
debug(" -> "); debug_hex(current_layer); debug("\n"); | |||||
} | |||||
layer_used = false; | |||||
last_fn = fn_bits; | |||||
last_mods = keyboard_report->mods; | |||||
last_timer = timer_read(); | |||||
} | |||||
// send Fn keys | |||||
for (uint8_t i = 0; i < 8; i++) { | |||||
if ((sent_fn & fn_bits) & (1<<i)) { | |||||
host_add_code(keymap_fn_keycode(1<<i)); | |||||
} | |||||
} | |||||
} | |||||
inline | |||||
static uint8_t new_layer(uint8_t fn_bits) | |||||
{ | |||||
return (fn_bits ? keymap_fn_layer(fn_bits) : default_layer); | |||||
} |
/* | |||||
Copyright 2011 Jun Wako <[email protected]> | |||||
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 | |||||
the Free Software Foundation, either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef LAYER_H | |||||
#define LAYER_H 1 | |||||
#include <stdint.h> | |||||
extern uint8_t default_layer; | |||||
extern uint8_t current_layer; | |||||
/* return keycode for switch */ | |||||
uint8_t layer_get_keycode(uint8_t row, uint8_t col); | |||||
/* process layer switching */ | |||||
void layer_switching(uint8_t fn_bits); | |||||
#endif |
#ifndef MATRIX_H | #ifndef MATRIX_H | ||||
#define MATRIX_H | #define MATRIX_H | ||||
#include <stdint.h> | |||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#if (MATRIX_COLS <= 8) | |||||
typedef uint8_t matrix_row_t; | |||||
#elif (MATRIX_COLS <= 16) | |||||
typedef uint16_t matrix_row_t; | |||||
#elif (MATRIX_COLS <= 32) | |||||
typedef uint32_t matrix_row_t; | |||||
#else | |||||
#error "MATRIX_COLS: invalid value" | |||||
#endif | |||||
#define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1<<col)) | |||||
/* number of matrix rows */ | /* number of matrix rows */ | ||||
uint8_t matrix_rows(void); | uint8_t matrix_rows(void); | ||||
/* number of matrix columns */ | /* number of matrix columns */ | ||||
/* whether a swtich is on */ | /* whether a swtich is on */ | ||||
bool matrix_is_on(uint8_t row, uint8_t col); | bool matrix_is_on(uint8_t row, uint8_t col); | ||||
/* matrix state on row */ | /* matrix state on row */ | ||||
#if (MATRIX_COLS <= 8) | |||||
uint8_t matrix_get_row(uint8_t row); | |||||
#else | |||||
uint16_t matrix_get_row(uint8_t row); | |||||
#endif | |||||
matrix_row_t matrix_get_row(uint8_t row); | |||||
/* count keys pressed */ | /* count keys pressed */ | ||||
uint8_t matrix_key_count(void); | uint8_t matrix_key_count(void); | ||||
/* print matrix for debug */ | /* print matrix for debug */ |
static report_mouse_t report; | static report_mouse_t report; | ||||
static report_mouse_t report_prev; | |||||
static uint8_t mousekey_repeat = 0; | static uint8_t mousekey_repeat = 0; | ||||
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys | * see wikipedia http://en.wikipedia.org/wiki/Mouse_keys | ||||
*/ | */ | ||||
#ifndef MOUSEKEY_DELAY_TIME | #ifndef MOUSEKEY_DELAY_TIME | ||||
# define MOUSEKEY_DELAY_TIME 255 | |||||
# define MOUSEKEY_DELAY_TIME 20 | |||||
#endif | #endif | ||||
#define MOUSEKEY_MOVE_INIT 5 | |||||
#define MOUSEKEY_WHEEL_INIT 1 | |||||
#define MOUSEKEY_MOVE_ACCEL 5 | |||||
#define MOUSEKEY_WHEEL_ACCEL 1 | |||||
static uint16_t last_timer = 0; | |||||
// acceleration parameters | // acceleration parameters | ||||
uint8_t mousekey_move_unit = 2; | |||||
uint8_t mousekey_resolution = 5; | |||||
//uint8_t mousekey_move_unit = 2; | |||||
//uint8_t mousekey_resolution = 5; | |||||
static inline uint8_t move_unit(void) | static inline uint8_t move_unit(void) | ||||
{ | { | ||||
uint16_t unit = 5 + mousekey_repeat*2; | |||||
uint16_t unit = 5 + mousekey_repeat*4; | |||||
return (unit > 63 ? 63 : unit); | return (unit > 63 ? 63 : unit); | ||||
} | } | ||||
void mousekey_decode(uint8_t code) | |||||
{ | |||||
if (code == KB_MS_UP) report.y = -move_unit(); | |||||
else if (code == KB_MS_DOWN) report.y = move_unit(); | |||||
else if (code == KB_MS_LEFT) report.x = -move_unit(); | |||||
else if (code == KB_MS_RIGHT) report.x = move_unit(); | |||||
else if (code == KB_MS_BTN1) report.buttons |= MOUSE_BTN1; | |||||
else if (code == KB_MS_BTN2) report.buttons |= MOUSE_BTN2; | |||||
else if (code == KB_MS_BTN3) report.buttons |= MOUSE_BTN3; | |||||
else if (code == KB_MS_BTN4) report.buttons |= MOUSE_BTN4; | |||||
else if (code == KB_MS_BTN5) report.buttons |= MOUSE_BTN5; | |||||
else if (code == KB_MS_WH_UP) report.v += move_unit()/4; | |||||
else if (code == KB_MS_WH_DOWN) report.v -= move_unit()/4; | |||||
else if (code == KB_MS_WH_LEFT) report.h -= move_unit()/4; | |||||
else if (code == KB_MS_WH_RIGHT)report.h += move_unit()/4; | |||||
} | |||||
bool mousekey_changed(void) | |||||
{ | |||||
return (report.buttons != report_prev.buttons || | |||||
report.x || report.y || report.v || report.h); | |||||
} | |||||
void mousekey_send(void) | |||||
void mousekey_task(void) | |||||
{ | { | ||||
static uint16_t last_timer = 0; | |||||
if (!mousekey_changed()) { | |||||
mousekey_repeat = 0; | |||||
mousekey_clear_report(); | |||||
if (timer_elapsed(last_timer) < MOUSEKEY_DELAY_TIME) | |||||
return; | return; | ||||
} | |||||
// send immediately when buttun state is changed | |||||
if (report.buttons == report_prev.buttons) { | |||||
if (timer_elapsed(last_timer) < 100) { | |||||
mousekey_clear_report(); | |||||
return; | |||||
} | |||||
} | |||||
if (report.x == 0 && report.y == 0 && report.v == 0 && report.h == 0) | |||||
return; | |||||
if (mousekey_repeat != 0xFF) { | |||||
if (mousekey_repeat != UINT8_MAX) | |||||
mousekey_repeat++; | mousekey_repeat++; | ||||
} | |||||
if (report.x > 0) report.x = move_unit(); | |||||
if (report.x < 0) report.x = move_unit() * -1; | |||||
if (report.y > 0) report.y = move_unit(); | |||||
if (report.y < 0) report.y = move_unit() * -1; | |||||
if (report.x && report.y) { | if (report.x && report.y) { | ||||
report.x *= 0.7; | report.x *= 0.7; | ||||
report.y *= 0.7; | report.y *= 0.7; | ||||
} | } | ||||
if (report.v > 0) report.v = move_unit(); | |||||
if (report.v < 0) report.v = move_unit() * -1; | |||||
if (report.h > 0) report.h = move_unit(); | |||||
if (report.h < 0) report.h = move_unit() * -1; | |||||
mousekey_send(); | |||||
} | |||||
void mousekey_on(uint8_t code) | |||||
{ | |||||
if (code == KB_MS_UP) report.y = MOUSEKEY_MOVE_INIT * -1; | |||||
else if (code == KB_MS_DOWN) report.y = MOUSEKEY_MOVE_INIT; | |||||
else if (code == KB_MS_LEFT) report.x = MOUSEKEY_MOVE_INIT * -1; | |||||
else if (code == KB_MS_RIGHT) report.x = MOUSEKEY_MOVE_INIT; | |||||
else if (code == KB_MS_WH_UP) report.v = MOUSEKEY_WHEEL_INIT; | |||||
else if (code == KB_MS_WH_DOWN) report.v = MOUSEKEY_WHEEL_INIT * -1; | |||||
else if (code == KB_MS_WH_LEFT) report.h = MOUSEKEY_WHEEL_INIT * -1; | |||||
else if (code == KB_MS_WH_RIGHT) report.h = MOUSEKEY_WHEEL_INIT; | |||||
else if (code == KB_MS_BTN1) report.buttons |= MOUSE_BTN1; | |||||
else if (code == KB_MS_BTN2) report.buttons |= MOUSE_BTN2; | |||||
else if (code == KB_MS_BTN3) report.buttons |= MOUSE_BTN3; | |||||
else if (code == KB_MS_BTN4) report.buttons |= MOUSE_BTN4; | |||||
else if (code == KB_MS_BTN5) report.buttons |= MOUSE_BTN5; | |||||
} | |||||
void mousekey_off(uint8_t code) | |||||
{ | |||||
if (code == KB_MS_UP && report.y < 0) report.y = 0; | |||||
else if (code == KB_MS_DOWN && report.y > 0) report.y = 0; | |||||
else if (code == KB_MS_LEFT && report.x < 0) report.x = 0; | |||||
else if (code == KB_MS_RIGHT && report.x > 0) report.x = 0; | |||||
else if (code == KB_MS_WH_UP && report.v > 0) report.v = 0; | |||||
else if (code == KB_MS_WH_DOWN && report.v < 0) report.v = 0; | |||||
else if (code == KB_MS_WH_LEFT && report.h < 0) report.h = 0; | |||||
else if (code == KB_MS_WH_RIGHT && report.h > 0) report.h = 0; | |||||
else if (code == KB_MS_BTN1) report.buttons &= ~MOUSE_BTN1; | |||||
else if (code == KB_MS_BTN2) report.buttons &= ~MOUSE_BTN2; | |||||
else if (code == KB_MS_BTN3) report.buttons &= ~MOUSE_BTN3; | |||||
else if (code == KB_MS_BTN4) report.buttons &= ~MOUSE_BTN4; | |||||
else if (code == KB_MS_BTN5) report.buttons &= ~MOUSE_BTN5; | |||||
if (report.x == 0 && report.y == 0 && report.v == 0 && report.h == 0) | |||||
mousekey_repeat = 0; | |||||
} | |||||
void mousekey_send(void) | |||||
{ | |||||
mousekey_debug(); | mousekey_debug(); | ||||
host_mouse_send(&report); | host_mouse_send(&report); | ||||
report_prev = report; | |||||
last_timer = timer_read(); | last_timer = timer_read(); | ||||
mousekey_clear_report(); | |||||
} | } | ||||
void mousekey_clear_report(void) | |||||
void mousekey_clear(void) | |||||
{ | { | ||||
report = (report_mouse_t){}; | |||||
/* | |||||
report.buttons = 0; | report.buttons = 0; | ||||
report.x = 0; | report.x = 0; | ||||
report.y = 0; | report.y = 0; | ||||
report.v = 0; | report.v = 0; | ||||
report.h = 0; | report.h = 0; | ||||
*/ | |||||
} | } | ||||
static void mousekey_debug(void) | static void mousekey_debug(void) |
#include <stdbool.h> | #include <stdbool.h> | ||||
#include "host.h" | #include "host.h" | ||||
void mousekey_decode(uint8_t code); | |||||
bool mousekey_changed(void); | |||||
void mousekey_task(void); | |||||
void mousekey_on(uint8_t code); | |||||
void mousekey_off(uint8_t code); | |||||
void mousekey_clear(void); | |||||
void mousekey_send(void); | void mousekey_send(void); | ||||
void mousekey_clear_report(void); | |||||
#endif | #endif |
// counter resolution 1ms | // counter resolution 1ms | ||||
// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }} | |||||
volatile uint32_t timer_count = 0; | volatile uint32_t timer_count = 0; | ||||
void timer_init(void) | void timer_init(void) |
#define IS_MOUSEKEY_BUTTON(code) (KB_MS_BTN1 <= (code) && (code) <= KB_MS_BTN5) | #define IS_MOUSEKEY_BUTTON(code) (KB_MS_BTN1 <= (code) && (code) <= KB_MS_BTN5) | ||||
#define IS_MOUSEKEY_WHEEL(code) (KB_MS_WH_UP <= (code) && (code) <= KB_MS_WH_RIGHT) | #define IS_MOUSEKEY_WHEEL(code) (KB_MS_WH_UP <= (code) && (code) <= KB_MS_WH_RIGHT) | ||||
#define MOD_BIT(code) (1<<((code) & 0x07)) | |||||
#define FN_BIT(code) (1<<((code) - KB_FN0)) | |||||
#define MOD_BIT(code) (1<<((code) & 0x07)) | |||||
#define FN_BIT(code) (1<<((code) - KB_FN0)) | |||||
#define FN_INDEX(code) ((code) - KB_FN0) | |||||
/* Short names */ | /* Short names */ |
#include "util.h" | #include "util.h" | ||||
// bit population | |||||
int bitpop(uint8_t bits) | |||||
// bit population - return number of on-bit | |||||
uint8_t bitpop(uint8_t bits) | |||||
{ | { | ||||
int c; | |||||
uint8_t c; | |||||
for (c = 0; bits; c++) | for (c = 0; bits; c++) | ||||
bits &= bits -1; | bits &= bits -1; | ||||
return c; | return c; | ||||
/* | |||||
const uint8_t bit_count[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; | |||||
return bit_count[bits>>4] + bit_count[bits&0x0F] | |||||
*/ | |||||
} | } | ||||
// most significant on-bit | |||||
int biton(uint8_t bits) | |||||
// most significant on-bit - return highest location of on-bit | |||||
uint8_t biton(uint8_t bits) | |||||
{ | { | ||||
int n = 0; | |||||
uint8_t n = 0; | |||||
if (bits >> 4) { bits >>= 4; n += 4;} | if (bits >> 4) { bits >>= 4; n += 4;} | ||||
if (bits >> 2) { bits >>= 2; n += 2;} | if (bits >> 2) { bits >>= 2; n += 2;} | ||||
if (bits >> 1) { bits >>= 1; n += 1;} | if (bits >> 1) { bits >>= 1; n += 1;} |
#define XSTR(s) #s | #define XSTR(s) #s | ||||
int bitpop(uint8_t bits); | |||||
int biton(uint8_t bits); | |||||
uint8_t bitpop(uint8_t bits); | |||||
uint8_t biton(uint8_t bits); | |||||
#endif | #endif |
/* matrix size */ | /* matrix size */ | ||||
#define MATRIX_ROWS 8 | #define MATRIX_ROWS 8 | ||||
#define MATRIX_COLS 8 | #define MATRIX_COLS 8 | ||||
/* define if matrix has ghost */ | |||||
//#define MATRIX_HAS_GHOST | |||||
/* key combination for command */ | /* key combination for command */ |
return KEYCODE(layer, row, col); | return KEYCODE(layer, row, col); | ||||
} | } | ||||
uint8_t keymap_fn_layer(uint8_t fn_bits) | |||||
uint8_t keymap_fn_layer(uint8_t index) | |||||
{ | { | ||||
return pgm_read_byte(&fn_layer[biton(fn_bits)]); | |||||
return pgm_read_byte(&fn_layer[index]); | |||||
} | } | ||||
uint8_t keymap_fn_keycode(uint8_t fn_bits) | |||||
uint8_t keymap_fn_keycode(uint8_t index) | |||||
{ | { | ||||
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]); | |||||
return pgm_read_byte(&fn_keycode[index]); | |||||
} | } |
// matrix state buffer(1:on, 0:off) | // matrix state buffer(1:on, 0:off) | ||||
#if (MATRIX_COLS <= 8) | |||||
static uint8_t *matrix; | |||||
static uint8_t *matrix_prev; | |||||
static uint8_t _matrix0[MATRIX_ROWS]; | |||||
static uint8_t _matrix1[MATRIX_ROWS]; | |||||
#else | |||||
static uint16_t *matrix; | |||||
static uint16_t *matrix_prev; | |||||
static uint16_t _matrix0[MATRIX_ROWS]; | |||||
static uint16_t _matrix1[MATRIX_ROWS]; | |||||
#endif | |||||
// HHKB has no ghost and no bounce. | |||||
#ifdef MATRIX_HAS_GHOST | |||||
static bool matrix_has_ghost_in_row(uint8_t row); | |||||
#endif | |||||
static matrix_row_t *matrix; | |||||
static matrix_row_t *matrix_prev; | |||||
static matrix_row_t _matrix0[MATRIX_ROWS]; | |||||
static matrix_row_t _matrix1[MATRIX_ROWS]; | |||||
// Matrix I/O ports | // Matrix I/O ports | ||||
} | } | ||||
// Ignore if this code region execution time elapses more than 20us. | // Ignore if this code region execution time elapses more than 20us. | ||||
// MEMO: 20[us] * (TIMER_RAW_FREQ / 1000000)[count per us] | |||||
// MEMO: then change above using this rule: a/(b/c) = a*1/(b/c) = a*(c/b) | |||||
if (TIMER_DIFF_RAW(TIMER_RAW, last) > 20/(1000000/TIMER_RAW_FREQ)) { | if (TIMER_DIFF_RAW(TIMER_RAW, last) > 20/(1000000/TIMER_RAW_FREQ)) { | ||||
matrix[row] = matrix_prev[row]; | matrix[row] = matrix_prev[row]; | ||||
} | } | ||||
inline | inline | ||||
bool matrix_has_ghost(void) | bool matrix_has_ghost(void) | ||||
{ | { | ||||
#ifdef MATRIX_HAS_GHOST | |||||
for (uint8_t i = 0; i < MATRIX_ROWS; i++) { | |||||
if (matrix_has_ghost_in_row(i)) | |||||
return true; | |||||
} | |||||
#endif | |||||
return false; | return false; | ||||
} | } | ||||
pbin_reverse(matrix_get_row(row)); | pbin_reverse(matrix_get_row(row)); | ||||
#else | #else | ||||
pbin_reverse16(matrix_get_row(row)); | pbin_reverse16(matrix_get_row(row)); | ||||
#endif | |||||
#ifdef MATRIX_HAS_GHOST | |||||
if (matrix_has_ghost_in_row(row)) { | |||||
print(" <ghost"); | |||||
} | |||||
#endif | #endif | ||||
print("\n"); | print("\n"); | ||||
} | } | ||||
} | } | ||||
return count; | return count; | ||||
} | } | ||||
#ifdef MATRIX_HAS_GHOST | |||||
inline | |||||
static bool matrix_has_ghost_in_row(uint8_t row) | |||||
{ | |||||
// no ghost exists in case less than 2 keys on | |||||
if (((matrix[row] - 1) & matrix[row]) == 0) | |||||
return false; | |||||
// ghost exists in case same state as other row | |||||
for (uint8_t i=0; i < MATRIX_ROWS; i++) { | |||||
if (i != row && (matrix[i] & matrix[row]) == matrix[row]) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
#endif |
keyboard_init(); | keyboard_init(); | ||||
host_set_driver(&lufa_driver); | host_set_driver(&lufa_driver); | ||||
while (1) { | while (1) { | ||||
keyboard_proc(); | |||||
keyboard_task(); | |||||
#if !defined(INTERRUPT_CONTROL_ENDPOINT) | #if !defined(INTERRUPT_CONTROL_ENDPOINT) | ||||
USB_USBTask(); | USB_USBTask(); |