]> git.donarmstrong.com Git - tmk_firmware.git/blobdiff - common/action.c
Fix tap key using delaying_layer and waiting_key.
[tmk_firmware.git] / common / action.c
index d4aae207f416f5ce3a19465d62928b20a08d453b..1a86f16d316406926e3e7dce52bc1589f903dc0f 100644 (file)
@@ -1,6 +1,6 @@
 #include "host.h"
 #include "timer.h"
-//#include "keymap.h"
+#include "keymap.h"
 #include "keycode.h"
 #include "keyboard.h"
 #include "mousekey.h"
@@ -78,8 +78,6 @@ typedef enum { IDLE, DELAYING, WAITING, PRESSING } kbdstate_t;
 
 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)
 {
@@ -96,17 +94,6 @@ static bool anykey_sent_to_host(void)
 }
 
 
-
-/*
-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);
@@ -118,6 +105,7 @@ static void layer_switch(uint8_t new_layer);
 
 /* tap */
 #define TAP_TIME    200
+#define LAYER_DELAY 200
 static keyevent_t last_event = {};
 static uint16_t last_event_time = 0;
 static uint8_t tap_count = 0;
@@ -125,17 +113,27 @@ static uint8_t tap_count = 0;
 /* layer */
 uint8_t default_layer = 0;
 uint8_t current_layer = 0;
-uint8_t waiting_layer = 0;
+keyrecord_t delaying_layer = {};
 
+keyrecord_t waiting_key = {};
 
-void action_exec(action_t action, keyevent_t event)
+// TODO: ring buffer: waiting_keys[]
+/*
+#define WAITING_KEYS_BUFFER 3
+static keyrecord_t waiting_keys[WAITING_KEYS_BUFFER] = {};
+static uint8_t waiting_keys_head = 0;
+static uint8_t waiting_keys_tail = 0;
+static void waiting_key_queue(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;
-    }
+}
+static void waiting_key_dequeue(keyevent_t event)
+{
+}
+*/
+
+static void process(keyevent_t event, action_t action)
+{
+    //action_t action = keymap_get_action(current_layer, event.key.row, event.key.col);
 
     debug("action: "); debug_hex16(action.code); debug("\n");
     debug("kind.id: "); debug_hex(action.kind.id); debug("\n");
@@ -144,79 +142,54 @@ void action_exec(action_t action, keyevent_t event)
     debug("key.mods: "); debug_hex(action.key.mods); debug("\n");
 
     switch (action.kind.id) {
+        /* Key and Mods */
         case ACT_LMODS:
+            // normal key or key plus mods
             if (event.pressed) {
-                register_mods(action.key.mods);
+                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);
-                unregister_mods(action.key.mods);
             }
             break;
         case ACT_RMODS:
             if (event.pressed) {
-                register_mods(action.key.mods<<4);
+                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();
+                }
                 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;
-            }
+        case ACT_LMOD_TAP:
             break;
+        case ACT_RMOD_TAP:
+            break;
+
+        /* other HID usage */
         case ACT_USAGE:
 #ifdef EXTRAKEY_ENABLE
             switch (action.usage.page) {
@@ -237,6 +210,8 @@ void action_exec(action_t action, keyevent_t event)
             }
 #endif
             break;
+
+        /* Mouse key */
         case ACT_MOUSEKEY:
 #ifdef MOUSEKEY_ENABLE
             if (event.pressed) {
@@ -248,155 +223,266 @@ void action_exec(action_t action, keyevent_t event)
             }
 #endif
             break;
-        case ACT_LMOD_TAP:
-        case ACT_RMOD_TAP:
+
+        /* Layer key */
+        case ACT_LAYER_PRESSED:
+            // layer action when pressed
+            switch (action.layer.code) {
+                case 0x00:
+                    if (event.pressed) {
+                        layer_switch(action.layer.opt);
+                    }
+                    break;
+                case 0xF0:
+                    // TODO: tap toggle
+                    break;
+                case 0xFF:
+                    if (event.pressed) {
+                        default_layer = action.layer.opt;
+                        layer_switch(default_layer);
+                    }
+                    break;
+                default:
+                    // with tap key
+                    debug("tap: "); debug_hex(tap_count); debug("\n");
+                    if (event.pressed) {
+                        if (tap_count == 0) {
+                            if (host_has_anykey()) {
+                                register_code(action.layer.code);
+                            } else {
+                                delaying_layer = (keyrecord_t){
+                                    .event = event,
+                                    .action = action,
+                                    .mods = host_get_mods()
+                                };
+                            }
+                        } else if (tap_count > 0) {
+                            register_code(action.layer.code);
+                        }
+                    } else {
+                        // tap key
+                        if (KEYEQ(event.key, delaying_layer.event.key) &&
+                                timer_elapsed(delaying_layer.event.time) < TAP_TIME) {
+                            uint8_t tmp_mods = host_get_mods();
+                            host_set_mods(delaying_layer.mods);
+                            register_code(delaying_layer.action.layer.code);
+                            host_set_mods(tmp_mods);
+                            unregister_code(delaying_layer.action.layer.code);
+                        } else {
+                            unregister_code(action.layer.code);
+                        }
+                        delaying_layer = (keyrecord_t){};
+                    }
+                    break;
+            }
+            break;
+        case ACT_LAYER_RELEASED:
+            switch (action.layer.code) {
+                case 0x00:
+                    if (event.pressed) {
+                        layer_switch(action.layer.opt);
+                    }
+                    break;
+                case 0xF0:
+                    // Ignored. LAYER_RELEASED with tap toggle is invalid action.
+                    break;
+                case 0xFF:
+                    if (!event.pressed) {
+                        default_layer = action.layer.opt;
+                        layer_switch(default_layer);
+                    }
+                    break;
+                default:
+                    // Ignored. LAYER_RELEASED with tap key is invalid action.
+                    break;
+            }
+            break;
+        case ACT_LAYER_BIT:
+            switch (action.layer.code) {
+                case 0x00:
+                    if (event.pressed) {
+                        layer_switch(current_layer | action.layer.opt);
+                    } else {
+                        layer_switch(current_layer & ~action.layer.opt);
+                    }
+                    break;
+                case 0xF0:
+                    // TODO: tap toggle
+                    break;
+                case 0xFF:
+                    // change default layer
+                    if (event.pressed) {
+                        default_layer = current_layer | action.layer.opt;
+                        layer_switch(default_layer);
+                    } else {
+                        default_layer = current_layer & ~action.layer.opt;
+                        layer_switch(default_layer);
+                    }
+                    break;
+                default:
+                    // with tap key
+                    debug("tap: "); debug_hex(tap_count); debug("\n");
+                    if (event.pressed) {
+                        if (tap_count == 0) {
+                            if (host_has_anykey()) {
+                                register_code(action.layer.code);
+                            } else {
+                                delaying_layer = (keyrecord_t){
+                                    .event = event,
+                                    .action = action,
+                                    .mods = keyboard_report->mods
+                                };
+                            }
+                        } else if (tap_count > 0) {
+                            register_code(action.layer.code);
+                        }
+                    } else {
+                        if (tap_count == 0) {
+                            // no tap
+                            layer_switch(current_layer & ~action.layer.opt);
+                        } else if (tap_count == 1) {
+                            // tap
+                            register_code(action.layer.code);
+                        }
+                        unregister_code(action.layer.code);
+                    }
+                    break;
+            }
+        case ACT_LAYER_EXT:
+            switch (action.layer.opt) {
+                case 0x00:
+                    // set default layer when pressed
+                    switch (action.layer.code) {
+                        case 0x00:
+                            if (event.pressed) {
+                                layer_switch(default_layer);
+                            }
+                            break;
+                        case 0xF0:
+                            // TODO: tap toggle
+                            break;
+                        case 0xFF:
+                            if (event.pressed) {
+                                default_layer = current_layer;
+                                layer_switch(default_layer);
+                            }
+                            break;
+                        default:
+                            // TODO: tap key
+                            break;
+                    }
+                    break;
+                case 0x01:
+                    // set default layer when released
+                    switch (action.layer.code) {
+                        case 0x00:
+                            if (!event.pressed) {
+                                layer_switch(default_layer);
+                            }
+                            break;
+                        case 0xFF:
+                            if (!event.pressed) {
+                                default_layer = current_layer;
+                                layer_switch(default_layer);
+                            }
+                            break;
+                        case 0xF0:
+                        default:
+                            // Ignore tap.
+                            if (!event.pressed) {
+                                layer_switch(default_layer);
+                            }
+                            break;
+                    }
+                    break;
+            }
+            break;
+
+        /* Extentions */
         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)
+void action_exec(keyevent_t event)
 {
-    if (event.pressed)
-        key_pressed(code, event);
-    else
-        key_released(code, 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;
+    }
 
-void fn_action(uint8_t code, keyevent_t event)
-{
-}
+    /* When delaying layer switch */
+    if (delaying_layer.action.code) {
+        /* Layer switch when delay time elapses or waiting key is released */
+        if ((timer_elapsed(delaying_layer.event.time) > LAYER_DELAY) ||
+            (!event.pressed && KEYEQ(event.key, waiting_key.event.key))) {
+            /* layer switch */
+            switch (delaying_layer.action.kind.id) {
+                case ACT_LAYER_PRESSED:
+                    layer_switch(delaying_layer.action.layer.opt);
+                    break;
+                case ACT_LAYER_BIT:
+                    layer_switch(current_layer | delaying_layer.action.layer.opt);
+                    break;
+            }
+            delaying_layer = (keyrecord_t){};
 
-/* 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;
+            /* Process waiting keys in new layer */
+            if (waiting_key.event.time) {
+                uint8_t tmp_mods = host_get_mods();
                 host_set_mods(waiting_key.mods);
-                keymap_process_event(waiting_key.event);
+                process(waiting_key.event, keymap_get_action(current_layer,
+                                                             waiting_key.event.key.row,
+                                                             waiting_key.event.key.col));
                 host_set_mods(tmp_mods);
-                keymap_process_event(event);
-            } else {
-                unregister_code(code);
+                waiting_key = (keyrecord_t){};
             }
-            break;
+        }
+        /* when delaying layer key is released within delay term */
+        else if (!event.pressed && KEYEQ(event.key, delaying_layer.event.key)) {
+            /* tap key down */
+            uint8_t tmp_mods = host_get_mods();
+            host_set_mods(delaying_layer.mods);
+            register_code(delaying_layer.action.layer.code);
+            delaying_layer = (keyrecord_t){};
+
+            /* process waiting keys */
+            if (waiting_key.event.time) {
+                host_set_mods(waiting_key.mods);
+                process(waiting_key.event, waiting_key.action);
+                waiting_key = (keyrecord_t){};
+            }
+            host_set_mods(tmp_mods);
+        }
     }
-}
 
-/* 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) {
+    action_t action = keymap_get_action(current_layer, event.key.row, event.key.col);
+
+    /* postpone key-down events while delaying layer */
+    if (delaying_layer.action.code) {
+        if (event.pressed) {
+            // TODO: waiting_keys[]
+            waiting_key = (keyrecord_t){
                 .event = event,
-                .code = code,
-                .mods = keyboard_report->mods,
-                .time = timer_read()
+                .action = action,
+                .mods = host_get_mods()
             };
-            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;
+        } else {
+            process(event, action);
+        }
+    } else {
+        process(event, action);
     }
+
+    /* last event */
+    last_event = event;
+    last_event_time = timer_read();
 }
-#endif
 
 
 static void register_code(uint8_t code)
@@ -415,89 +501,6 @@ static void register_code(uint8_t 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)
@@ -510,20 +513,6 @@ static void unregister_code(uint8_t 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)
@@ -568,5 +557,6 @@ static void layer_switch(uint8_t new_layer)
 
         current_layer = new_layer;
         clear_keyboard_but_mods(); // To avoid stuck keys
+        // TODO: update mods with full scan of matrix? if modifier changes between layers
     }
 }