~ruther/qmk_firmware

4ae979f6ef8dbf9e1d1f35be15322ad6d02e2958 — tmk 12 years ago 93e33fb
Initial version of new code for layer switch is added.
19 files changed, 586 insertions(+), 489 deletions(-)

M common.mk
M common/command.c
M common/host.c
M common/host.h
M common/keyboard.c -rw-r--r-- => -rwxr-xr-x
M common/keyboard.h -rw-r--r-- => -rwxr-xr-x
D common/layer.c
D common/layer.h
M common/matrix.h
M common/mousekey.c
M common/mousekey.h
M common/timer.c
M common/usb_keycodes.h
M common/util.c
M common/util.h
M keyboard/hhkb/config.h
M keyboard/hhkb/keymap.c
M keyboard/hhkb/matrix.c
M protocol/lufa/lufa.c
M common.mk => common.mk +0 -1
@@ 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 \

M common/command.c => common/command.c +1 -1
@@ 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"

M common/host.c => common/host.c +21 -1
@@ 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;
        }
    }
}

M common/host.h => common/host.h +4 -0
@@ 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);

M common/keyboard.c => common/keyboard.c +413 -130
@@ 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)

M common/keyboard.h => common/keyboard.h +27 -1
@@ 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

D common/layer.c => common/layer.c +0 -207
@@ 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);
}

D common/layer.h => common/layer.h +0 -32
@@ 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

M common/matrix.h => common/matrix.h +16 -5
@@ 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 */

M common/mousekey.c => common/mousekey.c +73 -47
@@ 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)

M common/mousekey.h => common/mousekey.h +4 -3
@@ 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

M common/timer.c => common/timer.c +1 -0
@@ 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)

M common/usb_keycodes.h => common/usb_keycodes.h +3 -2
@@ 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 */

M common/util.c => common/util.c +10 -6
@@ 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;}

M common/util.h => common/util.h +2 -2
@@ 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

M keyboard/hhkb/config.h => keyboard/hhkb/config.h +0 -2
@@ 35,8 35,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
/* matrix size */
#define MATRIX_ROWS 8
#define MATRIX_COLS 8
/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST


/* key combination for command */

M keyboard/hhkb/keymap.c => keyboard/hhkb/keymap.c +4 -4
@@ 210,12 210,12 @@ uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t 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]);
}

M keyboard/hhkb/matrix.c => keyboard/hhkb/matrix.c +6 -44
@@ 43,22 43,10 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.


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


@@ 192,6 180,8 @@ uint8_t matrix_scan(void)
            }

            // 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];
            }


@@ 219,12 209,6 @@ bool matrix_is_modified(void)
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;
}



@@ 258,11 242,6 @@ void matrix_print(void)
#else
        pbin_reverse16(matrix_get_row(row));
#endif
#ifdef MATRIX_HAS_GHOST
        if (matrix_has_ghost_in_row(row)) {
            print(" <ghost");
        }
#endif
        print("\n");
    }
}


@@ 279,20 258,3 @@ uint8_t matrix_key_count(void)
    }
    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

M protocol/lufa/lufa.c => protocol/lufa/lufa.c +1 -1
@@ 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();