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" diff --git a/src/device/preview/preview-fixtures.ts b/src/device/preview/preview-fixtures.ts index b0d74d87..a30d5061 100644 --- a/src/device/preview/preview-fixtures.ts +++ b/src/device/preview/preview-fixtures.ts @@ -343,6 +343,37 @@ 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, 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"], + name: "Cosmic Byte Kilonova 3335IC", + ui: { + family: "sinowealth-kilonova-3335ic", + settingsReady: false, + valuesVerified: true, + forceShowBattery: true, + hideProcessingCard: true, + defaultDisplayName: "Cosmic Byte Kilonova 3335IC", + 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: 1600, + dpiStages: [400, 800, 1600, 3200, 6400, 16000], + activeDpiStage: 2, + 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 +1117,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 ? (