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 = 200; // measured in ms private Dictionary deviceDict = new Dictionary(); private Dictionary revDeviceDict = new Dictionary(); private OutputDevice[] outputDevices = new OutputDevice[4]; private Queue actions = new Queue(); 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; deviceDict.Add(slot, outputDevice); revDeviceDict.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 (revDeviceDict.ContainsKey(outputDevice)) { int slot = revDeviceDict[outputDevice]; outputDevices[slot] = null; deviceDict.Remove(slot); revDeviceDict.Remove(outputDevice); outputDevice.Disconnect(); outdevs[inIdx] = null; if (!immediate) { Task.Delay(DELAY_TIME).Wait(); } } }); lock (actionLock) { actions.Enqueue(tempAction); } PrepareEventTask(); } } }