From c2480884aa1321ec4a0364f773476f0e7f7d3069 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sat, 5 Mar 2016 14:42:17 +0100 Subject: [PATCH 01/23] Fix the layer-dependent modifiers handling Closes #181. --- tmk_core/common/action.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 77ea39e942..be06e12aae 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -53,6 +53,26 @@ void action_exec(keyevent_t event) #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) +{ +#ifndef NO_ACTION_LAYER + static action_t pressed_actions[MATRIX_ROWS][MATRIX_COLS]; + + if (pressed) { + pressed_actions[key.row][key.col] = layer_switch_get_action(key); + } + return pressed_actions[key.row][key.col]; +#else + return layer_switch_get_action(key); +#endif +} + void process_action(keyrecord_t *record) { keyevent_t event = record->event; @@ -62,7 +82,7 @@ void process_action(keyrecord_t *record) if (IS_NOEVENT(event)) { return; } - 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(); From 8d55a12a9538742f510087f14fc59eb813b2ef42 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 8 Mar 2016 08:48:43 +0100 Subject: [PATCH 02/23] Document the issue of stuck modifiers --- README.md | 20 ++++++++++++++++++++ tmk_core/common/action.c | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a6bbed40b..d8dfd7c2bc 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,26 @@ 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 + +Warning: This option uses up 2 bytes of memory per key. For example on +Planck it uses 2\*4\*12=96 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). diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index be06e12aae..26a5fad7ac 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -61,7 +61,7 @@ void action_exec(keyevent_t event) */ action_t store_or_get_action(bool pressed, keypos_t key) { -#ifndef NO_ACTION_LAYER +#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) static action_t pressed_actions[MATRIX_ROWS][MATRIX_COLS]; if (pressed) { From 20dd9c032616722a54174d53b0f8824f639b5263 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 13 Mar 2016 00:18:20 +0100 Subject: [PATCH 03/23] process_action may be called either with key cache or without it If one wants to temporarily disable the key cache (for example because it interferes with a macro), `disable_action_cache` must be set to `true`. `process_action_nocache` is a simple wrapper doing just that for a single call. --- tmk_core/common/action.c | 15 +++++++++++++++ tmk_core/common/action.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 26a5fad7ac..1d3b738110 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -53,6 +53,17 @@ void action_exec(keyevent_t event) #endif } +#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +bool disable_action_cache = false; + +void process_action_nocache(keyrecord_t *record) +{ + disable_action_cache = true; + process_action(record); + disable_action_cache = false; +} +#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 @@ -64,6 +75,10 @@ action_t store_or_get_action(bool pressed, keypos_t key) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) static action_t pressed_actions[MATRIX_ROWS][MATRIX_COLS]; + if (disable_action_cache) { + return layer_switch_get_action(key); + } + if (pressed) { pressed_actions[key.row][key.col] = layer_switch_get_action(key); } diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h index 8a4736d7bc..34a794db29 100644 --- a/tmk_core/common/action.h +++ b/tmk_core/common/action.h @@ -59,6 +59,10 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt); void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); /* Utilities for actions. */ +#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +extern bool disable_action_cache; +void process_action_nocache(keyrecord_t *record); +#endif void process_action(keyrecord_t *record); void register_code(uint8_t code); void unregister_code(uint8_t code); From 73cb87740bd814c95007f9ef6ce3dcd542a62afd Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 15 Mar 2016 16:03:30 +0100 Subject: [PATCH 04/23] Always provide an implementation of process_action_nocache --- tmk_core/common/action.c | 5 +++++ tmk_core/common/action.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 1d3b738110..0a3822a06c 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -62,6 +62,11 @@ void process_action_nocache(keyrecord_t *record) process_action(record); disable_action_cache = false; } +#else +void process_action_nocache(keyrecord_t *record) +{ + process_action(record); +} #endif /* diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h index 34a794db29..533e5d1a01 100644 --- a/tmk_core/common/action.h +++ b/tmk_core/common/action.h @@ -61,8 +61,8 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); /* Utilities for actions. */ #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) extern bool disable_action_cache; -void process_action_nocache(keyrecord_t *record); #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); From a5cdc3aab1c430916eae66d4d9d751808613e700 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 15 Mar 2016 16:51:50 +0100 Subject: [PATCH 05/23] Expose the pressed_actions_cache global variable --- tmk_core/common/action.c | 7 +++---- tmk_core/common/action.h | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 0a3822a06c..fc09383ee0 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,6 +55,7 @@ void action_exec(keyevent_t event) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) bool disable_action_cache = false; +action_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; void process_action_nocache(keyrecord_t *record) { @@ -78,16 +79,14 @@ void process_action_nocache(keyrecord_t *record) action_t store_or_get_action(bool pressed, keypos_t key) { #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) - static action_t pressed_actions[MATRIX_ROWS][MATRIX_COLS]; - if (disable_action_cache) { return layer_switch_get_action(key); } if (pressed) { - pressed_actions[key.row][key.col] = layer_switch_get_action(key); + pressed_actions_cache[key.row][key.col] = layer_switch_get_action(key); } - return pressed_actions[key.row][key.col]; + return pressed_actions_cache[key.row][key.col]; #else return layer_switch_get_action(key); #endif diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h index 533e5d1a01..7a60f320e7 100644 --- a/tmk_core/common/action.h +++ b/tmk_core/common/action.h @@ -61,6 +61,7 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); /* Utilities for actions. */ #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) extern bool disable_action_cache; +extern action_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; #endif void process_action_nocache(keyrecord_t *record); void process_action(keyrecord_t *record); From b4f442dfeaf4d434ae0d8459dc5199cd8fefc1c7 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 27 Mar 2016 23:50:07 +0200 Subject: [PATCH 06/23] Cut the memory consumption of PREVENT_STUCK_MODIFIERS in half --- tmk_core/common/action.c | 6 +++--- tmk_core/common/action.h | 2 +- tmk_core/common/action_layer.c | 16 +++++++++------- tmk_core/common/action_layer.h | 3 +++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index fc09383ee0..acc6d11eab 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,7 @@ void action_exec(keyevent_t event) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) bool disable_action_cache = false; -action_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; +int8_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; void process_action_nocache(keyrecord_t *record) { @@ -84,9 +84,9 @@ action_t store_or_get_action(bool pressed, keypos_t key) } if (pressed) { - pressed_actions_cache[key.row][key.col] = layer_switch_get_action(key); + pressed_actions_cache[key.row][key.col] = layer_switch_get_layer(key); } - return pressed_actions_cache[key.row][key.col]; + return action_for_key(pressed_actions_cache[key.row][key.col], key); #else return layer_switch_get_action(key); #endif diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h index 7a60f320e7..2b43d001e1 100644 --- a/tmk_core/common/action.h +++ b/tmk_core/common/action.h @@ -61,7 +61,7 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); /* Utilities for actions. */ #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) extern bool disable_action_cache; -extern action_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; +extern int8_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; #endif void process_action_nocache(keyrecord_t *record); void process_action(keyrecord_t *record); diff --git a/tmk_core/common/action_layer.c b/tmk_core/common/action_layer.c index c535615f44..76164adb5d 100644 --- a/tmk_core/common/action_layer.c +++ b/tmk_core/common/action_layer.c @@ -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< Date: Mon, 28 Mar 2016 00:25:43 +0200 Subject: [PATCH 07/23] Update the memory consumption of PREVENT_STUCK_MODIFIERS in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8dfd7c2bc..083880b4e2 100644 --- a/README.md +++ b/README.md @@ -115,8 +115,8 @@ If such situation bothers you add this to your `config.h`: #define PREVENT_STUCK_MODIFIERS -Warning: This option uses up 2 bytes of memory per key. For example on -Planck it uses 2\*4\*12=96 bytes. +Warning: This option uses up 1 byte of memory per key. For example on +Planck it uses 4\*12=96 bytes. ### Remember: These are just aliases From 1a09e96b9558f3d08394ec50546cfb366271f014 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Mon, 28 Mar 2016 10:05:42 +0200 Subject: [PATCH 08/23] Update the memory consumption total value in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 083880b4e2..dc5f612f67 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ If such situation bothers you add this to your `config.h`: #define PREVENT_STUCK_MODIFIERS Warning: This option uses up 1 byte of memory per key. For example on -Planck it uses 4\*12=96 bytes. +Planck it uses 4\*12=48 bytes. ### Remember: These are just aliases From 317455178d177efc8eccdb8dc69ac18baf9e66e7 Mon Sep 17 00:00:00 2001 From: Eric-L-T Date: Fri, 1 Apr 2016 13:43:49 -0700 Subject: [PATCH 09/23] Update action.c --- tmk_core/common/action.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index acc6d11eab..4457d16d86 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,7 @@ void action_exec(keyevent_t event) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) bool disable_action_cache = false; -int8_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; +uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS) / 8) ? ((MATRIX_ROWS * MATRIX_COLS) / 8) : 1]; void process_action_nocache(keyrecord_t *record) { @@ -82,11 +82,22 @@ action_t store_or_get_action(bool pressed, keypos_t key) if (disable_action_cache) { return layer_switch_get_action(key); } - + uint8_t key_number = (key.col + (key.row * MATRIX_COLS)); + uint8_t storage_row = key_number / 8; + uint8_t storage_bit = key_number % 8; + uint8_t layer; if (pressed) { - pressed_actions_cache[key.row][key.col] = layer_switch_get_layer(key); + layer = layer_switch_get_layer(key); + for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { + source_layers_cache[bit_number][storage_row] ^= (-(!!(layer & (1 << bit_number)) ^ source_layers_cache[bit_number][storage_row])) & (1 << storage_bit); + } + } else { + layer = 0; + for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { + layer |= (!!(source_layers_cache[bit_number][storage_row] & (1 << storage_bit))) << bit_number; + } } - return action_for_key(pressed_actions_cache[key.row][key.col], key); + return action_for_key(layer, key); #else return layer_switch_get_action(key); #endif From cd8dd1b6d6a68c1d6ba48ba58e6ddad7dbbce6c2 Mon Sep 17 00:00:00 2001 From: Eric-L-T Date: Fri, 1 Apr 2016 13:45:01 -0700 Subject: [PATCH 10/23] Update action.h --- tmk_core/common/action.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h index 2b43d001e1..533e5d1a01 100644 --- a/tmk_core/common/action.h +++ b/tmk_core/common/action.h @@ -61,7 +61,6 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); /* Utilities for actions. */ #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) extern bool disable_action_cache; -extern int8_t pressed_actions_cache[MATRIX_ROWS][MATRIX_COLS]; #endif void process_action_nocache(keyrecord_t *record); void process_action(keyrecord_t *record); From 9a35f01c5516081a8c503d2344f0d082b1a29cd5 Mon Sep 17 00:00:00 2001 From: Eric-L-T Date: Fri, 1 Apr 2016 13:49:03 -0700 Subject: [PATCH 11/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 4457d16d86..9ba03675a1 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -82,7 +82,7 @@ action_t store_or_get_action(bool pressed, keypos_t key) if (disable_action_cache) { return layer_switch_get_action(key); } - uint8_t key_number = (key.col + (key.row * MATRIX_COLS)); + uint8_t key_number = key.col + (key.row * MATRIX_COLS); uint8_t storage_row = key_number / 8; uint8_t storage_bit = key_number % 8; uint8_t layer; From 420fc8620bfd47604848066b9d3798fb68a12e03 Mon Sep 17 00:00:00 2001 From: Eric-L-T Date: Fri, 1 Apr 2016 18:26:43 -0700 Subject: [PATCH 12/23] Update action.c --- tmk_core/common/action.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 9ba03675a1..e4cbac9e80 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -82,18 +82,18 @@ action_t store_or_get_action(bool pressed, keypos_t key) if (disable_action_cache) { return layer_switch_get_action(key); } - uint8_t key_number = key.col + (key.row * MATRIX_COLS); - uint8_t storage_row = key_number / 8; - uint8_t storage_bit = key_number % 8; - uint8_t layer; + int8_t key_number = key.col + (key.row * MATRIX_COLS); + int8_t storage_row = key_number / 8; + int8_t storage_bit = key_number % 8; + int8_t layer; if (pressed) { layer = layer_switch_get_layer(key); - for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { + for (int8_t bit_number = 0; bit_number <= 4; bit_number++) { source_layers_cache[bit_number][storage_row] ^= (-(!!(layer & (1 << bit_number)) ^ source_layers_cache[bit_number][storage_row])) & (1 << storage_bit); } } else { layer = 0; - for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { + for (int8_t bit_number = 0; bit_number <= 4; bit_number++) { layer |= (!!(source_layers_cache[bit_number][storage_row] & (1 << storage_bit))) << bit_number; } } From 307f1dee21ba8ffc94d50b6b9338d54fa2e4d191 Mon Sep 17 00:00:00 2001 From: Eric-L-T Date: Fri, 1 Apr 2016 19:54:02 -0700 Subject: [PATCH 13/23] Update action.c --- tmk_core/common/action.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index e4cbac9e80..eecfdbb6da 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -82,19 +82,19 @@ action_t store_or_get_action(bool pressed, keypos_t key) if (disable_action_cache) { return layer_switch_get_action(key); } - int8_t key_number = key.col + (key.row * MATRIX_COLS); - int8_t storage_row = key_number / 8; - int8_t storage_bit = key_number % 8; - int8_t layer; + uint8_t key_number = key.col + (key.row * MATRIX_COLS); + uint8_t storage_row = key_number / 8; + uint8_t storage_bit = key_number % 8; + uint8_t layer; if (pressed) { layer = layer_switch_get_layer(key); - for (int8_t bit_number = 0; bit_number <= 4; bit_number++) { - source_layers_cache[bit_number][storage_row] ^= (-(!!(layer & (1 << bit_number)) ^ source_layers_cache[bit_number][storage_row])) & (1 << storage_bit); + for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { + source_layers_cache[bit_number][storage_row] ^= (-(!!(layer & (1U << bit_number)) ^ source_layers_cache[bit_number][storage_row])) & (1U << storage_bit); } } else { layer = 0; - for (int8_t bit_number = 0; bit_number <= 4; bit_number++) { - layer |= (!!(source_layers_cache[bit_number][storage_row] & (1 << storage_bit))) << bit_number; + for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { + layer |= (uint8_t)(!!(source_layers_cache[bit_number][storage_row] & (1U << storage_bit))) << bit_number; } } return action_for_key(layer, key); From f5365d1c1c619c5cb85b9b1ba97ebd04a7f56e05 Mon Sep 17 00:00:00 2001 From: Eric-L-T Date: Fri, 1 Apr 2016 20:04:13 -0700 Subject: [PATCH 14/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index eecfdbb6da..f6fc8b0056 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -89,7 +89,7 @@ action_t store_or_get_action(bool pressed, keypos_t key) if (pressed) { layer = layer_switch_get_layer(key); for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { - source_layers_cache[bit_number][storage_row] ^= (-(!!(layer & (1U << bit_number)) ^ source_layers_cache[bit_number][storage_row])) & (1U << storage_bit); + source_layers_cache[bit_number][storage_row] ^= (-(bool)((layer & (1U << bit_number)) != 0) ^ source_layers_cache[bit_number][storage_row])) & (1U << storage_bit); } } else { layer = 0; From 680301e3e3f837aa4f8bda403af3fc42156516fa Mon Sep 17 00:00:00 2001 From: eltang Date: Sat, 2 Apr 2016 06:48:44 -0700 Subject: [PATCH 15/23] Update action.c --- tmk_core/common/action.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index f6fc8b0056..8735c7d648 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -91,7 +91,8 @@ action_t store_or_get_action(bool pressed, keypos_t key) for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { source_layers_cache[bit_number][storage_row] ^= (-(bool)((layer & (1U << bit_number)) != 0) ^ source_layers_cache[bit_number][storage_row])) & (1U << storage_bit); } - } else { + } + else { layer = 0; for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { layer |= (uint8_t)(!!(source_layers_cache[bit_number][storage_row] & (1U << storage_bit))) << bit_number; From fddccc95fe480a2ed039ffdac6aa9f3fac1f444f Mon Sep 17 00:00:00 2001 From: eltang Date: Sat, 2 Apr 2016 09:13:13 -0700 Subject: [PATCH 16/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 8735c7d648..a3c5b4c5a9 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -95,7 +95,7 @@ action_t store_or_get_action(bool pressed, keypos_t key) else { layer = 0; for (uint8_t bit_number = 0; bit_number <= 4; bit_number++) { - layer |= (uint8_t)(!!(source_layers_cache[bit_number][storage_row] & (1U << storage_bit))) << bit_number; + layer |= (uint8_t)((source_layers_cache[bit_number][storage_row] & (1U << storage_bit)) != 0) << bit_number; } } return action_for_key(layer, key); From da101b886689b3d2a8e4246ed20dee5f066bb1a1 Mon Sep 17 00:00:00 2001 From: eltang Date: Sat, 2 Apr 2016 09:29:32 -0700 Subject: [PATCH 17/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index a3c5b4c5a9..ae4e5545cf 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,7 @@ void action_exec(keyevent_t event) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) bool disable_action_cache = false; -uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS) / 8) ? ((MATRIX_ROWS * MATRIX_COLS) / 8) : 1]; +uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS) / 8) ? ((MATRIX_ROWS * MATRIX_COLS) / 8) : 1] = {}; void process_action_nocache(keyrecord_t *record) { From f4f592910c51c048b1e1a08408ce16fd14eb3c32 Mon Sep 17 00:00:00 2001 From: eltang Date: Sat, 2 Apr 2016 09:34:01 -0700 Subject: [PATCH 18/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index ae4e5545cf..43d03f744c 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,7 @@ void action_exec(keyevent_t event) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) bool disable_action_cache = false; -uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS) / 8) ? ((MATRIX_ROWS * MATRIX_COLS) / 8) : 1] = {}; +uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS) / 8) ? ((MATRIX_ROWS * MATRIX_COLS) / 8) : 1] = {0}; void process_action_nocache(keyrecord_t *record) { From 6c8e374d572f1cf0b62beb2a9718de84202c8a41 Mon Sep 17 00:00:00 2001 From: eltang Date: Sat, 2 Apr 2016 09:59:53 -0700 Subject: [PATCH 19/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 43d03f744c..f47256de77 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,7 @@ void action_exec(keyevent_t event) #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) bool disable_action_cache = false; -uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS) / 8) ? ((MATRIX_ROWS * MATRIX_COLS) / 8) : 1] = {0}; +uint8_t source_layers_cache[5][((MATRIX_ROWS * MATRIX_COLS + 7) / 8)] = {0}; void process_action_nocache(keyrecord_t *record) { From 5a9091689c3e1b4c444f56c9cb335817dc9fc2bb Mon Sep 17 00:00:00 2001 From: eltang Date: Sat, 2 Apr 2016 10:00:31 -0700 Subject: [PATCH 20/23] Update action.c --- tmk_core/common/action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index f47256de77..bf609f5e7b 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,7 @@ void action_exec(keyevent_t event) #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}; +uint8_t source_layers_cache[5][(MATRIX_ROWS * MATRIX_COLS + 7) / 8] = {0}; void process_action_nocache(keyrecord_t *record) { From 4dce7258d1b31be0d91f6de0693a10917f514dd8 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sat, 2 Apr 2016 18:00:28 +0200 Subject: [PATCH 21/23] Cleanup after merge - remove a superfluous parenthesis - wrap lines longer than 80 characters - add const specifiers where appropriate - remove unnecessary casts --- tmk_core/common/action.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index bf609f5e7b..78596a69cf 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -82,20 +82,26 @@ action_t store_or_get_action(bool pressed, keypos_t key) if (disable_action_cache) { return layer_switch_get_action(key); } - uint8_t key_number = key.col + (key.row * MATRIX_COLS); - uint8_t storage_row = key_number / 8; - uint8_t storage_bit = key_number % 8; + 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 <= 4; bit_number++) { - source_layers_cache[bit_number][storage_row] ^= (-(bool)((layer & (1U << bit_number)) != 0) ^ source_layers_cache[bit_number][storage_row])) & (1U << storage_bit); + 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 <= 4; bit_number++) { - layer |= (uint8_t)((source_layers_cache[bit_number][storage_row] & (1U << storage_bit)) != 0) << bit_number; + 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); From 8ef14d09b8451b3f2a77e6f019922eae0ac43642 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sat, 2 Apr 2016 19:45:02 +0200 Subject: [PATCH 22/23] Update PREVENT_STUCK_MODIFIERS documentation in README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dc5f612f67..82b2771652 100644 --- a/README.md +++ b/README.md @@ -115,8 +115,9 @@ If such situation bothers you add this to your `config.h`: #define PREVENT_STUCK_MODIFIERS -Warning: This option uses up 1 byte of memory per key. For example on -Planck it uses 4\*12=48 bytes. +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 From 567f256c5d4598adb4dcd63fa4e4a7b4df553b12 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 5 Apr 2016 10:54:47 +0200 Subject: [PATCH 23/23] Refactor the source layer cache encoding --- tmk_core/common/action.c | 41 ---------------------- tmk_core/common/action_layer.c | 63 ++++++++++++++++++++++++++++++++++ tmk_core/common/action_layer.h | 8 +++++ 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 20e1fc6149..6aa6dc2601 100644 --- a/tmk_core/common/action.c +++ b/tmk_core/common/action.c @@ -55,7 +55,6 @@ void action_exec(keyevent_t event) #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) { @@ -70,46 +69,6 @@ void process_action_nocache(keyrecord_t *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) {} diff --git a/tmk_core/common/action_layer.c b/tmk_core/common/action_layer.c index 76164adb5d..fc721a7323 100644 --- a/tmk_core/common/action_layer.c +++ b/tmk_core/common/action_layer.c @@ -110,6 +110,69 @@ void layer_debug(void) } #endif +#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +uint8_t source_layers_cache[MAX_LAYER_BITS][(MATRIX_ROWS * MATRIX_COLS + 7) / 8] = {0}; + +void update_source_layers_cache(keypos_t key, uint8_t layer) +{ + 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; + + for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { + source_layers_cache[bit_number][storage_row] ^= + (-((layer & (1U << bit_number)) != 0) + ^ source_layers_cache[bit_number][storage_row]) + & (1U << storage_bit); + } +} + +uint8_t read_source_layers_cache(keypos_t 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 = 0; + + for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) { + layer |= + ((source_layers_cache[bit_number][storage_row] + & (1U << storage_bit)) != 0) + << bit_number; + } + + return layer; +} +#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); + } + + uint8_t layer; + + if (pressed) { + layer = layer_switch_get_layer(key); + update_source_layers_cache(key, layer); + } + else { + layer = read_source_layers_cache(key); + } + return action_for_key(layer, key); +#else + return layer_switch_get_action(key); +#endif +} + int8_t layer_switch_get_layer(keypos_t key) { diff --git a/tmk_core/common/action_layer.h b/tmk_core/common/action_layer.h index 1a313a2590..3a4b1e3349 100644 --- a/tmk_core/common/action_layer.h +++ b/tmk_core/common/action_layer.h @@ -70,6 +70,14 @@ void layer_xor(uint32_t state); #define layer_debug() #endif +/* pressed actions cache */ +#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS) +/* The number of bits needed to represent the layer number: log2(32). */ +#define MAX_LAYER_BITS 5 +void update_source_layers_cache(keypos_t key, uint8_t layer); +uint8_t read_source_layers_cache(keypos_t key); +#endif +action_t store_or_get_action(bool pressed, keypos_t key); /* return the topmost non-transparent layer currently associated with key */ int8_t layer_switch_get_layer(keypos_t key);