-
Notifications
You must be signed in to change notification settings - Fork 10
Description
So, I've been working on making a virtual gamepad, but when I'm making it, there are some issues I've found on the making
-
When creating the controller, the axis value will not be exactly zero
-
I Believe the left analog axis is error, when it's the first value that changed and the analog is in the first quadrant ( 0 to 90 degrees ) and the third quadrant ( 180 - 270 degrees ). The right analog is just fine. It will look like this
Note: I've tried another tester. I've verified my input value. And etc. And in conclusion, I thought it's probably in the library itself.
The Code ( Bear with my code, lol ) :
`const feeder = require('./vigem');
var controllers = {};
const express = require('express');
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
const port = process.env.PORT || 7200;
const buttons = {
BOTTOM_BUTTON : "A",
RIGHT_BUTTON : "B",
TOP_BUTTON : "Y",
LEFT_BUTTON : "X",
RIGHT_SHOULDER : "RIGHT_SHOULDER",
LEFT_SHOULDER : "LEFT_SHOULDER",
START : "START",
BACK : "BACK"
}
const axes = {
ANALOG_LEFT : "left",
ANALOG_RIGHT: "right"
}
const shoulder = {
LEFT_TRIGGER : "left",
RIGHT_TRIGGER: "right"
}
// Set root to xbox layout
app.get('/', (req, res) => {
return res.sendFile(__dirname + "/static/s-new.html");
});
// Set /static as root so the assets and stuffs can be loaded
app.use('/', express.static(__dirname + '/static'));
// Socket.io
io.on('connection', (socket) => {
let notificationCallback = function(data)
{
if(data)
{
io.to(socket.id).emit("vibration", true);
} else {
io.to(socket.id).emit("vibration", false);
}
}
controllers[socket.id] = new feeder("x360", notificationCallback);
let client = controllers[socket.id];
// console.log(`a user connected with socketID of ${socket.id}`);
// // Sending to all client
// socket.emit("message", "can you hear me?");
// // Sending to specific client
// io.to(socket.id).emit("message", "I just met you");
socket.on('disconnect', () => {
console.log('user disconnected');
client.disconnect();
});
socket.on('message', (tes) => {
switch(tes.inputType)
{
case "axis":
if(tes.axis == "ANALOG_LEFT" || tes.axis == "ANALOG_RIGHT")
{
tes.x = client.clampIt(tes.x, tes.r)
tes.y = client.clampIt(tes.y, tes.r)
console.log(tes.x, tes.y)
client.xbox360SetAxisValue(`${axes[tes.axis]}X`, tes.x );
client.xbox360SetAxisValue(`${axes[tes.axis]}Y`, tes.y );
client.update();
}
break;
case "triggerAxis":
if(tes.axis == "LEFT_TRIGGER" || tes.axis == "RIGHT_TRIGGER")
{
tes.value = tes.value/tes.max;
client.xbox360SetAxisValue(`${shoulder[tes.axis]}Trigger`, tes.value );
client.update();
}
break;
case "button":
client.xbox360SetButtonValue(buttons[tes.button], !!tes.v);
break;
}
//console.log(`${JSON.stringify(tes)}`);
});
});
http.listen(port, () => {
console.log(Listenting on ${port}
);
});`
`const ViGEmClient = require('vigemclient');
class feeder {
constructor(controller, notificationCallback)
{
switch(controller) {
case "x360":
this._controllerName = "x360";
this.xbox360feeder(notificationCallback);
// this.xbox360reset();
break;
case "ds4":
this._controllerName = "ds4";
this.ds4feeder(notificationCallback);
break;
default:
this._controllerName = "x360";
this.xbox360feeder(notificationCallback);
}
}
connectClient()
{
this.client = new ViGEmClient();
let err = this.client.connect(); // establish connection to the ViGEmBus driver
return err;
}
connectController(controllerName)
{
switch(controllerName) {
case "x360":
this.controller = this.client.createX360Controller(); //Spawn x360 virtual controller
break;
case "ds4":
this.controller = this.client.createDS4Controller(); //Spawn ds4 virtual controller
break;
default:
this.controller = this.client.createX360Controller(); //Spawn x360 virtual controller
}
let err = this.controller.connect();
return err;
}
outputIDs(controllerName)
{
console.log("Vendor ID:", this.controller.vendorID);
console.log("Product ID:", this.controller.productID);
console.log("Index:", this.controller.index);
console.log("Type:", this.controller.type);
// if(controllerName == "x360")
// {
// console.log("User index:", this.controller.userIndex);
// }
}
clamp(value, min, max) {
return Math.min(max, Math.max(min, value));
}
update()
{
this.controller.update(); // update manually for better performance
}
disconnect()
{
let err = this.controller.disconnect(); // update manually for better performance
return err;
}
convertAngleToAxis(a, s) // To convert Angle and Strength of a circle to X and Y of square
{
let x = (s/100)*Math.cos(a*Math.PI/180);
let y = (s/100)*Math.sin(a*Math.PI/180);
let xSquare = 0.5*Math.sqrt(2+2*Math.sqrt(2)*x+Math.pow(x,2)-Math.pow(y,2)) - 0.5*Math.sqrt(2-2*Math.sqrt(2)*x+Math.pow(x,2)-Math.pow(y,2)); // x = ½ √( 2 + 2u√2 + u² - v² ) - ½ √( 2 - 2u√2 + u² - v² )
let ySquare = 0.5*Math.sqrt(2+2*Math.sqrt(2)*y-Math.pow(x,2)+Math.pow(y,2)) - 0.5*Math.sqrt(2-2*Math.sqrt(2)*y-Math.pow(x,2)+Math.pow(y,2)); // y = ½ √( 2 + 2v√2 - u² + v² ) - ½ √( 2 - 2v√2 - u² + v² )
if(isNaN(xSquare) && isNaN(ySquare)) {
if(x>=0)
{
xSquare = 1;
} else {
xSquare = -1;
}
if(y>=0)
{
ySquare = 1;
} else {
ySquare = -1;
}
}
return {x: xSquare, y: ySquare};
}
convertCircleCoordToSquareCoord(u, v)
{
u = u / 35 * 1; // 35 = radius of the joystick // u,v element u^2 + v^2 <= 1
v = -v / 35 * 1; // 35 = radius of the joystick // u,v element u^2 + v^2 <= 1 // The y is inverted, from the client so we need to invert it here
let xSquare = 0.5*Math.sqrt(2+2*Math.sqrt(2)*u+Math.pow(u,2)-Math.pow(v,2)) - 0.5*Math.sqrt(2-2*Math.sqrt(2)*u+Math.pow(u,2)-Math.pow(v,2)); // x = ½ √( 2 + 2u√2 + u² - v² ) - ½ √( 2 - 2u√2 + u² - v² )
let ySquare = 0.5*Math.sqrt(2+2*Math.sqrt(2)*v-Math.pow(u,2)+Math.pow(v,2)) - 0.5*Math.sqrt(2-2*Math.sqrt(2)*v-Math.pow(u,2)+Math.pow(v,2)); // y = ½ √( 2 + 2v√2 - u² + v² ) - ½ √( 2 - 2v√2 - u² + v² )
if(isNaN(xSquare) && isNaN(ySquare)) {
if(u>=0)
{
xSquare = 1;
} else {
xSquare = -1;
}
if(v>=0)
{
ySquare = 1;
} else {
ySquare = -1;
}
}
return {x: xSquare, y: ySquare};
}
clampIt(value, max)
{
return value/max;
}
//--------------------------------------------------[ XBOX 360 Feeder ]--------------------------------------------------//
xbox360reset()
{
let value = 0;
this.controller.button.X.setValue(value); // press X button
this.controller.button.Y.setValue(value); // press Y button
this.controller.button.A.setValue(value); // press A button
this.controller.button.B.setValue(value); // press B button
// this.controller.button.DPAD_UP.setValue(value); // press DPAD_UP button
// this.controller.button.DPAD_DOWN.setValue(value); // press DPAD_DOWN button
// this.controller.button.DPAD_LEFT.setValue(value); // press DPAD_LEFT button
// this.controller.button.DPAD_RIGHT.setValue(value); // press DPAD_RIGHT button
this.controller.button.START.setValue(value); // press START button
this.controller.button.BACK.setValue(value); // press BACK button
this.controller.button.LEFT_THUMB.setValue(value); // press LEFT_THUMB button
this.controller.button.RIGHT_THUMB.setValue(value); // press RIGHT_THUMB button
this.controller.button.LEFT_SHOULDER.setValue(value); // press LEFT_SHOULDER button
this.controller.button.RIGHT_SHOULDER.setValue(value); // press RIGHT_SHOULDER button
this.controller.button.GUIDE.setValue(value); // press GUIDE button
this.controller.axis.leftX.setValue(value); // Left analog X
this.controller.axis.leftY.setValue(value); // Left analog Y
this.controller.axis.leftTrigger.setValue(value); // Left Trigger
this.controller.axis.rightX.setValue(value); // Right analog X
this.controller.axis.rightY.setValue(value); // Right analog Y
this.controller.axis.rightTrigger.setValue(value); // Right Trigger
this.controller.axis.dpadHorz.setValue(value); // Horizontal DPAD
this.controller.axis.dpadVert.setValue(value); // Horizontal DPAD
}
xbox360feeder(notificationCallback)
{
let connectClient = this.connectClient(); // Connecting to ViGEmBus driver
if(connectClient == null) // Checking if connectclient returning null which what we wanted
{
let errConnectController = this.connectController(this._controllerName); // Connecting to virtual controller
if (errConnectController) // Checking if errconnectcontroller returning true which is error happenned
{
console.log(errConnectController.message); // Outputting the error message
process.exit(1);
}
this.outputIDs(this._controllerName); // Outputting vendor id and stuffs
// Controller notification
this.controller.on("notification", data => {
console.log("notification", data);
// if(data.LargeMotor > 0 || data.SmallMotor > 0)
// {
// notificationCallback(true);
// } else {
// notificationCallback(false);
// }
});
// this.controller.updateMode = "manual"; // requires manual calls to controller.update()
let tes = 0;
let testing = setInterval(function()
{
if(tes%2 == 0)
{
notificationCallback(true);
} else {
notificationCallback(false);
}
if(tes == 3){
clearInterval(testing);
}
tes++;
}, 10000);
}
}
xbox360SetButtonValue(buttonName, value)
{
let err = null;
if(value !== true && value !== false)
{
err = true;
}
if(!err)
{
switch(buttonName) {
case "X":
this.controller.button.X.setValue(value); // press X button
break;
case "Y":
this.controller.button.Y.setValue(value); // press Y button
break;
case "A":
this.controller.button.A.setValue(value); // press A button
break;
case "B":
this.controller.button.B.setValue(value); // press B button
break;
// case "DPAD_UP":
// this.controller.button.DPAD_UP.setValue(value); // press DPAD_UP button
// break;
// case "DPAD_DOWN":
// this.controller.button.DPAD_DOWN.setValue(value); // press DPAD_DOWN button
// break;
// case "DPAD_LEFT":
// this.controller.button.DPAD_LEFT.setValue(value); // press DPAD_LEFT button
// break;
// case "DPAD_RIGHT":
// this.controller.button.DPAD_RIGHT.setValue(value); // press DPAD_RIGHT button
// break;
case "START":
this.controller.button.START.setValue(value); // press START button
break;
case "BACK":
this.controller.button.BACK.setValue(value); // press BACK button
break;
case "LEFT_THUMB":
this.controller.button.LEFT_THUMB.setValue(value); // press LEFT_THUMB button
break;
case "RIGHT_THUMB":
this.controller.button.RIGHT_THUMB.setValue(value); // press RIGHT_THUMB button
break;
case "LEFT_SHOULDER":
this.controller.button.LEFT_SHOULDER.setValue(value); // press LEFT_SHOULDER button
break;
case "RIGHT_SHOULDER":
this.controller.button.RIGHT_SHOULDER.setValue(value); // press RIGHT_SHOULDER button
break;
case "GUIDE":
this.controller.button.GUIDE.setValue(value); // press GUIDE button
break;
default:
err = false;
}
}
if(this.controller.updateMode == "manual")
{
this.update();
}
return err;
}
xbox360ButtonToggle(index)
{
let err = null;
let buttons = Object.keys(this.controller.button);
if(index > buttons.length)
{
err = true;
}
if(!err)
{
this.controller.button[buttons[index]].setValue(!this.controller.button[buttons[index]].value); // invert button value
}
this.update();
return err;
}
xbox360SetAxisValue(axisName, value)
{
let err = null;
if((value == null) && (typeof(value) == "number"))
{
err = true;
}
if(!err)
{
switch(axisName)
{
case "leftX":
this.controller.axis.leftX.setValue(value); // Left analog X
break;
case "leftY":
this.controller.axis.leftY.setValue(value); // Left analog Y
break;
case "leftTrigger":
this.controller.axis.leftTrigger.setValue(value); // Left Trigger
break;
case "rightX":
this.controller.axis.rightX.setValue(value); // Right analog X
break;
case "rightY":
this.controller.axis.rightY.setValue(value); // Right analog Y
break;
case "rightTrigger":
this.controller.axis.rightTrigger.setValue(value); // Right Trigger
break;
case "dpadHorz":
this.controller.axis.dpadHorz.setValue(value); // Horizontal DPAD
break;
case "dpadVert":
this.controller.axis.dpadVert.setValue(value); // Horizontal DPAD
break;
default:
err = false;
}
}
if(this.controller.updateMode == "manual")
{
this.update();
}
return err;
}
//--------------------------------------------------[ XBOX 360 Feeder ]--------------------------------------------------//
}
module.exports = feeder;`