Skip to content

Commit

Permalink
major refactoring WIP, implemented ViGEmTargets (Xbox360, DualShock4)
Browse files Browse the repository at this point in the history
  • Loading branch information
Valkirie committed Dec 30, 2021
1 parent d504414 commit 9771c26
Show file tree
Hide file tree
Showing 9 changed files with 570 additions and 349 deletions.
96 changes: 37 additions & 59 deletions ControllerService/ControllerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ namespace ControllerService
public class ControllerService : IHostedService
{
// controllers vars
public XInputController PhysicalController;
private IVirtualGamepad VirtualController;
private ViGEmClient VirtualClient;
public XInputController XInputController;
private XInputGirometer Gyrometer;
private XInputAccelerometer Accelerometer;
private ViGEmClient VirtualClient;

private PipeServer PipeServer;
private DSUServer DSUServer;
Expand Down Expand Up @@ -87,53 +86,34 @@ public ControllerService(ILogger<ControllerService> logger)
Hidder = new HidHide(CurrentPathCli, logger, this);
Hidder.RegisterApplication(CurrentExe);

// initialize controller
switch (HIDmode)
{
default:
case "DualShock4Controller":
VirtualController = VirtualClient.CreateDualShock4Controller();
break;
case "Xbox360Controller":
VirtualController = VirtualClient.CreateXbox360Controller();
break;
}

if (VirtualController == null)
{
logger.LogCritical("No Virtual controller detected. Application will stop");
throw new InvalidOperationException();
}

// prepare physical controller
DirectInput dinput = new DirectInput();
IList<DeviceInstance> dinstances = dinput.GetDevices(DeviceClass.GameControl, DeviceEnumerationFlags.AttachedOnly);

for (int i = (int)UserIndex.One; i <= (int)UserIndex.Three; i++)
foreach (UserIndex idx in (UserIndex[])Enum.GetValues(typeof(UserIndex)))
{
XInputController tmpController = new XInputController((UserIndex)i, HIDrate, logger);
Controller controller = new Controller(idx);
if (!controller.IsConnected)
continue;

if (tmpController.controller.IsConnected)
{
PhysicalController = tmpController;
PhysicalController.instance = dinstances[i];
break;
}
XInputController = new XInputController(controller, idx, HIDrate, HIDmode, logger);
XInputController.instance = dinstances[(int)idx];
break;
}

if (PhysicalController == null)
if (XInputController == null)
{
logger.LogCritical("No physical controller detected. Application will stop");
throw new InvalidOperationException();
}

// default is 10ms rating
Gyrometer = new XInputGirometer(PhysicalController, logger);
Gyrometer = new XInputGirometer(XInputController, logger);
if (Gyrometer.sensor == null)
logger.LogWarning("No Gyrometer detected");

// default is 10ms rating
Accelerometer = new XInputAccelerometer(PhysicalController, logger);
Accelerometer = new XInputAccelerometer(XInputController, logger);
if (Accelerometer.sensor == null)
logger.LogWarning("No Accelerometer detected");

Expand Down Expand Up @@ -180,20 +160,20 @@ private void OnClientMessage(object sender, PipeMessage message)
switch (cursor.action)
{
case 0: // up
PhysicalController.touch.OnMouseUp((short)cursor.x, (short)cursor.y, cursor.button);
XInputController.target.touch.OnMouseUp((short)cursor.x, (short)cursor.y, cursor.button);
break;
case 1: // down
PhysicalController.touch.OnMouseDown((short)cursor.x, (short)cursor.y, cursor.button);
XInputController.target.touch.OnMouseDown((short)cursor.x, (short)cursor.y, cursor.button);
break;
case 2: // move
PhysicalController.touch.OnMouseMove((short)cursor.x, (short)cursor.y, cursor.button);
XInputController.target.touch.OnMouseMove((short)cursor.x, (short)cursor.y, cursor.button);
break;
}
break;

case PipeCode.CLIENT_SCREEN:
PipeClientScreen screen = (PipeClientScreen)message;
PhysicalController.touch.UpdateRatio(screen.width, screen.height);
XInputController.target.touch.UpdateRatio(screen.width, screen.height);
break;

case PipeCode.CLIENT_SETTINGS:
Expand All @@ -219,18 +199,18 @@ private void OnClientMessage(object sender, PipeMessage message)

private void OnClientDisconnected(object sender)
{
PhysicalController.touch.OnMouseUp(-1, -1, 1048576 /* MouseButtons.Left */);
XInputController.target.touch.OnMouseUp(-1, -1, 1048576 /* MouseButtons.Left */);
}

private void OnClientConnected(object sender)
{
// send controller details
PipeServer.SendMessage(new PipeServerController()
{
ProductName = PhysicalController.instance.ProductName,
InstanceGuid = PhysicalController.instance.InstanceGuid,
ProductGuid = PhysicalController.instance.ProductGuid,
ProductIndex = (int)PhysicalController.index
ProductName = XInputController.instance.ProductName,
InstanceGuid = XInputController.instance.InstanceGuid,
ProductGuid = XInputController.instance.ProductGuid,
ProductIndex = (int)XInputController.index
});

// send server settings
Expand All @@ -239,7 +219,7 @@ private void OnClientConnected(object sender)

internal void UpdateProfile(Profile profile)
{
PhysicalController.profile = profile;
XInputController.target.profile = profile;
}

public void UpdateSettings(Dictionary<string, string> args)
Expand Down Expand Up @@ -312,10 +292,10 @@ private void ApplySetting(string name, object prev_value, object value)
// todo
break;
case "HIDrate":
PhysicalController.SetPollRate((int)value);
XInputController.SetPollRate((int)value);
break;
case "HIDstrength":
PhysicalController.SetVibrationStrength((int)value);
XInputController.SetVibrationStrength((int)value);
break;
case "DSUEnabled":
switch ((bool)value)
Expand Down Expand Up @@ -343,22 +323,20 @@ public Task StartAsync(CancellationToken cancellationToken)
// turn on the cloaking
Hidder.SetCloaking(HIDcloaked);

VirtualController.Connect();
logger.LogInformation("Virtual {0} connected", VirtualController.GetType().Name);

PhysicalController.SetDSUServer(DSUServer);
PhysicalController.SetVirtualController(VirtualController);
PhysicalController.SetGyroscope(Gyrometer);
PhysicalController.SetAccelerometer(Accelerometer);
PhysicalController.SetVibrationStrength(HIDstrength);
// initialize virtual controller
XInputController.SetTarget(VirtualClient);
XInputController.SetDSUServer(DSUServer);
XInputController.SetGyroscope(Gyrometer);
XInputController.SetAccelerometer(Accelerometer);
XInputController.SetVibrationStrength(HIDstrength);

// start the Pipe Server
PipeServer.Start();

// send notification
PipeServer.SendMessage(new PipeServerToast
{
title = $"{VirtualController.GetType().Name}",
title = $"{XInputController.target.GetType().Name}",
content = "Virtual device is now connected"
});

Expand All @@ -369,15 +347,15 @@ public Task StopAsync(CancellationToken cancellationToken)
{
try
{
if (VirtualController != null)
if (XInputController.target != null)
{
VirtualController.Disconnect();
logger.LogInformation("Virtual {0} disconnected", VirtualController.GetType().Name);
XInputController.target.Disconnect();
logger.LogInformation("Virtual {0} disconnected", XInputController.target.GetType().Name);

// send notification
PipeServer.SendMessage(new PipeServerToast
{
title = $"{VirtualController.GetType().Name}",
title = $"{XInputController.target.GetType().Name}",
content = "Virtual device is now disconnected"
});
}
Expand All @@ -398,8 +376,8 @@ public Dictionary<string, string> GetSettings()
foreach (SettingsProperty s in Properties.Settings.Default.Properties)
settings.Add(s.Name, Properties.Settings.Default[s.Name].ToString());

settings.Add("gyrometer", $"{PhysicalController.gyrometer.sensor != null}");
settings.Add("accelerometer", $"{PhysicalController.accelerometer.sensor != null}");
settings.Add("gyrometer", $"{XInputController.gyrometer.sensor != null}");
settings.Add("accelerometer", $"{XInputController.accelerometer.sensor != null}");

return settings;
}
Expand Down
73 changes: 37 additions & 36 deletions ControllerService/DSUServer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using ControllerCommon;
using ControllerService.Targets;
using Force.Crc32;
using Microsoft.Extensions.Logging;
using SharpDX.XInput;
Expand Down Expand Up @@ -537,63 +538,63 @@ public void Stop()
Stopped?.Invoke(this);
}

private bool ReportToBuffer(XInputController hidReport, byte[] outputData, long microseconds, ref int outIdx)
private bool ReportToBuffer(ViGEmTarget hidReport, byte[] outputData, long microseconds, ref int outIdx)
{
unchecked
{
outputData[outIdx] = 0;

if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft)) outputData[outIdx] |= 0x80;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown)) outputData[outIdx] |= 0x40;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight)) outputData[outIdx] |= 0x20;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp)) outputData[outIdx] |= 0x10;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft)) outputData[outIdx] |= 0x80;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown)) outputData[outIdx] |= 0x40;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight)) outputData[outIdx] |= 0x20;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp)) outputData[outIdx] |= 0x10;

if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.Start)) outputData[outIdx] |= 0x08;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.RightThumb)) outputData[outIdx] |= 0x04;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftThumb)) outputData[outIdx] |= 0x02;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.Back)) outputData[outIdx] |= 0x01;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Start)) outputData[outIdx] |= 0x08;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightThumb)) outputData[outIdx] |= 0x04;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftThumb)) outputData[outIdx] |= 0x02;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Back)) outputData[outIdx] |= 0x01;

outputData[++outIdx] = 0;

if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.X)) outputData[outIdx] |= 0x80;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.A)) outputData[outIdx] |= 0x40;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.B)) outputData[outIdx] |= 0x20;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.Y)) outputData[outIdx] |= 0x10;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.X)) outputData[outIdx] |= 0x80;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.A)) outputData[outIdx] |= 0x40;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.B)) outputData[outIdx] |= 0x20;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Y)) outputData[outIdx] |= 0x10;

if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder)) outputData[outIdx] |= 0x08;
if (hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder)) outputData[outIdx] |= 0x04;
if (hidReport.gamepad.RightTrigger == byte.MaxValue) outputData[outIdx] |= 0x02;
if (hidReport.gamepad.LeftTrigger == byte.MaxValue) outputData[outIdx] |= 0x01;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder)) outputData[outIdx] |= 0x08;
if (hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder)) outputData[outIdx] |= 0x04;
if (hidReport.Gamepad.RightTrigger == byte.MaxValue) outputData[outIdx] |= 0x02;
if (hidReport.Gamepad.LeftTrigger == byte.MaxValue) outputData[outIdx] |= 0x01;

