Skip to content

Keep battery and connection type live: refresh by visibility, follow the cable - #10

Merged
snekxs merged 1 commit into
OpenMouse-Project:mainfrom
EmreO33:live-status-and-transport-switch
Sep 19, 2026
Merged

snekxs merged 1 commit into
OpenMouse-Project:mainfrom
EmreO33:live-status-and-transport-switch

Conversation

@EmreO33

@EmreO33 EmreO33 commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Two things I hit as a user of 0.0.28/0.0.29 with a DeathAdder V3 Pro, both fixed in use-mouse-connection.ts only:

  1. Battery never changed until I quit and relaunched.
  2. Plugging the cable in (or out) wasn't noticed: it kept saying Wireless until a relaunch.

Why

The background refresh skipped outright whenever the window was not the focused one, or the Performance tab was open. Those are the two most common ways to actually look at the app (glancing at it from a game or browser; sitting on DPI/polling), so in practice the status was frozen. And nothing re-enumerated interfaces after a connect, while the cable enumerates as a different product id (0x00b6) from the receiver (0x00b7), so "now wired" is a new interface appearing, not a status change on the one that's open.

Refresh cadence follows visibility instead of stopping

State Interval
Focused 5 s (unchanged)
Visible, another app focused 15 s
Performance tab open 30 s
Hidden / minimized / tray 60 s (from #9)

The Performance tab's staged values only reset when status.dpi etc. actually change (DevicePerformanceTab.tsx:71), so an unchanged background read has no visible effect mid-edit; the hid-open-lock still makes a tick that lands during a write skip. I kept it gentle (30 s) rather than the full 5 s out of respect for the "CONFIRMED jarring" note, but it no longer stops.

Transport hot-swap

A 3 s listCandidateInterfaces() (plain hidapi enumeration, nothing opened; measured at 19 calls/min in the dev log) while connected or while waiting for a vanished mouse:

  • Connected interface gone (cable pulled, dongle pulled): connect to the same mouse on its sibling transport if one is present. Otherwise drop to the list with a toast and keep watching; it reconnects by itself when the mouse or its sibling comes back.
  • Sibling appeared while on the receiver: read it, confirm it's the same unit (unitId match; product-string match with transport words stripped is the pre-filter), and move to the wired side. Wired is where the mouse actually is at that point and the only side that reports charging. Dongle inserted while wired deliberately does not switch.
  • Launch-time auto-reconnect also accepts the remembered mouse's sibling transport.

isSiblingTransport is exported for testing; the only network of assumptions is "same vendor, same product string modulo wired/wireless/dongle/receiver words", and the status read's unitId guards the switch on top of that.

Verified live (dev build, DeathAdder V3 Pro, firmware 2.1)

From the timestamped dev log: reads on 00b6 while wired; cable out → 00b7 opened at 16:51:35; cable back in → 00b6 at 16:51:45. Sequence I ran: dongle pulled → "disconnected" toast within a scan; cable in → auto-reconnected as Wired; dongle back in → stayed Wired; cable out → Wireless in ~3 s; cable in → Wired in ~3 s. No clicks. tsc --noEmit clean.

Not tested on macOS/Linux; nothing here is platform-specific beyond hidapi enumeration that already existed.

…the cable

Two user reports against the same root cause: the connected device's status
only ever moved while the window was focused and the Performance tab was
closed, and nothing re-scanned interfaces once something was connected. In
practice battery stayed frozen while glancing at the app from another
window or while sitting on the Performance tab, and plugging the cable in
or out (a different product id over USB than over the receiver) was not
noticed until the app was relaunched.

Refresh cadence now follows what the user can see instead of stopping:
5 s focused (unchanged), 15 s visible but unfocused, 30 s with the
Performance tab open, 60 s hidden/minimized. The Performance tab's staged
values only reset when the device value actually changes, so an unchanged
read has no visible effect there.

A 3 s interface enumeration (nothing opened) drives transport hot-swap:
- Connected interface vanished: connect to the same mouse on its sibling
  transport if present; otherwise drop to the list and keep watching,
  reconnecting on its own when the mouse or its sibling is back.
- Sibling appeared while on the receiver: read it, confirm it is the same
  unit (unitId, after a product-string pre-filter), and move to the wired
  side. Dongle inserted while wired does not switch.
- Launch-time auto-reconnect also accepts the remembered mouse's sibling.

Verified on a DeathAdder V3 Pro (0x00b6 wired / 0x00b7 receiver): dongle
pulled -> "disconnected" within a scan; cable in -> auto-reconnected wired;
dongle back in -> stayed wired; cable out -> wireless in ~3 s; cable in ->
wired in ~3 s. All without touching the app.
@snekxs
snekxs merged commit 5f78afe into OpenMouse-Project:main Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants