From 7012c721c2ce1ba2ae3a1f4b20a737c15e0f4123 Mon Sep 17 00:00:00 2001 From: ydw1904 Date: Tue, 25 Aug 2026 17:18:39 +0800 Subject: [PATCH] feat(keychron): claim the M6 with its own driver instead of Pulsar's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The M6 driver in @openmouse/protocol is enough for the registry to detect the mouse, but not for the app to drive it: the sidebar lists it as "Keychron · Available" and activating it fails with client.describeCollections is not a function pulsarClient() is a negative check — any active client not listed in DEDICATED is assumed to be a Pulsar client and routed into showPulsarExplorer(), which calls describeCollections(), a method only the Pulsar drivers have. A new driver class is therefore broken by default until it is named here, and the error points nowhere near the cause. KeychronM6HidClient joins NEEDS_OPEN, next to the Nape Pro's KeychronHidClient: its open() is what attaches the input-report listener its query/reply exchanges depend on, and NEEDS_OPEN feeds DEDICATED, so one entry covers both. Verified on a wired Keychron M6: the device connects and reports 800 DPI, 500 Hz, and battery, and a DPI change flashes to the mouse and reads back. Needs the M6 driver from OpenMouse-Project/mouse-protocol#33. --- src/device/controller.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/device/controller.ts b/src/device/controller.ts index 29c7980..3bf5c52 100644 --- a/src/device/controller.ts +++ b/src/device/controller.ts @@ -109,6 +109,7 @@ import { TeevolutionHidClient } from "@openmouse/protocol/drivers/teevolution/hi import { teevolutionProfileForCid } from "@openmouse/protocol/teevolution"; import { VgnF2HidClient } from "@openmouse/protocol/drivers/vgn/hid"; import { KeychronHidClient } from "@openmouse/protocol/drivers/keychron/hid"; +import { KeychronM6HidClient } from "@openmouse/protocol/drivers/keychron/m6-hid"; import { FantechHidClient } from "@openmouse/protocol/drivers/fantech/hid"; import { WallhackMouseHidClient } from "@openmouse/protocol/drivers/wallhack/mouse-hid"; import { WallhackKeyboardHidClient } from "@openmouse/protocol/drivers/wallhack/keyboard-hid"; @@ -163,7 +164,7 @@ function activeAs(...classes: ClientClass[]): T | null { const DM_CLASSES = [WLMouseHidClient, LamzuHidClient, AtkHidClient, NinjutsoHidClient] as const; const RAZER_CLASSES = [RazerHidClient, RazerViperMiniHidClient, RazerViperHidClient, RazerCobraHidClient] as const; -const NEEDS_OPEN = [TeevolutionHidClient, VgnF2HidClient, KeychronHidClient, ModdoHidClient, ZaunkoenigHidClient, FantechHidClient, WallhackMouseHidClient, WallhackKeyboardHidClient] as const; +const NEEDS_OPEN = [TeevolutionHidClient, VgnF2HidClient, KeychronHidClient, KeychronM6HidClient, ModdoHidClient, ZaunkoenigHidClient, FantechHidClient, WallhackMouseHidClient, WallhackKeyboardHidClient] as const; const DEDICATED = [ ...DM_CLASSES, ...RAZER_CLASSES, ...NEEDS_OPEN, EggOp1HidClient, LogitechHidppClient, OrbitalHidClient, RazerViperV4ProHidClient, FinalmouseHidClient,