1
0
Fork 0

Initial version of new code for layer switch is added.

This commit is contained in:
tmk 2012-10-06 02:23:12 +09:00
parent 93e33fb8f6
commit 4ae979f6ef
19 changed files with 592 additions and 495 deletions

View file

@ -2,7 +2,6 @@ COMMON_DIR = common
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 \

View file

@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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"

View file

@ -56,6 +56,19 @@ uint8_t host_keyboard_leds(void)
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)
{ {
@ -158,6 +171,14 @@ void host_send_keyboard_report(void)
{ {
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)
@ -216,7 +237,6 @@ static inline void del_key_byte(uint8_t code)
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;
} }
} }
} }

View file

@ -39,6 +39,10 @@ void host_set_driver(host_driver_t *driver);
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);

557
common/keyboard.c Normal file → Executable file
View file

@ -15,15 +15,16 @@ You should have received a copy of the GNU General Public License
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
@ -32,11 +33,377 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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;
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 ? MOUSEKEY_DOWN : MOUSEKEY_UP);
return NONE;
}
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");
}
}
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");
}
}
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;
}
}
}
}
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;
}
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;
}
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;
}
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;
}
// TODO: FAIL SAFE: unregister all keys when no key down
}
void keyboard_init(void) void keyboard_init(void)
{ {
debug_keyboard = true;
timer_init(); timer_init();
matrix_init(); matrix_init();
#ifdef PS2_MOUSE_ENABLE #ifdef PS2_MOUSE_ENABLE
@ -44,150 +411,66 @@ void keyboard_init(void)
#endif #endif
} }
void keyboard_proc(void) void keyboard_task(void)
{ {
uint8_t fn_bits = 0; static matrix_row_t matrix_prev[MATRIX_ROWS];
#ifdef EXTRAKEY_ENABLE matrix_row_t matrix_row = 0;
uint16_t consumer_code = 0; matrix_row_t matrix_change = 0;
uint16_t system_code = 0;
#endif
matrix_scan(); matrix_scan();
if (matrix_is_modified()) {
if (debug_matrix) matrix_print();
#ifdef DEBUG_LED
// LED flash for debug
DEBUG_LED_CONFIG;
DEBUG_LED_ON;
#endif
}
if (matrix_has_ghost()) {
// should send error?
debug("matrix has ghost!!\n");
return;
}
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();
}
#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;
}
#endif
else if (IS_KEY(code)) {
host_add_key(code);
}
#ifdef MOUSEKEY_ENABLE
else if (IS_MOUSEKEY(code)) {
mousekey_decode(code);
}
#endif
else {
debug("ignore keycode: "); debug_hex(code); debug("\n");
}
}
}
layer_switching(fn_bits);
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 for (int c = 0; c < MATRIX_COLS; c++) {
if (matrix_is_modified()) { if (matrix_change & (1<<c)) {
host_send_keyboard_report(); process_key((keyevent_t){
#ifdef EXTRAKEY_ENABLE .key = (key_t){ .row = r, .col = c },
host_consumer_send(consumer_code); .pressed = (matrix_row & (1<<c))
host_system_send(system_code); });
#endif // record a processed key
#ifdef DEBUG_LED matrix_prev[r] ^= (1<<c);
// LED flash for debug // process a key per task call
DEBUG_LED_CONFIG; goto MATRIX_LOOP_END;
DEBUG_LED_OFF; }
#endif }
}
}
MATRIX_LOOP_END:
// TODO: FAIL SAFE: clear all key if no key down
// 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 MOUSEKEY_ENABLE // mousekey repeat & acceleration
mousekey_send(); mousekey_task();
#endif
#ifdef PS2_MOUSE_ENABLE return;
// TODO: should comform new API
if (ps2_mouse_read() == 0)
ps2_mouse_usb_send();
#endif
if (last_leds != host_keyboard_leds()) {
keyboard_set_leds(host_keyboard_leds());
last_leds = host_keyboard_leds();
}
} }
void keyboard_set_leds(uint8_t leds) void keyboard_set_leds(uint8_t leds)

28
common/keyboard.h Normal file → Executable file
View file

@ -18,15 +18,41 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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

View file

@ -1,207 +0,0 @@
/*
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);
}

View file

@ -1,32 +0,0 @@
/*
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

View file

@ -18,8 +18,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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 */
@ -35,11 +50,7 @@ bool matrix_has_ghost(void);
/* 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) matrix_row_t matrix_get_row(uint8_t row);
uint8_t matrix_get_row(uint8_t row);
#else
uint16_t matrix_get_row(uint8_t row);
#endif
/* 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 */

View file

@ -26,7 +26,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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;
@ -38,84 +37,111 @@ static void mousekey_debug(void);
* 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_move_unit = 2;
uint8_t mousekey_resolution = 5; //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) void mousekey_task(void)
{ {
if (code == KB_MS_UP) report.y = -move_unit(); if (timer_elapsed(last_timer) < MOUSEKEY_DELAY_TIME)
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)
{
static uint16_t last_timer = 0;
if (!mousekey_changed()) {
mousekey_repeat = 0;
mousekey_clear_report();
return; return;
}
// send immediately when buttun state is changed if (report.x == 0 && report.y == 0 && report.v == 0 && report.h == 0)
if (report.buttons == report_prev.buttons) {
if (timer_elapsed(last_timer) < 100) {
mousekey_clear_report();
return; 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;
} }
mousekey_debug(); if (report.v > 0) report.v = move_unit();
host_mouse_send(&report); if (report.v < 0) report.v = move_unit() * -1;
report_prev = report; if (report.h > 0) report.h = move_unit();
last_timer = timer_read(); if (report.h < 0) report.h = move_unit() * -1;
mousekey_clear_report();
mousekey_send();
} }
void mousekey_clear_report(void) 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);
last_timer = timer_read();
}
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)

View file

@ -21,9 +21,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdbool.h> #include <stdbool.h>
#include "host.h" #include "host.h"
void mousekey_decode(uint8_t code); void mousekey_task(void);
bool mousekey_changed(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

View file

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// 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)

View file

@ -35,6 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MOD_BIT(code) (1<<((code) & 0x07)) #define MOD_BIT(code) (1<<((code) & 0x07))
#define FN_BIT(code) (1<<((code) - KB_FN0)) #define FN_BIT(code) (1<<((code) - KB_FN0))
#define FN_INDEX(code) ((code) - KB_FN0)
/* Short names */ /* Short names */

View file

@ -17,19 +17,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "util.h" #include "util.h"
// bit population // bit population - return number of on-bit
int bitpop(uint8_t bits) 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 // most significant on-bit - return highest location of on-bit
int biton(uint8_t bits) 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;}

View file

@ -28,7 +28,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define XSTR(s) #s #define XSTR(s) #s
int bitpop(uint8_t bits); uint8_t bitpop(uint8_t bits);
int biton(uint8_t bits); uint8_t biton(uint8_t bits);
#endif #endif

View file

@ -35,8 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* 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 */

View file

@ -210,12 +210,12 @@ uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
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]);
} }

View file

@ -43,22 +43,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// matrix state buffer(1:on, 0:off) // matrix state buffer(1:on, 0:off)
#if (MATRIX_COLS <= 8) static matrix_row_t *matrix;
static uint8_t *matrix; static matrix_row_t *matrix_prev;
static uint8_t *matrix_prev; static matrix_row_t _matrix0[MATRIX_ROWS];
static uint8_t _matrix0[MATRIX_ROWS]; static matrix_row_t _matrix1[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
// Matrix I/O ports // Matrix I/O ports
@ -192,6 +180,8 @@ uint8_t matrix_scan(void)
} }
// 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];
} }
@ -219,12 +209,6 @@ bool matrix_is_modified(void)
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;
} }
@ -257,11 +241,6 @@ void matrix_print(void)
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");
} }
@ -279,20 +258,3 @@ uint8_t matrix_key_count(void)
} }
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

View file

@ -475,7 +475,7 @@ int main(void)
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();