diff options
| author | tmk <nobody@nowhere> | 2013-01-27 16:38:19 +0900 | 
|---|---|---|
| committer | tmk <nobody@nowhere> | 2013-01-27 16:38:19 +0900 | 
| commit | bfd7fe586297d70f824a402fd476c3daa889fa56 (patch) | |
| tree | c903d4a878aa7317ca3c2bb62ece03fdb745d51b | |
| parent | 66d5dd284271d85da4c161529e12526b50b0f71d (diff) | |
| download | firmware-bfd7fe586297d70f824a402fd476c3daa889fa56.tar.gz firmware-bfd7fe586297d70f824a402fd476c3daa889fa56.tar.bz2 firmware-bfd7fe586297d70f824a402fd476c3daa889fa56.zip  | |
Add oneshot modifier action.
| -rw-r--r-- | common/action.c | 201 | ||||
| -rw-r--r-- | common/action.h | 198 | ||||
| -rw-r--r-- | keyboard/hhkb/keymap.c | 12 | 
3 files changed, 236 insertions, 175 deletions
diff --git a/common/action.c b/common/action.c index db31613bf..22f0bf0a0 100644 --- a/common/action.c +++ b/common/action.c @@ -97,6 +97,40 @@ static void waiting_buffer_process(void)  {  } +/* Oneshot modifier + * + * Problem: Want to capitalize like 'The' but the result tends to be 'THe'. + * Solution: Oneshot modifier have its effect on only one key coming next. + *           Tap Shift, then type 't', 'h' and 'e'. Not need to hold Shift key. + * + *  Hold:       works as normal modifier. + *  Tap:        one shot modifier. + *  2 Tap:      cancel one shot modifier. + *  5-Tap:      toggles enable/disable oneshot feature. + */ +static struct { +    uint8_t mods; +    uint8_t time; +    bool    ready; +    bool    disabled; +}   oneshot_state; +static void oneshot_start(uint8_t mods, uint16_t time) +{ +    oneshot_state.mods = mods; +    oneshot_state.time = time; +    oneshot_state.ready = true; +} +static void oneshot_cancel(void) +{ +    oneshot_state.mods = 0; +    oneshot_state.time = 0; +    oneshot_state.ready = false; +} +static void oneshot_toggle(void) +{ +    oneshot_state.disabled = !oneshot_state.disabled; +} +  /*   * Rule to judge tap: @@ -271,83 +305,102 @@ static void process(keyrecord_t *record)      switch (action.kind.id) {          /* Key and Mods */          case ACT_LMODS: -            //               |pressed                          |released -            // --------------+---------------------------------+------------ -            // key           |down(key)                        |up(key) -            // mods          |add(mods)                        |del(mods) -            // key with mods |add(mods), down(key), unset(mods)|up(key) -            if (event.pressed) { -                uint8_t tmp_mods = host_get_mods(); -                if (action.key.mods) { -                    host_add_mods(action.key.mods); -                    host_send_keyboard_report(); -                } -                register_code(action.key.code); -                if (action.key.mods && action.key.code) { -                    host_set_mods(tmp_mods); -                    host_send_keyboard_report(); -                } -            } else { -                if (action.key.mods && !action.key.code) { -                    host_del_mods(action.key.mods); -                    host_send_keyboard_report(); -                } -                unregister_code(action.key.code); -            } -            break;          case ACT_RMODS: -            //               |pressed                          |released -            // --------------+---------------------------------+------------ -            // key           |down(key)                        |up(key) -            // mods          |add(mods)                        |del(mods) -            // key with mods |add(mods), down(key), unset(mods)|up(key) -            if (event.pressed) { -                uint8_t tmp_mods = host_get_mods(); -                if (action.key.mods) { -                    host_add_mods(action.key.mods<<4); -                    host_send_keyboard_report(); -                } -                register_code(action.key.code); -                if (action.key.mods && action.key.code) { -                    host_set_mods(tmp_mods); -                    host_send_keyboard_report(); -                } -            } else { -                if (action.key.mods && !action.key.code) { -                    host_del_mods(action.key.mods<<4); -                    host_send_keyboard_report(); +            { +                uint8_t mods = (action.kind.id == ACT_LMODS) ?  action.key.mods : +                                                                action.key.mods<<4; +                if (event.pressed) { +                    uint8_t tmp_mods = host_get_mods(); +                    if (mods) { +                        host_add_mods(mods); +                        host_send_keyboard_report(); +                    } +                    register_code(action.key.code); +                    if (mods && action.key.code) { +                        host_set_mods(tmp_mods); +                        host_send_keyboard_report(); +                    } +                } else { +                    if (mods && !action.key.code) { +                        host_del_mods(mods); +                        host_send_keyboard_report(); +                    } +                    unregister_code(action.key.code);                  } -                unregister_code(action.key.code);              }              break;          case ACT_LMODS_TAP:          case ACT_RMODS_TAP:              { -                uint8_t tmp_mods = (action.kind.id == ACT_LMODS_TAP) ?  action.key.mods : -                                                                        action.key.mods<<4; -                if (event.pressed) { -                    if (IS_TAPPING_KEY(event.key) && tap_count > 0) { -                        if (waiting_buffer_has_anykey_pressed()) { -                            debug("MODS_TAP: Tap: Cancel: add_mods\n"); -                            // ad hoc: set 0 to cancel tap -                            record->tap_count = 0; -                            add_mods(tmp_mods); +                uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ?  action.key.mods : +                                                                    action.key.mods<<4; +                switch (action.layer.code) { +                    case 0x00: +                        // Oneshot modifier +                        if (event.pressed) { +                            if (tap_count == 0) { +                                debug("MODS_TAP: Oneshot: add_mods\n"); +                                add_mods(mods); +                            } +                            else if (tap_count == 1) { +                                debug("MODS_TAP: Oneshot: start\n"); +                                oneshot_start(mods, event.time); +                            } +                            else if (tap_count == 5) { +                                debug("MODS_TAP: Oneshot: toggle\n"); +                                oneshot_toggle(); +                            } +                            else { +                                debug("MODS_TAP: Oneshot: cancel&add_mods\n"); +                                // double tap cancels oneshot and works as normal modifier. +                                oneshot_cancel(); +                                add_mods(mods); +                            }                          } else { -                            debug("MODS_TAP: Tap: register_code\n"); -                            register_code(action.key.code); +                            if (tap_count == 0) { +                                debug("MODS_TAP: Oneshot: cancel/del_mods\n"); +                                // cancel oneshot by holding. +                                oneshot_cancel(); +                                del_mods(mods); +                            } +                            else if (tap_count == 1) { +                                debug("MODS_TAP: Oneshot: del_mods\n"); +                                // retain Oneshot +                                del_mods(mods); +                            } +                            else { +                                debug("MODS_TAP: Oneshot: del_mods\n"); +                                // cancel Mods +                                del_mods(mods); +                            }                          } -                    } else { -                        debug("MODS_TAP: No tap: add_mods\n"); -                        add_mods(tmp_mods); -                    } -                } else { -                    if (IS_TAPPING_KEY(event.key) && tap_count > 0) { -                        debug("MODS_TAP: Tap: unregister_code\n"); -                        unregister_code(action.key.code); -                    } else { -                        debug("MODS_TAP: No tap: add_mods\n"); -                        del_mods(tmp_mods); -                    } +                        break; +                    default: +                        if (event.pressed) { +                            if (tap_count > 0) { +                                if (waiting_buffer_has_anykey_pressed()) { +                                    debug("MODS_TAP: Tap: Cancel: add_mods\n"); +                                    // ad hoc: set 0 to cancel tap +                                    record->tap_count = 0; +                                    add_mods(mods); +                                } else { +                                    debug("MODS_TAP: Tap: register_code\n"); +                                    register_code(action.key.code); +                                } +                            } else { +                                debug("MODS_TAP: No tap: add_mods\n"); +                                add_mods(mods); +                            } +                        } else { +                            if (tap_count > 0) { +                                debug("MODS_TAP: Tap: unregister_code\n"); +                                unregister_code(action.key.code); +                            } else { +                                debug("MODS_TAP: No tap: add_mods\n"); +                                del_mods(mods); +                            } +                        } +                        break;                  }              }              break; @@ -579,7 +632,17 @@ void register_code(uint8_t code)      }      else if IS_KEY(code) {          // TODO: should push command_proc out of this block? -        if (!command_proc(code)) { +        if (command_proc(code)) return; + +        if (oneshot_state.mods && oneshot_state.ready && !oneshot_state.disabled) { +            uint8_t tmp_mods = host_get_mods(); +            host_add_mods(oneshot_state.mods); +            host_add_key(code); +            host_send_keyboard_report(); + +            host_set_mods(tmp_mods); +            oneshot_state.ready = false; +        } else {              host_add_key(code);              host_send_keyboard_report();          } diff --git a/common/action.h b/common/action.h index 327a009ef..1b5b30d86 100644 --- a/common/action.h +++ b/common/action.h @@ -3,10 +3,79 @@  #include "keyboard.h" + +/* Action struct. + * + * In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15).  + * AVR looks like a little endian in avr-gcc. + * + * TODO: not portable across compiler/endianness? + * 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 { +        uint16_t code   :8; +        uint16_t opt    :4; +        uint16_t kind   :4; +    } layer; +    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; +    struct action_function { +        uint8_t  id     :8; +        uint8_t  opt    :4; +        uint8_t  kind   :4; +    } func; +} action_t; + +/* Action record. For internal use. */ +typedef struct { +    keyevent_t  event; +    uint8_t     tap_count; +} keyrecord_t; + + +/* Tap count: Tap is comprised of press and release within TAP_TERM. + * 0    means no tap. + * >1   means tap. + */  extern uint8_t tap_count; + +/* current tap key event */  extern keyevent_t tapping_event; +/* action function */ +typedef void (*action_func_t)(keyevent_t event, uint8_t opt); + +// TODO: legacy keymap support +void action_exec(keyevent_t event); +void action_call_function(keyevent_t event, uint8_t id); + +  /*   * Utilities for actions.   */ @@ -25,33 +94,36 @@ bool is_tap_key(key_t key);  /* -Action codes -16bit code: action_kind(4bit) + action_parameter(12bit) - + * Action codes + * ============ + * 16bit code: action_kind(4bit) + action_parameter(12bit) + *  Keyboard Keys  -------------  ACT_LMODS(0000):  0000|0000|000000|00    No action -0000|mods|000000|00    Left mods Momentary -0000|mods|000000|01    Left mods OneShot -0000|mods|000000|10    (reserved) -0000|mods|000000|11    (reserved)  0000|0000| keycode     Key +0010|mods|000000|00    Left mods Momentary  0000|mods| keycode     Key+Left mods  ACT_RMODS(0001):  0001|0000|000000|00    No action +0001|0000| keycode     Key(no used)  0001|mods|000000|00    Right mods Momentary -0001|mods|000000|01    Right mods OneShot -0001|mods|000000|10    (reserved) -0001|mods|000000|11    (reserved) -0001|0000| keycode     Key  0001|mods| keycode     Key+Right mods  ACT_LMODS_TAP(0010): +0010|mods|000000|00    Left mods OneShot +0010|mods|000000|01    (reserved) +0010|mods|000000|10    (reserved) +0010|mods|000000|11    (reserved)  0010|mods| keycode     Left mods+tap Key  ACT_RMODS_TAP(0011): +0011|mods|000000|00    Right mods OneShot +0011|mods|000000|01    (reserved) +0011|mods|000000|10    (reserved) +0011|mods|000000|11    (reserved)  0011|mods| keycode     Right mods+tap Key @@ -108,24 +180,22 @@ Extensions(11XX)  NOTE: NOT FIXED  ACT_MACRO(1100): -1100|opt | id(8)      Macro play -1100|1111| id(8)      Macro record +1100|opt | id(8)      Macro play? +1100|1111| id(8)      Macro record?  ACT_COMMAND(1110):  1110|opt | id(8)      Built-in Command exec  ACT_FUNCTION(1111): -1111| address(12)     Function -1111|opt | id(8)      Function -                                                    Macro record(dynamicly) -                                                    Macro play(dynamicly) -TODO: modifier + [tap key /w mod] -    : layerkey + [tap key /w mod] +1111| address(12)     Function? +1111|opt | id(8)      Function? + +TODO: modifier + function by tap?      for example: LShift + '('[Shift+9] and RShift + ')'[Shift+0]      http://deskthority.net/workshop-f7/tmk-keyboard-firmware-collection-t4478.html#p90052 -*/ + */ -enum action_id { +enum action_kind_id {      ACT_LMODS           = 0b0000,      ACT_RMODS           = 0b0001,      ACT_LMODS_TAP       = 0b0010, @@ -144,74 +214,11 @@ enum action_id {      ACT_FUNCTION        = 0b1111  }; -// TODO: not portable across compiler/endianness? -/* -In avr-gcc bit fields seems to be assigned from LSB(bit0) to MSB(bit15).  -AVR looks like a 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 { -        uint16_t code   :8; -        uint16_t opt    :4; -        uint16_t kind   :4; -    } layer; -    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; -    struct action_function { -        uint8_t  id     :8; -        uint8_t  opt    :4; -        uint8_t  kind   :4; -    } func; -} action_t; - - -enum stroke_cmd { -    STROKE_DOWN, -    STROKE_UP, -    STROKE_ALLUP, /* release all keys in reverse order */ +enum acion_param { +    ONE_SHOT            = 0x00,  }; -typedef struct { -    keyevent_t  event; -    uint8_t     tap_count; -} keyrecord_t; - -/* action function */ -typedef void (*action_func_t)(keyevent_t event, uint8_t opt); - -// TODO: legacy keymap support -void action_exec(keyevent_t event); -void action_call_function(keyevent_t event, uint8_t id); - - -// TODO: proper names  /* action_t utility */  #define ACTION_NO                       0  #define ACTION(kind, param)             ((kind)<<12 | (param)) @@ -221,16 +228,12 @@ void action_call_function(keyevent_t event, uint8_t id);  #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, MOD_BITS(mods)<<8 | (key)) +#define ACTION_LMODS_ONESHOT(mods)      ACTION(ACT_LMODS_TAP, MOD_BITS(mods)<<8 | ONE_SHOT)  #define ACTION_RMODS_TAP(mods, key)     ACTION(ACT_RMODS_TAP, MOD_BITS(mods)<<8 | (key))  /* Layer Switch */ @@ -268,15 +271,4 @@ void action_call_function(keyevent_t event, uint8_t id);  /* Function */  #define ACTION_FUNCTION(id, opt)        ACTION(ACT_FUNCTION, (opt)<<8 | id) - -/* 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 */ diff --git a/keyboard/hhkb/keymap.c b/keyboard/hhkb/keymap.c index e4eeb3e39..b74dc71ba 100644 --- a/keyboard/hhkb/keymap.c +++ b/keyboard/hhkb/keymap.c @@ -61,6 +61,8 @@ static const uint16_t PROGMEM fn_actions[] = {      ACTION_LAYER_SET_TAP_KEY(5, KC_SPC),    // Fn5      ACTION_LMODS_TAP(MOD_BIT(KC_LCTL), KC_BSPC), // Fn6      ACTION_RMODS_TAP(MOD_BIT(KC_RCTL), KC_ENT), // Fn7 + +    ACTION_LMODS_TAP(MOD_BIT(KC_LSFT), ONE_SHOT),   // Fn8  }; @@ -81,7 +83,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {      KEYMAP(ESC, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSLS,GRV, \             TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSPC, \             FN6, A,   S,   D,   F,   G,   H,   J,   K,   L,   FN3, QUOT,FN7, \ -           LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, FN2, RSFT,FN1, \ +           FN8, Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, FN2, RSFT,FN1, \                  LGUI,LALT,          FN5,                RALT,FN4),      /* Layer 1: HHKB mode (HHKB Fn) @@ -205,8 +207,12 @@ action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col) {              action.code = ACTION_RMODS(MOD_BIT(key)>>4);              break;  */ -        case KC_FN0 ... KC_FN7: -            action.code = pgm_read_word(&fn_actions[FN_INDEX(key)]); +        case KC_FN0 ... FN_MAX: +            if (FN_INDEX(key) < sizeof(fn_actions) / sizeof(fn_actions[0])) { +                action.code = pgm_read_word(&fn_actions[FN_INDEX(key)]); +            } else { +                action.code = ACTION_NO; +            }              break;          case KC_NO ... KC_UNDEFINED:          default:  | 
