UNPKG

dualsense-ts

Version:

A natural interface for your DualSense controller, with Typescript

136 lines 4.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebHIDProvider = void 0; const hid_provider_1 = require("./hid_provider"); class WebHIDProvider extends hid_provider_1.HIDProvider { constructor() { super(); // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!navigator.hid) throw new Error("WebHID not supported by this browser"); navigator.hid.addEventListener("disconnect", ({ device }) => { if (device === this.device) { this.device = undefined; this.disconnect(); } }); navigator.hid.addEventListener("connect", ({ device }) => { if (!this.device) this.attach(device); }); } /** * WebHID API doesn't indicate whether we are connected through the controller's * USB or Bluetooth interface. The protocol is different depending on the connection * type so we will try to detect it based on the collection information. */ detectConnectionType() { this.wireless = undefined; if (!this.device) { return; } for (const c of this.device.collections) { if (c.usagePage !== hid_provider_1.HIDProvider.usagePage || c.usage !== hid_provider_1.HIDProvider.usage) { continue; } // Compute the maximum input report byte length and compare against known values. const maxInputReportBytes = (c.inputReports ?? []).reduce((max, report) => { return Math.max(max, (report.items ?? []).reduce((sum, item) => { return sum + (item.reportSize ?? 0) * (item.reportCount ?? 0); }, 0)); }, 0); if (maxInputReportBytes == 504) { this.wireless = false; } else if (maxInputReportBytes == 616) { this.wireless = true; } } } attach(device) { device .open() .then(() => { this.device = device; this.detectConnectionType(); // Enable accelerometer, gyro, touchpad return this.device.receiveFeatureReport(0x05); }) .then(() => { if (!this.device) throw Error("Controller disconnected before setup"); this.device.addEventListener("inputreport", ({ reportId, data }) => { this.buffer = data; this.onData(this.process({ reportId, buffer: data })); }); }) .catch((err) => { this.onError(err); this.disconnect(); }); } /** * You need to get HID device permissions from an interactive * component, like a button. This returns a callback for triggering * the permissions request. */ getRequest() { return () => navigator.hid .requestDevice({ filters: [ { vendorId: hid_provider_1.HIDProvider.vendorId, productId: hid_provider_1.HIDProvider.productId, usagePage: hid_provider_1.HIDProvider.usagePage, usage: hid_provider_1.HIDProvider.usage, }, ], }) .then((devices) => { if (devices.length === 0) { return this.onError(new Error(`No controllers available`)); } this.attach(devices[0]); }) .catch((err) => { this.onError(err); }); } connect() { // Nothing to be done. } get connected() { return this.device !== undefined; } disconnect() { if (this.device) { this.device.close().finally(() => this.reset()); } else { this.reset(); } } async write(data) { if (!this.device) return; return this.device.sendFeatureReport(0, data); } process({ reportId, buffer, }) { // DataView does not report the first byte (the report id), we simulate it const report = { length: buffer.byteLength + 1, readUint8(offset) { return offset > 0 ? buffer.getUint8(offset - 1) : reportId; }, readUint16LE(offset) { return offset > 0 ? buffer.getUint16(offset - 1, true) : (reportId << 8) | buffer.getUint8(0); }, }; return this.processReport(report); } } exports.WebHIDProvider = WebHIDProvider; //# sourceMappingURL=web_hid_provider.js.map