Last active
March 4, 2021 00:20
-
-
Save Ryochan7/736cbd9c488e6b6409fa4757b08f0aaf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs | |
index a47dfb0b..86a9d578 100644 | |
--- a/DS4Windows/DS4Control/ControlService.cs | |
+++ b/DS4Windows/DS4Control/ControlService.cs | |
@@ -10,6 +10,7 @@ using System.Windows.Threading; | |
using DS4WinWPF.DS4Control; | |
using Microsoft.Win32; | |
using Sensorit.Base; | |
+using System.Linq; | |
namespace DS4Windows | |
{ | |
@@ -256,6 +257,22 @@ namespace DS4Windows | |
DualSenseControllerOptions dSOpts = tempDSDev.NativeOptionsStore; | |
dSOpts.LedModeChanged += (sender, e) => { tempDSDev.CheckControllerNumDeviceSettings(activeControllers); }; | |
} | |
+ else if (device.DeviceType == InputDevices.InputDeviceType.JoyConL || | |
+ device.DeviceType == InputDevices.InputDeviceType.JoyConR) | |
+ { | |
+ InputDevices.JoyConDevice tempJoyDev = device as InputDevices.JoyConDevice; | |
+ tempJoyDev.PerformStateMerge = true; | |
+ if (device.DeviceType == InputDevices.InputDeviceType.JoyConL) | |
+ { | |
+ tempJoyDev.PrimaryDevice = true; | |
+ tempJoyDev.OutputMapGyro = false; | |
+ } | |
+ else | |
+ { | |
+ tempJoyDev.PrimaryDevice = false; | |
+ tempJoyDev.OutputMapGyro = true; | |
+ } | |
+ } | |
} | |
public bool CheckForSupportedDevice(HidDevice device, VidPidInfo metaInfo) | |
@@ -623,7 +640,7 @@ namespace DS4Windows | |
return temp; | |
} | |
- private void EstablishOutFeedback(int index, OutContType contType, | |
+ public void EstablishOutFeedback(int index, OutContType contType, | |
OutputDevice outDevice, DS4Device device) | |
{ | |
int devIndex = index; | |
@@ -638,7 +655,7 @@ namespace DS4Windows | |
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex); | |
}; | |
tempXbox.cont.FeedbackReceived += p; | |
- tempXbox.forceFeedbackCall = p; | |
+ tempXbox.forceFeedbackCall.Add(index, p); | |
} | |
else if (contType == OutContType.DS4) | |
{ | |
@@ -717,13 +734,15 @@ namespace DS4Windows | |
} | |
} | |
- public void RemoveOutFeedback(OutContType contType, OutputDevice outDevice) | |
+ public void RemoveOutFeedback(OutContType contType, OutputDevice outDevice, int inIdx) | |
{ | |
if (contType == OutContType.X360) | |
{ | |
Xbox360OutDevice tempXbox = outDevice as Xbox360OutDevice; | |
- tempXbox.cont.FeedbackReceived -= tempXbox.forceFeedbackCall; | |
- tempXbox.forceFeedbackCall = null; | |
+ tempXbox.cont.FeedbackReceived -= tempXbox.forceFeedbackCall[inIdx]; | |
+ tempXbox.forceFeedbackCall.Remove(inIdx); | |
+ //tempXbox.cont.FeedbackReceived -= tempXbox.forceFeedbackCall; | |
+ //tempXbox.forceFeedbackCall = null; | |
} | |
else if (contType == OutContType.DS4) | |
{ | |
@@ -790,7 +809,17 @@ namespace DS4Windows | |
// Enable ViGem feedback callback handler only if lightbar/rumble data output is enabled (if those are disabled then no point enabling ViGem callback handler call) | |
if (Global.EnableOutputDataToDS4[index]) | |
+ { | |
EstablishOutFeedback(index, OutContType.X360, tempXbox, device); | |
+ if (device.JointDeviceSlotNumber != -1) | |
+ { | |
+ DS4Device tempDS4Device = DS4Controllers[device.JointDeviceSlotNumber]; | |
+ if (tempDS4Device != null) | |
+ { | |
+ EstablishOutFeedback(device.JointDeviceSlotNumber, OutContType.X360, tempXbox, tempDS4Device); | |
+ } | |
+ } | |
+ } | |
outputslotMan.DeferredPlugin(tempXbox, index, outputDevices, contType); | |
//slotDevice.CurrentInputBound = OutSlotDevice.InputBound.Bound; | |
@@ -810,8 +839,19 @@ namespace DS4Windows | |
// Enable ViGem feedback callback handler only if lightbar/rumble data output is enabled (if those are disabled then no point enabling ViGem callback handler call) | |
if (Global.EnableOutputDataToDS4[index]) | |
+ { | |
EstablishOutFeedback(index, OutContType.X360, tempXbox, device); | |
+ if (device.JointDeviceSlotNumber != -1) | |
+ { | |
+ DS4Device tempDS4Device = DS4Controllers[device.JointDeviceSlotNumber]; | |
+ if (tempDS4Device != null) | |
+ { | |
+ EstablishOutFeedback(device.JointDeviceSlotNumber, OutContType.X360, tempXbox, tempDS4Device); | |
+ } | |
+ } | |
+ } | |
+ | |
outputslotMan.EventDispatcher.BeginInvoke((Action)(() => | |
{ | |
outputDevices[index] = tempXbox; | |
@@ -838,8 +878,19 @@ namespace DS4Windows | |
// Enable ViGem feedback callback handler only if DS4 lightbar/rumble data output is enabled (if those are disabled then no point enabling ViGem callback handler call) | |
if (Global.EnableOutputDataToDS4[index]) | |
+ { | |
EstablishOutFeedback(index, OutContType.DS4, tempDS4, device); | |
- | |
+ | |
+ if (device.JointDeviceSlotNumber != -1) | |
+ { | |
+ DS4Device tempDS4Device = DS4Controllers[device.JointDeviceSlotNumber]; | |
+ if (tempDS4Device != null) | |
+ { | |
+ EstablishOutFeedback(device.JointDeviceSlotNumber, OutContType.DS4, tempDS4, tempDS4Device); | |
+ } | |
+ } | |
+ } | |
+ | |
outputslotMan.DeferredPlugin(tempDS4, index, outputDevices, contType); | |
//slotDevice.CurrentInputBound = OutSlotDevice.InputBound.Bound; | |
@@ -858,8 +909,19 @@ namespace DS4Windows | |
// Enable ViGem feedback callback handler only if lightbar/rumble data output is enabled (if those are disabled then no point enabling ViGem callback handler call) | |
if (Global.EnableOutputDataToDS4[index]) | |
+ { | |
EstablishOutFeedback(index, OutContType.DS4, tempDS4, device); | |
+ if (device.JointDeviceSlotNumber != -1) | |
+ { | |
+ DS4Device tempDS4Device = DS4Controllers[device.JointDeviceSlotNumber]; | |
+ if (tempDS4Device != null) | |
+ { | |
+ EstablishOutFeedback(device.JointDeviceSlotNumber, OutContType.DS4, tempDS4, tempDS4Device); | |
+ } | |
+ } | |
+ } | |
+ | |
outputslotMan.EventDispatcher.BeginInvoke((Action)(() => | |
{ | |
outputDevices[index] = tempDS4; | |
@@ -912,7 +974,8 @@ namespace DS4Windows | |
{ | |
slotDevice.CurrentInputBound = OutSlotDevice.InputBound.Unbound; | |
dev.ResetState(); | |
- RemoveOutFeedback(currentType, dev); | |
+ dev.RemoveFeedbacks(); | |
+ //RemoveOutFeedback(currentType, dev, index); | |
} | |
//dev.Disconnect(); | |
//LogDebug(tempType + " Controller # " + (index + 1) + " unplugged"); | |
@@ -974,6 +1037,7 @@ namespace DS4Windows | |
//for (int i = 0, devCount = devices.Count(); i < devCount; i++) | |
int i = 0; | |
+ InputDevices.JoyConDevice tempPrimaryJoyDev = null; | |
for (var devEnum = devices.GetEnumerator(); devEnum.MoveNext() && loopControllers; i++) | |
{ | |
DS4Device device = devEnum.Current; | |
@@ -990,10 +1054,34 @@ namespace DS4Windows | |
Task task = new Task(() => { Thread.Sleep(5); WarnExclusiveModeFailure(device); }); | |
task.Start(); | |
+ PostDS4DeviceInit(device); | |
+ | |
+ if ((device.DeviceType == InputDevices.InputDeviceType.JoyConL || | |
+ device.DeviceType == InputDevices.InputDeviceType.JoyConR) && device.PerformStateMerge) | |
+ { | |
+ if (tempPrimaryJoyDev == null) | |
+ { | |
+ tempPrimaryJoyDev = device as InputDevices.JoyConDevice; | |
+ } | |
+ else | |
+ { | |
+ InputDevices.JoyConDevice currentJoyDev = device as InputDevices.JoyConDevice; | |
+ tempPrimaryJoyDev.JointDevice = currentJoyDev; | |
+ currentJoyDev.JointDevice = tempPrimaryJoyDev; | |
+ | |
+ tempPrimaryJoyDev.JointState = currentJoyDev.JointState; | |
+ | |
+ InputDevices.JoyConDevice parentJoy = tempPrimaryJoyDev; | |
+ tempPrimaryJoyDev.Removal += (sender, args) => { currentJoyDev.JointDevice = null; }; | |
+ currentJoyDev.Removal += (sender, args) => { parentJoy.JointDevice = null; }; | |
+ | |
+ tempPrimaryJoyDev = null; | |
+ } | |
+ } | |
+ | |
DS4Controllers[i] = device; | |
device.DeviceSlotNumber = i; | |
Global.LoadControllerConfigs(device); | |
- PostDS4DeviceInit(device); | |
device.LoadStoreSettings(); | |
device.CheckControllerNumDeviceSettings(numControllers); | |
@@ -1030,7 +1118,28 @@ namespace DS4Windows | |
if (!getDInputOnly(i) && device.isSynced()) | |
{ | |
//useDInputOnly[i] = false; | |
- PluginOutDev(i, device); | |
+ if (device.PrimaryDevice) | |
+ { | |
+ PluginOutDev(i, device); | |
+ } | |
+ else if (device.JointDeviceSlotNumber != DS4Device.DEFAULT_JOINT_SLOT_NUMBER) | |
+ { | |
+ int otherIdx = device.JointDeviceSlotNumber; | |
+ OutputDevice tempOutDev = outputDevices[otherIdx]; | |
+ if (tempOutDev != null) | |
+ { | |
+ OutContType tempConType = activeOutDevType[otherIdx]; | |
+ EstablishOutFeedback(i, tempConType, tempOutDev, device); | |
+ outputDevices[i] = tempOutDev; | |
+ Global.activeOutDevType[i] = tempConType; | |
+ | |
+ //useDInputOnly[i] = false; | |
+ //Global.activeOutDevType[i] = OutContType.X360; | |
+ } | |
+ | |
+ //useDInputOnly[i] = true; | |
+ //Global.activeOutDevType[i] = OutContType.None; | |
+ } | |
} | |
else | |
{ | |
@@ -1038,7 +1147,25 @@ namespace DS4Windows | |
Global.activeOutDevType[i] = OutContType.None; | |
} | |
- TouchPadOn(i, device); | |
+ if (device.PrimaryDevice && device.OutputMapGyro) | |
+ { | |
+ TouchPadOn(i, device); | |
+ } | |
+ else if (device.JointDeviceSlotNumber != DS4Device.DEFAULT_JOINT_SLOT_NUMBER) | |
+ { | |
+ int otherIdx = device.JointDeviceSlotNumber; | |
+ DS4Device tempDev = DS4Controllers[otherIdx]; | |
+ if (tempDev != null) | |
+ { | |
+ int mappedIdx = tempDev.PrimaryDevice ? otherIdx : i; | |
+ DS4Device gyroDev = device.OutputMapGyro ? device : (tempDev.OutputMapGyro ? tempDev : null); | |
+ if (gyroDev != null) | |
+ { | |
+ TouchPadOn(mappedIdx, gyroDev); | |
+ } | |
+ } | |
+ } | |
+ | |
CheckProfileOptions(i, device, true); | |
} | |
@@ -1048,7 +1175,7 @@ namespace DS4Windows | |
this.On_Report(sender, e, tempIdx); | |
}; | |
- if (_udpServer != null && i < UdpServer.NUMBER_SLOTS) | |
+ if (_udpServer != null && i < UdpServer.NUMBER_SLOTS && device.PrimaryDevice) | |
{ | |
DS4Device.ReportHandler<EventArgs> tempEvnt = (sender, args) => | |
{ | |
@@ -1287,6 +1414,13 @@ namespace DS4Windows | |
activeControllers = numControllers; | |
//foreach (DS4Device device in devices) | |
//for (int i = 0, devlen = devices.Count(); i < devlen; i++) | |
+ InputDevices.JoyConDevice tempPrimaryJoyDev = devices.Where(d => | |
+ (d.DeviceType == InputDevices.InputDeviceType.JoyConL || d.DeviceType == InputDevices.InputDeviceType.JoyConR) | |
+ && d.PrimaryDevice && d.JointDeviceSlotNumber == -1).FirstOrDefault() as InputDevices.JoyConDevice; | |
+ InputDevices.JoyConDevice tempSecondaryJoyDev = devices.Where(d => | |
+ (d.DeviceType == InputDevices.InputDeviceType.JoyConL || d.DeviceType == InputDevices.InputDeviceType.JoyConR) | |
+ && !d.PrimaryDevice && d.JointDeviceSlotNumber == -1).FirstOrDefault() as InputDevices.JoyConDevice; | |
+ | |
for (var devEnum = devices.GetEnumerator(); devEnum.MoveNext() && loopControllers;) | |
{ | |
DS4Device device = devEnum.Current; | |
@@ -1328,10 +1462,49 @@ namespace DS4Windows | |
Task task = new Task(() => { Thread.Sleep(5); WarnExclusiveModeFailure(device); }); | |
task.Start(); | |
+ | |
+ PostDS4DeviceInit(device); | |
+ | |
+ if ((device.DeviceType == InputDevices.InputDeviceType.JoyConL || | |
+ device.DeviceType == InputDevices.InputDeviceType.JoyConR) && device.PerformStateMerge) | |
+ { | |
+ if (device.PrimaryDevice && | |
+ tempSecondaryJoyDev != null) | |
+ { | |
+ InputDevices.JoyConDevice currentJoyDev = device as InputDevices.JoyConDevice; | |
+ tempSecondaryJoyDev.JointDevice = currentJoyDev; | |
+ currentJoyDev.JointDevice = tempSecondaryJoyDev; | |
+ | |
+ tempSecondaryJoyDev.JointState = currentJoyDev.JointState; | |
+ | |
+ InputDevices.JoyConDevice secondaryJoy = tempSecondaryJoyDev; | |
+ secondaryJoy.Removal += (sender, args) => { currentJoyDev.JointDevice = null; }; | |
+ currentJoyDev.Removal += (sender, args) => { secondaryJoy.JointDevice = null; }; | |
+ | |
+ tempSecondaryJoyDev = null; | |
+ tempPrimaryJoyDev = null; | |
+ } | |
+ else if (!device.PrimaryDevice && | |
+ tempPrimaryJoyDev != null) | |
+ { | |
+ InputDevices.JoyConDevice currentJoyDev = device as InputDevices.JoyConDevice; | |
+ tempPrimaryJoyDev.JointDevice = currentJoyDev; | |
+ currentJoyDev.JointDevice = tempPrimaryJoyDev; | |
+ | |
+ tempPrimaryJoyDev.JointState = currentJoyDev.JointState; | |
+ | |
+ InputDevices.JoyConDevice parentJoy = tempPrimaryJoyDev; | |
+ tempPrimaryJoyDev.Removal += (sender, args) => { currentJoyDev.JointDevice = null; }; | |
+ currentJoyDev.Removal += (sender, args) => { parentJoy.JointDevice = null; }; | |
+ | |
+ tempPrimaryJoyDev = null; | |
+ } | |
+ } | |
+ | |
+ | |
DS4Controllers[Index] = device; | |
device.DeviceSlotNumber = Index; | |
Global.LoadControllerConfigs(device); | |
- PostDS4DeviceInit(device); | |
device.LoadStoreSettings(); | |
device.CheckControllerNumDeviceSettings(numControllers); | |
@@ -1368,7 +1541,28 @@ namespace DS4Windows | |
if (!getDInputOnly(Index) && device.isSynced()) | |
{ | |
//useDInputOnly[Index] = false; | |
- PluginOutDev(Index, device); | |
+ if (device.PrimaryDevice) | |
+ { | |
+ PluginOutDev(Index, device); | |
+ } | |
+ else | |
+ { | |
+ int otherIdx = (device as InputDevices.JoyConDevice).JointDevice.DeviceSlotNumber; | |
+ OutputDevice tempOutDev = outputDevices[otherIdx]; | |
+ if (tempOutDev != null) | |
+ { | |
+ OutContType tempConType = activeOutDevType[otherIdx]; | |
+ EstablishOutFeedback(Index, tempConType, tempOutDev, device); | |
+ outputDevices[Index] = tempOutDev; | |
+ Global.activeOutDevType[Index] = tempConType; | |
+ | |
+ //useDInputOnly[i] = false; | |
+ //Global.activeOutDevType[i] = OutContType.X360; | |
+ } | |
+ | |
+ //useDInputOnly[Index] = true; | |
+ //Global.activeOutDevType[Index] = OutContType.None; | |
+ } | |
} | |
else | |
{ | |
@@ -1376,7 +1570,25 @@ namespace DS4Windows | |
Global.activeOutDevType[Index] = OutContType.None; | |
} | |
- TouchPadOn(Index, device); | |
+ if (device.PrimaryDevice && device.OutputMapGyro) | |
+ { | |
+ TouchPadOn(Index, device); | |
+ } | |
+ else if (device.JointDeviceSlotNumber != DS4Device.DEFAULT_JOINT_SLOT_NUMBER) | |
+ { | |
+ int otherIdx = device.JointDeviceSlotNumber; | |
+ DS4Device tempDev = DS4Controllers[otherIdx]; | |
+ if (tempDev != null) | |
+ { | |
+ int mappedIdx = tempDev.PrimaryDevice ? otherIdx : Index; | |
+ DS4Device gyroDev = device.OutputMapGyro ? device : (tempDev.OutputMapGyro ? tempDev : null); | |
+ if (gyroDev != null) | |
+ { | |
+ TouchPadOn(mappedIdx, gyroDev); | |
+ } | |
+ } | |
+ } | |
+ | |
CheckProfileOptions(Index, device); | |
} | |
@@ -1386,7 +1598,7 @@ namespace DS4Windows | |
this.On_Report(sender, e, tempIdx); | |
}; | |
- if (_udpServer != null && Index < UdpServer.NUMBER_SLOTS) | |
+ if (_udpServer != null && Index < UdpServer.NUMBER_SLOTS && device.PrimaryDevice) | |
{ | |
DS4Device.ReportHandler<EventArgs> tempEvnt = (sender, args) => | |
{ | |
@@ -1766,6 +1978,15 @@ namespace DS4Windows | |
{ | |
UnplugOutDev(ind, device); | |
} | |
+ else if (!device.PrimaryDevice) | |
+ { | |
+ OutputDevice outDev = outputDevices[ind]; | |
+ if (outDev != null) | |
+ { | |
+ outDev.RemoveFeedback(ind); | |
+ outputDevices[ind] = null; | |
+ } | |
+ } | |
// Use Task to reset device synth state and commit it | |
Task.Run(() => | |
@@ -1873,8 +2094,18 @@ namespace DS4Windows | |
} | |
} | |
- device.getCurrentState(CurrentState[ind]); | |
- DS4State cState = CurrentState[ind]; | |
+ DS4State cState; | |
+ if (!device.PerformStateMerge) | |
+ { | |
+ cState = CurrentState[ind]; | |
+ device.getRawCurrentState(cState); | |
+ } | |
+ else | |
+ { | |
+ cState = device.JointState; | |
+ device.MergeStateData(cState); | |
+ } | |
+ | |
DS4State pState = device.getPreviousStateRef(); | |
//device.getPreviousState(PreviousState[ind]); | |
//DS4State pState = PreviousState[ind]; | |
@@ -1912,6 +2143,12 @@ namespace DS4Windows | |
// */ | |
//} | |
+ if (!device.PrimaryDevice) | |
+ { | |
+ // Skip mapping routine if part of a joined device | |
+ return; | |
+ } | |
+ | |
if (getEnableTouchToggle(ind)) | |
CheckForTouchToggle(ind, cState, pState); | |
@@ -1983,6 +2220,11 @@ namespace DS4Windows | |
// Update the GUI/whatever. | |
DS4LightBar.updateLightBar(device, ind); | |
+ | |
+ if (device.PerformStateMerge) | |
+ { | |
+ device.PreserveMergedStateData(); | |
+ } | |
} | |
} | |
diff --git a/DS4Windows/DS4Control/DS4OutDevice.cs b/DS4Windows/DS4Control/DS4OutDevice.cs | |
index 8dab686a..9b1248a1 100644 | |
--- a/DS4Windows/DS4Control/DS4OutDevice.cs | |
+++ b/DS4Windows/DS4Control/DS4OutDevice.cs | |
@@ -42,5 +42,18 @@ namespace DS4Windows | |
cont = null; | |
} | |
public override string GetDeviceType() => devtype; | |
+ | |
+ public override void RemoveFeedbacks() | |
+ { | |
+ if (forceFeedbackCall != null) | |
+ { | |
+ cont.FeedbackReceived -= forceFeedbackCall; | |
+ forceFeedbackCall = null; | |
+ } | |
+ } | |
+ | |
+ public override void RemoveFeedback(int inIdx) | |
+ { | |
+ } | |
} | |
} | |
diff --git a/DS4Windows/DS4Control/OutputDevice.cs b/DS4Windows/DS4Control/OutputDevice.cs | |
index ada31e46..154f650e 100644 | |
--- a/DS4Windows/DS4Control/OutputDevice.cs | |
+++ b/DS4Windows/DS4Control/OutputDevice.cs | |
@@ -11,5 +11,9 @@ namespace DS4Windows | |
public abstract void Disconnect(); | |
public abstract void ResetState(bool submit=true); | |
public abstract string GetDeviceType(); | |
+ | |
+ public abstract void RemoveFeedbacks(); | |
+ | |
+ public abstract void RemoveFeedback(int inIdx); | |
} | |
} | |
diff --git a/DS4Windows/DS4Control/ScpUtil.cs b/DS4Windows/DS4Control/ScpUtil.cs | |
index 97380f13..c90404f6 100644 | |
--- a/DS4Windows/DS4Control/ScpUtil.cs | |
+++ b/DS4Windows/DS4Control/ScpUtil.cs | |
@@ -5081,10 +5081,14 @@ namespace DS4Windows | |
// Only change xinput devices under certain conditions. Avoid | |
// performing this upon program startup before loading devices. | |
- if (xinputChange) | |
+ if (xinputChange && device < ControlService.CURRENT_DS4_CONTROLLER_LIMIT) | |
{ | |
- CheckOldDevicestatus(device, control, oldContType, | |
- out xinputPlug, out xinputStatus); | |
+ DS4Device tempDev = control.DS4Controllers[device]; | |
+ if (tempDev != null) | |
+ { | |
+ CheckOldDevicestatus(device, control, oldContType, | |
+ out xinputPlug, out xinputStatus); | |
+ } | |
} | |
try | |
@@ -7062,25 +7066,27 @@ namespace DS4Windows | |
{ | |
tempDev.setIdleTimeout(idleDisconnectTimeout[device]); | |
tempDev.setBTPollRate(btPollRate[device]); | |
- if (xinputStatus && xinputPlug) | |
+ if (xinputStatus && tempDev.PrimaryDevice) | |
{ | |
- OutputDevice tempOutDev = control.outputDevices[device]; | |
- if (tempOutDev != null) | |
+ if (xinputPlug) | |
+ { | |
+ OutputDevice tempOutDev = control.outputDevices[device]; | |
+ if (tempOutDev != null) | |
+ { | |
+ tempOutDev = null; | |
+ //Global.activeOutDevType[device] = OutContType.None; | |
+ control.UnplugOutDev(device, tempDev); | |
+ } | |
+ | |
+ OutContType tempContType = outputDevType[device]; | |
+ control.PluginOutDev(device, tempDev); | |
+ //Global.useDInputOnly[device] = false; | |
+ } | |
+ else | |
{ | |
- tempOutDev = null; | |
//Global.activeOutDevType[device] = OutContType.None; | |
control.UnplugOutDev(device, tempDev); | |
} | |
- | |
- OutContType tempContType = outputDevType[device]; | |
- control.PluginOutDev(device, tempDev); | |
- //Global.useDInputOnly[device] = false; | |
- | |
- } | |
- else if (xinputStatus && !xinputPlug) | |
- { | |
- //Global.activeOutDevType[device] = OutContType.None; | |
- control.UnplugOutDev(device, tempDev); | |
} | |
tempDev.RumbleAutostopTime = rumbleAutostopTime[device]; | |
diff --git a/DS4Windows/DS4Control/Xbox360OutDevice.cs b/DS4Windows/DS4Control/Xbox360OutDevice.cs | |
index 6c4df1fc..6f736e78 100644 | |
--- a/DS4Windows/DS4Control/Xbox360OutDevice.cs | |
+++ b/DS4Windows/DS4Control/Xbox360OutDevice.cs | |
@@ -2,6 +2,7 @@ | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
+using System.Threading; | |
using System.Threading.Tasks; | |
using Nefarius.ViGEm.Client; | |
using Nefarius.ViGEm.Client.Targets; | |
@@ -19,7 +20,10 @@ namespace DS4Windows | |
public const string devType = "X360"; | |
public IXbox360Controller cont; | |
- public Xbox360FeedbackReceivedEventHandler forceFeedbackCall; | |
+ // Input index, Xbox360FeedbackReceivedEventHandler instance | |
+ public Dictionary<int, Xbox360FeedbackReceivedEventHandler> forceFeedbackCall = | |
+ new Dictionary<int, Xbox360FeedbackReceivedEventHandler>(); | |
+ private ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim(); | |
public Xbox360OutDevice(ViGEmClient client) | |
{ | |
@@ -32,6 +36,7 @@ namespace DS4Windows | |
if (!connected) return; | |
//cont.ResetReport(); | |
+ | |
ushort tempButtons = 0; | |
unchecked | |
@@ -125,6 +130,7 @@ namespace DS4Windows | |
} | |
cont.SubmitReport(); | |
+ | |
} | |
private short AxisScale(Int32 Value, Boolean Flip) | |
@@ -152,8 +158,13 @@ namespace DS4Windows | |
{ | |
if (forceFeedbackCall != null) | |
{ | |
- cont.FeedbackReceived -= forceFeedbackCall; | |
- forceFeedbackCall = null; | |
+ foreach(KeyValuePair<int, Xbox360FeedbackReceivedEventHandler> pair in forceFeedbackCall) | |
+ { | |
+ cont.FeedbackReceived -= pair.Value; | |
+ } | |
+ | |
+ //forceFeedbackCall = null; | |
+ forceFeedbackCall.Clear(); | |
} | |
connected = false; | |
@@ -170,5 +181,25 @@ namespace DS4Windows | |
cont.SubmitReport(); | |
} | |
} | |
+ | |
+ public override void RemoveFeedbacks() | |
+ { | |
+ foreach (KeyValuePair<int, Xbox360FeedbackReceivedEventHandler> pair in forceFeedbackCall) | |
+ { | |
+ cont.FeedbackReceived -= pair.Value; | |
+ } | |
+ | |
+ //forceFeedbackCall = null; | |
+ forceFeedbackCall.Clear(); | |
+ } | |
+ | |
+ public override void RemoveFeedback(int inIdx) | |
+ { | |
+ if (forceFeedbackCall.TryGetValue(inIdx, out Xbox360FeedbackReceivedEventHandler handler)) | |
+ { | |
+ cont.FeedbackReceived -= handler; | |
+ forceFeedbackCall.Remove(inIdx); | |
+ } | |
+ } | |
} | |
} | |
diff --git a/DS4Windows/DS4Forms/MainWindow.xaml b/DS4Windows/DS4Forms/MainWindow.xaml | |
index 5c09b3e0..0064b2de 100644 | |
--- a/DS4Windows/DS4Forms/MainWindow.xaml | |
+++ b/DS4Windows/DS4Forms/MainWindow.xaml | |
@@ -95,11 +95,11 @@ | |
</DataTemplate> | |
</GridViewColumn.CellTemplate> | |
</GridViewColumn> | |
- <GridViewColumn x:Name="LinkProfColumn" Header="Link Profile/ID" Width="100" > | |
+ <GridViewColumn x:Name="LinkProfColumn" Header="Link Profile/ID" Width="100"> | |
<GridViewColumn.CellTemplate> | |
<DataTemplate> | |
<StackPanel Width="{Binding ElementName=LinkProfColumn, Path=Width}"> | |
- <CheckBox IsChecked="{Binding LinkedProfile}" HorizontalAlignment="Center" /> | |
+ <CheckBox IsChecked="{Binding LinkedProfile}" HorizontalAlignment="Center" IsEnabled="{Binding PrimaryDevice}" /> | |
</StackPanel> | |
</DataTemplate> | |
</GridViewColumn.CellTemplate> | |
@@ -109,7 +109,7 @@ | |
<DataTemplate> | |
<StackPanel Width="{Binding Path=Width, ElementName=selectProfileColumn, Mode=OneWay}" HorizontalAlignment="Center"> | |
<ComboBox x:Name="selectProfCombo" Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" | |
- ItemsSource="{Binding ProfileListCol}" SelectedIndex="{Binding SelectedIndex}" Height="Auto" Tag="{Binding DevIndex, Mode=OneTime}" Margin="0" | |
+ ItemsSource="{Binding ProfileListCol}" SelectedIndex="{Binding SelectedIndex}" IsEnabled="{Binding PrimaryDevice}" Height="Auto" Tag="{Binding DevIndex, Mode=OneTime}" Margin="0" | |
SelectionChanged="SelectProfCombo_SelectionChanged" KeyDown="SelectProfCombo_KeyDown"> | |
<ComboBox.ItemTemplate> | |
<DataTemplate> | |
@@ -125,7 +125,7 @@ | |
<GridViewColumn.CellTemplate> | |
<DataTemplate> | |
<StackPanel Width="{Binding ElementName=editColumn, Path=Width}"> | |
- <xctk:SplitButton x:Name="ProfEditSBtn" Content="{lex:Loc Edit}" Height="20" MinWidth="60" | |
+ <xctk:SplitButton x:Name="ProfEditSBtn" Content="{lex:Loc Edit}" Height="20" MinWidth="60" IsEnabled="{Binding PrimaryDevice}" | |
Tag="{Binding DevIndex, Mode=OneTime}" Click="ProfEditSBtn_Click" HorizontalAlignment="Center"> | |
<xctk:SplitButton.DropDownContent> | |
<Button x:Name="newProfBtn" Content="{lex:Loc NewProfile}" MinWidth="120" Tag="{Binding DevIndex, Mode=OneTime}" Click="NewProfBtn_Click" /> | |
diff --git a/DS4Windows/DS4Forms/MainWindow.xaml.cs b/DS4Windows/DS4Forms/MainWindow.xaml.cs | |
index a5a1ed26..d1f9e7fd 100644 | |
--- a/DS4Windows/DS4Forms/MainWindow.xaml.cs | |
+++ b/DS4Windows/DS4Forms/MainWindow.xaml.cs | |
@@ -903,6 +903,7 @@ Suspend support not enabled.", true); | |
{ | |
Image img = sender as Image; | |
int tag = Convert.ToInt32(img.Tag); | |
+ conLvViewModel.CurrentIndex = tag; | |
CompositeDeviceModel item = conLvViewModel.CurrentItem; | |
//CompositeDeviceModel item = conLvViewModel.ControllerDict[tag]; | |
if (item != null) | |
diff --git a/DS4Windows/DS4Forms/ViewModels/ControllerListViewModel.cs b/DS4Windows/DS4Forms/ViewModels/ControllerListViewModel.cs | |
index c8e4163f..42807ed5 100644 | |
--- a/DS4Windows/DS4Forms/ViewModels/ControllerListViewModel.cs | |
+++ b/DS4Windows/DS4Forms/ViewModels/ControllerListViewModel.cs | |
@@ -339,6 +339,11 @@ namespace DS4WinWPF.DS4Forms.ViewModels | |
} | |
} | |
+ public bool PrimaryDevice | |
+ { | |
+ get => device.PrimaryDevice; | |
+ } | |
+ | |
public delegate void CustomColorHandler(CompositeDeviceModel sender); | |
public event CustomColorHandler RequestColorPicker; | |
diff --git a/DS4Windows/DS4Library/DS4Device.cs b/DS4Windows/DS4Library/DS4Device.cs | |
index 484e7312..a00eaac2 100644 | |
--- a/DS4Windows/DS4Library/DS4Device.cs | |
+++ b/DS4Windows/DS4Library/DS4Device.cs | |
@@ -578,6 +578,49 @@ namespace DS4Windows | |
protected event EventHandler DeviceSlotNumberChanged; | |
protected byte deviceSlotMask = 0x00; | |
+ protected DS4State jointState = new DS4State(); | |
+ protected DS4State jointPreviousState = new DS4State(); | |
+ public DS4State JointState | |
+ { | |
+ get => jointState; | |
+ set => jointState = value; | |
+ } | |
+ | |
+ public DS4State JointPreviousState | |
+ { | |
+ get => jointPreviousState; | |
+ set => jointPreviousState = value; | |
+ } | |
+ | |
+ protected bool performStateMerge; | |
+ public bool PerformStateMerge | |
+ { | |
+ get => performStateMerge; | |
+ set => performStateMerge = value; | |
+ } | |
+ | |
+ protected bool primaryDevice = true; | |
+ public bool PrimaryDevice | |
+ { | |
+ get => primaryDevice; | |
+ set => primaryDevice = value; | |
+ } | |
+ | |
+ public const int DEFAULT_JOINT_SLOT_NUMBER = -1; | |
+ protected int jointDeviceSlotNumber = DEFAULT_JOINT_SLOT_NUMBER; | |
+ public virtual int JointDeviceSlotNumber | |
+ { | |
+ get => jointDeviceSlotNumber; | |
+ set => jointDeviceSlotNumber = value; | |
+ } | |
+ | |
+ protected bool outputMapGyro = true; | |
+ public bool OutputMapGyro | |
+ { | |
+ get => outputMapGyro; | |
+ set => outputMapGyro = value; | |
+ } | |
+ | |
public DS4Device(HidDevice hidDevice, string disName, VidPidFeatureSet featureSet = VidPidFeatureSet.DefaultDS4) | |
{ | |
hDevice = hidDevice; | |
@@ -1904,26 +1947,40 @@ namespace DS4Windows | |
return pState.Clone(); | |
} | |
- public void getCurrentState(DS4State state) | |
+ public void getRawCurrentState(DS4State state) | |
{ | |
cState.CopyTo(state); | |
} | |
- public void getPreviousState(DS4State state) | |
+ public void getRawPreviousState(DS4State state) | |
{ | |
pState.CopyTo(state); | |
} | |
- public DS4State getCurrentStateRef() | |
+ public virtual DS4State getCurrentStateRef() | |
+ { | |
+ return cState; | |
+ } | |
+ | |
+ public virtual DS4State getPreviousStateRef() | |
+ { | |
+ return pState; | |
+ } | |
+ | |
+ public DS4State GetRawCurrentStateRef() | |
{ | |
return cState; | |
} | |
- public DS4State getPreviousStateRef() | |
+ public DS4State GetRawPreviousStateRef() | |
{ | |
return pState; | |
} | |
+ public virtual void PreserveMergedStateData() | |
+ { | |
+ } | |
+ | |
public bool isDS4Idle() | |
{ | |
if (cState.Square || cState.Cross || cState.Circle || cState.Triangle) | |
@@ -2055,5 +2112,9 @@ namespace DS4Windows | |
PrepareOutputFeaturesByte(); | |
} | |
} | |
+ | |
+ public virtual void MergeStateData(DS4State dState) | |
+ { | |
+ } | |
} | |
} | |
diff --git a/DS4Windows/DS4Library/InputDevices/JoyConDevice.cs b/DS4Windows/DS4Library/InputDevices/JoyConDevice.cs | |
index 92325d77..ef5bfd56 100644 | |
--- a/DS4Windows/DS4Library/InputDevices/JoyConDevice.cs | |
+++ b/DS4Windows/DS4Library/InputDevices/JoyConDevice.cs | |
@@ -215,6 +215,37 @@ namespace DS4Windows.InputDevices | |
private JoyConControllerOptions nativeOptionsStore; | |
+ private ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim(); | |
+ private JoyConDevice jointDevice; | |
+ public JoyConDevice JointDevice | |
+ { | |
+ get => jointDevice; | |
+ set | |
+ { | |
+ jointDevice = value; | |
+ if (jointDevice == null) | |
+ { | |
+ } | |
+ else | |
+ { | |
+ } | |
+ } | |
+ } | |
+ | |
+ public override int JointDeviceSlotNumber | |
+ { | |
+ get | |
+ { | |
+ int result = -1; | |
+ if (jointDevice != null) | |
+ { | |
+ result = jointDevice.deviceSlotNumber; | |
+ } | |
+ | |
+ return result; | |
+ } | |
+ } | |
+ | |
public override event ReportHandler<EventArgs> Report = null; | |
public override event EventHandler<EventArgs> Removal = null; | |
public override event EventHandler BatteryChanged; | |
@@ -1288,5 +1319,94 @@ namespace DS4Windows.InputDevices | |
enableHomeLED = nativeOptionsStore.EnableHomeLED; | |
} | |
} | |
+ | |
+ public override DS4State getCurrentStateRef() | |
+ { | |
+ DS4State tempState = null; | |
+ if (!performStateMerge) | |
+ { | |
+ tempState = cState; | |
+ } | |
+ else | |
+ { | |
+ tempState = jointState; | |
+ } | |
+ | |
+ return tempState; | |
+ } | |
+ | |
+ public override DS4State getPreviousStateRef() | |
+ { | |
+ DS4State tempState = null; | |
+ if (!performStateMerge) | |
+ { | |
+ tempState = pState; | |
+ } | |
+ else | |
+ { | |
+ tempState = jointPreviousState; | |
+ } | |
+ | |
+ return tempState; | |
+ } | |
+ | |
+ public override void PreserveMergedStateData() | |
+ { | |
+ jointState.CopyTo(jointPreviousState); | |
+ } | |
+ | |
+ public override void MergeStateData(DS4State dState) | |
+ { | |
+ using (WriteLocker locker = new WriteLocker(lockSlim)) | |
+ { | |
+ if (DeviceType == InputDeviceType.JoyConL) | |
+ { | |
+ dState.LX = cState.LX; | |
+ dState.LY = cState.LY; | |
+ dState.L1 = cState.L1; | |
+ dState.L2 = cState.L2; | |
+ dState.L3 = cState.L3; | |
+ dState.L2Btn = cState.L2Btn; | |
+ dState.DpadUp = cState.DpadUp; | |
+ dState.DpadDown = cState.DpadDown; | |
+ dState.DpadLeft = cState.DpadLeft; | |
+ dState.DpadRight = cState.DpadRight; | |
+ dState.Share = cState.Share; | |
+ if (primaryDevice) | |
+ { | |
+ dState.elapsedTime = cState.elapsedTime; | |
+ dState.totalMicroSec = cState.totalMicroSec; | |
+ dState.ReportTimeStamp = cState.ReportTimeStamp; | |
+ } | |
+ | |
+ if (outputMapGyro) dState.Motion = cState.Motion; | |
+ //dState.Motion = cState.Motion; | |
+ } | |
+ else if (DeviceType == InputDeviceType.JoyConR) | |
+ { | |
+ dState.RX = cState.RX; | |
+ dState.RY = cState.RY; | |
+ dState.R1 = cState.R1; | |
+ dState.R2 = cState.R2; | |
+ dState.R3 = cState.R3; | |
+ dState.R2Btn = cState.R2Btn; | |
+ dState.Cross = cState.Cross; | |
+ dState.Circle = cState.Circle; | |
+ dState.Triangle = cState.Triangle; | |
+ dState.Square = cState.Square; | |
+ dState.PS = cState.PS; | |
+ dState.Options = cState.Options; | |
+ if (primaryDevice) | |
+ { | |
+ dState.elapsedTime = cState.elapsedTime; | |
+ dState.totalMicroSec = cState.totalMicroSec; | |
+ dState.ReportTimeStamp = cState.ReportTimeStamp; | |
+ } | |
+ | |
+ if (outputMapGyro) dState.Motion = cState.Motion; | |
+ //dState.Motion = cState.Motion; | |
+ } | |
+ } | |
+ } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment