From c2480884aa1321ec4a0364f773476f0e7f7d3069 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sat, 5 Mar 2016 14:42:17 +0100 Subject: Fix the layer-dependent modifiers handling Closes #181. --- tmk_core/common/action.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'tmk_core') diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 77ea39e94..be06e12aa 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(); -- cgit v1.2.3 From 8d55a12a9538742f510087f14fc59eb813b2ef42 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 8 Mar 2016 08:48:43 +0100 Subject: Document the issue of stuck modifiers --- README.md | 20 ++++++++++++++++++++ tmk_core/common/action.c | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'tmk_core') diff --git a/README.md b/README.md index 6a6bbed40..d8dfd7c2b 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 be06e12aa..26a5fad7a 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) { -- cgit v1.2.3 From 20dd9c032616722a54174d53b0f8824f639b5263 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 13 Mar 2016 00:18:20 +0100 Subject: 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(+) (limited to 'tmk_core') diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 26a5fad7a..1d3b73811 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 8a4736d7b..34a794db2 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); -- cgit v1.2.3 From 73cb87740bd814c95007f9ef6ce3dcd542a62afd Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 15 Mar 2016 16:03:30 +0100 Subject: 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(-) (limited to 'tmk_core') diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 1d3b73811..0a3822a06 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 34a794db2..533e5d1a0 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); -- cgit v1.2.3 From a5cdc3aab1c430916eae66d4d9d751808613e700 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Tue, 15 Mar 2016 16:51:50 +0100 Subject: 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(-) (limited to 'tmk_core') diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index 0a3822a06..fc09383ee 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 533e5d1a0..7a60f320e 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); -- cgit v1.2.3 From b4f442dfeaf4d434ae0d8459dc5199cd8fefc1c7 Mon Sep 17 00:00:00 2001 From: Wojciech Siewierski Date: Sun, 27 Mar 2016 23:50:07 +0200 Subject: 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(-) (limited to 'tmk_core') diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c index fc09383ee..acc6d11ea 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 7a60f320e..2b43d001e 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 c535615f4..76164adb5 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<