Added output slot manager. Added plug and unplug delay of 100 ms for output devices.

Related to issue #879
This commit is contained in:
Travis Nickles 2019-12-11 09:58:31 -06:00
parent 424b456175
commit 21518134fc
3 changed files with 179 additions and 24 deletions

View File

@ -50,6 +50,7 @@ namespace DS4Windows
public bool suspending;
//SoundPlayer sp = new SoundPlayer();
private UdpServer _udpServer;
private OutputSlotManager outputslotMan;
private class X360Data
{
@ -193,6 +194,8 @@ namespace DS4Windows
PreviousState[i] = new DS4State();
ExposedState[i] = new DS4StateExposed(CurrentState[i]);
}
outputslotMan = new OutputSlotManager();
}
private void TestQueueBus(Action temp)
@ -366,58 +369,53 @@ namespace DS4Windows
{
if (contType == OutContType.X360)
{
//LogDebug("Plugging in X360 Controller for input #" + (index + 1));
LogDebug("Plugging in X360 Controller for input #" + (index + 1));
activeOutDevType[index] = OutContType.X360;
Xbox360OutDevice tempXbox = new Xbox360OutDevice(vigemTestClient);
//Xbox360OutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, vigemTestClient)
// as Xbox360OutDevice;
outputDevices[index] = tempXbox;
//Xbox360OutDevice tempXbox = new Xbox360OutDevice(vigemTestClient);
Xbox360OutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, vigemTestClient)
as Xbox360OutDevice;
//outputDevices[index] = tempXbox;
int devIndex = index;
tempXbox.cont.FeedbackReceived += (sender, args) =>
{
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
};
//outputslotMan.DeferredPlugin(tempXbox, index, outputDevices);
tempXbox.Connect();
LogDebug("X360 Controller #" + (index + 1) + " connected");
outputslotMan.DeferredPlugin(tempXbox, index, outputDevices);
}
else if (contType == OutContType.DS4)
{
//LogDebug("Plugging in DS4 Controller for input #" + (index + 1));
LogDebug("Plugging in DS4 Controller for input #" + (index + 1));
activeOutDevType[index] = OutContType.DS4;
DS4OutDevice tempDS4 = new DS4OutDevice(vigemTestClient);
//DS4OutDevice tempDS4 = outputslotMan.AllocateController(OutContType.DS4, vigemTestClient)
// as DS4OutDevice;
outputDevices[index] = tempDS4;
//DS4OutDevice tempDS4 = new DS4OutDevice(vigemTestClient);
DS4OutDevice tempDS4 = outputslotMan.AllocateController(OutContType.DS4, vigemTestClient)
as DS4OutDevice;
//outputDevices[index] = tempDS4;
int devIndex = index;
tempDS4.cont.FeedbackReceived += (sender, args) =>
{
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
};
//outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
tempDS4.Connect();
LogDebug("DS4 Controller #" + (index + 1) + " connected");
outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
}
}
useDInputOnly[index] = false;
}
public void UnplugOutDev(int index, DS4Device device)
public void UnplugOutDev(int index, DS4Device device, bool immediate = false)
{
if (!useDInputOnly[index])
{
//OutContType contType = Global.OutContType[index];
string tempType = outputDevices[index].GetDeviceType();
LogDebug("Unplugging " + tempType + " Controller for input #" + (index + 1), false);
OutputDevice dev = outputDevices[index];
outputDevices[index] = null;
activeOutDevType[index] = OutContType.None;
//outputslotMan.DeferredRemoval(dev);
dev.Disconnect();
LogDebug(tempType + " Controller # " + (index + 1) + " unplugged");
outputslotMan.DeferredRemoval(dev, index, outputDevices, immediate);
useDInputOnly[index] = true;
}
}
@ -646,10 +644,15 @@ namespace DS4Windows
}
CurrentState[i].Battery = PreviousState[i].Battery = 0; // Reset for the next connection's initial status change.
outputDevices[i]?.Disconnect();
outputDevices[i] = null;
useDInputOnly[i] = true;
Global.activeOutDevType[i] = OutContType.None;
OutputDevice tempout = outputDevices[i];
if (tempout != null)
{
UnplugOutDev(i, tempDevice, true);
}
//outputDevices[i] = null;
//useDInputOnly[i] = true;
//Global.activeOutDevType[i] = OutContType.None;
DS4Controllers[i] = null;
touchPad[i] = null;
lag[i] = false;
@ -669,6 +672,11 @@ namespace DS4Windows
if (showlog)
LogDebug(Properties.Resources.StoppedDS4Windows);
while (outputslotMan.RunningQueue)
{
Thread.SpinWait(500);
}
stopViGEm();
}

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nefarius.ViGEm.Client;
namespace DS4Windows
{
public class OutputSlotManager
{
private const int DELAY_TIME = 100; // measured in ms
private Dictionary<int, OutputDevice> devictDict = new Dictionary<int, OutputDevice>();
private Dictionary<OutputDevice, int> revDevictDict = new Dictionary<OutputDevice, int>();
private OutputDevice[] outputDevices = new OutputDevice[4];
private Queue<Action> actions = new Queue<Action>();
private object actionLock = new object();
private bool runningQueue;
public bool RunningQueue { get => runningQueue; }
public OutputDevice AllocateController(OutContType contType, ViGEmClient client)
{
OutputDevice outputDevice = null;
switch(contType)
{
case OutContType.X360:
outputDevice = new Xbox360OutDevice(client);
break;
case OutContType.DS4:
outputDevice = new DS4OutDevice(client);
break;
case OutContType.None:
default:
break;
}
return outputDevice;
}
private int FindSlot()
{
int result = -1;
for (int i = 0; i < outputDevices.Length && result == -1; i++)
{
OutputDevice tempdev = outputDevices[i];
if (tempdev == null)
{
result = i;
}
}
return result;
}
private void LaunchEvents()
{
bool hasItems = false;
Action act = null;
lock (actionLock)
{
hasItems = actions.Count > 0;
}
while (hasItems)
{
lock (actionLock)
{
act = actions.Dequeue();
}
act.Invoke();
lock (actionLock)
{
hasItems = actions.Count > 0;
}
}
}
private void PrepareEventTask()
{
if (!runningQueue)
{
runningQueue = true;
Task.Run(() =>
{
LaunchEvents();
runningQueue = false;
});
}
}
public void DeferredPlugin(OutputDevice outputDevice, int inIdx, OutputDevice[] outdevs)
{
Action tempAction = new Action(() =>
{
int slot = FindSlot();
if (slot != -1)
{
outputDevice.Connect();
outputDevices[slot] = outputDevice;
devictDict.Add(slot, outputDevice);
revDevictDict.Add(outputDevice, slot);
Task.Delay(DELAY_TIME).Wait();
outdevs[inIdx] = outputDevice;
}
});
lock (actionLock)
{
actions.Enqueue(tempAction);
}
PrepareEventTask();
}
public void DeferredRemoval(OutputDevice outputDevice, int inIdx, OutputDevice[] outdevs, bool immediate = false)
{
Action tempAction = new Action(() =>
{
if (revDevictDict.ContainsKey(outputDevice))
{
int slot = revDevictDict[outputDevice];
outputDevices[slot] = null;
devictDict.Remove(slot);
revDevictDict.Remove(outputDevice);
outputDevice.Disconnect();
outdevs[inIdx] = null;
if (!immediate)
{
Task.Delay(DELAY_TIME).Wait();
}
}
});
lock (actionLock)
{
actions.Enqueue(tempAction);
}
PrepareEventTask();
}
}
}

View File

@ -152,6 +152,7 @@
<Compile Include="DS4Control\MouseCursor.cs" />
<Compile Include="DS4Control\MouseWheel.cs" />
<Compile Include="DS4Control\OutputDevice.cs" />
<Compile Include="DS4Control\OutputSlotManager.cs" />
<Compile Include="DS4Control\ProfilePropGroups.cs" />
<Compile Include="DS4Control\ScpUtil.cs" />
<Compile Include="DS4Control\UdpServer.cs" />