feat: reach a mouse through OpenMouse Bridge where WebHID is missing - #127
Open
ydw1904 wants to merge 1 commit into
Open
feat: reach a mouse through OpenMouse Bridge where WebHID is missing#127ydw1904 wants to merge 1 commit into
ydw1904 wants to merge 1 commit into
Conversation
Firefox has no WebHID and Mozilla's position on it is negative, so the control panel is currently a dead end there — as it is in any browser without the API. Bridge already runs on the user's machine and now exposes native HID over its loopback socket, so this implements `navigator.hid` against it and installs the shim when the browser has none of its own. Nothing else changes. The shim satisfies the same WebHID surface `@openmouse/protocol`'s drivers are written against, so the registry's auto-detection, every driver, and every card in the panel work unmodified and never learn they are not in Chrome. `installBridgeHid()` also accepts `force`, for the case where WebHID exists but withholds a collection a device needs. Two places where Bridge cannot match WebHID exactly, both deliberate: - `getDevices()` returns every supported mouse rather than only ones the user granted through a picker. Bridge has no per-site grant and does not need one — the user installed a companion app for this site, and Bridge only accepts sockets from its own origin allowlist. A supported mouse is simply present on load, with nothing to click through. - Hot-plug comes from re-enumerating every two seconds rather than a push, which keeps connect and disconnect handling in one place. Safari is still out: it does not treat loopback as a trustworthy origin and blocks the socket as mixed content. Reaching Safari means having Bridge serve the app itself over loopback, which is a separate change. Deciding whether the browser is supported now waits on the loopback probe, which either answers in milliseconds or not at all.
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.
Why
Firefox has no WebHID and Mozilla's standards position on it is negative, so the control panel is a dead end there — as it is in any browser without the API. Today
browser-support.tscan only tell those users to switch browsers.OpenMouse Bridge already runs on the user's machine. With OpenMouse-Project/OpenMouse-Bridge#3 it exposes native HID over its loopback socket, so this implements
navigator.hidagainst it and installs the shim when the browser has none of its own.Depends on OpenMouse-Project/OpenMouse-Bridge#3. Without a Bridge build carrying
/v1/hid,installBridgeHid()finds nothing on loopback and everything behaves exactly as it does today.What changes
src/bridge-hid.tsimplements the WebHID surface the@openmouse/protocoldrivers are written against, backed by the socket.control.tsxawaitsinstallBridgeHid()before deciding the unsupported notice, andbrowser-support.tsnow names Bridge in the non-Chromium copy.Nothing else changes. The driver registry's auto-detection, every driver, and every card work unmodified and never learn they are not in Chrome — Bridge parses the report descriptor, so
device.collectionsis real andisSupported()behaves as it does over WebHID. That is what lets this reuse the app wholesale instead of maintaining a parallel brand table the way Bridge'snative-hid/and the Desktop app have to.installBridgeHid()also acceptsforce, for the case where WebHID exists but withholds a collection a device needs.Where Bridge cannot match WebHID exactly
Both deliberate, both documented in the module:
getDevices()returns every supported mouse, not only ones granted through a picker. Bridge has no per-site grant and does not need one: the user installed a companion application for this site specifically, and Bridge only accepts sockets from its own origin allowlist. The practical effect is that a supported mouse is simply present on load, with nothing to click through.Verification
npm run buildandnpm testpass. Four new tests drive the shim through a fake transport: a full device round trip (list, open,sendReport, an input report arriving as aDataView,receiveFeatureReport), rejected requests surfacing Bridge's reason, re-enumeration preserving device identity while reporting hot-plug both ways, and a dropped socket closing every device and rejecting what was in flight.Validated in Firefox against a Keychron M6 over Bridge: the device auto-detects,
readStatus()reports 800 DPI / 500 Hz / 100% wired, and a DPI change flashes to the mouse and reads back.Out of scope
forceoption exists, but nothing calls it; Chrome keeps using its own WebHID.🤖 Generated with Claude Code