dualsense-ts
Version:
The natural interface for your DualSense Classic and DualSense Access controllers, with Typescript
112 lines • 6.27 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AccessHIDProvider = exports.DefaultAccessHIDState = exports.AccessInputId = void 0;
const hid_provider_1 = require("../hid_provider");
const access_hid_1 = require("../access_hid");
const access_hid_state_1 = require("./access_hid_state");
Object.defineProperty(exports, "AccessInputId", { enumerable: true, get: function () { return access_hid_state_1.AccessInputId; } });
Object.defineProperty(exports, "DefaultAccessHIDState", { enumerable: true, get: function () { return access_hid_state_1.DefaultAccessHIDState; } });
/** Supports a connection to a physical or virtual DualSense Access device */
class AccessHIDProvider {
constructor() {
/** Callback to use for new input events */
this.onData = () => { };
/** Callback to use for Error events */
this.onError = () => { };
/** Callback fired the moment a device is fully attached and ready for I/O */
this.onConnect = () => { };
/** Callback fired the moment a device detaches (cleanly or via error) */
this.onDisconnect = () => { };
}
/**
* Selects the correct method for reading the report.
*/
processReport(buffer) {
const reportId = buffer.readUint8(0);
switch (reportId) {
case 0x01:
return this.wireless
? this.processBluetoothInputReport01(buffer)
: this.processUsbInputReport01(buffer);
case 0x31:
return this.processBluetoothInputReport31(buffer);
default:
this.onError(new Error(`Cannot process report, unexpected report id: ${reportId}`));
this.disconnect();
return { ...access_hid_state_1.DefaultAccessHIDState };
}
}
/** Reset the provider state when the device is disconnected */
reset() {
const wasAttached = this.device !== undefined;
if (this.deviceId) {
AccessHIDProvider.claimedDevices.delete(this.deviceId);
}
this.device = undefined;
this.wireless = undefined;
this.buffer = undefined;
this.deviceId = undefined;
this.serialNumber = undefined;
this.onData(access_hid_state_1.DefaultAccessHIDState);
if (wasAttached)
this.onDisconnect();
}
/**
* Process a BT input report 0x01 (limited mode, pre-Feature 0x05).
* Only has the mapped DualSense-compatible header, no Access-specific data.
*/
processBluetoothInputReport01(_buffer // eslint-disable-line @typescript-eslint/no-unused-vars
) {
// BT 0x01 only contains the mapped DualSense-compatible header.
// Without the Access-specific section, we can't read raw buttons,
// raw stick, battery, or profile. Return default state.
return { ...access_hid_state_1.DefaultAccessHIDState };
}
/** Process BT input report 0x31 (full mode, offset +1 from USB) */
processBluetoothInputReport31(buffer) {
const o = access_hid_1.AccessInput.BT_OFFSET; // +1
return this.parseAccessReport(buffer, o);
}
/** Process USB input report 0x01 (full Access report) */
processUsbInputReport01(buffer) {
return this.parseAccessReport(buffer, 0);
}
/** Parse Access-specific fields from the report buffer at the given offset */
parseAccessReport(buffer, offset) {
const rawButtons1 = buffer.readUint8(access_hid_1.AccessInput.RAW_BUTTONS_1 + offset);
const rawButtons2 = buffer.readUint8(access_hid_1.AccessInput.RAW_BUTTONS_2 + offset);
const batteryByte = buffer.readUint8(access_hid_1.AccessInput.BATTERY + offset);
const profileByte = buffer.readUint8(access_hid_1.AccessInput.PROFILE + offset);
return {
[access_hid_state_1.AccessInputId.B1]: (rawButtons1 & access_hid_1.AccessButton1.B1) > 0,
[access_hid_state_1.AccessInputId.B2]: (rawButtons1 & access_hid_1.AccessButton1.B2) > 0,
[access_hid_state_1.AccessInputId.B3]: (rawButtons1 & access_hid_1.AccessButton1.B3) > 0,
[access_hid_state_1.AccessInputId.B4]: (rawButtons1 & access_hid_1.AccessButton1.B4) > 0,
[access_hid_state_1.AccessInputId.B5]: (rawButtons1 & access_hid_1.AccessButton1.B5) > 0,
[access_hid_state_1.AccessInputId.B6]: (rawButtons1 & access_hid_1.AccessButton1.B6) > 0,
[access_hid_state_1.AccessInputId.B7]: (rawButtons1 & access_hid_1.AccessButton1.B7) > 0,
[access_hid_state_1.AccessInputId.B8]: (rawButtons1 & access_hid_1.AccessButton1.B8) > 0,
[access_hid_state_1.AccessInputId.Center]: (rawButtons2 & access_hid_1.AccessButton2.CENTER) > 0,
[access_hid_state_1.AccessInputId.StickClick]: (rawButtons2 & access_hid_1.AccessButton2.STICK) > 0,
[access_hid_state_1.AccessInputId.PS]: (rawButtons2 & access_hid_1.AccessButton2.PS) > 0,
[access_hid_state_1.AccessInputId.Profile]: (rawButtons2 & access_hid_1.AccessButton2.PROFILE) > 0,
[access_hid_state_1.AccessInputId.StickX]: (0, hid_provider_1.mapAxis)(buffer.readUint8(access_hid_1.AccessInput.RAW_STICK_X + offset)),
[access_hid_state_1.AccessInputId.StickY]: (0, hid_provider_1.mapAxis)(buffer.readUint8(access_hid_1.AccessInput.RAW_STICK_Y + offset)),
[access_hid_state_1.AccessInputId.BatteryLevel]: (0, hid_provider_1.mapBatteryLevel)(batteryByte),
[access_hid_state_1.AccessInputId.BatteryStatus]: (batteryByte >> 4),
[access_hid_state_1.AccessInputId.ProfileId]: (profileByte & 0x07) || 1,
};
}
}
exports.AccessHIDProvider = AccessHIDProvider;
/** HID vendorId for a DualSense Access controller */
AccessHIDProvider.vendorId = 0x054c;
/** HID productId for a DualSense Access controller */
AccessHIDProvider.productId = 0x0e5f;
/** HID usagePage for a DualSense Access controller */
AccessHIDProvider.usagePage = 0x0001;
/** HID usage for a DualSense Access controller */
AccessHIDProvider.usage = 0x0005;
/** Global set of device paths currently claimed by a provider instance */
AccessHIDProvider.claimedDevices = new Set();
//# sourceMappingURL=access_hid_provider.js.map