SOURCE / PINNED RELEASE
Made of little things.
Poly Dogfight
- Release
- b8511ee374e3…
- Author-recorded commit
- 5579434b9d8b…
- License
- LICENSE
- Author’s source reference
- nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.napplet.soy%2F/n-44f63e5422b
Archive hash verified: bcadd2430d8ea2bc…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import assert from 'node:assert/strict';
import test from 'node:test';
import { createGamepadInput } from '../src/gamepad.ts';
import { createInput } from '../src/input.ts';
import { planRoster } from '../src/players.ts';
const sample = (index, id = `pad-${index}`, mapping = 'standard') => ({ index, id, mapping, connected: true, axes: [0, 0, 0, 0], buttons: Array.from({ length: 17 }, () => ({ value: 0, pressed: false })) });
const bindings = { turn: [{ axis: 0 }], start: [{ button: 0 }] };
test('polling discovers idle pads, sparse slots, unplugging and reconnection without events', () => {
let pads = [];
const input = createGamepadInput(bindings, { read: () => pads, active: () => true });
assert.equal(input.poll().status, 'waiting');
pads = [sample(0), null, sample(3)];
assert.deepEqual(input.poll().connected, [0, 3]);
assert.deepEqual(input.poll().players.map(p => p.index), [0, 3]);
pads = [sample(0)]; assert.deepEqual(input.poll().disconnected, [3]);
pads.push(sample(3)); assert.deepEqual(input.poll().connected, [3]);
input.dispose(); assert.equal(input.poll().status, 'closed');
});
test('temporary read errors neutralize controls without losing seats or explicit mappings', () => {
const pad = sample(2, 'custom', ''); let error = null;
const input = createGamepadInput(bindings, { read: () => { if (error) throw error; return [pad]; }, active: () => true });
input.poll(); input.remap(2, bindings); input.poll();
pad.axes[0] = 1; pad.buttons[0].value = 1;
assert.equal(input.poll().players[0].actions.start.pressed, true);
for (const name of ['Error', 'SecurityError']) {
error = new Error('temporary access failure'); error.name = name;
const frame = input.poll();
assert.equal(frame.status, name === 'SecurityError' ? 'blocked' : 'unavailable');
assert.deepEqual(frame.disconnected, []); assert.deepEqual(frame.connected, []);
assert.equal(frame.players[0].mapped, true);
assert.equal(frame.players[0].actions.turn.value, 0); assert.equal(frame.players[0].actions.start.down, false);
error = null;
const recovered = input.poll();
assert.deepEqual(recovered.connected, []);
assert.equal(recovered.players[0].actions.start.pressed, false);
assert.equal(recovered.players[0].actions.turn.value, 1);
}
input.dispose();
});
test('focus recovery keeps devices and suppresses held start, pause and mode presses', () => {
let active = true; const pad = sample(0);
const input = createGamepadInput(bindings, { read: () => [pad], active: () => active });
input.poll(); pad.buttons[0].value = 1; assert.equal(input.poll().players[0].actions.start.pressed, true);
active = false; const blurred = input.poll();
assert.equal(blurred.status, 'inactive'); assert.equal(blurred.players[0].actions.start.down, false);
assert.deepEqual(blurred.disconnected, []);
active = true; assert.equal(input.poll().players[0].actions.start.pressed, false);
pad.buttons[0].value = 0; input.poll(); pad.buttons[0].value = 1;
assert.equal(input.poll().players[0].actions.start.pressed, true);
input.dispose();
});
test('replacement resets an explicit mapping instead of assigning it to a different device', () => {
let pad = sample(1, 'old', '');
const input = createGamepadInput(bindings, { read: () => [pad], active: () => true });
input.poll(); input.remap(1, bindings); assert.equal(input.poll().players[0].mapped, true);
pad = sample(1, 'new', ''); const frame = input.poll();
assert.deepEqual(frame.connected, [1]); assert.deepEqual(frame.disconnected, [1]);
assert.equal(frame.players[0].mapped, false); input.dispose();
});
test('game input assigns idle controllers immediately and preserves roster across focus/read failures', () => {
const originals = ['window', 'document', 'navigator'].map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)]);
class Element extends EventTarget { style = {}; }
const doc = new Element(); doc.hidden = false; doc.hasFocus = () => focused;
const win = new Element(); win.document = doc;
let pads = [], focused = true, error = false;
Object.defineProperty(globalThis, 'window', { configurable: true, value: win });
Object.defineProperty(globalThis, 'document', { configurable: true, value: doc });
Object.defineProperty(globalThis, 'navigator', { configurable: true, value: { getGamepads: () => { if(error) throw new Error('temporary');return pads; } } });
let input;
try {
input = createInput(Object.fromEntries(['stick','stickKnob','throttle','boost','yawLeft','yawRight','fire','rocket'].map(key => [key, new Element()])));
let roster = [null];
const poll = () => { const frame = input.poll(1/60);roster = planRoster(roster, frame.activePads).map(p => p.pad);return frame; };
assert.deepEqual(poll().activePads, []);
pads = [sample(0), null, sample(3), sample(4, 'unsupported', '')];
assert.deepEqual(poll().activePads, [0,3]); assert.deepEqual(roster, [0,3]);
focused = false; assert.deepEqual(poll().activePads, [0,3]); assert.deepEqual(roster, [0,3]);
error = true; assert.deepEqual(poll().activePads, [0,3]); assert.deepEqual(roster, [0,3]);
error = false; focused = true; assert.deepEqual(poll().activePads, [0,3]);
pads = [sample(0)];poll();assert.deepEqual(roster, [0]);
pads.push(sample(3));poll();assert.deepEqual(roster, [0,3]);
} finally {
input?.dispose();
for (const [key, descriptor] of originals) { if(descriptor)Object.defineProperty(globalThis,key,descriptor);else delete globalThis[key]; }
}
});
