Repository navigation
Description
I maintain open-directional-dpi, a small open protocol and C engine for per-direction mouse sensitivity: one gain per 45° direction, 0.0625x to 4x. On the Glorious Series One Pro Wireless it runs as a patch to the stock v1.0.0.0 firmware. The patch keeps every stock command and adds the protocol to the same 64-byte Feature report the classic driver already uses (interface 2, usage page 0xFFFF). I'd like to add it here after #303. I have it on a branch already (0zLloen/mouse-protocol feat/open-directional-dpi, on top of #303) and would like your view on where it goes before I open the PR.
- Protocol, engine and patch: https://github.com/0zLloen/open-directional-dpi. The spec this port follows is at commit
1acd0fd: https://github.com/0zLloen/open-directional-dpi/blob/1acd0fd/spec/hid-protocol-v1.md - Firmware notes and Compx tools: https://github.com/0zLloen/mouse-firmware-re
Verified on hardware (one retail mouse, Linux hidraw with the project's tools/odd_profile.py, 2026-11-13, three patch builds)
- Stamp: the stock firmware-version reply carries "DP01", at bytes 16..19 by cable
258a:2018and at 12..15 through the receiver258a:2031(builds from505404con, the first with the receiver relay). A stock mouse answers the same query without it (checked by cable; through the receiver this is inferred, since the stock firmware has no stamp code). - First build (before
505404c), by cable: GET_CAPABILITIES and GET_PROFILE. SET_PROFILE with "up" at 0.50x moved the up/down count ratio from 0.913 to 0.618. A SAVE_FLASH survived a reboot and two full reflashes. 505404c, through the receiver: GET_CAPABILITIES, GET_PROFILE, SET_PROFILE and SAVE_FLASH. With "up" at 0.50x the ratio went from 0.938 to 0.570.21ea252, the current build: by cable, GET_CAPABILITIES with the firmware's idle-reset clock at 1000.0 ticks/s. Through the receiver, "up" at 0.50x gave 0.681 (0.938 flat on505404c), a save that erased flash answered after 402 ms and an unchanged save after 24 ms, and the saved profile survived power-off.- Receiver relay: requests go with body[2] = 0x02 and body[3] = 0x3A, outside the CRC. The receiver can show 0xA4 for a few hundred ms during an erase, so hosts poll up to 2 s and treat only a final 0xA4 as unreachable. While the mouse sends no reports the receiver also answers 0xA4.
- Not verified: anything over WebHID on hardware (the code below is tested against fake devices only).
Safety: no protocol packet is sent until the stamp is seen. Requests carry seq 5..255 in body[4]. Stock firmware rejects body[4] >= 5 before any handler runs, and the receiver runs its local handlers only when body[4] = 0. So a request cannot trigger a stock command or the receiver's mode (0x00) or RF ID (0x0A) handlers. Every request through the receiver has body[2] = 0x02.
What the branch does
- Codec:
src/open-directional-dpi/index.ts, subpath@openmouse/protocol/open-directional-dpi, namespaceopenDirectionalDpi. It holds the CRC, the 28-byte profile codec (magic, version, CRC and range checks), the 64-byte request framing, a response parser that returns null for anything but the answer to that seq and opcode, and capabilities parsing. It is not Glorious-specific. - Glorious specifics in
src/glorious-classic/index.ts: the relayed version query (buildGloriousClassicFirmwareRequestPayload({ relay: true })), the stamp check and the relay envelope. - Driver: methods on
GloriousClassicHidClient, gated on 258a:2018 / 258a:2031 and the stamp.readStatus()fills an optionaldirectionalDpifield (profile, sensor DPI, whether it can save); a detection error never fails the status read, and the read is skipped while the receiver's battery answer says the mouse is asleep (0xA4).setDirectionalDpiProfile()returns the profile the mouse echoes, andsaveDirectionalDpi()writes it to flash. Feature-report transactions are queued, so a battery read cannot land between a request and its answer. No registry or vendors.ts change. - Tests with node:test: codec cases (CRC check value, profiles serialized by the C engine, rejected inputs, framing, answers), a fake stock mouse that never receives a protocol packet, and fake patched cable and receiver devices (stale answers, transient and final 0xA4, 65-byte replies, no read while asleep).
docs/glorious-series-one-pro.mdgets a short section on the patched firmware.- OpenMouse builds and passes its tests against the local package unchanged. Its JS bundle grows by about 5.5 kB and stays under the budget. The OpenMouse card would follow in its own PR once a release has these methods.
Questions
- An own subpath for the codec, or only a re-export through glorious-classic like
src/compx? - Methods on
GloriousClassicHidClient, or a Series One Pro subclass with its own registry entry? - Is an optional
directionalDpifield onMouseStatus(likelunafury) the shape you want for the UI? - Devices that identify by the product string "[OpenDDPIv1]" (Zephyr builds) have no fixed IDs and none is verified yet. I'd leave them out for now. OK?
open-directional-dpi is MIT; I'll contribute the port under this repo's AGPL-3.0-or-later.
Activity