qmk/qmk_firmware

[Bug] Combos have inconsistent triggering

Open

#15.911 aperta il 17 gen 2022

Vedi su GitHub
 (1 commento) (0 reazioni) (0 assegnatari)C (43.867 fork)batch import
bughelp wanted

Metriche repository

Star
 (20.368 star)
Metriche merge PR
 (Merge medio 20g 9h) (27 PR mergiate in 30 g)

Descrizione

Currently, combos have somewhat surprising timing and triggering behavior. I'd like to propose and discuss refactoring the combo code to achieve more consistent and dependable combo triggering. Particularly, there is no guarantee that a combo will trigger even if all keys are pressed within COMBO_TERM of each other, and there is no guarantee that a combo will fail to trigger even if the keys are not pressed within COMBO_TERM of each other.

Description

Suppose Combo1 is triggered by a+b and Combo2 is triggered by c+d.

  • With COMBO_STRICT_TIMER, if a, b, and c are all pressed within COMBO_TERM, and d is pressed within COMBO_TERM of c, but not within COMBO_TERM of a, then Combo1 fires but Combo2 does not. Since a+b were pressed within COMBO_TERM, and also c+d were pressed within COMBO_TERM, it would be natural to expect both to fire
  • Without COMBO_STRICT_TIMER, if a, c, and b are pressed, in that order, with each press coming just a bit less than COMBO_TERM after the previous one, then Combo1 will trigger, even though a and b were not pressed together within COMBO_TERM. Even with COMBO_STRICT_TIMER, if COMBO_TERM_PER_COMBO is also set and Combo2 has a longer term than Combo1, we still trigger Combo1 even though a and b were not pressed together within Combo1's combo term.
  • Any key release event resets the whole buffer, so quickly typing c followed by a+b fails to trigger Combo1 (above) if c happens to be released between pressing a and b.
  • Pressing a, then x, then b, all within COMBO_TERM, will trigger Combo 1 if x belongs to some other combo, but not if x belongs to no combo.

The general issue is that the combo key buffer is all-or-nothing: there is no way to release some key presses or combos while keeping other key presses in the buffer and preserving partial activation state of other combos.

Proposed solution

I suggest that combos should provide a behavior guarantee such as the following:

A combo will trigger if and only if

  1. all of its keys are pressed within its combo term, and
  2. none of the following occurs
  • One of the combo's keys was released before the final key was pressed
  • Two events (press and/or release) for the same keycode occur between the first and last triggering key presses
  • The combo has the "tap" requirement, but no triggering key is released within the hold term
  • The combo has the "hold" requirement, but a triggering key is released within the hold term
  • The combo is disabled
  • An overlapping combo with higher priority triggers instead
  • The key buffer overflows between the first and last key presses of the combo

Relatedly, it would be nice to have a new feature that allows specifying whether a combo must have all its key presses contiguous or not. A contiguous combo (the default?) would fail to trigger if any unrelated key (whether or not it is associated to another combo) is pressed between the first and last key presses. A non-contiguous combo would have no such condition. Contiguous combos would be useful for avoiding accidental combo triggers, and non-contiguous combos would be useful for combos that do things like trigger mods, where one might want to fire multiple combos simultaneously.

I hope to submit a PR in the next few days addressing this issue.

Guida contributor