From 7279e8f72cbf38c3357e420b44780ca3d28de628 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:31:43 +0000 Subject: [PATCH 1/3] chore(protocol): bump @openmouse/protocol to 0.46.0 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43e1251d..add7aac7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "AGPL-3.0-or-later", "dependencies": { "@openmouse/keyboard-protocol": "1.1.0", - "@openmouse/protocol": "0.45.2", + "@openmouse/protocol": "0.46.0", "lucide-react": "^1.43.0", "posthog-js": "^1.438.17", "preact": "^10.29.8" @@ -492,9 +492,9 @@ } }, "node_modules/@openmouse/protocol": { - "version": "0.45.2", - "resolved": "https://registry.npmjs.org/@openmouse/protocol/-/protocol-0.45.2.tgz", - "integrity": "sha512-971Aihm8fJOuRHxNvhEPKYpWe5BM4v9GO8bahHKTxGa4nMrtKYd46A9gPKDqIZk0T+mnyjfBloH1T4vum5Qzag==", + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@openmouse/protocol/-/protocol-0.46.0.tgz", + "integrity": "sha512-7/llEdOV4tslecHd39h9ZD+YfgqvV/vJie1F012GD0+Pc82Vh+41Z461lJDeO8cHFG3VnqYP52OxPqJM4Xe6ZQ==", "license": "AGPL-3.0-or-later", "engines": { "node": ">=20" diff --git a/package.json b/package.json index 52889f6e..b9917100 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@openmouse/keyboard-protocol": "1.1.0", - "@openmouse/protocol": "0.45.2", + "@openmouse/protocol": "0.46.0", "lucide-react": "^1.43.0", "posthog-js": "^1.438.17", "preact": "^10.29.8" From 294783338fd05cc3b61cffbbd4a8ad0066ecd124 Mon Sep 17 00:00:00 2001 From: m4milaad Date: Fri, 23 Oct 2026 19:17:38 +0530 Subject: [PATCH 2/3] feat(devices): render driver status note and battery hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drivers already declare two shell hints in MouseUiHints that nothing rendered: `statusNote` (an extra sentence for the connected status line, explained why a connection is limited) and `forceShowBattery` (show the battery column even when the percent is unknown). The Cosmic Byte Kilonova 3335IC driver in OpenMouse-Project/mouse-protocol#249 is the first one that relies on both, so with the current shell its page showed the device and nothing else. - The hero's connected status line now appends `status.ui.statusNote` after the connection detail. - `forceShowBattery` now keeps the battery present in the hero stats and the current-setup figures, shown as "–" while the percent is unknown, instead of only when a percent exists. Wired devices that report no percent until they flunk a battery read (Endgame Gear OP1 V2 fixtures already set the hint) gain the same column. - Adds a `?preview=kilonova` fixture mirroring the driver's browser status so the composition is visible without the hardware. --- src/device/preview/preview-fixtures.ts | 31 ++++++++++++++++++++++++++ src/device/preview/preview-modes.ts | 2 ++ src/features/devices/DeviceHero.tsx | 4 ++++ src/features/devices/DeviceStats.tsx | 5 +++++ 4 files changed, 42 insertions(+) diff --git a/src/device/preview/preview-fixtures.ts b/src/device/preview/preview-fixtures.ts index b0d74d87..57f384fe 100644 --- a/src/device/preview/preview-fixtures.ts +++ b/src/device/preview/preview-fixtures.ts @@ -343,6 +343,36 @@ const ATTACKSHARK: MouseStatus = { firmware: ["Mouse 1.0.4", "Dongle 1.0.3"], }; +/** + * The Cosmic Byte Kilonova 3335IC through its receiver (SinoWealth + * `258a:002f`), browser transport: identity and connection only, with battery + * and link waiting on OpenMouse Bridge to claim report 5. The driver refuses + * writes until the bank is decoded, so the shell shows the device, the note, + * and no settings cards. + */ +const KILONOVA: MouseStatus = { + brand: "Cosmic Byte" as MouseStatus["brand"], + name: "Cosmic Byte Kilonova 3335IC", + ui: { + family: "sinowealth-kilonova-3335ic", + settingsReady: false, + valuesVerified: false, + forceShowBattery: true, + hideProcessingCard: true, + defaultDisplayName: "Cosmic Byte Kilonova 3335IC", + statusNote: "OpenMouse recognizes this receiver as a Cosmic Byte Kilonova 3335IC and leaves its settings untouched: the settings layout is not decoded yet. The battery and awake check need OpenMouse Bridge.", + }, + batteryPercent: null, + batteryState: "Unknown", + dpi: 0, + pollingRateHz: 0, + activeProfile: null, + connectionType: "Wireless", + connectionDetail: "2.4 GHz receiver", + liftOffDistance: null, + firmware: [], +}; + const M3K: MouseStatus = { brand: "Zaunkoenig" as MouseStatus["brand"], name: "Zaunkoenig M3K", @@ -1086,6 +1116,7 @@ export const PREVIEW_FIXTURES: Record = { wlmouse: { label: "WLMouse BEAST X", status: WLMOUSE }, lamzu: { label: "Lamzu Atlantis OG V2", status: LAMZU }, "attack-shark": { label: "Attack Shark R5 Ultra", status: ATTACKSHARK }, + kilonova: { label: "Cosmic Byte Kilonova 3335IC", status: KILONOVA }, crdrako: { label: "CRDRAKO KO-ONE", status: CRDRAKO }, m3k: { label: "Zaunkoenig M3K", status: M3K }, atk: { label: "ATK A9 Ultra", status: ATK }, diff --git a/src/device/preview/preview-modes.ts b/src/device/preview/preview-modes.ts index fe185d70..69e5db06 100644 --- a/src/device/preview/preview-modes.ts +++ b/src/device/preview/preview-modes.ts @@ -20,6 +20,7 @@ export const PREVIEW_KEYS = [ "wlmouse", "lamzu", "attack-shark", + "kilonova", "crdrako", "m3k", "atk", @@ -70,6 +71,7 @@ export function parsePreviewMode(value: string | null): PreviewMode | null { case "wlmouse": return "wlmouse"; case "lamzu": return "lamzu"; case "attack-shark": return "attack-shark"; + case "kilonova": return "kilonova"; case "crdrako": return "crdrako"; case "m3k": return "m3k"; case "atk": return "atk"; diff --git a/src/features/devices/DeviceHero.tsx b/src/features/devices/DeviceHero.tsx index 0fecfaea..be48690f 100644 --- a/src/features/devices/DeviceHero.tsx +++ b/src/features/devices/DeviceHero.tsx @@ -30,6 +30,7 @@ export function DeviceHero({ const activeEntry = snapshot.devices.find((device) => device.selected) ?? null; const name = status?.name ?? keyboard?.name ?? activeEntry?.name ?? ""; const brand = status ? noirBrandLabel(status) : null; + const statusNote = status?.ui?.statusNote ?? null; const image = snapshot.deviceArtwork ?? (keyboard ? deviceImage({ vendorId: keyboard.vendorId, productId: keyboard.productId } as HIDDevice, keyboard.name) : null); const needsArtwork = Boolean(status && active && (imageFailed || isUnknownDevice( @@ -82,6 +83,7 @@ export function DeviceHero({ {brand ? <>{displayText(locale, brand)} : null} {status?.connectionDetail ? <>{displayText(locale, status.connectionDetail)} : null} {activeEntry?.transport === "bridge" ? <>{t(locale, "bridge.title")} : null} + {statusNote ? <>{statusNote} : null}

{status ? : null} @@ -152,6 +154,8 @@ export function CurrentSetupPanel({ snapshot }: { snapshot: ControlSnapshot }): unit: "%", sub: displayText(locale, status.batteryState), }); + } else if (status.ui?.forceShowBattery === true) { + figures.push({ key: "battery", label: t(locale, "ov.batteryLabel"), value: "–" }); } if (status.activeProfile != null) { figures.push({ key: "profile", label: t(locale, "ov.onboardProfile"), value: String(status.activeProfile) }); diff --git a/src/features/devices/DeviceStats.tsx b/src/features/devices/DeviceStats.tsx index 1552cf09..cc77b77d 100644 --- a/src/features/devices/DeviceStats.tsx +++ b/src/features/devices/DeviceStats.tsx @@ -41,6 +41,11 @@ export function DeviceStats({ {status.batteryPercent}% {estimate && full ? {estimate.time} : null} + ) : status.ui?.forceShowBattery === true ? ( + + + {"–"} + ) : null} {status.pollingRateHz > 0 ? ( From b631b0bbaa62d23b4a8fe17472c63837b377aa28 Mon Sep 17 00:00:00 2001 From: m4milaad Date: Sat, 24 Oct 2026 17:50:46 +0530 Subject: [PATCH 3/3] fix(preview): update Kilonova fixture to show decoded DPI --- src/device/preview/preview-fixtures.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/device/preview/preview-fixtures.ts b/src/device/preview/preview-fixtures.ts index 57f384fe..a30d5061 100644 --- a/src/device/preview/preview-fixtures.ts +++ b/src/device/preview/preview-fixtures.ts @@ -345,10 +345,9 @@ const ATTACKSHARK: MouseStatus = { /** * The Cosmic Byte Kilonova 3335IC through its receiver (SinoWealth - * `258a:002f`), browser transport: identity and connection only, with battery - * and link waiting on OpenMouse Bridge to claim report 5. The driver refuses - * writes until the bank is decoded, so the shell shows the device, the note, - * and no settings cards. + * `258a:002f`), browser transport: identity, battery, link, and read-only DPI. + * The driver refuses writes until the full bank is decoded, so the shell shows + * DPI read-out but no settings cards. */ const KILONOVA: MouseStatus = { brand: "Cosmic Byte" as MouseStatus["brand"], @@ -356,15 +355,17 @@ const KILONOVA: MouseStatus = { ui: { family: "sinowealth-kilonova-3335ic", settingsReady: false, - valuesVerified: false, + valuesVerified: true, forceShowBattery: true, hideProcessingCard: true, defaultDisplayName: "Cosmic Byte Kilonova 3335IC", - statusNote: "OpenMouse recognizes this receiver as a Cosmic Byte Kilonova 3335IC and leaves its settings untouched: the settings layout is not decoded yet. The battery and awake check need OpenMouse Bridge.", + statusNote: "OpenMouse reads this Cosmic Byte Kilonova 3335IC's DPI from its onboard memory; other settings are not decoded and changes are refused. The battery and awake check need OpenMouse Bridge.", }, batteryPercent: null, batteryState: "Unknown", - dpi: 0, + dpi: 1600, + dpiStages: [400, 800, 1600, 3200, 6400, 16000], + activeDpiStage: 2, pollingRateHz: 0, activeProfile: null, connectionType: "Wireless",