From 1dc57e7ea6b308bee81a5a78aea40bad6ec697b1 Mon Sep 17 00:00:00 2001 From: Garretonzo Date: Sun, 8 Jun 2025 11:13:16 -0700 Subject: [PATCH 1/3] feature to update keycode on press and read keycode on release using map cache --- docs/config_options.md | 2 ++ quantum/action_layer.c | 41 ++++++++++++++++++++++++++++++++++++++++- quantum/action_layer.h | 5 +++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/config_options.md b/docs/config_options.md index b2a2117693d..7c456702e1d 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -142,6 +142,8 @@ 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. ## Behaviors That Can Be Configured diff --git a/quantum/action_layer.c b/quantum/action_layer.c index 5828dcb8240..e692150bfd6 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c @@ -306,6 +306,32 @@ uint8_t read_source_layers_cache(keypos_t key) { # endif // ENCODER_MAP_ENABLE return 0; } + +# ifdef KEYCODE_CACHE_ENABLE +static uint16_t keycode_map[MATRIX_ROWS][MATRIX_COLS] = {{KC_NO}}; + +/** \brief update keycode map + * + * Updates map of keycodes when a key is pressed down + */ +void update_keycode_map(keypos_t key, uint16_t keycode) { + if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { + keycode_map[key.row][key.col] = keycode; + } +} + +/** \brief read keycode map + * + * reads from map of keycodes when a key is released + */ +uint16_t read_keycode_map(keypos_t key) { + if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { + return keycode_map[key.row][key.col]; + } + return KC_NO; +} +# endif + #endif /** \brief Store or get action (FIXME: Needs better summary) @@ -322,14 +348,27 @@ action_t store_or_get_action(bool pressed, keypos_t key) { } uint8_t layer; - +# ifdef KEYCODE_CACHE_ENABLE + uint16_t keycode; +# 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); + update_keycode_map(key, keycode); +# endif } else { layer = read_source_layers_cache(key); +# ifdef KEYCODE_CACHE_ENABLE + keycode = read_keycode_map(key); +# endif } +# ifndef KEYCODE_CACHE_ENABLE return action_for_key(layer, key); +# else + return action_for_keycode(keycode); +# 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); From c6bbe8031a0fca957ab327221f498f467a513d88 Mon Sep 17 00:00:00 2001 From: Garretonzo Date: Mon, 9 Jun 2025 09:56:52 -0700 Subject: [PATCH 2/3] implemented array of historical_keycode_t to cache keycodes, with configurable limit --- docs/config_options.md | 2 ++ quantum/action_layer.c | 82 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/docs/config_options.md b/docs/config_options.md index 7c456702e1d..c82fad22d05 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -144,6 +144,8 @@ If you define these options you will enable the associated feature, which may in * 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 e692150bfd6..8c8504044fc 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c @@ -308,25 +308,69 @@ uint8_t read_source_layers_cache(keypos_t key) { } # ifdef KEYCODE_CACHE_ENABLE -static uint16_t keycode_map[MATRIX_ROWS][MATRIX_COLS] = {{KC_NO}}; +# ifndef KEYCODE_CACHE_LIMIT +#define KEYCODE_CACHE_LIMIT (MATRIX_ROWS * MATRIX_COLS) +# endif -/** \brief update keycode map +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 * - * Updates map of keycodes when a key is pressed down + * returns index of keycode_cache for given key */ -void update_keycode_map(keypos_t key, uint16_t keycode) { - if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { - keycode_map[key.row][key.col] = keycode; +static int16_t find_keycode_cache_index(keypos_t key) { + for (uint16_t i = 0; i < keycode_cache_count; ++i) { + if (keycode_cache[i].row == key.row && keycode_cache[i].col == key.col) { + return i; + } + } + 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 idx = find_keycode_cache_index(key); + if (idx >= 0) { + 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 read keycode map +/** \brief remove keycode cache * - * reads from map of keycodes when a key is released + * remove from cache of keycodes after a key is released */ -uint16_t read_keycode_map(keypos_t key) { - if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) { - return keycode_map[key.row][key.col]; +static void remove_keycode_cache(keypos_t key) { + int16_t idx = find_keycode_cache_index(key); + if (idx >= 0) { + 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 idx = find_keycode_cache_index(key); + if (idx >= 0) { + return keycode_cache[idx].keycode; } return KC_NO; } @@ -350,24 +394,34 @@ 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); - update_keycode_map(key, keycode); + 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_map(key); + 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 - return action_for_keycode(keycode); + if (cache_used) { + return action_for_keycode(keycode); + } else { + return action_for_key(layer, key); + } # endif #else return layer_switch_get_action(key); From 2f15e1e3b3180cd40b52b23b4fd82f0af490894d Mon Sep 17 00:00:00 2001 From: Garretonzo Date: Mon, 9 Jun 2025 10:04:14 -0700 Subject: [PATCH 3/3] idx variable name --- quantum/action_layer.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/quantum/action_layer.c b/quantum/action_layer.c index 8c8504044fc..db9ae8e3496 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c @@ -325,9 +325,9 @@ static uint16_t keycode_cache_count = 0; * returns index of keycode_cache for given key */ static int16_t find_keycode_cache_index(keypos_t key) { - for (uint16_t i = 0; i < keycode_cache_count; ++i) { - if (keycode_cache[i].row == key.row && keycode_cache[i].col == key.col) { - return i; + 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; @@ -338,9 +338,9 @@ static int16_t find_keycode_cache_index(keypos_t key) { * add to cache of keycodes after a key is pressed down */ static void add_keycode_cache(keypos_t key, uint16_t keycode) { - int16_t idx = find_keycode_cache_index(key); - if (idx >= 0) { - keycode_cache[idx].keycode = 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) { @@ -356,9 +356,9 @@ static void add_keycode_cache(keypos_t key, uint16_t keycode) { * remove from cache of keycodes after a key is released */ static void remove_keycode_cache(keypos_t key) { - int16_t idx = find_keycode_cache_index(key); - if (idx >= 0) { - keycode_cache[idx] = keycode_cache[keycode_cache_count - 1]; + 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--; } } @@ -368,9 +368,9 @@ static void remove_keycode_cache(keypos_t key) { * reads from cache of keycodes for when a key is releasing */ static uint16_t read_keycode_cache(keypos_t key) { - int16_t idx = find_keycode_cache_index(key); - if (idx >= 0) { - return keycode_cache[idx].keycode; + 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; }