outputData[++outIdx] = (byte)0; // (hidReport.PS) ? (byte)1 :
outputData[++outIdx] = (byte)0; // (hidReport.TouchButton) ? (byte)1 :

//Left stick
outputData[++outIdx] = Utils.NormalizeInput(hidReport.gamepad.LeftThumbX);
outputData[++outIdx] = Utils.NormalizeInput(hidReport.gamepad.LeftThumbY);
outputData[++outIdx] = Utils.NormalizeInput(hidReport.Gamepad.LeftThumbX);
outputData[++outIdx] = Utils.NormalizeInput(hidReport.Gamepad.LeftThumbY);
outputData[outIdx] = (byte)(byte.MaxValue - outputData[outIdx]); //invert Y by convention

//Right stick
outputData[++outIdx] = Utils.NormalizeInput(hidReport.gamepad.RightThumbX);
outputData[++outIdx] = Utils.NormalizeInput(hidReport.gamepad.RightThumbY);
outputData[++outIdx] = Utils.NormalizeInput(hidReport.Gamepad.RightThumbX);
outputData[++outIdx] = Utils.NormalizeInput(hidReport.Gamepad.RightThumbY);
outputData[outIdx] = (byte)(byte.MaxValue - outputData[outIdx]); //invert Y by convention

//we don't have analog buttons on DS4 :(
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadLeft) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadDown) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadRight) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.DPadUp) ? (byte)0xFF : (byte)0x00;

outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.X) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.A) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.B) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.Y) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.X) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.A) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.B) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.Y) ? (byte)0xFF : (byte)0x00;

outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.RightShoulder) ? (byte)0xFF : (byte)0x00;
outputData[++outIdx] = hidReport.Gamepad.Buttons.HasFlag(GamepadButtonFlags.LeftShoulder) ? (byte)0xFF : (byte)0x00;

outputData[++outIdx] = hidReport.gamepad.RightTrigger;
outputData[++outIdx] = hidReport.gamepad.LeftTrigger;
outputData[++outIdx] = hidReport.Gamepad.RightTrigger;
outputData[++outIdx] = hidReport.Gamepad.LeftTrigger;

outIdx++;

Expand Down Expand Up @@ -657,13 +658,13 @@ private bool ReportToBuffer(XInputController hidReport, byte[] outputData, long
return true;
}

public void NewReportIncoming(XInputController hidReport, long microseconds)
public void NewReportIncoming(ViGEmTarget hidReport)
{
if (!running)
return;

// update status
padMeta.IsActive = hidReport.controller.IsConnected;
padMeta.IsActive = hidReport.Controller.IsConnected;

var clientsList = new List<IPEndPoint>();
var now = DateTime.UtcNow;
Expand Down Expand Up @@ -750,7 +751,7 @@ public void NewReportIncoming(XInputController hidReport, long microseconds)
Array.Copy(BitConverter.GetBytes((uint)udpPacketCount++), 0, outputData, outIdx, 4);
outIdx += 4;

if (!ReportToBuffer(hidReport, outputData, microseconds, ref outIdx))
if (!ReportToBuffer(hidReport, outputData, hidReport.microseconds, ref outIdx))
return;
else
FinishPacket(outputData);
Expand Down
2 changes: 1 addition & 1 deletion ControllerService/HidHide.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public void SetCloaking(bool status)
process.WaitForExit();
process.StandardOutput.ReadToEnd();

logger.LogInformation("{0} cloak status set to {1}", service.PhysicalController.instance.ProductName, status);
logger.LogInformation("{0} cloak status set to {1}", service.XInputController.instance.ProductName, status);
}

public void RegisterDevice(string deviceInstancePath)
Expand Down
Loading

0 comments on commit 9771c26

Please sign in to comment.