Skip to content

feat(glorious): driver for the Model O 2 PRO 4K/8K - #181

Merged
snekxs merged 2 commits into
OpenMouse-Project:mainfrom
ydw1904:feat/glorious-o2-pro-4k8k
Oct 8, 2026
Merged

snekxs merged 2 commits into
OpenMouse-Project:mainfrom
ydw1904:feat/glorious-o2-pro-4k8k

Conversation

@ydw1904

@ydw1904 ydw1904 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Capture from Discord ticket 0160 (there is no GitHub issue for this one). App wiring: OpenMouse-Project/openmouse#675 (draft). Catalog: OpenMouse-Project/openmouse-landing-page#37.

What the mouse is

The Model O 2 PRO 4K/8K (USB 0x258a:0x201b on the cable, 0x258a:0x2035 receiver) speaks the Glorious CORE feature-report protocol that korkje/mxw documents for the Model O/D Wireless, with a different register map and per-profile data. A request is an unnumbered 64-byte feature report on the collection with usage page 0xffff, usage 0 (interface 2): 00 00 02 <len> <bank> <register> <data...>. Bank 0 is system, 1 per-profile settings, 2 per-profile lighting, and the profile id comes first in every per-profile register. A reply is the GET_REPORT about 60 ms later, with status 0xa1 in byte 0. There is no checksum.

The capture is a community USBPcap of Glorious CORE on a wired unit while the owner stepped through the polling rate, Motion Sync and debounce. It shows the bytes. What each register is comes from CORE 2.1.21's own frame builders (the MouseV2ProDeviceHandler class, which also drives the Model O/D Wireless; CORE's device table lists this mouse as "MODEL O 2 PRO 4k/8kHz Edition", config channel 0xffff:0, DPI 100 to 26000, three profiles). That settled what the capture only shows by example: register 0x09 is Motion Sync, 0x08 is a debounce block (simple or advanced; the capture's 00 00 0a 0a 08 is CORE's default advanced times), 0x0b is lift-off. Nothing from CORE is committed.

What this adds

  • src/glorious-core2/index.ts, exported as @openmouse/protocol/glorious-core2 and gloriousCore2 on the root: the frame builder, a reply decoder, and one encoder per field (DPI stages, stage colors, active stage, polling rate, debounce in both modes, Motion Sync, profile select, firmware and battery reads). Tests re-encode all 116 captured requests (22 distinct) byte for byte, decode the firmware reply (1.0.15.0) and the ten battery replies, and check the 11 DPI-button input reports against the stage table CORE wrote.
  • src/drivers/glorious/core2-hid.ts: GloriousCore2HidClient for the cable and the receiver. It reads firmware and battery and writes DPI stages (value, count up to 6, color, active stage), polling rate (125 to 8000 Hz, 4000 Hz on the receiver), debounce (4 to 16 ms), Motion Sync and the active profile, pausing between frames as CORE does (30 ms, 120 ms after the active stage). The mouse has no read for those settings, so the client keeps its last-written values per profile in localStorage and reports valuesVerified: false.
  • Registry entry and GLORIOUS_CORE2_HID_FILTERS (VID, PID, usage page 0xffff). 0x201b and 0x2035 leave GLORIOUS_CLASSIC_PRODUCTS so that exactly one driver claims them; the registry overlap test covers it.
  • captures/glorious-o2-pro-4k8k-wired/: the config-interface frames and the DPI-button reports, with a README giving each file's trust level, what the owner did, and the register table. docs/glorious-o2-pro-4k8k.md: sources, assumptions and a test list for the owner.

What is deliberately missing

  • Reading any setting back. CORE never does and no command is known, so DPI, polling, debounce, Motion Sync and the active profile are the driver's last writes, not the mouse's.
  • The active profile. Every setting is written to one of three profiles and the mouse cannot say which is active. The client assumes profile 1 until the user picks one in the Profile card, which sends CORE's own select frame (00 00 02 01 00 05 <n>). That is the one frame here that is not in the capture: CORE already had profile 2 selected, and mxw sends the same bytes.
  • Lift-off. CORE writes the same value for both of its 1.0 mm and 2.0 mm options, so the value to distance map is unknown.
  • Auto sleep, lighting, buttons and macros. Not captured. The advanced debounce encoder exists because the capture contains the frame, but the client does not offer it.
  • The receiver. No capture. The frames are the ones CORE sends over either link, but reading the receiver's own firmware (target byte 0) comes from CORE's code only.
  • The Model D2 Pro 4K/8K (0x201c, 0x2036) has the same handler in CORE and probably the same frames, but no capture of it exists here, so it stays on the classic driver.

Verification

npm run check: build clean, 2193 pass, 0 fail (registry probe matrix included), pack dry-run OK. Not tested on hardware. Next from the owner: connect on the cable, check battery and firmware, set 1000 and 8000 Hz and measure, change a DPI stage, and if nothing changes pick the profile CORE shows. The full list is in docs/glorious-o2-pro-4k8k.md.

The Model O 2 PRO 4K/8K (0x258a:0x201b on the cable, 0x2035 through its
receiver) speaks the Glorious CORE feature-report protocol: unnumbered
64-byte reports on the 0xffff:0 collection, `00 00 02 len bank register
data`, with the profile id first in every per-profile register.

The codec (src/glorious-core2/index.ts) re-encodes all 116 requests of a
community capture of Glorious CORE on a wired unit (Discord ticket 0160)
byte for byte. What each register is comes from CORE's own frame
builders: DPI stages and colors, active stage, polling rate (one code for
the cable and one for 2.4 GHz), simple and advanced debounce, motion
sync, profile select, and the firmware and battery reads.

GloriousCore2HidClient reads firmware and battery and writes DPI stages,
polling rate (125 to 8000 Hz, 4000 Hz on the receiver), debounce, motion
sync and the active profile. The mouse has no read for those settings, so
the client keeps its last-written values per profile. Lift-off, auto
sleep, lighting and buttons are left out: not captured, or, for lift-off,
CORE writes the same value for both of its options.

0x201b and 0x2035 leave GLORIOUS_CLASSIC_PRODUCTS so that exactly one
driver claims them. Not tested on hardware.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Resolve SupportedClient union: keep GloriousCore2HidClient from this
branch alongside CorsairBragiHidClient and AjazzHidClient from main.
@snekxs
snekxs merged commit 03a5f34 into OpenMouse-Project:main Oct 8, 2026
5 checks passed
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 0.30.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants