~ruther/qmk_firmware

8a709c2750eab09ec0f83450410a13640931d48e — tmk 12 years ago 77f1579
Add initial fix for new keymap.
M common.mk => common.mk +1 -0
@@ 1,6 1,7 @@
COMMON_DIR = common
SRC +=	$(COMMON_DIR)/host.c \
	$(COMMON_DIR)/keyboard.c \
	$(COMMON_DIR)/action.c \
	$(COMMON_DIR)/command.c \
	$(COMMON_DIR)/timer.c \
	$(COMMON_DIR)/print.c \

A common/action.c => common/action.c +572 -0
@@ 0,0 1,572 @@
#include "host.h"
#include "timer.h"
//#include "keymap.h"
#include "keycode.h"
#include "keyboard.h"
#include "mousekey.h"
#include "command.h"
#include "util.h"
#include "debug.h"
#include "action.h"

#define Kdebug(s)       do { if (debug_keyboard) debug(s); } while(0)
#define Kdebug_P(s)     do { if (debug_keyboard) debug_P(s); } while(0)
#define Kdebug_hex(s)   do { if (debug_keyboard) debug_hex(s); } while(0)


/*
 *
 * Event/State|IDLE          PRESSING      DELAYING[f]      WAITING[f,k]         
 * -----------+------------------------------------------------------------------
 * Fn  Down   |(L+)          -*1           WAITING(Sk)      IDLE(Rf,Ps)*7        
 *     Up     |(L-)          IDLE(L-)*8    IDLE(L-)*8       IDLE(L-)*8           
 * Fnk Down   |DELAYING(Sf)* (Rf)          WAITING(Sk)      IDLE(Rf,Ps,Rf)       
 *     Up     |(L-)          IDLE(L-/Uf)*8 IDLE(Rf,Uf/L-)*3 IDLE(Rf,Ps,Uf/L-)*3  
 * Key Down   |PRESSING(Rk)  (Rk)          WAITING(Sk)      IDLE(Rf,Ps,Rk)       
 *     Up     |(Uk)          IDLE(Uk)*4    (Uk)             IDLE(L+,Ps,Pk)/(Uk)*a
 *            |
 * Delay      |-             -             IDLE(L+)         IDLE(L+,Ps)          
 * Magic Key  |COMMAND*5
 *
 * *1: ignore Fn if other key is down.
 * *2: register Fnk if any key is pressing
 * *3: register/unregister delayed Fnk and move to IDLE if code == delayed Fnk, else *8
 * *4: if no keys registered to host
 * *5: unregister all keys
 * *6: only if no keys down
 * *7: ignore Fn because Fnk key and stored key are down.
 * *8: move to IDLE if layer switch(off) occurs, else stay at current state
 * *9: repeat key if pressing Fnk twice quickly(move to PRESSING)
 * *a: layer switch and process waiting key and code if code == wainting key, else unregister key
 *
 * States:
 *      IDLE: No key is down except modifiers
 *      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
 *      Delay: layer switch delay term is elapsed
 *
 * Actions:
 *      Rk: register key
 *      Uk: unregister key
 *      Rf: register Fn(alt keycode)
 *      Uf: unregister Fn(alt keycode)
 *      Rs: register stored key
 *      Us: unregister stored key
 *      Sk: Store key(waiting Key)
 *      Sf: Store Fn(delayed Fn)
 *      Ps: Process stored key
 *      Ps: Process key
 *      Is: Interpret stored keys in current layer
 *      L+: Switch to new layer(*unregister* all keys but modifiers)
 *      L-: Switch back to last layer(*unregister* all keys but modifiers)
 *      Ld: Switch back to default layer(*unregister* all keys but modifiers)
 */


typedef enum { IDLE, DELAYING, WAITING, PRESSING } kbdstate_t;
#define NEXT(state)     do { \
    Kdebug("NEXT: "); Kdebug_P(state_str(kbdstate)); \
    kbdstate = state; \
    Kdebug(" -> "); Kdebug_P(state_str(kbdstate)); Kdebug("\n"); \
} while (0)


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 bool anykey_sent_to_host(void)
{
    return (host_has_anykey() || host_mouse_in_use() ||
            host_last_sysytem_report() || host_last_consumer_report());
}



/*
static void layer_switch_on(uint8_t code);
static void layer_switch_off(uint8_t code);
static void key_action(uint8_t code, keyevent_t event);
static void key_pressed(uint8_t code, keyevent_t event);
static void key_released(uint8_t code, keyevent_t event);
static void mod_pressed(uint8_t code, keyevent_t event);
static void mod_released(uint8_t code, keyevent_t event);
*/

static void register_code(uint8_t code);
static void unregister_code(uint8_t code);
static void register_mods(uint8_t mods);
static void unregister_mods(uint8_t mods);
static void clear_keyboard(void);
static void clear_keyboard_but_mods(void);
static void layer_switch(uint8_t new_layer);


/* tap */
#define TAP_TIME    200
static keyevent_t last_event = {};
static uint16_t last_event_time = 0;
static uint8_t tap_count = 0;

/* layer */
uint8_t default_layer = 0;
uint8_t current_layer = 0;
uint8_t waiting_layer = 0;


void action_exec(action_t action, keyevent_t event)
{
    /* count tap when key is up */
    if (KEYEQ(event.key, last_event.key) && timer_elapsed(last_event_time) < TAP_TIME) {
        if (!event.pressed) tap_count++;
    } else {
        tap_count = 0;
    }

    debug("action: "); debug_hex16(action.code); debug("\n");
    debug("kind.id: "); debug_hex(action.kind.id); debug("\n");
    debug("kind.param: "); debug_hex16(action.kind.param); debug("\n");
    debug("key.code: "); debug_hex(action.key.code); debug("\n");
    debug("key.mods: "); debug_hex(action.key.mods); debug("\n");

    switch (action.kind.id) {
        case ACT_LMODS:
            if (event.pressed) {
                register_mods(action.key.mods);
                register_code(action.key.code);
            } else {
                unregister_code(action.key.code);
                unregister_mods(action.key.mods);
            }
            break;
        case ACT_RMODS:
            if (event.pressed) {
                register_mods(action.key.mods<<4);
                register_code(action.key.code);
            } else {
                unregister_code(action.key.code);
                unregister_mods(action.key.mods<<4);
            }
            break;
        case ACT_LAYER:
            switch (action.layer_key.code) {
                case 0x00:  // Momentary switch
                    // TODO: history of layer switch
                    if (event.pressed) {
                        layer_switch(action.layer_key.layer);
                    } else {
                        layer_switch(default_layer);
                    }
                    break;
                case 0x01:  // Oneshot switch
                    // TODO:
                    break;
                case 0x02:  // reserved
                case 0x03:  // reserved
                    break;
                case 0xF0 ... 0xF7: // Tap to enable/disable
                case 0xF8 ... 0xFF: // Tap to toggle layer
                    // TODO:
                    break;
                default:    // with keycode for tap
                    debug("tap: "); debug_hex(tap_count); debug("\n");
                    // TODO: layer switch
                    // TODO: in case tap is interrupted by other key

                    
                    if (event.pressed) {
                        // when any key down
                        if (host_has_anykey()) {
                            if (tap_count == 0)
                            register_code(action.layer_key.code);
                        } else {
                        }

                        if (tap_count == 0) {
                            if (host_has_anykey()) {
                                register_code(action.layer_key.code);
                            } else {
                                waiting_layer = action.layer_key.layer;
                            }
                        }
                        // register key when press after a tap
                        if (tap_count > 0) {
                            register_code(action.layer_key.code);
                        }
                    } else {
                        // type key after tap
                        if (tap_count == 1) {
                            register_code(action.layer_key.code);
                        }
                        unregister_code(action.layer_key.code);
                    }
                    break;
            }
            break;
        case ACT_USAGE:
#ifdef EXTRAKEY_ENABLE
            switch (action.usage.page) {
                case ACTION_USAGE_PAGE_SYSTEM:
                    if (event.pressed) {
                        host_system_send(action.usage.code);
                    } else {
                        host_system_send(0);
                    }
                    break;
                case ACTION_USAGE_PAGE_CONSUMER:
                    if (event.pressed) {
                        host_consumer_send(action.usage.code);
                    } else {
                        host_consumer_send(0);
                    }
                    break;
            }
#endif
            break;
        case ACT_MOUSEKEY:
#ifdef MOUSEKEY_ENABLE
            if (event.pressed) {
                mousekey_on(action.key.code);
                mousekey_send();
            } else {
                mousekey_off(action.key.code);
                mousekey_send();
            }
#endif
            break;
        case ACT_LMOD_TAP:
        case ACT_RMOD_TAP:
        case ACT_MACRO:
        case ACT_COMMAND:
        case ACT_FUNCTION:
        default:
            break;
    }

    /* last event */
    last_event = event;
    last_event_time = timer_read();
}


#if 0
/* Key Action */
inline
static void key_action(uint8_t code, keyevent_t event)
{
    if (event.pressed)
        key_pressed(code, event);
    else
        key_released(code, event);
}

void fn_action(uint8_t code, keyevent_t event)
{
}

/* Key */
inline static void key_pressed(uint8_t code, keyevent_t event)
{
    uint8_t tmp_mods;
    switch (kbdstate) {
        case IDLE:
            register_code(code);
            NEXT(PRESSING);
            break;
        case PRESSING:
            register_code(code);
            break;
        case DELAYING:
            waiting_key = (keyrecord_t) {
                .event = event,
                .code = code,
                .mods = keyboard_report->mods,
                .time = timer_read()
            };
            NEXT(WAITING);
            break;
        case WAITING:
            // play back key stroke
            tmp_mods = keyboard_report->mods;
            host_set_mods(delayed_fn.mods);
            register_code(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;
    }
}
inline static void key_released(uint8_t code, keyevent_t event)
{
    uint8_t tmp_mods;
    switch (kbdstate) {
        case IDLE:
            unregister_code(code);
            break;
        case PRESSING:
            unregister_code(code);
            if (!anykey_sent_to_host())
                NEXT(IDLE);
            break;
        case DELAYING:
            unregister_code(code);
            break;
        case WAITING:
            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);
                keymap_process_event(waiting_key.event);
                host_set_mods(tmp_mods);
                keymap_process_event(event);
            } else {
                unregister_code(code);
            }
            break;
    }
}

/* layer switch momentary */
inline static void layerkey_pressed(uint8_t code, keyevent_t event)
{
    uint8_t tmp_mods;
    switch (kbdstate) {
        case IDLE:
            layer_switch_on(code);
            break;
        case PRESSING:
            // ignore
            break;
        case DELAYING:
            waiting_key = (keyrecord_t) {
                .event = event,
                .code = code,
                .mods = keyboard_report->mods,
                .time = timer_read()
            };
            NEXT(WAITING);
            break;
        case WAITING:
            tmp_mods = keyboard_report->mods;
            host_set_mods(delayed_fn.mods);
            register_code(delayed_fn.code);
            host_set_mods(waiting_key.mods);
            register_code(waiting_key.code);
            host_set_mods(tmp_mods);
            if (kind == FN_DOWN) {
                // ignore Fn
            } else if (kind == FNK_DOWN) {
                register_code(code);
            } else if (kind == KEY_DOWN) {
                register_code(code);
            }
            NEXT(IDLE);
            break;
    }
}
inline static void layerkey_released(uint8_t code, keyevent_t event)
{
    switch (kbdstate) {
        case IDLE:
            layer_switch_off(code);
            break;
        case PRESSING:
        case DELAYING:
        case WAITING:
            if (layer_switch_off(code))
                NEXT(IDLE);
            break;
    }
}
#endif


static void register_code(uint8_t code)
{
    if (code == KC_NO) {
        return;
    }
    else if IS_KEY(code) {
        // TODO: should push command_proc out of this block?
        if (!command_proc(code)) {
            host_add_key(code);
            host_send_keyboard_report();
        }
    }
    else if IS_MOD(code) {
        host_add_mods(MOD_BIT(code));
        host_send_keyboard_report();
    }
#ifdef MOUSEKEY_ENABLE
    else if IS_MOUSEKEY(code) {
        mousekey_on(code);
        mousekey_send();
    }
#endif
#ifdef EXTRAKEY_ENABLE
    else if IS_CONSUMER(code) {
        uint16_t usage = 0;
        switch (code) {
            case KC_AUDIO_MUTE:
                usage = AUDIO_MUTE;
                break;
            case KC_AUDIO_VOL_UP:
                usage = AUDIO_VOL_UP;
                break;
            case KC_AUDIO_VOL_DOWN:
                usage = AUDIO_VOL_DOWN;
                break;
            case KC_MEDIA_NEXT_TRACK:
                usage = TRANSPORT_NEXT_TRACK;
                break;
            case KC_MEDIA_PREV_TRACK:
                usage = TRANSPORT_PREV_TRACK;
                break;
            case KC_MEDIA_STOP:
                usage = TRANSPORT_STOP;
                break;
            case KC_MEDIA_PLAY_PAUSE:
                usage = TRANSPORT_PLAY_PAUSE;
                break;
            case KC_MEDIA_SELECT:
                usage = AL_CC_CONFIG;
                break;
            case KC_MAIL:
                usage = AL_EMAIL;
                break;
            case KC_CALCULATOR:
                usage = AL_CALCULATOR;
                break;
            case KC_MY_COMPUTER:
                usage = AL_LOCAL_BROWSER;
                break;
            case KC_WWW_SEARCH:
                usage = AC_SEARCH;
                break;
            case KC_WWW_HOME:
                usage = AC_HOME;
                break;
            case KC_WWW_BACK:
                usage = AC_BACK;
                break;
            case KC_WWW_FORWARD:
                usage = AC_FORWARD;
                break;
            case KC_WWW_STOP:
                usage = AC_STOP;
                break;
            case KC_WWW_REFRESH:
                usage = AC_REFRESH;
                break;
            case KC_WWW_FAVORITES:
                usage = AC_BOOKMARKS;
                break;
        }
        host_consumer_send(usage);
    }
    else if IS_SYSTEM(code) {
        uint16_t usage = 0;
        switch (code) {
            case KC_SYSTEM_POWER:
                usage = SYSTEM_POWER_DOWN;
                break;
            case KC_SYSTEM_SLEEP:
                usage = SYSTEM_SLEEP;
                break;
            case KC_SYSTEM_WAKE:
                usage = SYSTEM_WAKE_UP;
                break;
        }
        host_system_send(usage);
    }
#endif
}

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_mods(MOD_BIT(code));
        host_send_keyboard_report();
    }
#ifdef MOUSEKEY_ENABLE
    else if IS_MOUSEKEY(code) {
        mousekey_off(code);
        mousekey_send();
    }
#endif
#ifdef EXTRAKEY_ENABLE
    else if IS_CONSUMER(code) {
        host_consumer_send(0x0000);
    }
    else if IS_SYSTEM(code) {
        host_system_send(0x0000);
    }
#endif
}

static void register_mods(uint8_t mods)
{
    if (!mods) return;
    host_add_mods(mods);
    host_send_keyboard_report();
}

static void unregister_mods(uint8_t mods)
{
    if (!mods) return;
    host_del_mods(mods);
    host_send_keyboard_report();
}

static void clear_keyboard(void)
{
    host_clear_mods();
    clear_keyboard_but_mods();
}

static void clear_keyboard_but_mods(void)
{
    host_clear_keys();
    host_send_keyboard_report();
#ifdef MOUSEKEY_ENABLE
    mousekey_clear();
    mousekey_send();
#endif
#ifdef EXTRAKEY_ENABLE
    host_system_send(0);
    host_consumer_send(0);
#endif
}

static void layer_switch(uint8_t new_layer)
{
    if (current_layer != new_layer) {
        Kdebug("Layer Switch: "); Kdebug_hex(current_layer);
        Kdebug(" -> "); Kdebug_hex(new_layer); Kdebug("\n");

        current_layer = new_layer;
        clear_keyboard_but_mods(); // To avoid stuck keys
    }
}

A common/action.h => common/action.h +219 -0
@@ 0,0 1,219 @@
#ifndef ACTION_H
#define ACTION_H

#include "keyboard.h"


/* Key Action(16bit code)
 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
------------------------------------------------
ACT_LMODS(0000)
  0  0  0  0| 0  0  0  0| 0  0  0  0  0  0| 0  0    No action
  0  0  0  0| 0  0  0  0|     keycode(8)            Key
  0  0  0  0|  mods(4)  | 0  0  0  0  0  0| 0  0    Lmods Momentary
  0  0  0  0|  mods(4)  | 0  0  0  0  0  0| 0  1    Lmods OneShot
  0  0  0  0|  mods(4)  | 0  0  0  0  0  0| 1  0    (reserved)
  0  0  0  0|  mods(4)  | 0  0  0  0  0  0| 1  1    (reserved)
  0  0  0  0|  mods(4)  |     keycode(8)            Key+Lmods
???
  0  0  0  0|  mods(4)  | 1  1  1  1  0| tap(3)     Lmods+tap Switch(enable/disable)
  0  0  0  0|  mods(4)  | 1  1  1  1  1| tap(3)     Lmods+tap Toggle(on/off)
???

ACT_RMODS(0001)
  0  0  0  1| 0  0  0  0| 0  0  0  0  0  0  0  0    No action(not used)
  0  0  0  1| 0  0  0  0|     keycode(8)            Key(not used)
  0  0  0  1|  mods(4)  | 0  0  0  0  0  0| 0  0    Rmods Momentary
  0  0  0  1|  mods(4)  | 0  0  0  0  0  0| 0  1    Rmods OneShot
  0  0  0  1|  mods(4)  | 0  0  0  0  0  0| 1  0    (reserved)
  0  0  0  1|  mods(4)  | 0  0  0  0  0  0| 1  1    (reserved)
  0  0  0  1|  mods(4)  |     keycode(8)            Key+Rmod
???
  0  0  0  1|  mods(4)  | 1  1  1  1  0| tap(3)     Rmods+tap Switch(enable/disable)
  0  0  0  1|  mods(4)  | 1  1  1  1  1| tap(3)     Rmods+tap Toggle(on/off)
???

ACT_LMODS_TAP(0010)
  0  0  1  0| 0  0  0  0| X  X  X  X  X  X  X  X    (reserved)[00-FF]
  0  0  1  0|  mods(4)  | 0  0  0  0  0  0| X  X    (reserved)
  0  0  1  0|  mods(4)  |     keycode(8)            Lmods+tap Key
  0  0  1  0|  mods(4)  | 1  1  1  1| X  X  X  X    (reserved)[F0-FF]

ACT_RMODS_TAP(0011)
  0  0  1  1| 0  0  0  0| X  X  X  X  X  X  X  X    (reserved)[00-FF]
  0  0  1  1|  mods(4)  | 0  0  0  0  0  0| X  X    (reserved)
  0  0  1  1|  mods(4)  |     keycode(8)            Rmods+tap Key
  0  0  1  1|  mods(4)  | 1  1  1  1| X  X  X  X    (reserved)[F0-FF]
 
ACT_LAYER(0100)
  0  1  0  0|  layer(4) | 0  0  0  0  0  0| 0  0    Momentary
  0  1  0  0|  layer(4) | 0  0  0  0  0  0| 0  1    Oneshot
  0  1  0  0|  layer(4) | 0  0  0  0  0  0| 1  0    (reserved)
  0  1  0  0|  layer(4) | 0  0  0  0  0  0| 1  1    (reserved)
  0  1  0  0|  layer(4) |     keycode(8)            Fn momentary + tap Key
  0  1  0  0|  layer(4) | 1  1  1  1  0| tap(3)     Fn+tap Switch(enable/disable)
  0  1  0  0|  layer(4) | 1  1  1  1  1| tap(3)     Fn+tap Toggle(on/off)

ACT_USAGE(0101)
  0  1  0  1| 0  0|         usage(10)               System usage
  0  1  0  1| 0  1|         usage(10)               Consumer usage
  0  1  0  1| 1  0|         usage(10)               (reserved)
  0  1  0  1| 1  1|         usage(10)               (reserved)

ACT_MOUSEKEY(0110)
  0  1  1  0| X  X  X  X|        keycode(8)         Mouse key
??? TODO: refactor
  0  1  1  0| 0  0  X  X|  accel(5)    |cursor(3)   Mouse key
  0  1  1  0| 0  1  X  X|  accel(5)    |wheel(3)    Mouse key
  0  1  1  0| 1  0  X  X|        button(8)          Mouse key
  0  1  1  0| 1  1  X  X|        button(8)          Mouse key
???

  0  1  1  1|                                       (reserved)
  1  0  0  0|                                       (reserved)
  1  0  0  1|                                       (reserved)
  1  0  1  0|                                       (reserved)
  1  0  1  1|                                       (reserved)
  1  1  0  0|                                       (reserved)

ACT_MACRO(1100)
  1  1  0  0| option(4) |     macro-table id(8)     Macro play(Flash)
  1  1  0  0| option(4) |     macro-table id(8)     Macro play(EEPROM)
  1  1  0  0| 1  1  1  1|     macro-table id(8)     Macro record

ACT_COMMAND(1110)
  1  1  1  0| option(4) |     comamnd id(8)         Built-in Command exec

ACT_FUNCTION(1111)
  1  1  1  1|   function address(4K range)          Function
                                                    Macro record(dynamicly)
                                                    Macro play(dynamicly)
*/

enum action_id {
    ACT_LMODS = 0,
    ACT_RMODS,
    ACT_LMOD_TAP,
    ACT_RMOD_TAP,
    ACT_LAYER,
    ACT_USAGE,
    ACT_MOUSEKEY,
    ACT_MACRO = 14,
    ACT_COMMAND = 15,
    ACT_FUNCTION = 16
};

// TODO: not portable across compiler/endianness?
/*
In avr-gcc bit fields seems to be assigned from LSB(bit0) to MSB(bit15). 
AVR seems like little endian in avr-gcc.

Byte order and bit order of 0x1234:
Big endian:     15 ...  8 7 ... 210
               |  0x12   |  0x34   |
                0001 0010 0011 0100
Little endian:  012 ... 7  8 ... 15
               |  0x34   |  0x12   |
                0010 1100 0100 1000
*/
typedef union {
    uint16_t code;
    struct action_kind {
        uint16_t param  :12;
        uint16_t id     :4;
    } kind;
    struct action_key {
        uint16_t code   :8;
        uint16_t mods   :4;
        uint16_t kind   :4;
    } key;
    struct action_layer_key {
        uint16_t code   :8;
        uint16_t layer  :4;
        uint16_t kind   :4;
    } layer_key;
    struct action_layer_tap {
        uint16_t count  :3;
        uint16_t rest   :5;
        uint16_t layer  :4;
        uint16_t kind   :4;
    } layer_tap;
    struct action_usage {
        uint16_t code   :10;
        uint16_t page   :2;
        uint16_t kind   :4;
    } usage;
    struct action_command {
        uint16_t id     :8;
        uint16_t option :4;
        uint16_t kind   :4;
    } command;
} action_t;


enum stroke_cmd {
    STROKE_DOWN,
    STROKE_UP,
    STROKE_ALLUP, /* release all keys in reverse order */
};

void action_exec(action_t act, keyevent_t event);
/*
void key_action(uint8_t code, keyevent_t event);
void mod_action(uint8_t code, keyevent_t event);
void fn_action(uint8_t code, keyevent_t event);
*/


/* action_t utility */
#define ACTION(kind, param)             { .code = ((kind)<<12 | (param)) }
#define NO_ACTION                       ACTION(0, 0)
#define LAYER_PARAM(layer, key)         ((layer)<<8|(key))

/* Key & Mods */
#define ACTION_KEY(key)                 ACTION(ACT_LMODS,    key)
#define ACTION_LMODS(mods)              ACTION(ACT_LMODS,    (mods)<<8 | 0x00)
#define ACTION_LMODS_KEY(mods, key)     ACTION(ACT_LMODS,    (mods)<<8 | (key))
#define ACTION_LMODS_ONESHOT(mods)      ACTION(ACT_LMODS,    (mods)<<8 | 0x01)
#define ACTION_LMODS_SWITCH(mods, tap)  ACTION(ACT_LMODS,    (mods)<<8 | 0xF0 | (tap))
#define ACTION_LMODS_TOGGLE(mods, tap)  ACTION(ACT_LMODS,    (mods)<<8 | 0xF1 | (tap))
#define ACTION_RMODS(mods)              ACTION(ACT_RMODS,    (mods)<<8 | 0x00)
#define ACTION_RMODS_KEY(mods, key)     ACTION(ACT_RMODS,    (mods)<<8 | (key))
#define ACTION_RMODS_ONESHOT(mods)      ACTION(ACT_RMODS,    (mods)<<8 | 0x01)
#define ACTION_RMODS_SWITCH(mods, tap)  ACTION(ACT_RMODS,    (mods)<<8 | 0xF0 | (tap))
#define ACTION_RMODS_TOGGLE(mods, tap)  ACTION(ACT_RMODS,    (mods)<<8 | 0xF1 | (tap))
/* Mods + Tap key */
#define ACTION_LMODS_TAP(mods, key)     ACTION(ACT_LMODS_TAP,(mods)<<8 | (key))
#define ACTION_RMODS_TAP(mods, key)     ACTION(ACT_RMODS_TAP,(mods)<<8 | (key))
/* Layer Switch */
#define ACTION_LAYER(layer)             ACTION(ACT_LAYER,    (layer)<<8 | 0x00)
#define ACTION_LAYER_ONESHOT(layer)     ACTION(ACT_LAYER,    (layer)<<8 | 0x01)
#define ACTION_LAYER_KEY(layer, key)    ACTION(ACT_LAYER,    (layer)<<8 | (key))
#define ACTION_LAYER_SWITCH(layer, tap) ACTION(ACT_LAYER,    (layer)<<8 | 0xF0 | (tap))
#define ACTION_LAYER_TOGGLE(layer, tap) ACTION(ACT_LAYER,    (layer)<<8 | 0xF1 | (tap))
/* HID Usage */
#define ACTION_USAGE_PAGE_SYSTEM        0
#define ACTION_USAGE_PAGE_CONSUMER      1
#define ACTION_USAGE_SYSTEM(id)         ACTION(ACT_USAGE,    ACTION_USAGE_PAGE_SYSTEM<<10 | (id))
#define ACTION_USAGE_CONSUMER(id)       ACTION(ACT_USAGE,    ACTION_USAGE_PAGE_CONSUMER<<10 | (id))
/* Mousekey */
#define ACTION_MOUSEKEY(key)            ACTION(ACT_MOUSEKEY, key)
/* Macro */
#define ACTION_MACRO(opt, id)           ACTION(ACT_FUNCTION, (opt)<<8 | (addr))
/* Command */
#define ACTION_COMMAND(opt, id)         ACTION(ACT_COMMAND,  (opt)<<8 | (addr))
/* Function */
#define ACTION_FUNCTION(addr)           ACTION(ACT_FUNCTION, addr)


/* helpers for readability */
#define LAYER(layer)    (layer)
#define TAP(tap)        (tap)
#define DOUBLE_TAP      2
#define TRIPLE_TAP      3
#define QUADRUPLE_TAP   4
#define QUINTUPLE_TAP   5
#define DOWN(key)       (key)
#define UP(key)         STROKE_UP, (key)

#endif  /* ACTION_H */

M common/host.c => common/host.c +4 -4
@@ 127,14 127,14 @@ void host_clear_keys(void)
    }
}

void host_add_mod_bit(uint8_t mod)
void host_add_mods(uint8_t mods)
{
    keyboard_report->mods |= mod;
    keyboard_report->mods |= mods;
}

void host_del_mod_bit(uint8_t mod)
void host_del_mods(uint8_t mods)
{
    keyboard_report->mods &= ~mod;
    keyboard_report->mods &= ~mods;
}

void host_set_mods(uint8_t mods)

M common/host.h => common/host.h +2 -2
@@ 51,8 51,8 @@ void host_consumer_send(uint16_t data);
void host_add_key(uint8_t key);
void host_del_key(uint8_t key);
void host_clear_keys(void);
void host_add_mod_bit(uint8_t mod);
void host_del_mod_bit(uint8_t mod);
void host_add_mods(uint8_t mods);
void host_del_mods(uint8_t mods);
void host_set_mods(uint8_t mods);
void host_clear_mods(void);
uint8_t host_has_anykey(void);

M common/keyboard.c => common/keyboard.c +6 -544
@@ 31,517 31,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#endif


#define Kdebug(s)       do { if (debug_keyboard) debug(s); } while(0)
#define Kdebug_P(s)     do { if (debug_keyboard) debug_P(s); } while(0)
#define Kdebug_hex(s)   do { if (debug_keyboard) debug_hex(s); } while(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,
} keykind_t;

typedef enum { IDLE, DELAYING, WAITING, PRESSING } kbdstate_t;


#ifdef KEYMAP_DEFAULT_LAYER
uint8_t default_layer = KEYMAP_DEFAULT_LAYER;
uint8_t current_layer = KEYMAP_DEFAULT_LAYER;
#else
uint8_t default_layer = 0;
uint8_t current_layer = 0;
#endif

/* 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 ? KEY_DOWN : KEY_UP);
    if IS_SYSTEM(code)      return (pressed ? KEY_DOWN : KEY_UP);
    if IS_CONSUMER(code)    return (pressed ? KEY_DOWN : KEY_UP);
    return  NONE;
}

static void clear_keyboard(void)
{
    host_clear_keys();
    host_clear_mods();
    host_send_keyboard_report();

    host_system_send(0);
    host_consumer_send(0);

#ifdef MOUSEKEY_ENABLE
    mousekey_clear();
    mousekey_send();
#endif
}

static void clear_keyboard_but_mods(void)
{
    host_clear_keys();
    host_send_keyboard_report();

    host_system_send(0);
    host_consumer_send(0);

#ifdef MOUSEKEY_ENABLE
    mousekey_clear();
    mousekey_send();
#endif
}

static bool anykey_sent_to_host(void)
{
    return (host_has_anykey() || host_mouse_in_use() ||
            host_last_sysytem_report() || host_last_consumer_report());
}

static void layer_switch_on(uint8_t code)
{
    if (!IS_FN(code)) return;
    fn_state_bits |= FN_BIT(code);
    uint8_t new_layer = (fn_state_bits ? keymap_fn_layer(biton(fn_state_bits)) : default_layer);
    if (current_layer != new_layer) {
        Kdebug("Layer Switch(on): "); Kdebug_hex(current_layer);
        Kdebug(" -> "); Kdebug_hex(new_layer); Kdebug("\n");

        clear_keyboard_but_mods();
        current_layer = new_layer;
    }
}

static bool layer_switch_off(uint8_t code)
{
    if (!IS_FN(code)) return false;
    fn_state_bits &= ~FN_BIT(code);
    uint8_t new_layer = (fn_state_bits ? keymap_fn_layer(biton(fn_state_bits)) : default_layer);
    if (current_layer != new_layer) {
        Kdebug("Layer Switch(off): "); Kdebug_hex(current_layer);
        Kdebug(" -> "); Kdebug_hex(new_layer); Kdebug("\n");

        clear_keyboard_but_mods();
        current_layer = new_layer;
        return true;
    }
    return false;
}

static void register_code(uint8_t code)
{
    if IS_KEY(code) {
        if (!command_proc(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_FN(code) {
        if (!command_proc(keymap_fn_keycode(FN_INDEX(code)))) {
            host_add_key(keymap_fn_keycode(FN_INDEX(code)));
            host_send_keyboard_report();
        }
    }
    else if IS_MOUSEKEY(code) {
#ifdef MOUSEKEY_ENABLE
        mousekey_on(code);
        mousekey_send();
#endif
    }
    else if IS_CONSUMER(code) {
        uint16_t usage = 0;
        switch (code) {
            case KC_AUDIO_MUTE:
                usage = AUDIO_MUTE;
                break;
            case KC_AUDIO_VOL_UP:
                usage = AUDIO_VOL_UP;
                break;
            case KC_AUDIO_VOL_DOWN:
                usage = AUDIO_VOL_DOWN;
                break;
            case KC_MEDIA_NEXT_TRACK:
                usage = TRANSPORT_NEXT_TRACK;
                break;
            case KC_MEDIA_PREV_TRACK:
                usage = TRANSPORT_PREV_TRACK;
                break;
            case KC_MEDIA_STOP:
                usage = TRANSPORT_STOP;
                break;
            case KC_MEDIA_PLAY_PAUSE:
                usage = TRANSPORT_PLAY_PAUSE;
                break;
            case KC_MEDIA_SELECT:
                usage = AL_CC_CONFIG;
                break;
            case KC_MAIL:
                usage = AL_EMAIL;
                break;
            case KC_CALCULATOR:
                usage = AL_CALCULATOR;
                break;
            case KC_MY_COMPUTER:
                usage = AL_LOCAL_BROWSER;
                break;
            case KC_WWW_SEARCH:
                usage = AC_SEARCH;
                break;
            case KC_WWW_HOME:
                usage = AC_HOME;
                break;
            case KC_WWW_BACK:
                usage = AC_BACK;
                break;
            case KC_WWW_FORWARD:
                usage = AC_FORWARD;
                break;
            case KC_WWW_STOP:
                usage = AC_STOP;
                break;
            case KC_WWW_REFRESH:
                usage = AC_REFRESH;
                break;
            case KC_WWW_FAVORITES:
                usage = AC_BOOKMARKS;
                break;
        }
        host_consumer_send(usage);
    }
    else if IS_SYSTEM(code) {
        uint16_t usage = 0;
        switch (code) {
            case KC_SYSTEM_POWER:
                usage = SYSTEM_POWER_DOWN;
                break;
            case KC_SYSTEM_SLEEP:
                usage = SYSTEM_SLEEP;
                break;
            case KC_SYSTEM_WAKE:
                usage = SYSTEM_WAKE_UP;
                break;
        }
        host_system_send(usage);
    }

}

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_FN(code) {
        host_del_key(keymap_fn_keycode(FN_INDEX(code)));
        host_send_keyboard_report();
    }
    else if IS_MOUSEKEY(code) {
#ifdef MOUSEKEY_ENABLE
        mousekey_off(code);
        mousekey_send();
#endif
    }
    else if IS_CONSUMER(code) {
        host_consumer_send(0x0000);
    }
    else if IS_SYSTEM(code) {
        host_system_send(0x0000);
    }
}

/*
 *
 * Event/State|IDLE          PRESSING      DELAYING[f]      WAITING[f,k]         
 * -----------+------------------------------------------------------------------
 * Fn  Down   |(L+)          -*1           WAITING(Sk)      IDLE(Rf,Ps)*7        
 *     Up     |(L-)          IDLE(L-)*8    IDLE(L-)*8       IDLE(L-)*8           
 * Fnk Down   |DELAYING(Sf)* (Rf)          WAITING(Sk)      IDLE(Rf,Ps,Rf)       
 *     Up     |(L-)          IDLE(L-/Uf)*8 IDLE(Rf,Uf/L-)*3 IDLE(Rf,Ps,Uf/L-)*3  
 * Key Down   |PRESSING(Rk)  (Rk)          WAITING(Sk)      IDLE(Rf,Ps,Rk)       
 *     Up     |(Uk)          IDLE(Uk)*4    (Uk)             IDLE(L+,Ps,Pk)/(Uk)*a
 *            |
 * Delay      |-             -             IDLE(L+)         IDLE(L+,Ps)          
 * Magic Key  |COMMAND*5
 *
 * *1: ignore Fn if other key is down.
 * *2: register Fnk if any key is pressing
 * *3: register/unregister delayed Fnk and move to IDLE if code == delayed Fnk, else *8
 * *4: if no keys registered to host
 * *5: unregister all keys
 * *6: only if no keys down
 * *7: ignore Fn because Fnk key and stored key are down.
 * *8: move to IDLE if layer switch(off) occurs, else stay at current state
 * *9: repeat key if pressing Fnk twice quickly(move to PRESSING)
 * *a: layer switch and process waiting key and code if code == wainting key, else unregister key
 *
 * States:
 *      IDLE: No key is down except modifiers
 *      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
 *      Delay: layer switch delay term is elapsed
 *
 * Actions:
 *      Rk: register key
 *      Uk: unregister key
 *      Rf: register Fn(alt keycode)
 *      Uf: unregister Fn(alt keycode)
 *      Rs: register stored key
 *      Us: unregister stored key
 *      Sk: Store key(waiting Key)
 *      Sf: Store Fn(delayed Fn)
 *      Ps: Process stored key
 *      Ps: Process key
 *      Is: Interpret stored keys in current layer
 *      L+: Switch to new layer(*unregister* all keys but modifiers)
 *      L-: Switch back to last layer(*unregister* all keys but modifiers)
 *      Ld: Switch back to default layer(*unregister* all keys but modifiers)
 */
#define NEXT(state)     do { \
    Kdebug("NEXT: "); Kdebug_P(state_str(kbdstate)); \
    kbdstate = state; \
    Kdebug(" -> "); Kdebug_P(state_str(kbdstate)); Kdebug("\n"); \
} while (0)

static inline void process_key(keyevent_t event)
{
    uint8_t code = keymap_get_keycode(current_layer, event.key.row, event.key.col);
    keykind_t kind = get_keykind(code, event.pressed);

    uint8_t tmp_mods;

    Kdebug("state: "); Kdebug_P(state_str(kbdstate));
    Kdebug(" kind: "); Kdebug_hex(kind);
    Kdebug(" code: "); Kdebug_hex(code);
    if (event.pressed) { Kdebug("d"); } else { Kdebug("u"); }
    Kdebug("\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:
                    // repeat Fn alt key when press Fn key down, up then down again quickly
                    if (KEYEQ(delayed_fn.event.key, event.key) &&
                            timer_elapsed(delayed_fn.time) < LAYER_DELAY) {
                        register_code(code);
                        NEXT(PRESSING);
                    } else {
                        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:
                    register_code(code);
                    NEXT(PRESSING);
                    break;
                case MOD_DOWN:
                    register_code(code);
                    break;
                case KEY_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:
                    if (layer_switch_off(code))
                        NEXT(IDLE);
                    break;
                case FNK_DOWN:
                    register_code(code);
                    break;
                case FNK_UP:
                    if (layer_switch_off(code)) {
                        NEXT(IDLE);
                    } else {
                        unregister_code(code);
                        if (!anykey_sent_to_host())
                            NEXT(IDLE);
                    }
                    break;
                case KEY_DOWN:
                case MOD_DOWN:
                    register_code(code);
                    break;
                case KEY_UP:
                case MOD_UP:
                    unregister_code(code);
                    if (!anykey_sent_to_host())
                        NEXT(IDLE);
                    break;
                default:
                    break;
            }
            break;
        case DELAYING:
            switch (kind) {
                case FN_DOWN:
                case FNK_DOWN:
                case KEY_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:
                    if (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(delayed_fn.code);
                        unregister_code(delayed_fn.code);
                        host_set_mods(tmp_mods);
                        NEXT(IDLE);
                    } else {
                        if (layer_switch_off(code))
                            NEXT(IDLE);
                    }
                    break;
                case KEY_UP:
                case MOD_UP:
                    unregister_code(code);
                    break;
                default:
                    break;
            }
            break;
        case WAITING:
            switch (kind) {
                case FN_DOWN:
                case FNK_DOWN:
                case KEY_DOWN:
                    tmp_mods = keyboard_report->mods;
                    host_set_mods(delayed_fn.mods);
                    register_code(delayed_fn.code);
                    host_set_mods(waiting_key.mods);
                    register_code(waiting_key.code);
                    host_set_mods(tmp_mods);
                    if (kind == FN_DOWN) {
                        // ignore Fn
                    } else if (kind == FNK_DOWN) {
                        register_code(code);
                    } else if (kind == KEY_DOWN) {
                        register_code(code);
                    }
                    NEXT(IDLE);
                    break;
                case MOD_DOWN:
                    register_code(code);
                    break;
                case FN_UP:
                    if (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(delayed_fn.code);
                        host_set_mods(waiting_key.mods);
                        register_code(waiting_key.code);
                        unregister_code(delayed_fn.code);
                        host_set_mods(tmp_mods);
                        NEXT(IDLE);
                    } else {
                        if (layer_switch_off(code))
                            NEXT(IDLE);
                    }
                    break;
                case KEY_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;
    }
}

void keyboard_init(void)
{
    // TODO: to enable debug print magic key bind on boot time


@@ 556,6 45,10 @@ void keyboard_init(void)
#endif
}

/*
 * Do keyboard routine jobs: scan mantrix, light LEDs, ...
 * This is repeatedly called as fast as possible.
 */
void keyboard_task(void)
{
    static matrix_row_t matrix_prev[MATRIX_ROWS];


@@ 572,8 65,8 @@ void keyboard_task(void)

            for (int c = 0; c < MATRIX_COLS; c++) {
                if (matrix_change & (1<<c)) {
                    process_key((keyevent_t){
                        .key = (key_t){ .row = r, .col = c },
                    keymap_process_event((keyevent_t){
                        .key = (keypos_t){ .row = r, .col = c },
                        .pressed = (matrix_row & (1<<c))
                    });
                    // record a processed key


@@ 586,42 79,11 @@ void keyboard_task(void)
    }
    MATRIX_LOOP_END:

    // 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_task();
#endif

    // FAIL SAFE: clear all key if no key down
    if (matrix_change) {
        matrix_row_t is_matrix_on = 0;
        for (int r = 0; r < MATRIX_ROWS; r++) {
            is_matrix_on |= matrix_get_row(r);
        }
        if (!is_matrix_on) {
            Kdebug("FAIL SAFE: clear all keys(default layer).\n");
            clear_keyboard();
            current_layer = default_layer;
        }
    }

    // update LED
    if (led_status != host_keyboard_leds()) {
        led_status = host_keyboard_leds();

M common/keyboard.h => common/keyboard.h +2 -3
@@ 29,10 29,10 @@ extern "C" {
typedef struct {
    uint8_t row;
    uint8_t col;
} key_t;
} keypos_t;

typedef struct {
    key_t    key;
    keypos_t key;
    bool     pressed;
} keyevent_t;



@@ 45,7 45,6 @@ typedef struct {

#define KEYEQ(keya, keyb)     (keya.row == keyb.row && keya.col == keyb.col)


extern uint8_t current_layer;
extern uint8_t default_layer;


M common/keycode.h => common/keycode.h +2 -0
@@ 43,6 43,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define MOD_INDEX(code) ((code) & 0x07)
#define FN_BIT(code)    (1<<FN_INDEX(code))
#define FN_INDEX(code)  ((code) - KC_FN0)
#define FN_MIN          KC_FN0
#define FN_MAX          KC_FN7


/*

M common/keymap.h => common/keymap.h +10 -4
@@ 20,15 20,21 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <stdint.h>
#include <stdbool.h>
#include "action.h"


/* keycode in specific layer */
/* 
 * legacy keymap interface: keycode
 */
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col);

/* layer to move during press Fn key */
uint8_t keymap_fn_layer(uint8_t fn_bits);

/* keycode to send when release Fn key without using */
uint8_t keymap_fn_keycode(uint8_t fn_bits);

/* 
 * new keymap interface: action
 */
action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col);
uint8_t keymap_process_event(keyevent_t event);

#endif

M common/report.h => common/report.h +81 -0
@@ 19,6 19,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#define REPORT_H

#include <stdint.h>
#include <keycode.h>


/* report id */


@@ 97,6 98,86 @@ typedef struct {
    int8_t h;
} __attribute__ ((packed)) report_mouse_t;


static uint16_t key2system(uint8_t key)
{
    uint16_t usage = 0;
    switch (key) {
        case KC_SYSTEM_POWER:
            usage = SYSTEM_POWER_DOWN;
            break;
        case KC_SYSTEM_SLEEP:
            usage = SYSTEM_SLEEP;
            break;
        case KC_SYSTEM_WAKE:
            usage = SYSTEM_WAKE_UP;
            break;
    }
    return usage;
}

static uint16_t key2consumer(uint8_t key)
{
    uint16_t usage = 0;
    switch (key) {
        case KC_AUDIO_MUTE:
            usage = AUDIO_MUTE;
            break;
        case KC_AUDIO_VOL_UP:
            usage = AUDIO_VOL_UP;
            break;
        case KC_AUDIO_VOL_DOWN:
            usage = AUDIO_VOL_DOWN;
            break;
        case KC_MEDIA_NEXT_TRACK:
            usage = TRANSPORT_NEXT_TRACK;
            break;
        case KC_MEDIA_PREV_TRACK:
            usage = TRANSPORT_PREV_TRACK;
            break;
        case KC_MEDIA_STOP:
            usage = TRANSPORT_STOP;
            break;
        case KC_MEDIA_PLAY_PAUSE:
            usage = TRANSPORT_PLAY_PAUSE;
            break;
        case KC_MEDIA_SELECT:
            usage = AL_CC_CONFIG;
            break;
        case KC_MAIL:
            usage = AL_EMAIL;
            break;
        case KC_CALCULATOR:
            usage = AL_CALCULATOR;
            break;
        case KC_MY_COMPUTER:
            usage = AL_LOCAL_BROWSER;
            break;
        case KC_WWW_SEARCH:
            usage = AC_SEARCH;
            break;
        case KC_WWW_HOME:
            usage = AC_HOME;
            break;
        case KC_WWW_BACK:
            usage = AC_BACK;
            break;
        case KC_WWW_FORWARD:
            usage = AC_FORWARD;
            break;
        case KC_WWW_STOP:
            usage = AC_STOP;
            break;
        case KC_WWW_REFRESH:
            usage = AC_REFRESH;
            break;
        case KC_WWW_FAVORITES:
            usage = AC_BOOKMARKS;
            break;
    }
    return usage;
}

#ifdef __cplusplus
}
#endif

M keyboard/hhkb/Makefile.lufa => keyboard/hhkb/Makefile.lufa +3 -0
@@ 121,3 121,6 @@ VPATH += $(TOP_DIR)
include $(TOP_DIR)/protocol/lufa.mk
include $(TOP_DIR)/common.mk
include $(TOP_DIR)/rules.mk

debug-on: EXTRAFLAGS += -DDEBUG
debug-on: all

M keyboard/hhkb/Makefile.vusb => keyboard/hhkb/Makefile.vusb +3 -0
@@ 89,3 89,6 @@ VPATH += $(TOP_DIR)
include $(TOP_DIR)/protocol/vusb.mk
include $(TOP_DIR)/common.mk
include $(TOP_DIR)/rules.mk

debug-on: EXTRAFLAGS += -DDEBUG
debug-on: all

M keyboard/hhkb/keymap.c => keyboard/hhkb/keymap.c +55 -54
@@ 26,6 26,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include "print.h"
#include "debug.h"
#include "util.h"
#include "action.h"
#include "keymap.h"




@@ 49,33 50,18 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
    { KC_##K70, KC_##K71, KC_##K72, KC_##K73, KC_##K74, KC_##K75, KC_##K76, KC_NO    } \
}

#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))


// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
static const uint8_t PROGMEM fn_layer[] = {
    0,              // Fn0
    1,              // Fn1
    2,              // Fn2
    3,              // Fn3
    3,              // Fn4
    5,              // Fn5
    0,              // Fn6
    0               // Fn7
static const action_t PROGMEM fn_actions[] = {
    ACTION_LAYER(0),                    // Fn0
    ACTION_LAYER(1),                    // Fn1
    ACTION_LAYER_KEY(2, KC_SLASH),      // Fn2
    ACTION_LAYER_KEY(3, KC_SCLN),       // Fn3
    ACTION_LAYER(3),                    // Fn3
    ACTION_LAYER_KEY(5, KC_SPC),        // Fn5
    NO_ACTION,                          // Fn6
    NO_ACTION,                          // Fn7
};

// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
// See layer.c for details.
static const uint8_t PROGMEM fn_keycode[] = {
    KC_NO,          // Fn0
    KC_NO,          // Fn1
    KC_SLSH,        // Fn2
    KC_SCLN,        // Fn3
    KC_NO,          // Fn4
    KC_SPC,         // Fn5
    KC_NO,          // Fn6
    KC_NO           // Fn7
};

static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    /* Layer 0: Default Layer


@@ 149,24 135,11 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
     *      `--------------------------------------------'
     * Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel 
     */
#ifdef HOST_IWRAP
// iWRAP does not support mouse wheel, use these keycodes to remap as wheel
#define KC_KPPL KC_KP_PLUS
#define KC_KPMI KC_KP_MINUS
#define KC_KPAS KC_KP_ASTERISK
#define KC_KPSL KC_KP_SLASH
    KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
           TAB, KPAS,KPPL,MS_U,KPMI,KPSL,KPAS,KPPL,KPMI,KPSL,NO,  NO,  NO,  BSPC, \
           LCTL,NO,  MS_L,MS_D,MS_R,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
           LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,NO,  NO,  NO,  RSFT,NO, \
                LGUI,LALT,          BTN1,               RALT,FN4),
#else
    KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
           TAB, NO,  NO,  NO,  NO,  NO,  WH_L,WH_D,WH_U,WH_R,NO,  NO,  NO,  BSPC, \
           LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
           LSFT,NO,  NO,  NO,  NO,  BTN3,BTN2,BTN1,BTN4,BTN5,NO,  RSFT,NO, \
                LGUI,LALT,          BTN1,               RALT,FN4),
#endif

    /* Layer 4: Matias half keyboard style (Space)
     * ,-----------------------------------------------------------.


@@ 188,33 161,61 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
                LGUI,LALT,          FN5,                RALT,RGUI),

    /* Layer5: another Mouse mode (Space) */
#ifdef HOST_IWRAP
    KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
           TAB, KPAS,KPPL,MS_U,KPMI,KPSL,KPAS,KPPL,KPMI,KPSL,NO,  NO,  NO,  BSPC, \
           LCTL,NO,  MS_L,MS_D,MS_R,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
           LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,BTN4,BTN5,NO,  RSFT,NO, \
                LGUI,LALT,          FN5,                RALT,RGUI),
#else
    KEYMAP(ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12, INS, DEL, \
           TAB, NO,  NO,  NO,  NO,  NO,  WH_L,WH_D,WH_U,WH_R,NO,  NO,  NO,  BSPC, \
           LCTL,NO,  ACL0,ACL1,ACL2,NO,  MS_L,MS_D,MS_U,MS_R,FN3, NO,  ENT, \
           LSFT,NO,  NO,  NO,  NO,  BTN3,BTN2,BTN1,BTN4,BTN5,NO,  RSFT,NO, \
                LGUI,LALT,          FN5,                RALT,RGUI),
#endif
};

#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))

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 index)
{
    return pgm_read_byte(&fn_layer[index]);
/* legacy interface */
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col) { return 0; }
uint8_t keymap_fn_layer(uint8_t fn_bits) { return 0; }
uint8_t keymap_fn_keycode(uint8_t fn_bits) { return 0; }


