Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update store_or_get_action to cache keycode on key press, return cached keycode on key release #24517

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from

Conversation

Garretonzo
Copy link

@Garretonzo Garretonzo commented Oct 23, 2024

Description

Changes behavior of store_or_get_action to cache a keycode for a pressed key and then return the cached keycode when releasing a key.

I would not exactly call this a "bugfix" but it does prevent keys from getting "stuck" when editing layouts through VIA hotswapping, for example.

This semi-replaces the source layers cache implementation to cache the entire keycode for a key location.

Feature must be opted into with #define KEYCODE_CACHE_ENABLE.

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Keyboard (addition or update)
  • Keymap/layout (addition or update)
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project: C, Python
  • I have read the PR Checklist document and have made the appropriate changes.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

@github-actions github-actions bot added the core label Oct 23, 2024
@zvecr zvecr changed the base branch from master to develop October 23, 2024 19:06
@Garretonzo Garretonzo marked this pull request as draft October 23, 2024 19:09
@Garretonzo Garretonzo marked this pull request as ready for review October 23, 2024 20:31
@drashna drashna requested a review from a team October 24, 2024 01:36
quantum/dynamic_keymap.c Outdated Show resolved Hide resolved
lint formatting

Co-authored-by: Drashna Jaelre <[email protected]>
@drashna drashna requested a review from a team October 24, 2024 20:45
// Big endian, so we can read/write EEPROM directly from host if we want
eeprom_update_byte(address, (uint8_t)(keycode >> 8));
eeprom_update_byte(address + 1, (uint8_t)(keycode & 0xFF));
unregister_code(prev_keycode);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on discord, this wont correctly handle keycode that are non-basic, and changing it to unregister_code16 would then only handle basic+modded. Using clear_keyboard() covers more scenarios but still does not cover any side effects of quantum keycodes.

Im also not a fan of coupling storage directly to its eventual use, wherever in the tmk action code. I agree updating via.c to be responsible would be error prone for other eventual uses of dynamic_keymap_set_keycode, but it still feels like the cleaner workaround till a better solution is implemented.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A reason I handled things in here was to cover the scenario of:

  1. key pressed
  2. dynamic keymap set
  3. dynamic keymap set (again)
  4. key released

Is changing unregister_code to handle non-basic keycodes an option?
Or creating a new, all-encompassing function to handle unregistering any code?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, when you suggest to have via.c be responsible, would having the same logic but instead immediately before and after the call to dynamic_keymap_set_keycode within the id_dynamic_keymap_set_keycode case suffice? Or would there be more to having this happen in via.c?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolving since I made via.c responsible to handle this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving as its still using unregister_code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unresolving as its still using unregister_code.

Hey mate, if you have time and still have interest, I think my new implementation is ready for further review

@Garretonzo Garretonzo marked this pull request as draft November 2, 2024 04:57
@Garretonzo
Copy link
Author

Garretonzo commented Nov 2, 2024

I made some heavy changes following a suggestion from the discussion on discord when this was first brought up.

I modified the logic of what get_event_keycode returns. A cache is used to store a keycode when a key is pressed, then that cache is read from when a key is released.

I know there is some overlap with the introduction of this implementation but I don't know what all depends on the source layers cache, so I focused solely on what get_event_keycode returns.

@Garretonzo Garretonzo changed the title Unregister previous keycode after dynamic keymap set Update get_event_keycode to cache keycode on key press, return cached keycode on key release Nov 2, 2024
@Garretonzo Garretonzo marked this pull request as ready for review November 9, 2024 20:27
@Garretonzo Garretonzo requested review from zvecr and drashna November 9, 2024 20:39
@drashna drashna requested a review from a team November 9, 2024 22:09
@drashna drashna added the breaking_change_2025q1 Targeting breaking changes Q1 2025 label Nov 9, 2024
@tzarc
Copy link
Member

tzarc commented Nov 14, 2024

This may need to be opt-in, given the added RAM requirement. A TKL would use somewhere of the order of 400-500 extra bytes, and not everyone has that free.

@Garretonzo Garretonzo changed the title Update get_event_keycode to cache keycode on key press, return cached keycode on key release Update store_or_get_action to cache keycode on key press, return cached keycode on key release Nov 15, 2024
Comment on lines 292 to 295
uint16_t keycode_map[((MATRIX_ROWS * MATRIX_COLS) + (CHAR_BIT)-1) / (CHAR_BIT)][16] = {{KC_NO}};
# ifdef ENCODER_MAP_ENABLE
uint16_t encoder_keycode_map[(NUM_ENCODERS + (CHAR_BIT)-1) / (CHAR_BIT)][16] = {{KC_NO}};
# endif // ENCODER_MAP_ENABLE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks overcomplicated. The source layer cache code uses such tricks to avoid allocating a whole byte for each entry that needs just 2 bits in the most common case (4 layers); if you are storing the whole 16-bit keycode, you may just use

static uint16_t keycode_map[MATRIX_ROWS][MATRIX_COLS];

and

static uint16_t encoder_keycode_map[NUM_ENCODERS][NUM_DIRECTIONS];

(Actually the encoder code might not need such handling at all, because the press and release events are emitted without running the rest of main loop code in between, therefore keymap updates should not happen.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a ton for the feedback, I cleaned up the overcomplicated keycode_map and also removed the encoder handling

Comment on lines 340 to 341
else if (key.row == KEYLOC_ENCODER_CW || key.row == KEYLOC_ENCODER_CCW) {
const uint16_t entry_number = key.col;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general you may need to consider key.row too (so that entries for different rotation direction don't overwrite each other); maybe it's simple to just do that instead of thinking why that should not happen.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since I removed the encoder handling code, is this safe to not consider?

@Garretonzo Garretonzo requested a review from sigprof November 15, 2024 16:22
@@ -287,6 +287,31 @@ 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}};
Copy link
Member

@tzarc tzarc Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps keeping an array of, say, 10 of:

typedef struct historical_keycode_t {
    uint8_t row;
    uint8_t col;
    uint16_t keycode;
} historical_keycode_t;

...should significantly decrease the RAM requirements at the cost of a slightly more complicated algorithm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking_change_2025q1 Targeting breaking changes Q1 2025 core documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants