Skip to content

fix: preserve QuickAccess chord duration for pulse events - #661

Open
nileshchakraborty wants to merge 3 commits into
ShadowBlip:mainfrom
nileshchakraborty:fix/serialized-translated-events
Open

fix: preserve QuickAccess chord duration for pulse events#661
nileshchakraborty wants to merge 3 commits into
ShadowBlip:mainfrom
nileshchakraborty:fix/serialized-translated-events

Conversation

@nileshchakraborty

@nileshchakraborty nileshchakraborty commented Aug 23, 2026

Copy link
Copy Markdown

Summary

Preserve the synthesized Steam Quick Access chord when source firmware emits an almost instantaneous press/release pulse.

Fixes #657.

Root cause

The Event emitted too quickly. Delaying emission. message does not mean the event was dropped. That branch already re-queues the translated event. The message is emitted only while the same translated capability remains in InputPlumber's 4 ms debounce set, so the report itself establishes that the next edge arrived less than 4 ms after the first. After the existing debounce delay, the target still sees only a few milliseconds of effective hold time.

Targets without a native Quick Access button synthesize Steam's Guide+South chord:

  • Guide press: immediately
  • South press: after 160 ms
  • South release: 160 ms after the source release
  • Guide release: 240 ms after the source release

For a pulse-style source, South is consequently pressed and released only a few milliseconds apart. Steam can miss that chord even though InputPlumber delivered both translated events.

Why 80 ms

This is based on the existing QAM timing established by #216, not an arbitrary new delay. That change introduced the current 160/240 ms cadence in 80 ms steps and was hardware-tested on MSI Claw, Win600, ROG Ally, and Ayaneo Air Plus.

For a source pulse shorter than 80 ms, this change schedules the same sequence produced by an 80 ms physical press:

0 ms    Guide down
160 ms  South down
240 ms  South up
320 ms  Guide up

Each chord phase therefore remains visible for one established 80 ms interval. Source presses of 80 ms or longer keep the existing timing unchanged.

Implementation

The common scheduler records when Quick Access was pressed and extends only releases that would make a chord phase shorter than 80 ms. Xbox, DualSense, and Ultimate 2 use the shared implementation so their identical behavior cannot drift.

The composite-device command loop remains non-blocking. This replaces the earlier revision that serialized delayed events in that loop; the current PR diff contains none of that approach.

Validation

Ran the repository's supported container test target:

make in-docker TARGET=test
  • 13 unit tests passed
  • focused coverage verifies a 1 ms pulse, an 80 ms normal press, and an unmatched release
  • 4 doctests passed
  • Clippy passed with -D warnings
  • git diff --check passed

The failing pulse duration is derived directly from #657's debounce log, while the minimum cadence and cross-device hardware evidence come from #216.

@nileshchakraborty
nileshchakraborty force-pushed the fix/serialized-translated-events branch from 67b1c9e to 2c0873d Compare August 23, 2026 20:26
@nileshchakraborty

Copy link
Copy Markdown
Author

Pausing this PR as a draft pending a more rigorous design and regression coverage.

The current revision preserves the WriteEvent/HandleEvent dispatcher paths, but deeper review identified two concerns that need to be resolved before merge:

  • waiting in the composite-device command loop can add input-processing backpressure;
  • the existing logs do not prove that the delayed event is actually dropped, so the proposed race fix needs a focused event-ordering regression test.

The next revision should make delayed ordering atomic without blocking normal input processing and test a QuickAccess-style press/release sequence end to end.

@nileshchakraborty
nileshchakraborty marked this pull request as draft August 23, 2026 20:31
@nileshchakraborty nileshchakraborty changed the title fix: preserve ordering for delayed translated events fix: preserve QuickAccess chord duration for pulse events Aug 23, 2026
@nileshchakraborty

Copy link
Copy Markdown
Author

I replaced the command-loop serialization approach after tracing the full event path. The debounce already re-queues the translated release; blocking the composite-device loop introduced backpressure without addressing the failure. The current diff instead preserves the synthesized Guide+South chord at the target boundary and adds focused timing tests.

@nileshchakraborty
nileshchakraborty marked this pull request as ready for review August 23, 2026 23:56
@nileshchakraborty

Copy link
Copy Markdown
Author

Marked ready after grounding the timing in two upstream facts: #657 proves a sub-4 ms translated edge through the debounce condition, and #216 established the existing 80 ms QAM cadence with hardware testing across ROG Ally, MSI Claw, Win600, and Ayaneo Air Plus. The PR now documents the resulting 0/160/240/320 ms sequence and preserves existing timing for presses of 80 ms or longer.

@pastaq

pastaq commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

I'm not really a fan of how these changes look overall. I seem to have missed a few target devices in
https://github.com/ShadowBlip/InputPlumber/pull/650/changes which had a more simple pattern to achieve the same thing. Can you test if that approach resolves your issue for the targets I didn't modify?

Also, this is screaming LLM usage. Please add disclosure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ROG Ally X: Armory Crate button (QuickAccess) event stuck at "Delaying emission", overlay/QAM never opens

2 participants