diff --git a/docs/config_options.md b/docs/config_options.md index 91c17cf09d7..cf728926483 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -142,6 +142,10 @@ If you define these options you will enable the associated feature, which may in * Enables the `QK_MAKE` keycode * `#define STRICT_LAYER_RELEASE` * force a key release to be evaluated using the current layer stack instead of remembering which layer it came from (used for advanced cases) +* `#define KEYCODE_CACHE_ENABLE` + * Cache keycode for pressed keys, to be used on key release, across entire physical keyboard layout. +* `#define KEYCODE_CACHE_LIMIT 10` + * Optionally limit the number of keycodes able to be cached. Keys pressed beyond the limit will behave as without using the keycode cache. ## Behaviors That Can Be Configured diff --git a/quantum/action_layer.c b/quantum/action_layer.c index 5828dcb8240..db9ae8e3496 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c @@ -306,6 +306,76 @@ uint8_t read_source_layers_cache(keypos_t key) { # endif // ENCODER_MAP_ENABLE return 0; } + +# ifdef KEYCODE_CACHE_ENABLE +# ifndef KEYCODE_CACHE_LIMIT +#define KEYCODE_CACHE_LIMIT (MATRIX_ROWS * MATRIX_COLS) +# endif + +typedef struct historical_keycode_t { + uint8_t row; + uint8_t col; + uint16_t keycode; +} historical_keycode_t; +static historical_keycode_t keycode_cache[KEYCODE_CACHE_LIMIT]; +static uint16_t keycode_cache_count = 0; + +/** \brief find keycode cache index + * + * returns index of keycode_cache for given key + */ +static int16_t find_keycode_cache_index(keypos_t key) { + for (uint16_t keycode_cache_idx = 0; keycode_cache_idx < keycode_cache_count; ++keycode_cache_idx) { + if (keycode_cache[keycode_cache_idx].row == key.row && keycode_cache[keycode_cache_idx].col == key.col) { + return keycode_cache_idx; + } + } + return -1; +} + +/** \brief add keycode cache + * + * add to cache of keycodes after a key is pressed down + */ +static void add_keycode_cache(keypos_t key, uint16_t keycode) { + int16_t keycode_cache_idx = find_keycode_cache_index(key); + if (keycode_cache_idx >= 0) { + keycode_cache[keycode_cache_idx].keycode = keycode; + return; + } + if (keycode_cache_count < KEYCODE_CACHE_LIMIT) { + keycode_cache[keycode_cache_count].row = key.row; + keycode_cache[keycode_cache_count].col = key.col; + keycode_cache[keycode_cache_count].keycode = keycode; + keycode_cache_count++; + } +} + +/** \brief remove keycode cache + * + * remove from cache of keycodes after a key is released + */ +static void remove_keycode_cache(keypos_t key) { + int16_t keycode_cache_idx = find_keycode_cache_index(key); + if (keycode_cache_idx >= 0) { + keycode_cache[keycode_cache_idx] = keycode_cache[keycode_cache_count - 1]; + keycode_cache_count--; + } +} + +/** \brief read keycode cache + * + * reads from cache of keycodes for when a key is releasing + */ +static uint16_t read_keycode_cache(keypos_t key) { + int16_t keycode_cache_idx = find_keycode_cache_index(key); + if (keycode_cache_idx >= 0) { + return keycode_cache[keycode_cache_idx].keycode; + } + return KC_NO; +} +# endif + #endif /** \brief Store or get action (FIXME: Needs better summary) @@ -322,14 +392,37 @@ action_t store_or_get_action(bool pressed, keypos_t key) { } uint8_t layer; - +# ifdef KEYCODE_CACHE_ENABLE + uint16_t keycode; + bool cache_used = false; +# endif if (pressed) { layer = layer_switch_get_layer(key); update_source_layers_cache(key, layer); +# ifdef KEYCODE_CACHE_ENABLE + keycode = keymap_key_to_keycode(layer, key); + if (keycode_cache_count < KEYCODE_CACHE_LIMIT) { + add_keycode_cache(key, keycode); + cache_used = true; + } +# endif } else { layer = read_source_layers_cache(key); +# ifdef KEYCODE_CACHE_ENABLE + keycode = read_keycode_cache(key); + remove_keycode_cache(key); + cache_used = (keycode != KC_NO); +# endif } +# ifndef KEYCODE_CACHE_ENABLE return action_for_key(layer, key); +# else + if (cache_used) { + return action_for_keycode(keycode); + } else { + return action_for_key(layer, key); + } +# endif #else return layer_switch_get_action(key); #endif diff --git a/quantum/action_layer.h b/quantum/action_layer.h index 067e33cdb5c..f2ac7cca5b3 100644 --- a/quantum/action_layer.h +++ b/quantum/action_layer.h @@ -163,6 +163,11 @@ layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_ void update_source_layers_cache(keypos_t key, uint8_t layer); uint8_t read_source_layers_cache(keypos_t key); +# ifdef KEYCODE_CACHE_ENABLE +void update_keycode_map(keypos_t key, uint16_t keycode); +uint16_t read_keycode_map(keypos_t key); +uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key); +# endif #endif action_t store_or_get_action(bool pressed, keypos_t key);