From bfd7fe586297d70f824a402fd476c3daa889fa56 Mon Sep 17 00:00:00 2001 From: tmk Date: Sun, 27 Jan 2013 16:38:19 +0900 Subject: [PATCH] Add oneshot modifier action. --- common/action.c | 201 +++++++++++++++++++++++++++-------------- common/action.h | 198 +++++++++++++++++++--------------------- 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(); + { + 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); } - 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(); - } - 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: