diff --git a/src/drivers/lamzu/hid.test.ts b/src/drivers/lamzu/hid.test.ts index 78d2943..77fd79c 100644 --- a/src/drivers/lamzu/hid.test.ts +++ b/src/drivers/lamzu/hid.test.ts @@ -413,10 +413,27 @@ test("each Inca connection gets the rate list that connection actually offers", assert.equal(LAMZU_INCA_PRODUCTS.get(0x0010)?.wireless, true); }); -test("the Inca's DFU bootloader identities are not offered as mice", () => { - // 0x000a is the mouse's flashing identity and 0x0002 the dongle's; neither - // speaks the config protocol, so a picker entry for them would be dead. - for (const bootloader of [0x000a, 0x0002]) { +test("the Paro Aurora carries the same split as the Inca, from the same vendor table", () => { + // Issue #167: Lamzu's own env-models.json gives the Paro Aurora PIDWired + // 0x0007, _1KDongle 0x000d and _8KDongle 0x000e, with the same + // IsNewProtocol/IsCompx flags and DPIMax as the Inca. None exercised on + // hardware yet, so the catalog is the only claim. + assert.equal(lamzuProduct(LAMZU_INCA_VENDOR_ID, 0x0007)?.model, "Paro Aurora"); + assert.equal(lamzuProduct(LAMZU_INCA_VENDOR_ID, 0x000d)?.model, "Paro Aurora"); + assert.equal(lamzuProduct(LAMZU_INCA_VENDOR_ID, 0x000e)?.model, "Paro Aurora"); + assert.deepEqual(LAMZU_INCA_PRODUCTS.get(0x0007)?.pollingRates, [125, 250, 500, 1000]); + assert.deepEqual(LAMZU_INCA_PRODUCTS.get(0x000d)?.pollingRates, [125, 250, 500, 1000]); + assert.deepEqual(LAMZU_INCA_PRODUCTS.get(0x000e)?.pollingRates, [500, 1000, 2000, 4000, 8000]); + assert.equal(LAMZU_INCA_PRODUCTS.get(0x0007)?.wireless, false); + assert.equal(LAMZU_INCA_PRODUCTS.get(0x000d)?.wireless, true); + assert.equal(LAMZU_INCA_PRODUCTS.get(0x000e)?.wireless, true); +}); + +test("the Inca's and Paro Aurora's DFU bootloader identities are not offered as mice", () => { + // 0x000a is the Inca mouse's flashing identity and 0x0002 the shared dongle's; + // the Paro adds 0x0008 (mouse) and 0x0004 (1K dongle). None speaks the config + // protocol, so a picker entry for one would be dead. + for (const bootloader of [0x000a, 0x0002, 0x0008, 0x0004]) { assert.equal(LAMZU_INCA_PRODUCTS.has(bootloader), false); assert.equal(LamzuHidClient.isSupported(fakeInca(bootloader)), false); } diff --git a/src/lamzu/index.ts b/src/lamzu/index.ts index b655bfd..f4f16d7 100644 --- a/src/lamzu/index.ts +++ b/src/lamzu/index.ts @@ -92,15 +92,28 @@ export const LAMZU_VENDOR_IDS: readonly number[] = [LAMZU_VENDOR_ID, LAMZU_INCA_ * has NOT been exercised on hardware; the protocol is the receiver protocol * either way, so the risk is a wrong rate list rather than a dead device. * + * The Paro Aurora (released mid-2025, PAW3950) is also entered here from that + * table, under the same vendor id and protocol flags as the Inca + * (`IsNewProtocol`: 1, `IsCompx`: 0, `DPIMax` 30000 — the driver default, so + * no `maxDpi` override). Its three ids are `PIDWired` 0x0007 (125-1000), + * `_1KDongle` 0x000d (125-1000) and `_8KDongle` 0x000e (500-8000). None of + * them has been exercised on hardware yet — issue #167 — so a wrong rate list + * is the failure mode, not a dead device. + * * Deliberately absent: 0x000a and 0x0002, which Aurora lists as * `DeviceBLPID` and `Receiver4K8KBLPID` — the DFU bootloader identities the * mouse and dongle take while flashing firmware. They never speak this - * protocol and must not be offered in the picker. + * protocol and must not be offered in the picker. The Paro's own bootloader + * ids, 0x0008 (`DeviceBLPID`) and 0x0004 (`_1KDongleIDVD`), are excluded for + * the same reason; its 8K dongle shares 0x0002 with the Inca. */ export const LAMZU_INCA_PRODUCTS: ReadonlyMap = new Map([ [0x0009, { model: "Inca 8K", wireless: false, pollingRates: RATES_1K }], [0x000f, { model: "Inca 8K", wireless: true, pollingRates: RATES_1K }], [0x0010, { model: "Inca 8K", wireless: true, pollingRates: RATES_8K }], + [0x0007, { model: "Paro Aurora", wireless: false, pollingRates: RATES_1K }], + [0x000d, { model: "Paro Aurora", wireless: true, pollingRates: RATES_1K }], + [0x000e, { model: "Paro Aurora", wireless: true, pollingRates: RATES_8K }], ]); /**