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

feat(behaviors): sticky keys no longer sticky after being held #1788

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

nguyendown
Copy link
Contributor

@nguyendown nguyendown commented May 1, 2023

Awesome suggestion from RexxStone.
https://discord.com/channels/719497620560543766/1112676462089207828/1112676462089207828

A tap will stick.

      press            release
        ^                 ^
========|-----------------|===========================
          no-sticky-after-hold-ms
        <------------------------->

                            release-after-ms
                          <------------------>
========|-----------------|------------------|========
        v                                    v
     activate                            deactivate

A hold won't stick.

      press                        release
        ^                             ^
========|-----------------------------|===============
          no-sticky-after-hold-ms
        <------------------------->
========|-----------------------------|===============
        v                             v
     activate                     deactivate

Sticky keys will act like normal keys if they are held for longer than a configurable amount of time. I am deciding on a name for this property. Please help me.

  • no-sticky-after-hold-ms
  • max-hold-ms
  • deactivate-from-hold-ms

Currently, the property is optional and won't break existing configs. The default value is set to be the same as release-after-ms.

// adjust timer in case this behavior was queued by a hold-tap
int32_t ms_left = sticky_key->release_at - k_uptime_get();
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see how this is accounting for the comment above about adjusting for being held.. The timestamp in the event might be "older" than the actual time if the release was captured then re-released.

Did you test this in combination of hold taps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I included this change by mistake. I wanted to test if it would break.

Did you test this in combination of hold taps?

I planned to, but I haven't had the chance to test it yet.

@@ -210,14 +212,6 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
continue;
}

// If this event was queued, the timer may be triggered late or not at all.
Copy link
Contributor

Choose a reason for hiding this comment

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

What was your reasoning for deleting this? I believe it stands as a failsafe for an edge case for a laggy timer, but I'm not 100% sure exactly when it is being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

release_at is calculated upon key press. This failsafe deactivates sticky keys while they are being held. The unit test 13-active-until-release covers this.

I have been using this for a month now without noticing any issues. Perhaps my keymap isn't complicated enough to cause any problems?

There is certainly a way to keep the failsafe but I haven't thought much about it. Personally, I prefer not to rely on failsafes and believe that unexpected behaviors should be fixed and verified through testing. (Maybe I'm just being lazy.) Let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

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

For sure... I don't know enough to say for sure why the failsafe is there, but I think it would be wise to really understand why it was needed in the first place and whether it is safe to remove.

Copy link
Contributor

@theol0403 theol0403 left a comment

Choose a reason for hiding this comment

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

This implementation looks good to me, and considers everything discussed in #1636

// adjust timer in case this behavior was queued by a hold-tap
int32_t ms_left = sticky_key->release_at - k_uptime_get();
if (ms_left > 0) {
k_work_schedule(&sticky_key->release_timer, K_MSEC(ms_left));
if (ms_left < 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Small cleanup

Suggested change
if (ms_left < 0) {
k_work_schedule(&sticky_key->release_timer, K_MSEC(ms_left > 0 ? ms_left : 0));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Compilers probably optimize this already. Even if they do not, it's not worth sacrificing readability here, considering that the code is not run often.

@nguyendown nguyendown changed the title fix(behaviors): deactivate sticky keys immediately after being held feat(behaviors): sticky keys no longer sticky after being held Jun 30, 2023
@theol0403
Copy link
Contributor

theol0403 commented Jun 30, 2023

Personally, I preferred the PR without the config option. I think this change is a sane default and I can't imagine any usecase for the timeout after release. I think the config option adds redundant complexity.

Edit: I read the usecase about using it instead of a tap hold for "don't hold sticky if held". While I think this is a good feature, I think that the tap-hold approach is superior, as a) it composes existing features without introducing new ones b) it handles edge cases including that happens if another key is pressed during held, hold-while-undecided, etc.

@nguyendown
Copy link
Contributor Author

usecase for the timeout after release

My focus is on no-sticky-after-hold. Whether the release (deactivate) timer starts on binding press or binding release, it is a separate issue. The reason I changed it in d1a0027 is that I could make use of release_at to solve two issues at once.

tap-hold approach

Sticky key needs a standalone feature and does not rely on any workarounds or other behaviors. Besides, keymaps could be much more simple.

&sk {
    no-sticky-after-hold-ms = <200>;
};

And I don't have to read through the Hold-Tap documentation or understand ten different hold-tap flavors. (I did read it but am still confused btw.)

@kvietcong
Copy link

Are there any blockers in getting this merged? I love this feature but it seems to be quite behind master at this point.

Sticky keys that are pressed down for longer than
`no-sticky-after-hold-ms` will immediately deactivate upon release. If
the property `no-sticky-after-hold-ms` does not exist, the value of
`release-after-ms` will be used as a fallback.
@nguyendown nguyendown force-pushed the behaviors/sticky-key-deactivate-after-hold branch from b8f52da to 95185e3 Compare November 22, 2023 08:19
@nguyendown nguyendown marked this pull request as ready for review November 22, 2023 08:23
@nguyendown nguyendown requested a review from a team as a code owner November 22, 2023 08:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants