vigemclient
Version:
Native bindings to the ViGem virtual gamepad driver
179 lines (149 loc) • 4.42 kB
JavaScript
const { clamp, rangeMap } = require('./common');
const { DS4ControllerReport } = require('./DS4ControllerReport');
class DS4TrackpadTouch {
constructor() {
this._timestamp = 0;
this._finger1 = null;
this._finger2 = null;
}
_toNativeObject() {
return {
packetCounter: this._timestamp,
finger1: this._finger1 !== null,
finger1_x: (this._finger1 !== null) ? clamp(this._finger1.x, 0, 1920) : 0,
finger1_y: (this._finger1 !== null) ? clamp(this._finger1.y, 0, 943) : 0,
finger2: this._finger2 !== null,
finger2_x: (this._finger2 !== null) ? clamp(this._finger2.x, 0, 1920) : 0,
finger2_y: (this._finger2 !== null) ? clamp(this._finger2.y, 0, 943) : 0,
};
}
getFingersDown() {
return ((this._finger1 !== null) ? 1 : 0) + ((this._finger2 !== null) ? 1 : 0);
}
addFingerDown(x, y) {
if (this._finger1 === null) {
this._finger1 = { x, y };
} else if (this._finger2 === null) {
this._finger2 = { x, y };
} else {
throw new Error("You can only add up to two fingers to this DS4TrackpadTouch object.");
}
}
allFingersUp() {
this._finger1 = null;
this._finger2 = null;
}
}
class DS4ControllerExtendedReport extends DS4ControllerReport {
constructor(parent) {
super();
this.reset();
this._touchTimestamp = 0; // will not be reset
this._parent = parent;
}
reset() {
super.reset();
this.reportObj = {
wButtons: 8, // dpad_none
bThumbLX: 127,
bThumbLY: 127,
bThumbRX: 127,
bThumbRY: 127,
bTriggerL: 0,
bTriggerR: 0,
bSpecial: 0,
wTimestamp: 0,
bBatteryLvl: 0,
wGyroX: 0,
wGyroY: 0,
wGyroZ: 0,
wAccelX: 0,
wAccelY: 0,
wAccelZ: 0,
// bBatteryLvlSpecial: 0,
bTouchPacketsN: 0,
touches: [],
};
this._lastSend = 0;
}
addTouch(touch) {
if (!(touch instanceof DS4TrackpadTouch)) throw new Error("Invalid touch type");
this.reportObj.touches.unshift(touch); // add to the front of the touches array
if (this._parent.updateMode == "auto") {
this._parent.update();
}
}
/**
* Set the gyro to a rotation. Each value is between -2000deg and 2000deg
* @param {number} pitch
* @param {number} yaw
* @param {number} roll
*/
setGyro(pitch, yaw, roll) {
const gyroSpec = {
minIn: -2000,
maxIn: 2000,
minOut: -32767,
maxOut: 32767,
};
this.reportObj.wGyroX = rangeMap(pitch, gyroSpec);
this.reportObj.wGyroY = rangeMap(yaw, gyroSpec);
this.reportObj.wGyroZ = rangeMap(roll, gyroSpec);
}
/**
* Set the accelerometer measurement. Each value is measured in g-force and between -4 and 4.
* @param {number} x
* @param {number} y
* @param {number} z
*/
setAccelerometer(x, y, z) {
const accelSpec = {
minIn: -4,
maxIn: 4,
minOut: -32767,
maxOut: 32767,
};
this.reportObj.wAccelX = rangeMap(x, accelSpec);
this.reportObj.wAccelY = rangeMap(y, accelSpec);
this.reportObj.wAccelZ = rangeMap(z, accelSpec);
}
/**
* Prepare this report for sending:
* - update bTouchPacketsN
* - update wTimestamp
* - prepare touches array
*/
prepareSend() {
if (this.reportObj.touches.length > 3) {
this.reportObj.touches = this.reportObj.touches.slice(0, 3);
}
this.reportObj.touches.forEach(touch => touch._timestamp = this._touchTimestamp++);
this.reportObj.touches = this.reportObj.touches.map(touch => touch._toNativeObject());
this.reportObj.bTouchPacketsN = this.reportObj.touches.length;
if (this._lastSend == 0) {
this.reportObj.wTimestamp = 0;
} else {
const now = microNow();
const msecDiff = now - this._lastSend;
// apparently (according to "documentation"), the value is commonly incremented by 188 at an update rate of 1.25ms per update.
// I'm just going to emulate this behavior here, but if this doesn't work we might need to change this in the future
this.reportObj.wTimestamp += msecDiff / 1.25 * 188;
this._lastSend = now;
}
}
/**
* Mark this report as sent, which resets the touches and the touch counter
*/
finishSend() {
this.reportObj.bTouchPacketsN = 0;
this.reportObj.touches = [];
}
}
function microNow() {
const [ sec, nsec ] = process.hrtime();
return sec * 1000000 + nsec / 1000;
}
module.exports = {
DS4ControllerExtendedReport,
DS4TrackpadTouch,
};