SRC += $(COMMON_DIR)/host.c \
$(COMMON_DIR)/keyboard.c \
$(COMMON_DIR)/command.c \
- $(COMMON_DIR)/layer.c \
$(COMMON_DIR)/timer.c \
$(COMMON_DIR)/print.c \
$(COMMON_DIR)/debug.c \
#include "debug.h"
#include "util.h"
#include "timer.h"
-#include "layer.h"
+#include "keyboard.h"
#include "matrix.h"
#include "bootloader.h"
#include "command.h"
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 */
void host_add_key(uint8_t key)
{
{
if (!driver) return;
(*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)
for (; i < REPORT_KEYS; i++) {
if (keyboard_report->keys[i] == code) {
keyboard_report->keys[i] = 0;
- break;
}
}
}
host_driver_t *host_get_driver(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 */
void host_add_key(uint8_t key);
void host_del_key(uint8_t key);
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "keyboard.h"
-#include "host.h"
-#include "layer.h"
#include "matrix.h"
+#include "keymap.h"
+#include "host.h"
#include "led.h"
#include "usb_keycodes.h"
#include "timer.h"
#include "print.h"
#include "debug.h"
#include "command.h"
+#include "util.h"
#ifdef MOUSEKEY_ENABLE
#include "mousekey.h"
#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()) {
+ 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();
- // 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)
#ifndef KEYBOARD_H
#define KEYBOARD_H
+#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#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_proc(void);
+void keyboard_task(void);
void keyboard_set_leds(uint8_t leds);
+
#ifdef __cplusplus
}
#endif
+++ /dev/null
-/*
-Copyright 2011 Jun Wako <wakojun@gmail.com>
-
-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);
-}
+++ /dev/null
-/*
-Copyright 2011 Jun Wako <wakojun@gmail.com>
-
-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
#define MATRIX_H
+#include <stdint.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 */
uint8_t matrix_rows(void);
/* number of matrix columns */
/* whether a swtich is on */
bool matrix_is_on(uint8_t row, uint8_t col);
/* 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 */
uint8_t matrix_key_count(void);
/* print matrix for debug */
static report_mouse_t report;
-static report_mouse_t report_prev;
static uint8_t mousekey_repeat = 0;
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys
*/
#ifndef MOUSEKEY_DELAY_TIME
-# define MOUSEKEY_DELAY_TIME 255
+# define MOUSEKEY_DELAY_TIME 20
#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
-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)
{
- uint16_t unit = 5 + mousekey_repeat*2;
+ uint16_t unit = 5 + mousekey_repeat*4;
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;
- }
- // 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++;
- }
+
+
+ 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) {
report.x *= 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();
host_mouse_send(&report);
- report_prev = report;
last_timer = timer_read();
- mousekey_clear_report();
}
-void mousekey_clear_report(void)
+void mousekey_clear(void)
{
+ report = (report_mouse_t){};
+/*
report.buttons = 0;
report.x = 0;
report.y = 0;
report.v = 0;
report.h = 0;
+*/
}
static void mousekey_debug(void)
#include <stdbool.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_clear_report(void);
#endif
// counter resolution 1ms
+// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
volatile uint32_t timer_count = 0;
void timer_init(void)
#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 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 */
#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++)
bits &= bits -1;
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 >> 2) { bits >>= 2; n += 2;}
if (bits >> 1) { bits >>= 1; n += 1;}
#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
/* matrix size */
#define MATRIX_ROWS 8
#define MATRIX_COLS 8
-/* define if matrix has ghost */
-//#define MATRIX_HAS_GHOST
/* key combination for command */
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)
-#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
}
// 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)) {
matrix[row] = matrix_prev[row];
}
inline
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;
}
pbin_reverse(matrix_get_row(row));
#else
pbin_reverse16(matrix_get_row(row));
-#endif
-#ifdef MATRIX_HAS_GHOST
- if (matrix_has_ghost_in_row(row)) {
- print(" <ghost");
- }
#endif
print("\n");
}
}
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();
host_set_driver(&lufa_driver);
while (1) {
- keyboard_proc();
+ keyboard_task();
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();