Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion build/check-bundle-size.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { join } from "node:path";
// measured 3_171_143 bytes with it.
const BUDGET_BYTES: Record<string, number> = {
".css": 165_000,
".js": 3_200_000,
// Raised from 3_200_000 for the Amkette XS driver and its shared 0x04F3 codec
// in @openmouse/protocol: +18,624 bytes measured against mouse-protocol main.
".js": 3_220_000,
};

const ASSETS = join("dist", "assets");
Expand Down
3 changes: 3 additions & 0 deletions src/device/traits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ const BY_FAMILY: Readonly<Record<string, Partial<DriverTraits>>> = {
// it publishes its own sleep and debounce option lists.
"mchose-v3": { advancedSection: true, sleep: true, debounce: true },
dareu: { advancedSection: true, sleep: true },
// Amkette's XS firmware stores auto sleep as whole minutes and publishes its
// own list through getSleepOptions.
"amkette-xs": { advancedSection: true, sleep: true },
// The Model O2 Pro 4K/8K writes a debounce block and a motion sync flag; it
// has no sleep command wired in, so no sleep flag.
"glorious-core2": { advancedSection: true, debounce: true },
Expand Down
10 changes: 10 additions & 0 deletions src/shared/device-images.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ test("PRO X3 SUPERSTRIKE gets its own render, not the X2's", () => {
assert.equal(deviceImage(null, "Attack Shark X3"), CDN + "attackshark-x3.png");
});

test("Amkette XS Flow 2 Speed resolves by model name, never from the shared ids", () => {
assert.equal(deviceImage(dev(0x04f3, 0x026e), "XS Flow 2 Speed"), CDN + "amkette-xs-flow-2-speed.png");
assert.equal(deviceImage(dev(0x04f3, 0x026d), "XS Flow 2 Speed"), CDN + "amkette-xs-flow-2-speed.png");
assert.equal(deviceImage(null, "Amkette XS Flow 2 Speed"), CDN + "amkette-xs-flow-2-speed.png");
// Without a model name the mouse could be any XS model, or share ids with a
// Ryunix Kyu Pro MX1, so it keeps the placeholder.
assert.equal(deviceImage(dev(0x04f3, 0x026e), "XS series"), CDN + "unknown-device.png");
assert.equal(deviceImage(dev(0x04f3, 0x026e), "Kyu Pro MX1"), CDN + "unknown-device.png");
});

test("Razer Orochi V2 resolves by name", () => {
assert.equal(deviceImage(dev(0x1532, 0x0094), "Razer Orochi V2"), CDN + "razer-orochi-v2.png");
});
Expand Down
5 changes: 5 additions & 0 deletions src/shared/device-images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ function computeDeviceImageFilename(displayName: string): string {
}
if (/\br5\s*ultra\b/i.test(displayName)) return "attackshark-r5-ultra.png";
if (/\bfloat\s*88\b/i.test(displayName)) return "ipi-float-88.png";
// Amkette XS Flow 2 Speed: the driver reports this model name only once the
// mouse names itself ("XS Speed" over USB, "XS speed N" over Bluetooth). Its
// nameless fallback, "XS series", could be any XS model, so it keeps the
// placeholder rather than guess.
if (/\bxs\s*flow\s*2\s*speed\b/i.test(displayName)) return "amkette-xs-flow-2-speed.png";
if (/\batk\s*zero\b/i.test(displayName)) return "atk-zero.png";
// R2 shares PID 0x402D with the Lingbao M5 Pro, so it can only be told apart
// by the name the gearhub driver reads back from the device id.
Expand Down
Loading