Uh oh!
There was an error while loading. Please reload this page.
Add Logitech Pebble M350s support - #39
Closed
CharlieNR wants to merge 1 commit into
Closed
Conversation
The Logitech driver only reached mice through a USB vendor interface. Over Bluetooth the same HID++ protocol moves to usage page 0xff43 and drops the 0x10 short report, so a Bluetooth mouse was never offered by the picker and would not have answered if it had been. - Detect the Bluetooth control interface and address it on device index 0xFF, kept separate from the direct-connect USB list so the Pebble does not inherit the G402's read-only polling rate. - Send every request as a long report when the transport has no short report. - Read Battery Level Status (0x1000), which is what mice on a replaceable cell expose instead of the rechargeable-pack features. - Treat a missing DPI or report-rate feature as "not present" rather than an error. An office mouse has neither, and the read used to fail on its behalf. The shell now hides the polling card when a driver reports an explicitly empty rate list, matching how an empty lift-off list already hides the sensor card.
snekxs
commented
Aug 8, 2026
Member
Closing because this branch conflicts with the current Logitech implementation on dev. Please rebase and resubmit the Pebble M350s support as a focused change with the current HID++ tests passing. |
dwei30 pushed a commit
to dwei30/openmouse
that referenced
this pull request
Aug 30, 2026
Picks up Keychron M6 (OpenMouse-Project#33), Nape Pro (OpenMouse-Project#37), Glorious Model O 2/I 2 (OpenMouse-Project#38), and SteelSeries Rival 3 (OpenMouse-Project#39) support from mouse-protocol main. The bump retires the generic KeychronHidClient in favor of KeychronNapeHidClient (a strict superset), which this app's controller.ts still imported by its old path. Also widens the Glorious lighting call site since SupportedClient now includes GloriousHidClient's stricter setLighting signature. Verified with npm ci, npm run build, and the full test suite (84/84). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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 freeto 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.
Adds the Logitech Pebble M350s (
046d:b036), which pairs over Bluetooth ratherthan through a receiver.
Why it did not work
The Logitech driver assumed a USB vendor interface throughout. Over Bluetooth
the same HID++ protocol behaves differently in three ways:
usagePage 0xff00/usage 0x0001tousagePage 0xff43, so the mouse was never offered by the WebHID picker;0x11) exists, sorequest()sending a0x10shortreport would have been rejected even if the mouse had been reachable;
0xFFrather than a receiver slot.On top of that,
readStatus()andgetDpiOptions()threw when a mouse exposedno DPI or report-rate feature. An office mouse exposes neither, so the read
failed on its behalf rather than reporting what the mouse could actually do.
Changes
protocol.ts:LOGITECH_BLUETOOTH_PRODUCT_IDSandisBluetoothProduct(),kept separate from
LOGITECH_DIRECT_PRODUCT_IDSso a Bluetooth mouse routesto index
0xFFwithout inheriting the G402's read-only polling rate or its"close Logitech Gaming Software" timeout message. Adds
decodeBatteryLevelStatus()for HID++0x1000.hidpp.ts: recognises the Bluetooth control interface, sends every request asa long report on that transport, reads Battery Level Status (
0x1000) whenthe rechargeable-pack features are absent, and treats a missing DPI or
report-rate feature as "not present" instead of an error.
vendors.ts:LOGITECH_BLUETOOTH_FILTERS, so the picker offers the mouse.control.ts: hides the polling card when a driver reports an explicitly emptyrate list, mirroring how an empty
supportedLiftOffDistancesalready hidesthe sensor card. Without this a mouse with DPI but no report rate showed an
empty card and a
0 Hzlive-status line.Battery Level Status is the feature Logitech's AA/AAA-powered mice expose. It
returns a coarse level rather than a continuous reading, and
0means"cannot measure" rather than "empty" — hence the explicit
null.Testing
npm run checkandnpm run sizepass (98 tests). New unit tests cover theBluetooth device-index routing, the separation from the direct-connect path, and
the
0x1000decoding.Behaviour was exercised against a scripted WebHID device standing in for the
mouse, in three configurations:
0x1000only — connects, shows battery, firmware andWireless / Bluetooth, hides the whole settings grid, and sends every
request as a 19-byte
0x11report;0x2201— DPI card appears on its own with the advertisedvalues, polling and sensor cards stay hidden;
c54dreceiver with0x2202/0x8061/0x1004— unchanged: DPIpresets, all seven rates, lift-off buttons, and short
0x10reports.Not yet confirmed on hardware
I have the mouse but cannot complete a hardware pass yet: macOS gates HID access
behind Input Monitoring, which I have not been able to grant on this machine.
The transport details above are decoded from the mouse's own HID report
descriptor, and the expectation that it exposes no DPI or report-rate feature is
inference from it being an office mouse, not a capture.
src/devices/logitech/TESTING.mdrecords this and lists what to check, so thefeature indexes it really answers with can be recorded once someone runs it.
Happy to hold this open until I can post that capture.