mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-30 21:02:32 +01:00 
			
		
		
		
	Merge pull request #182 from Vifon/modifier-release-fix
Fix the layer-dependent modifiers handling
This commit is contained in:
		
						commit
						153a6fb0d3
					
				
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								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). | ||||
|  | ||||
| @ -53,6 +53,22 @@ 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; | ||||
| } | ||||
| #else | ||||
| void process_action_nocache(keyrecord_t *record) | ||||
| { | ||||
|     process_action(record); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| __attribute__ ((weak)) | ||||
| void process_action_kb(keyrecord_t *record) {} | ||||
| 
 | ||||
| @ -67,7 +83,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(); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -110,9 +110,71 @@ 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 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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 +186,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); | ||||
| } | ||||
|  | ||||
| @ -70,6 +70,17 @@ 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); | ||||
| 
 | ||||
| /* return action depending on current layer status */ | ||||
| action_t layer_switch_get_action(keypos_t key); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Erez Zukerman
						Erez Zukerman