]> git.friedersdorff.com Git - max/tmk_keyboard.git/commitdiff
Add oneshot modifier action.
authortmk <nobody@nowhere>
Sun, 27 Jan 2013 07:38:19 +0000 (16:38 +0900)
committertmk <nobody@nowhere>
Sun, 27 Jan 2013 07:38:19 +0000 (16:38 +0900)
common/action.c
common/action.h
keyboard/hhkb/keymap.c

index db31613bf625740960d6086a725fbeadf45dc3d2..22f0bf0a0db9edac1f417ae2985c3d39fc7a35e9 100644 (file)
@@ -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();
         }
index 327a009ef9a0ba599f35df3e47fdde535d6bb4b2..1b5b30d865153953f5641c7523b250acf5399a2e 100644 (file)
@@ -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 */
index e4eeb3e39f17d54985a9d50e71b092d8e09a0a98..b74dc71ba5ce8a4b86d3fc31c1ae7cb450bada51 100644 (file)
@@ -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: