getreuer / qmk-keymap

My keymap & reusable QMK gems
Apache License 2.0
301 stars 45 forks source link

[Bug] Double mod keypress when using eager mods #53

Open JanValiska opened 7 months ago

JanValiska commented 7 months ago

Hi, I'm using manna harbours miryoku layout on skeletyl keyboard + achordion library to fix some issues with home row mods. I'm quiet happy with current configuration except the eager mods feature from achordion library.

OS: archlinux. using gmk tool version: 1.1.2 I have custom branch based on commit 31a9d2d00dc732ca29be2213dbf915d6f6ffc76d

Problem: When I tap and hold WIN(also alt,win,shift are affected) key, the event is quickly registered by OS as hold(I can move/resize my window by mouse dragging). But after couple of milliseconds(~200-300) there is second hold event sent to the OS, which breaks current dragging/resizing of the window and I need to mouse click and drag/resize window again.

I also provide screen record of xev output which demonstrates the problem little bit.

https://github.com/getreuer/qmk-keymap/assets/755186/6a239179-3bc0-4fe8-bb54-3ae45ca7bf35

Information

Do the keys involved use any of the following features?

getreuer commented 6 months ago

@JanValiska thank you for the detailed bug report! Your explanation and video make the problem very clear.

Problem

In hindsight, I can see why this defect occurs. The sequence of events:

  1. The mod-tap key is held.
  2. QMK passes the hold press event to Achordion. Achordion applies the eager mod.
  3. After achordion_timeout() (default 1000 ms), Achordion settles the key as held. In doing so, it clears the eager mod and plumbs the hold press event. Specifically in this code.
  4. The hold press event sets the mod again.

From the computer's point of view, the mod is held, briefly released, then held again. This release would be a few milliseconds, the time needed for QMK to send another keyboard report to the computer.

Sketch of potential solution

I don't know when I will have a chance to fix this. I'd like to at least describe a potential solution, in case someone is willing to pick this up.

The essential problem is this hand-off from Achordion to QMK core in holding the eager mod. To avoid having a hand-off and to ensure the mod is held continuously, either Achordion or QMK core, and not both, should hold the mod. I'd prefer the latter if possible in principle, since deferring work to QMK is generally a good approach for interoperability with other features.

QMK core holding the mod

  1. The mod-tap key is held.
  2. QMK passes the hold press event to Achordion. Achordion allows the event to continue immediately to eagerly apply the mod.
  3. If Achordion later settles the key as tapped, it plumbs the hold release, to clear the mod, then plumbs the tap event. If instead Achordion settles the key as held, this is a no-op.

Achordion holding the mod

  1. The mod-tap key is held.
  2. QMK passes the hold press event to Achordion. Achordion never plumbs events for this key, rather it handles the mod directly. The eager mod is applied.
  3. When the key is released or settled as a tap, Achordion clears the eager mod.