Conversation
The Lingbao M5 Pro (PixArt PAW3395) enumerates under VID 0x3151 on the
very same 0xFFFF/0x02 vendor interface FantechHidClient claims, so the
registry handed it to that driver — which could not read a single value
from it, and reported fabricated ones rather than failing.
0x3151 belongs to MicLink/mlzn, the ODM, not to Fantech. The mouse is
configured by GearHub-V5 (qmk.top); its protocol was read out of that
bundle and then verified byte for byte against real hardware.
LingbaoHidClient implements the three things the Fantech driver lacks:
- The Bit7 checksum, byte[7] = 255 - sum(bytes 0..6). Without it the
device ACKs the write and answers 64 zero bytes, silently.
- The 2.4G relay. A receiver does not forward a command just because
one was written to it: select the target (0xF6 0x05), poll status
until ready (0xF7), send, then notice-read (0xFC) before reading
back. 0xF7 also carries link state and battery.
- The mouse-class command set (GET_DPI 0xD4 / SET_DPI 0x54) and its
seven-entry report-rate table, in which code 5 means 250 Hz. The
Fantech driver carries the six-entry keyboard table, where code 5
means 125 Hz instead.
Commands are serialised through a queue. The relay is stateful, so two
exchanges in flight at once interleave and corrupt each other —
readStatus() ran into this on its first concurrent read.
Scoped to the M5 Pro's two product ids (0x402D receiver, 0x4026 wired) so
it cannot shadow Fantech's own hardware, and FantechHidClient now leaves
those two ids alone; the registry's one-driver-per-device test enforces it.
Verified live on a Lingbao M5 Pro receiver: DPI stages 400/800/1600/3200/
6400/26000 with stage 2 active, 8000 Hz, battery 44%, firmware v3.03,
device id 2285. Bluetooth mode is not covered — over BLE the mouse moves
to a different usage page and a separate read path.
The same investigation showed FantechHidClient inventing data on any
device that does not answer, so this also fixes:
- readStatus() throws instead of returning 1600 DPI / 8000 Hz decoded
from an all-zero reply, letting the caller try the next driver
- setDpiForSlot() no longer zeroes every DPI slot it is not writing
- 250 Hz is no longer advertised when it cannot be encoded, so the UI
cannot render a button that throws on click
- the hardcoded "Wired (USB)" and the placeholder firmware string are
gone rather than mislabelling wireless units
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts: # src/drivers/mouse-types.ts # src/drivers/registry.ts
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.
Rebase/merge of #49 onto current main, resolving additive brand-union conflicts in mouse-types.ts/registry.ts against #50/#53/#54/#55. Closes #49.