Quellcode durchsuchen

Initial version of new code for layer switch is added.

core
tmk vor 11 Jahren
Ursprung
Commit
4edc5ab99c
16 geänderte Dateien mit 576 neuen und 439 gelöschten Zeilen
  1. 0
    1
      common.mk
  2. 1
    1
      common/command.c
  3. 21
    1
      common/host.c
  4. 4
    0
      common/host.h
  5. 413
    130
      common/keyboard.c
  6. 27
    1
      common/keyboard.h
  7. 0
    207
      common/layer.c
  8. 0
    32
      common/layer.h
  9. 16
    5
      common/matrix.h
  10. 73
    47
      common/mousekey.c
  11. 4
    3
      common/mousekey.h
  12. 1
    0
      common/timer.c
  13. 3
    2
      common/usb_keycodes.h
  14. 10
    6
      common/util.c
  15. 2
    2
      common/util.h
  16. 1
    1
      protocol/lufa/lufa.c

+ 0
- 1
common.mk Datei anzeigen

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

+ 1
- 1
common/command.c Datei anzeigen

@@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "debug.h"
#include "util.h"
#include "timer.h"
#include "layer.h"
#include "keyboard.h"
#include "matrix.h"
#include "bootloader.h"
#include "command.h"

+ 21
- 1
common/host.c Datei anzeigen

@@ -56,6 +56,19 @@ uint8_t host_keyboard_leds(void)
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)
{
@@ -158,6 +171,14 @@ void host_send_keyboard_report(void)
{
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)
@@ -216,7 +237,6 @@ static inline void del_key_byte(uint8_t code)
for (; i < REPORT_KEYS; i++) {
if (keyboard_report->keys[i] == code) {
keyboard_report->keys[i] = 0;
break;
}
}
}

+ 4
- 0
common/host.h Datei anzeigen

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

+ 413
- 130
common/keyboard.c Datei anzeigen

@@ -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/>.
*/
#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
@@ -32,162 +33,444 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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)

+ 27
- 1
common/keyboard.h Datei anzeigen

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

+ 0
- 207
common/layer.c Datei anzeigen

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

+ 0
- 32
common/layer.h Datei anzeigen

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

+ 16
- 5
common/matrix.h Datei anzeigen

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

+ 73
- 47
common/mousekey.c Datei anzeigen

@@ -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_prev;

static uint8_t mousekey_repeat = 0;

@@ -38,84 +37,111 @@ static void mousekey_debug(void);
* 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)

+ 4
- 3
common/mousekey.h Datei anzeigen

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

+ 1
- 0
common/timer.c Datei anzeigen

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


// 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)

+ 3
- 2
common/usb_keycodes.h Datei anzeigen

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

+ 10
- 6
common/util.c Datei anzeigen

@@ -17,19 +17,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.

#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;}

+ 2
- 2
common/util.h Datei anzeigen

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

+ 1
- 1
protocol/lufa/lufa.c Datei anzeigen

@@ -475,7 +475,7 @@ int main(void)
keyboard_init();
host_set_driver(&lufa_driver);
while (1) {
keyboard_proc();
keyboard_task();

#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();