import assert from 'node:assert/strict'; import { normalizeXInput, NativeController } from '../native-controller.mjs'; import { neutral } from '../dist/controls.mjs'; const frame = (overrides) => ({ connected: true, index: 0, buttons: 0, leftTrigger: 0, rightTrigger: 0, leftX: 0, leftY: 0, rightX: 0, rightY: 0, ...overrides, }); let pad = normalizeXInput( frame({ leftX: 32767, leftY: 32767, rightX: -32768, rightY: -32768, buttons: 0x1000 | 0x200 | 0x10, leftTrigger: 128, rightTrigger: 255, }), ); assert.deepEqual(pad.axes, [1, -1, -1, 1]); assert.equal(pad.buttons[0].value, 1); assert.equal(pad.buttons[5].value, 1); assert.equal(pad.buttons[9].pressed, true); assert.equal(pad.buttons[6].value, 128 / 255); assert.equal(pad.buttons[7].value, 1); assert.equal(normalizeXInput({ connected: false }), null); let time = 0, pose = neutral(), cameras = 0, statuses = []; const controller = new NativeController({ clock: () => time, onPose: (p) => (pose = { ...p }), onCamera: () => cameras++, onStatus: (s) => statuses.push(s), }); controller.accept( frame({ leftX: 32767, rightY: 32767, buttons: 0x1000 | 0x10, rightTrigger: 255 }), ); time += 16; controller.tick(); assert.equal(controller.active, true); assert.equal(pose.yaw, 30); assert.equal(pose.gazeY, 1); assert.equal(pose.roll, 20); assert.equal(pose.blinkL, 1); assert.equal(pose.blinkR, 1); assert.equal(cameras, 1); time += 16; controller.tick(); assert.equal(cameras, 1, 'Held Menu must not repeatedly reset the camera'); controller.configure({ enabled: false }); time += 16; controller.tick(); assert.equal(controller.active, false); assert.equal(pose.yaw, 30, 'Switching to sliders should retain the pose'); controller.configure({ enabled: true, behavior: 'hold' }); controller.pose = neutral(); controller.accept(frame({ leftX: 32767 })); time += 50; controller.tick(); assert.equal(pose.yaw, 2.7); controller.accept(frame()); time += 50; controller.tick(); assert.equal(pose.yaw, 2.7, 'Native hold must retain the pose at rest'); controller.configure({ reset: true }); assert.deepEqual(pose, neutral(), 'UI reset must also reset the native hold pose'); controller.accept({ connected: false }); time += 16; controller.tick(); assert.deepEqual(pose, neutral(), 'Disconnect must release blinks and return to neutral'); controller.accept(frame({ buttons: 0x100 })); time += 16; controller.tick(); assert.equal(pose.blinkL, 1); assert.equal(pose.blinkR, 0); time += 2600; controller.tick(); assert.deepEqual(pose, neutral(), 'A stalled helper must release the pose'); assert.equal(controller.status().connected, false); assert(statuses.some((s) => s.connected) && statuses.some((s) => !s.connected)); controller.configure({ sensitivity: 99, deadzone: 0, invert: true }); assert.equal(controller.settings.sensitivity, 1.5); assert.equal(controller.settings.deadzone, 0.03); assert.equal(controller.settings.invert, true); console.log( 'Windows packet mapping, head/gaze/blinks, trigger tilt, held Menu, slider handoff, hold mode, disconnect and stale-input release pass without a browser.', );