action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col) {
    /* convert from legacy keycode to action */
    uint8_t key = KEYCODE(layer, row, col);
    action_t action;
    switch (key) {
        case KC_A ... KC_EXSEL:
            action = (action_t)ACTION_KEY(key);
            break;
        case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
            action = (action_t)ACTION_USAGE_SYSTEM(key2system(key));
            break;
        case KC_AUDIO_MUTE ... KC_WWW_FAVORITES:
            action = (action_t)ACTION_USAGE_CONSUMER(key2consumer(key));
            break;
        case KC_MS_UP ... KC_MS_ACCEL2:
            action = (action_t)ACTION_MOUSEKEY(key);
            break;
        case KC_LCTRL ... KC_LGUI:
            action = (action_t)ACTION_LMODS(MOD_BIT(key));
            break;
        case KC_RCTRL ... KC_RGUI:
            action = (action_t)ACTION_RMODS(MOD_BIT(key)>>4);
            break;
        case KC_FN0 ... KC_FN7:
            action = (action_t)pgm_read_word(&fn_actions[FN_INDEX(key)]);
            break;
        case KC_NO ... KC_UNDEFINED:
        default:
            action = (action_t)NO_ACTION;
            break;
    }
    debug("action: "); debug_hex16(action.code); debug("\n");
    return action;
}

uint8_t keymap_fn_keycode(uint8_t index)

uint8_t keymap_process_event(keyevent_t event)
{
    return pgm_read_byte(&fn_keycode[index]);
    action_t action = keymap_get_action(current_layer, event.key.row, event.key.col);
    action_exec(action, event);
    return 0;
}

M keyboard/hhkb/matrix.c => keyboard/hhkb/matrix.c +7 -0
@@ 24,6 24,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include <avr/interrupt.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
#include "util.h"
#include "timer.h"
#include "matrix.h"


@@ 135,6 136,12 @@ uint8_t matrix_cols(void)

void matrix_init(void)
{
#ifdef DEBUG
    print_enable = true;
    debug_enable = true;
    debug_keyboard = true;
#endif

    KEY_INIT();

    // initialize matrix state: all keys off