Resync HID command stream after a stale report (fixes #228) - #436
Open
OmleNessumsa wants to merge 1 commit into
Open
OmleNessumsa wants to merge 1 commit into
OmleNessumsa wants to merge 1 commit into
Conversation
KeyboardAPI._hidCommand wrote one report, read exactly one report and threw "Receiving incorrect response for command" on an echo mismatch, without ever draining the mismatched report. A single stray reply (a second tab or client on the same device, a concurrent command) therefore shifted every following response by one, and because the next command was already sent before the late reply arrived, fastForwardGlobalBuffer could not discard it. The stream stayed shifted until the page was reloaded (the-via#228). _hidCommand now discards replies whose echo belongs to another command and reads again, bounded by RESYNC_MAX_STALE_READS (4) and a 250 ms per-read timeout. A reply starting with 0xFF (QMK id_unhandled) is still treated as the real answer and fails immediately, so unsupported commands cannot stall the queue. The WebHID shim gains readWithTimeout(), which removes its own waiter on timeout. Verified on a Keychron Q3 Pro (0x3434:0x0630, protocol 11) on macOS 26.5 with Chrome 153: the previously permanent off-by-one no longer occurs and the full keymap loads with an empty error log. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VYbTK39cVBDbhebBZ5UQWg
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
KeyboardAPI._hidCommandwrites one report, reads exactly one report and throwsReceiving incorrect response for commandwhen the echo does not match. The mismatched report is never drained. As soon as one stray reply enters the stream (a second tab or client holding the same device, a concurrent command), every following response is shifted by one: the reply to command N is read as the answer to command N+1. Because the next command is already on the wire before the late reply lands,fastForwardGlobalBuffercannot discard it, and the stream stays shifted until the page is reloaded.This is the pattern in #228 (Keebio Quefrency) and it reproduces identically on a Keychron Q3 Pro (
0x3434:0x0630, protocol 11). Sample from the error log, every entry is the previous command's reply:367 of 386 logged errors in a 16 s session followed this exact off-by-one, across 8 automatic retries.
Fix
_hidCommanddiscards a reply whose echo belongs to another command and reads again, bounded byRESYNC_MAX_STALE_READS(4) and a 250 ms per-read timeout.0xFF(QMKid_unhandled) is still treated as the real answer to this command and fails immediately, so unsupported commands cannot stall the queue.readWithTimeout(ms), which removes its own waiter on timeout so a report that never arrives cannot wedge later reads.No behaviour change on a healthy stream: the first read matches and the loop body never runs.
Verification
tsc --noEmitpasses. Prettier applied to the added code only (the shim file was not prettier-clean before this change, its existing formatting is left untouched).Fixes #228
🤖 Generated with Claude Code
https://claude.ai/code/session_01VYbTK39cVBDbhebBZ5UQWg