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

0.12.4 breaks typing across tap dance start keys #12445

Closed
tommyalatalo opened this issue Mar 31, 2021 · 5 comments
Closed

0.12.4 breaks typing across tap dance start keys #12445

tommyalatalo opened this issue Mar 31, 2021 · 5 comments

Comments

@tommyalatalo
Copy link

Commit 765d8a33d breaks tap dance in a way where pressing another key outside the tap dance sequence is affected by the modifier that the tap dance is using. Using my configuration as:

#pragma once
#define UNICODE_SELECTED_MODES UC_LNX
#define PERMISSIVE_HOLD
#define PERMISSIVE_HOLD_PER_KEY
#define TAPPING_TERM 140
#define IGNORE_MOD_TAP_INTERRUPT
#define IGNORE_MOD_TAP_INTERRUPT_PER_KEY
// Tap Dance definitions
qk_tap_dance_action_t tap_dance_actions[] = {
    // Tap once for ö, twice for semicolon
    [TD_OE] = ACTION_TAP_DANCE_DOUBLE(RALT(KC_P), KC_SCLN),
}; 

When typing öl quickly, the output instead becomes öø, i.e. the RALT modifier from the tap dance is applied to the L key, which on the US International layout results in ø. This results in a lot of incorrect characters being sent when typing across keys that begin tap dance sequences.

I have verified this by flashing the same config on 58e733b5a, and then 765d8a33d. On 58e733b5a typing over tap dance keys works just fine, but starting from 765d8a33d tap dance breaks and you start to get a lot of incorrect output.

@tommyalatalo tommyalatalo changed the title 0.12.4 breaks tap dance 0.12.4 breaks typing across tap dance start keys Mar 31, 2021
@IsaacElenbaas
Copy link
Contributor

IsaacElenbaas commented Mar 31, 2021

Haha, I both fixed and broke nearly the exact same scenario. I don't know if there is a better place to put the clear tap dance apparently needs, but it isn't like calling clearing twice unnecessarily is a huge deal. 240-244 can just be readded. https://github.com/qmk/qmk_firmware/pull/9941/files see my next comment, changed my opinion

@drashna
Copy link
Member

drashna commented Apr 2, 2021

Just a heads up, no need to wrap the commit hashes. Github will do that, and add a link for them, if you just post them. For instance: 765d8a3

@IsaacElenbaas
Copy link
Contributor

As those issues have some pretty long conversations, TL;DR: the move was necessary for rolling to Tap Dance keys, Auto Shifted keys, or any other keys that would manually register before process_action, as weak mods clear just before QMK sends a key, not just before it's possible to send a key at all.

When rolling from a Tap Dance (or Auto Shift, if it hadn't accounted for the issue) key, the action is evaluated on the down event of another and so TD/AS must send their key to get it in before the new one and return true. The mod clear should have already happened at that point, as one expects weak mods from the last key to not affect new keypresses. Tap Dance does not clean up after itself like Auto Shift.

Upon thinking about it further, IMO this should be fixed in Tap Dance, actually, instead of readding the old clear. Users (and features) should be able to add weak mods for the current record and return true instead of registering the key with the modifier themselves.

@sigprof
Copy link
Contributor

sigprof commented Apr 3, 2021

A more interesting question here is: Should weak mods be cleared when a key is physically pressed (which might not actually result in sending any key events to the host), or when QMK is about to send a key press event to the host (which might not even correspond to a physical key press at all)? The current code ties the reset of weak mods to physical key presses (in various places on the processing path), but it seems that at least for weak mods set by register_code16() the more proper way would be to reset them on any next call to register_code() which specifies a non-modifier key (so weak mods would be retained while the key for which they were set could autorepeat, but would be reset when the autorepeat for that key should stop because of another key press — no matter what caused that second key press event to be sent). Of course, this cannot actually be implemented that way, because it would break even the code which was trying to do what register_code16() does internally…

Fixing this particular problem by calling clear_weak_mods() from preprocess_tap_dance() (maybe only after some tap dance was actually interrupted) should certainly be possible. The old clear was definitely done too late to be useful in all cases.

@IsaacElenbaas
Copy link
Contributor

We definitely can't clear before register_code. action.c, process_tap_dance.c, and process_auto_shift.c, along with some user keymaps, all depend on being able to construct weak mods much before registering.

Why are we clearing on key press anyway? Weak mods should apply to one key, we should clear after register_code and process_action. If no keyboard reports are sent until the next key, if it is the same one, it should still be able to keyrepeat as the OS never knew the modifier was removed, and if it is not the same one, the modifier is gone.
Trouble is, there are superflious keyboard reports. I know KC_NO, at least, sends them, which I unsuccessfully tried to fix once upon a time. Even if there are no others and that can be fixed, that would lead to very hard to analyze bugs.

Maybe we should have very_weak_mods, which are set when a keyboard report with more than one key is sent, always OR'd with reports, and cleared at the top of register_code and process_action. weak_mods are blank when we start constructing a record, are added to as the key value is decided, and then all mods are moved to very_weak_mods to be preserved until the next key registration and weak_mods cleared.

sigprof added a commit to sigprof/qmk_firmware that referenced this issue Apr 3, 2021
Tap dance callbacks may register weak mods; one case when it happens
is when a tap dance registers a key with modifiers.  When the tap
dance is interrupted by pressing another key, these weak mods could
affect the interrupting key (normally any stale weak mods are cleared
at the start of action_exec() when handling a keypress event, but the
tap dance interrupt check code is called later, and the weak mods left
by that code were not cleared).  Add another clear_weak_mods() call to
preprocess_tap_dance() to make sure that the interrupting keypress is
not affected by unrelated weak mods from the previous tap dance.

Fixes qmk#12445.
@tzarc tzarc closed this as completed in da6e888 Apr 25, 2021
makenova pushed a commit to makenova/qmk_firmware that referenced this issue Apr 26, 2021
…k#12471)

Tap dance callbacks may register weak mods; one case when it happens
is when a tap dance registers a key with modifiers.  When the tap
dance is interrupted by pressing another key, these weak mods could
affect the interrupting key (normally any stale weak mods are cleared
at the start of action_exec() when handling a keypress event, but the
tap dance interrupt check code is called later, and the weak mods left
by that code were not cleared).  Add another clear_weak_mods() call to
preprocess_tap_dance() to make sure that the interrupting keypress is
not affected by unrelated weak mods from the previous tap dance.

Fixes qmk#12445.
rizo pushed a commit to rizo/qmk_firmware that referenced this issue May 10, 2021
…k#12471)

Tap dance callbacks may register weak mods; one case when it happens
is when a tap dance registers a key with modifiers.  When the tap
dance is interrupted by pressing another key, these weak mods could
affect the interrupting key (normally any stale weak mods are cleared
at the start of action_exec() when handling a keypress event, but the
tap dance interrupt check code is called later, and the weak mods left
by that code were not cleared).  Add another clear_weak_mods() call to
preprocess_tap_dance() to make sure that the interrupting keypress is
not affected by unrelated weak mods from the previous tap dance.

Fixes qmk#12445.
toddyamakawa pushed a commit to toddyamakawa/qmk_firmware that referenced this issue May 19, 2021
…k#12471)

Tap dance callbacks may register weak mods; one case when it happens
is when a tap dance registers a key with modifiers.  When the tap
dance is interrupted by pressing another key, these weak mods could
affect the interrupting key (normally any stale weak mods are cleared
at the start of action_exec() when handling a keypress event, but the
tap dance interrupt check code is called later, and the weak mods left
by that code were not cleared).  Add another clear_weak_mods() call to
preprocess_tap_dance() to make sure that the interrupting keypress is
not affected by unrelated weak mods from the previous tap dance.

Fixes qmk#12445.
HokieGeek pushed a commit to HokieGeek/qmk_firmware that referenced this issue Jul 11, 2021
…k#12471)

Tap dance callbacks may register weak mods; one case when it happens
is when a tap dance registers a key with modifiers.  When the tap
dance is interrupted by pressing another key, these weak mods could
affect the interrupting key (normally any stale weak mods are cleared
at the start of action_exec() when handling a keypress event, but the
tap dance interrupt check code is called later, and the weak mods left
by that code were not cleared).  Add another clear_weak_mods() call to
preprocess_tap_dance() to make sure that the interrupting keypress is
not affected by unrelated weak mods from the previous tap dance.

Fixes qmk#12445.
BorisTestov pushed a commit to BorisTestov/qmk_firmware that referenced this issue May 23, 2024
…k#12471)

Tap dance callbacks may register weak mods; one case when it happens
is when a tap dance registers a key with modifiers.  When the tap
dance is interrupted by pressing another key, these weak mods could
affect the interrupting key (normally any stale weak mods are cleared
at the start of action_exec() when handling a keypress event, but the
tap dance interrupt check code is called later, and the weak mods left
by that code were not cleared).  Add another clear_weak_mods() call to
preprocess_tap_dance() to make sure that the interrupting keypress is
not affected by unrelated weak mods from the previous tap dance.

Fixes qmk#12445.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants