]> git.donarmstrong.com Git - qmk_firmware.git/commitdiff
Merge branch 'master' of https://github.com/jackhumbert/qmk_firmware into modifier...
authorWojciech Siewierski <wojciech.siewierski@onet.pl>
Sun, 3 Apr 2016 09:14:08 +0000 (11:14 +0200)
committerWojciech Siewierski <wojciech.siewierski@onet.pl>
Sun, 3 Apr 2016 09:23:00 +0000 (11:23 +0200)
README.md
tmk_core/common/action.c
tmk_core/common/action.h
tmk_core/common/action_layer.c
tmk_core/common/action_layer.h

index 98573306793ab5e534413e246ce74960596dff78..ab7373023a02ef9922ff06671ff5ad7cf7ea219d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -98,6 +98,27 @@ We've added shortcuts to make common modifier/tap (mod-tap) mappings more compac
 
 `DF(layer)` - sets default layer to *layer*. The default layer is the one at the "bottom" of the layer stack - the ultimate fallback layer. This currently does not persist over power loss. When you plug the keyboard back in, layer 0 will always be the default. It is theoretically possible to work around that, but that's not what `DF` does.
 
+### Prevent stuck modifiers
+
+Consider the following scenario:
+
+1. Layer 0 has a key defined as Shift.
+2. The same key is defined on layer 1 as the letter A.
+3. User presses Shift.
+4. User switches to layer 1 for whatever reason.
+5. User releases Shift, or rather the letter A.
+6. User switches back to layer 0.
+
+Shift was actually never released and is still considered pressed.
+
+If such situation bothers you add this to your `config.h`:
+
+    #define PREVENT_STUCK_MODIFIERS
+
+This option uses 5 bytes of memory per every 8 keys on the keyboard
+rounded up (5 bits per key). For example on Planck (48 keys) it uses
+(48/8)\*5 = 30 bytes.
+
 ### Remember: These are just aliases
 
 These functions work the same way that their `ACTION_*` functions do - they're just quick aliases. To dig into all of the tmk ACTION_* functions, please see the [TMK documentation](https://github.com/jackhumbert/qmk_firmware/blob/master/tmk_core/doc/keymap.md#2-action).
index 2ccc0e0b947bdd79342e3b31e02b89a02de72397..20e1fc6149f232912846f5db789952440a315faa 100644 (file)
@@ -53,6 +53,63 @@ void action_exec(keyevent_t event)
 #endif
 }
 
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+bool disable_action_cache = false;
+uint8_t source_layers_cache[5][(MATRIX_ROWS * MATRIX_COLS + 7) / 8] = {0};
+
+void process_action_nocache(keyrecord_t *record)
+{
+    disable_action_cache = true;
+    process_action(record);
+    disable_action_cache = false;
+}
+#else
+void process_action_nocache(keyrecord_t *record)
+{
+    process_action(record);
+}
+#endif
+
+/*
+ * Make sure the action triggered when the key is released is the same
+ * one as the one triggered on press. It's important for the mod keys
+ * when the layer is switched after the down event but before the up
+ * event as they may get stuck otherwise.
+ */
+action_t store_or_get_action(bool pressed, keypos_t key)
+{
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+    if (disable_action_cache) {
+        return layer_switch_get_action(key);
+    }
+    const uint8_t key_number = key.col + (key.row * MATRIX_COLS);
+    const uint8_t storage_row = key_number / 8;
+    const uint8_t storage_bit = key_number % 8;
+    uint8_t layer;
+    if (pressed) {
+        layer = layer_switch_get_layer(key);
+        for (uint8_t bit_number = 0; bit_number < 5; bit_number++) {
+            source_layers_cache[bit_number][storage_row] ^=
+                (-((layer & (1U << bit_number)) != 0)
+                 ^ source_layers_cache[bit_number][storage_row])
+                & (1U << storage_bit);
+        }
+    }
+    else {
+        layer = 0;
+        for (uint8_t bit_number = 0; bit_number < 5; bit_number++) {
+            layer |=
+                ((source_layers_cache[bit_number][storage_row]
+                  & (1U << storage_bit)) != 0)
+                << bit_number;
+        }
+    }
+    return action_for_key(layer, key);
+#else
+    return layer_switch_get_action(key);
+#endif
+}
+
 __attribute__ ((weak))
 void process_action_kb(keyrecord_t *record) {}
 
@@ -67,7 +124,7 @@ void process_action(keyrecord_t *record)
 
     process_action_kb(record);
 
-    action_t action = layer_switch_get_action(event.key);
+    action_t action = store_or_get_action(event.pressed, event.key);
     dprint("ACTION: "); debug_action(action);
 #ifndef NO_ACTION_LAYER
     dprint(" layer_state: "); layer_debug();
index 9f528af4b98ddd5603f17efaeb59038baa60f285..44ec3047ba5a03a0fdb33c39edee4085c7b7e92c 100644 (file)
@@ -62,6 +62,10 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt);
 void process_action_kb(keyrecord_t *record);
 
 /* Utilities for actions.  */
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+extern bool disable_action_cache;
+#endif
+void process_action_nocache(keyrecord_t *record);
 void process_action(keyrecord_t *record);
 void register_code(uint8_t code);
 void unregister_code(uint8_t code);
index c535615f44d44a8fa669e1f86825142b9c56b616..76164adb5d80eebbb036226d91784615fbea0b77 100644 (file)
@@ -111,8 +111,7 @@ void layer_debug(void)
 #endif
 
 
-
-action_t layer_switch_get_action(keypos_t key)
+int8_t layer_switch_get_layer(keypos_t key)
 {
     action_t action;
     action.code = ACTION_TRANSPARENT;
@@ -124,15 +123,18 @@ action_t layer_switch_get_action(keypos_t key)
         if (layers & (1UL<<i)) {
             action = action_for_key(i, key);
             if (action.code != ACTION_TRANSPARENT) {
-                return action;
+                return i;
             }
         }
     }
     /* fall back to layer 0 */
-    action = action_for_key(0, key);
-    return action;
+    return 0;
 #else
-    action = action_for_key(biton32(default_layer_state), key);
-    return action;
+    return biton32(default_layer_state);
 #endif
 }
+
+action_t layer_switch_get_action(keypos_t key)
+{
+    return action_for_key(layer_switch_get_layer(key), key);
+}
index b6da353cfdbe851d6bfb5689b6173135b8697d84..1a313a2590472a72efb581557191cc8fbbad7ba2 100644 (file)
@@ -71,6 +71,9 @@ void layer_xor(uint32_t state);
 #endif
 
 
+/* return the topmost non-transparent layer currently associated with key */
+int8_t layer_switch_get_layer(keypos_t key);
+
 /* return action depending on current layer status */
 action_t layer_switch_get_action(keypos_t key);