diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs
index 2895df5..a9ae63b 100644
--- a/DS4Windows/DS4Control/ControlService.cs
+++ b/DS4Windows/DS4Control/ControlService.cs
@@ -5,13 +5,14 @@ using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using static DS4Windows.Global;
-using Nefarius.ViGEm.Client;
+//using Nefarius.ViGEm.Client;
namespace DS4Windows
{
public class ControlService
{
- public ViGEmClient vigemTestClient = null;
+ public X360BusDevice x360Bus = null;
+ //public ViGEmClient vigemTestClient = null;
public const int DS4_CONTROLLER_COUNT = 4;
public DS4Device[] DS4Controllers = new DS4Device[DS4_CONTROLLER_COUNT];
public Mouse[] touchPad = new Mouse[DS4_CONTROLLER_COUNT];
@@ -357,7 +358,8 @@ namespace DS4Windows
private void startViGEm()
{
- tempThread = new Thread(() => { try { vigemTestClient = new ViGEmClient(); } catch { } });
+ tempThread = new Thread(() => { try { x360Bus = new X360BusDevice(); } catch { } });
+ //tempThread = new Thread(() => { try { vigemTestClient = new ViGEmClient(); } catch { } });
tempThread.Priority = ThreadPriority.AboveNormal;
tempThread.IsBackground = true;
tempThread.Start();
@@ -371,11 +373,18 @@ namespace DS4Windows
private void stopViGEm()
{
- if (vigemTestClient != null)
+ if (x360Bus != null)
{
- vigemTestClient.Dispose();
- vigemTestClient = null;
+ x360Bus.UnplugAll();
+ x360Bus.Stop();
+ x360Bus = null;
}
+
+ //if (vigemTestClient != null)
+ //{
+ // vigemTestClient.Dispose();
+ // vigemTestClient = null;
+ //}
}
public void PluginOutDev(int index, DS4Device device)
@@ -389,94 +398,98 @@ namespace DS4Windows
activeOutDevType[index] = OutContType.X360;
//Xbox360OutDevice tempXbox = new Xbox360OutDevice(vigemTestClient);
- Xbox360OutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, vigemTestClient)
- as Xbox360OutDevice;
+ Xbox360ScpOutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, x360Bus, index)
+ as Xbox360ScpOutDevice;
//outputDevices[index] = tempXbox;
int devIndex = index;
- Nefarius.ViGEm.Client.Targets.Xbox360FeedbackReceivedEventHandler p = (sender, args) =>
- {
- SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
- };
- tempXbox.cont.FeedbackReceived += p;
- tempXbox.forceFeedbackCall = p;
+ tempXbox.FeedbackReceived += (sender, small, large, slotIdx) =>
+ {
+ SetDevRumble(device, large, small, devIndex);
+ };
+ //Nefarius.ViGEm.Client.Targets.Xbox360FeedbackReceivedEventHandler p = (sender, args) =>
+ // {
+ // SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
+ // };
+ //tempXbox.cont.FeedbackReceived += p;
+ //tempXbox.forceFeedbackCall = p;
outputslotMan.DeferredPlugin(tempXbox, index, outputDevices);
//tempXbox.Connect();
//LogDebug("X360 Controller #" + (index + 1) + " connected");
}
- else if (contType == OutContType.DS4)
- {
- 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;
- int devIndex = index;
- Nefarius.ViGEm.Client.Targets.DualShock4FeedbackReceivedEventHandler p = (sender, args) =>
- {
- //bool useRumble = false; bool useLight = false;
- byte largeMotor = args.LargeMotor;
- byte smallMotor = args.SmallMotor;
- SetDevRumble(device, largeMotor, smallMotor, devIndex);
- //DS4Color color = new DS4Color(args.LightbarColor.Red,
- // args.LightbarColor.Green,
- // args.LightbarColor.Blue);
- ///*Console.WriteLine("IN EVENT");
- //Console.WriteLine("Rumble ({0}, {1}) | Light ({2}, {3}, {4}) {5}",
- // largeMotor, smallMotor, color.red, color.green, color.blue, DateTime.Now.ToLongTimeString());
- // */
- //if (largeMotor != 0 || smallMotor != 0)
- //{
- // useRumble = true;
- //}
+ //else if (contType == OutContType.DS4)
+ //{
+ // 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;
+ // int devIndex = index;
+ // //Nefarius.ViGEm.Client.Targets.DualShock4FeedbackReceivedEventHandler p = (sender, args) =>
+ // // {
+ // // //bool useRumble = false; bool useLight = false;
+ // // byte largeMotor = args.LargeMotor;
+ // // byte smallMotor = args.SmallMotor;
+ // // SetDevRumble(device, largeMotor, smallMotor, devIndex);
+ // // //DS4Color color = new DS4Color(args.LightbarColor.Red,
+ // // // args.LightbarColor.Green,
+ // // // args.LightbarColor.Blue);
+ // // ///*Console.WriteLine("IN EVENT");
+ // // //Console.WriteLine("Rumble ({0}, {1}) | Light ({2}, {3}, {4}) {5}",
+ // // // largeMotor, smallMotor, color.red, color.green, color.blue, DateTime.Now.ToLongTimeString());
+ // // // */
+ // // //if (largeMotor != 0 || smallMotor != 0)
+ // // //{
+ // // // useRumble = true;
+ // // //}
- //if (color.red != 0 || color.green != 0 || color.blue != 0)
- //{
- // useLight = true;
- //}
+ // // //if (color.red != 0 || color.green != 0 || color.blue != 0)
+ // // //{
+ // // // useLight = true;
+ // // //}
- //if (!useRumble && !useLight)
- //{
- // //Console.WriteLine("Fallback");
- // if (device.LeftHeavySlowRumble != 0 || device.RightLightFastRumble != 0)
- // {
- // useRumble = true;
- // }
- // /*else if (device.LightBarColor.red != 0 ||
- // device.LightBarColor.green != 0 ||
- // device.LightBarColor.blue != 0)
- // {
- // useLight = true;
- // }
- // */
- //}
+ // // //if (!useRumble && !useLight)
+ // // //{
+ // // // //Console.WriteLine("Fallback");
+ // // // if (device.LeftHeavySlowRumble != 0 || device.RightLightFastRumble != 0)
+ // // // {
+ // // // useRumble = true;
+ // // // }
+ // // // /*else if (device.LightBarColor.red != 0 ||
+ // // // device.LightBarColor.green != 0 ||
+ // // // device.LightBarColor.blue != 0)
+ // // // {
+ // // // useLight = true;
+ // // // }
+ // // // */
+ // // //}
- //if (useRumble)
- //{
- // //Console.WriteLine("Perform rumble");
- // SetDevRumble(device, largeMotor, smallMotor, devIndex);
- //}
+ // // //if (useRumble)
+ // // //{
+ // // // //Console.WriteLine("Perform rumble");
+ // // // SetDevRumble(device, largeMotor, smallMotor, devIndex);
+ // // //}
- //if (useLight)
- //{
- // //Console.WriteLine("Change lightbar color");
- // DS4HapticState haptics = new DS4HapticState
- // {
- // LightBarColor = color,
- // };
- // device.SetHapticState(ref haptics);
- //}
+ // // //if (useLight)
+ // // //{
+ // // // //Console.WriteLine("Change lightbar color");
+ // // // DS4HapticState haptics = new DS4HapticState
+ // // // {
+ // // // LightBarColor = color,
+ // // // };
+ // // // device.SetHapticState(ref haptics);
+ // // //}
- //Console.WriteLine();
- };
- tempDS4.cont.FeedbackReceived += p;
- tempDS4.forceFeedbackCall = p;
+ // // //Console.WriteLine();
+ // //};
+ // //tempDS4.cont.FeedbackReceived += p;
+ // //tempDS4.forceFeedbackCall = p;
- outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
- //tempDS4.Connect();
- //LogDebug("DS4 Controller #" + (index + 1) + " connected");
- }
+ // outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
+ // //tempDS4.Connect();
+ // //LogDebug("DS4 Controller #" + (index + 1) + " connected");
+ //}
}
useDInputOnly[index] = false;
@@ -506,8 +519,8 @@ namespace DS4Windows
public bool Start(bool showlog = true)
{
startViGEm();
- if (vigemTestClient != null)
- //if (x360Bus.Open() && x360Bus.Start())
+ //if (vigemTestClient != null)
+ if (x360Bus.Open() && x360Bus.Start())
{
if (showlog)
LogDebug(DS4WinWPF.Properties.Resources.Starting);
diff --git a/DS4Windows/DS4Control/OutputSlotManager.cs b/DS4Windows/DS4Control/OutputSlotManager.cs
index 429a143..d630c45 100644
--- a/DS4Windows/DS4Control/OutputSlotManager.cs
+++ b/DS4Windows/DS4Control/OutputSlotManager.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using Nefarius.ViGEm.Client;
+//using Nefarius.ViGEm.Client;
namespace DS4Windows
{
@@ -20,16 +20,32 @@ namespace DS4Windows
public bool RunningQueue { get => runningQueue; }
- public OutputDevice AllocateController(OutContType contType, ViGEmClient client)
+ //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;
+ //}
+
+ public OutputDevice AllocateController(OutContType contType, X360BusDevice client, int idx)
{
OutputDevice outputDevice = null;
- switch(contType)
+ switch (contType)
{
case OutContType.X360:
- outputDevice = new Xbox360OutDevice(client);
- break;
- case OutContType.DS4:
- outputDevice = new DS4OutDevice(client);
+ outputDevice = new Xbox360ScpOutDevice(client, idx);
break;
case OutContType.None:
default:
diff --git a/DS4Windows/DS4Control/ScpDevice.cs b/DS4Windows/DS4Control/ScpDevice.cs
new file mode 100644
index 0000000..19eabfa
--- /dev/null
+++ b/DS4Windows/DS4Control/ScpDevice.cs
@@ -0,0 +1,693 @@
+using System;
+using System.Collections.Generic;
+
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Win32.SafeHandles;
+
+namespace DS4Windows
+{
+ [SuppressUnmanagedCodeSecurity]
+ public class ScpDevice
+ {
+ public virtual Boolean IsActive
+ {
+ get { return m_IsActive; }
+ }
+
+ public virtual String Path
+ {
+ get { return m_Path; }
+ }
+
+ public ScpDevice(String Class)
+ {
+ this.m_Class = new Guid(Class);
+ }
+
+
+ public virtual Boolean Open(Int32 Instance = 0)
+ {
+ String DevicePath = String.Empty;
+ m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE;
+
+ if (Find(m_Class, ref DevicePath, Instance))
+ {
+ Open(DevicePath);
+ }
+
+ return m_IsActive;
+ }
+
+ public virtual Boolean Open(String DevicePath)
+ {
+ m_Path = DevicePath.ToUpper();
+ m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE;
+
+ if (GetDeviceHandle(m_Path))
+ {
+ if (WinUsb_Initialize(m_FileHandle, ref m_WinUsbHandle))
+ {
+ if (InitializeDevice())
+ {
+ m_IsActive = true;
+ }
+ else
+ {
+ WinUsb_Free(m_WinUsbHandle);
+ m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE;
+ }
+ }
+ else
+ {
+ m_FileHandle.Close();
+ }
+ }
+
+ return m_IsActive;
+ }
+
+ public virtual Boolean Start()
+ {
+ return m_IsActive;
+ }
+
+ public virtual Boolean Stop()
+ {
+ m_IsActive = false;
+
+ if (!(m_WinUsbHandle == (IntPtr) INVALID_HANDLE_VALUE))
+ {
+ WinUsb_AbortPipe(m_WinUsbHandle, m_IntIn);
+ WinUsb_AbortPipe(m_WinUsbHandle, m_BulkIn);
+ WinUsb_AbortPipe(m_WinUsbHandle, m_BulkOut);
+
+ WinUsb_Free(m_WinUsbHandle);
+ m_WinUsbHandle = (IntPtr) INVALID_HANDLE_VALUE;
+ }
+
+ if (m_FileHandle != null && !m_FileHandle.IsInvalid && !m_FileHandle.IsClosed)
+ {
+ m_FileHandle.Close();
+ m_FileHandle = null;
+ }
+
+ return true;
+ }
+
+ public virtual Boolean Close()
+ {
+ return Stop();
+ }
+
+
+ public virtual Boolean ReadIntPipe (Byte[] Buffer, Int32 Length, ref Int32 Transfered)
+ {
+ if (!m_IsActive) return false;
+
+ return WinUsb_ReadPipe(m_WinUsbHandle, m_IntIn, Buffer, Length, ref Transfered, IntPtr.Zero);
+ }
+
+ public virtual Boolean ReadBulkPipe (Byte[] Buffer, Int32 Length, ref Int32 Transfered)
+ {
+ if (!m_IsActive) return false;
+
+ return WinUsb_ReadPipe(m_WinUsbHandle, m_BulkIn, Buffer, Length, ref Transfered, IntPtr.Zero);
+ }
+
+ public virtual Boolean WriteIntPipe (Byte[] Buffer, Int32 Length, ref Int32 Transfered)
+ {
+ if (!m_IsActive) return false;
+
+ return WinUsb_WritePipe(m_WinUsbHandle, m_IntOut, Buffer, Length, ref Transfered, IntPtr.Zero);
+ }
+
+ public virtual Boolean WriteBulkPipe(Byte[] Buffer, Int32 Length, ref Int32 Transfered)
+ {
+ if (!m_IsActive) return false;
+
+ return WinUsb_WritePipe(m_WinUsbHandle, m_BulkOut, Buffer, Length, ref Transfered, IntPtr.Zero);
+ }
+
+
+ public virtual Boolean SendTransfer(Byte RequestType, Byte Request, UInt16 Value, Byte[] Buffer, ref Int32 Transfered)
+ {
+ if (!m_IsActive) return false;
+
+ WINUSB_SETUP_PACKET Setup = new WINUSB_SETUP_PACKET();
+
+ Setup.RequestType = RequestType;
+ Setup.Request = Request;
+ Setup.Value = Value;
+ Setup.Index = 0;
+ Setup.Length = (UInt16) Buffer.Length;
+
+ return WinUsb_ControlTransfer(m_WinUsbHandle, Setup, Buffer, Buffer.Length, ref Transfered, IntPtr.Zero);
+ }
+
+
+ #region Constant and Structure Definitions
+ public const Int32 SERVICE_CONTROL_STOP = 0x00000001;
+ public const Int32 SERVICE_CONTROL_SHUTDOWN = 0x00000005;
+ public const Int32 SERVICE_CONTROL_DEVICEEVENT = 0x0000000B;
+ public const Int32 SERVICE_CONTROL_POWEREVENT = 0x0000000D;
+
+ public const Int32 DBT_DEVICEARRIVAL = 0x8000;
+ public const Int32 DBT_DEVICEQUERYREMOVE = 0x8001;
+ public const Int32 DBT_DEVICEREMOVECOMPLETE = 0x8004;
+ public const Int32 DBT_DEVTYP_DEVICEINTERFACE = 0x0005;
+ public const Int32 DBT_DEVTYP_HANDLE = 0x0006;
+
+ public const Int32 PBT_APMRESUMEAUTOMATIC = 0x0012;
+ public const Int32 PBT_APMSUSPEND = 0x0004;
+
+ public const Int32 DEVICE_NOTIFY_WINDOW_HANDLE = 0x0000;
+ public const Int32 DEVICE_NOTIFY_SERVICE_HANDLE = 0x0001;
+ public const Int32 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = 0x0004;
+
+ public const Int32 WM_CREATE = 0x0001;
+ public const Int32 WM_DEVICECHANGE = 0x0219;
+
+ public const Int32 DIGCF_PRESENT = 0x0002;
+ public const Int32 DIGCF_DEVICEINTERFACE = 0x0010;
+
+ public delegate Int32 ServiceControlHandlerEx(Int32 Control, Int32 Type, IntPtr Data, IntPtr Context);
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class DEV_BROADCAST_DEVICEINTERFACE
+ {
+ internal Int32 dbcc_size;
+ internal Int32 dbcc_devicetype;
+ internal Int32 dbcc_reserved;
+ internal Guid dbcc_classguid;
+ internal Int16 dbcc_name;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public class DEV_BROADCAST_DEVICEINTERFACE_M
+ {
+ public Int32 dbcc_size;
+ public Int32 dbcc_devicetype;
+ public Int32 dbcc_reserved;
+
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 16)]
+ public Byte[] dbcc_classguid;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
+ public Char[] dbcc_name;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class DEV_BROADCAST_HDR
+ {
+ public Int32 dbch_size;
+ public Int32 dbch_devicetype;
+ public Int32 dbch_reserved;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct SP_DEVICE_INTERFACE_DATA
+ {
+ internal Int32 cbSize;
+ internal Guid InterfaceClassGuid;
+ internal Int32 Flags;
+ internal IntPtr Reserved;
+ }
+
+ protected const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80;
+ protected const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;
+ protected const UInt32 FILE_SHARE_READ = 1;
+ protected const UInt32 FILE_SHARE_WRITE = 2;
+ protected const UInt32 GENERIC_READ = 0x80000000;
+ protected const UInt32 GENERIC_WRITE = 0x40000000;
+ protected const Int32 INVALID_HANDLE_VALUE = -1;
+ protected const UInt32 OPEN_EXISTING = 3;
+ protected const UInt32 DEVICE_SPEED = 1;
+ protected const Byte USB_ENDPOINT_DIRECTION_MASK = 0x80;
+
+ protected enum POLICY_TYPE
+ {
+ SHORT_PACKET_TERMINATE = 1,
+ AUTO_CLEAR_STALL = 2,
+ PIPE_TRANSFER_TIMEOUT = 3,
+ IGNORE_SHORT_PACKETS = 4,
+ ALLOW_PARTIAL_READS = 5,
+ AUTO_FLUSH = 6,
+ RAW_IO = 7,
+ }
+
+ protected enum USBD_PIPE_TYPE
+ {
+ UsbdPipeTypeControl = 0,
+ UsbdPipeTypeIsochronous = 1,
+ UsbdPipeTypeBulk = 2,
+ UsbdPipeTypeInterrupt = 3,
+ }
+
+ protected enum USB_DEVICE_SPEED
+ {
+ UsbLowSpeed = 1,
+ UsbFullSpeed = 2,
+ UsbHighSpeed = 3,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct USB_CONFIGURATION_DESCRIPTOR
+ {
+ internal Byte bLength;
+ internal Byte bDescriptorType;
+ internal UInt16 wTotalLength;
+ internal Byte bNumInterfaces;
+ internal Byte bConfigurationValue;
+ internal Byte iConfiguration;
+ internal Byte bmAttributes;
+ internal Byte MaxPower;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct USB_INTERFACE_DESCRIPTOR
+ {
+ internal Byte bLength;
+ internal Byte bDescriptorType;
+ internal Byte bInterfaceNumber;
+ internal Byte bAlternateSetting;
+ internal Byte bNumEndpoints;
+ internal Byte bInterfaceClass;
+ internal Byte bInterfaceSubClass;
+ internal Byte bInterfaceProtocol;
+ internal Byte iInterface;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct WINUSB_PIPE_INFORMATION
+ {
+ internal USBD_PIPE_TYPE PipeType;
+ internal Byte PipeId;
+ internal UInt16 MaximumPacketSize;
+ internal Byte Interval;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ protected struct WINUSB_SETUP_PACKET
+ {
+ internal Byte RequestType;
+ internal Byte Request;
+ internal UInt16 Value;
+ internal UInt16 Index;
+ internal UInt16 Length;
+ }
+
+ protected const Int32 DIF_PROPERTYCHANGE = 0x12;
+ protected const Int32 DICS_ENABLE = 1;
+ protected const Int32 DICS_DISABLE = 2;
+ protected const Int32 DICS_PROPCHANGE = 3;
+ protected const Int32 DICS_FLAG_GLOBAL = 1;
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct SP_CLASSINSTALL_HEADER
+ {
+ internal Int32 cbSize;
+ internal Int32 InstallFunction;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ protected struct SP_PROPCHANGE_PARAMS
+ {
+ internal SP_CLASSINSTALL_HEADER ClassInstallHeader;
+ internal Int32 StateChange;
+ internal Int32 Scope;
+ internal Int32 HwProfile;
+ }
+ #endregion
+
+ #region Protected Data Members
+ protected Guid m_Class = Guid.Empty;
+ protected String m_Path = String.Empty;
+
+ protected SafeFileHandle m_FileHandle = null;
+ protected IntPtr m_WinUsbHandle = IntPtr.Zero;
+
+ protected Byte m_IntIn = 0xFF;
+ protected Byte m_IntOut = 0xFF;
+ protected Byte m_BulkIn = 0xFF;
+ protected Byte m_BulkOut = 0xFF;
+
+ protected Boolean m_IsActive = false;
+ #endregion
+
+ #region Static Helper Methods
+ public enum Notified { Ignore = 0x0000, Arrival = 0x8000, QueryRemove = 0x8001, Removal = 0x8004 };
+
+ public static Boolean RegisterNotify(IntPtr Form, Guid Class, ref IntPtr Handle, Boolean Window = true)
+ {
+ IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero;
+
+ try
+ {
+ DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE();
+ Int32 Size = Marshal.SizeOf(devBroadcastDeviceInterface);
+
+ devBroadcastDeviceInterface.dbcc_size = Size;
+ devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+ devBroadcastDeviceInterface.dbcc_reserved = 0;
+ devBroadcastDeviceInterface.dbcc_classguid = Class;
+
+ devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(Size);
+ Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true);
+
+ Handle = RegisterDeviceNotification(Form, devBroadcastDeviceInterfaceBuffer, Window ? DEVICE_NOTIFY_WINDOW_HANDLE : DEVICE_NOTIFY_SERVICE_HANDLE);
+
+ Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface);
+
+ return Handle != IntPtr.Zero;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message);
+ throw;
+ }
+ finally
+ {
+ if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero)
+ {
+ Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer);
+ }
+ }
+ }
+
+ public static Boolean UnregisterNotify(IntPtr Handle)
+ {
+ try
+ {
+ return UnregisterDeviceNotification(Handle);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message);
+ throw;
+ }
+ }
+ #endregion
+
+ #region Protected Methods
+ protected virtual Boolean Find(Guid Target, ref String Path, Int32 Instance = 0)
+ {
+ IntPtr detailDataBuffer = IntPtr.Zero;
+ IntPtr deviceInfoSet = IntPtr.Zero;
+
+ try
+ {
+ SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(), da = new SP_DEVICE_INTERFACE_DATA();
+ Int32 bufferSize = 0, memberIndex = 0;
+
+ deviceInfoSet = SetupDiGetClassDevs(ref Target, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ DeviceInterfaceData.cbSize = da.cbSize = Marshal.SizeOf(DeviceInterfaceData);
+
+ while (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref Target, memberIndex, ref DeviceInterfaceData))
+ {
+ SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, ref da);
+ {
+ detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
+
+ Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
+
+ if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, ref da))
+ {
+ IntPtr pDevicePathName = new IntPtr(IntPtr.Size == 4 ? detailDataBuffer.ToInt32() + 4: detailDataBuffer.ToInt64() + 4);
+
+ Path = Marshal.PtrToStringAuto(pDevicePathName).ToUpper();
+ Marshal.FreeHGlobal(detailDataBuffer);
+
+ if (memberIndex == Instance) return true;
+ }
+ else Marshal.FreeHGlobal(detailDataBuffer);
+ }
+
+ memberIndex++;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message);
+ throw;
+ }
+ finally
+ {
+ if (deviceInfoSet != IntPtr.Zero)
+ {
+ SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ }
+ }
+
+ return false;
+ }
+
+ protected virtual Boolean GetDeviceInstance(ref String Instance)
+ {
+ IntPtr detailDataBuffer = IntPtr.Zero;
+ IntPtr deviceInfoSet = IntPtr.Zero;
+
+ try
+ {
+ SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(), da = new SP_DEVICE_INTERFACE_DATA();
+ Int32 bufferSize = 0, memberIndex = 0;
+
+ deviceInfoSet = SetupDiGetClassDevs(ref m_Class, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ DeviceInterfaceData.cbSize = da.cbSize = Marshal.SizeOf(DeviceInterfaceData);
+
+ while (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref m_Class, memberIndex, ref DeviceInterfaceData))
+ {
+ SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, ref da);
+ {
+ detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
+
+ Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8);
+
+ if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref DeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, ref da))
+ {
+ IntPtr pDevicePathName = new IntPtr(IntPtr.Size == 4 ? detailDataBuffer.ToInt32() + 4 : detailDataBuffer.ToInt64() + 4);
+
+ String Current = Marshal.PtrToStringAuto(pDevicePathName).ToUpper();
+ Marshal.FreeHGlobal(detailDataBuffer);
+
+ if (Current == Path)
+ {
+ Int32 nBytes = 256;
+ IntPtr ptrInstanceBuf = Marshal.AllocHGlobal(nBytes);
+
+ CM_Get_Device_ID(da.Flags, ptrInstanceBuf, nBytes, 0);
+ Instance = Marshal.PtrToStringAuto(ptrInstanceBuf).ToUpper();
+
+ Marshal.FreeHGlobal(ptrInstanceBuf);
+ return true;
+ }
+ }
+ else Marshal.FreeHGlobal(detailDataBuffer);
+ }
+
+ memberIndex++;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message);
+ throw;
+ }
+ finally
+ {
+ if (deviceInfoSet != IntPtr.Zero)
+ {
+ SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ }
+ }
+
+ return false;
+ }
+
+ protected virtual Boolean GetDeviceHandle(String Path)
+ {
+ m_FileHandle = CreateFile(Path, (GENERIC_WRITE | GENERIC_READ), FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | 0x20000000 | 0x80000000, 0);
+
+ return !m_FileHandle.IsInvalid;
+ }
+
+ protected virtual Boolean UsbEndpointDirectionIn(Int32 addr)
+ {
+ return (addr & 0x80) == 0x80;
+ }
+
+ protected virtual Boolean UsbEndpointDirectionOut(Int32 addr)
+ {
+ return (addr & 0x80) == 0x00;
+ }
+
+ protected virtual Boolean InitializeDevice()
+ {
+ try
+ {
+ USB_INTERFACE_DESCRIPTOR ifaceDescriptor = new USB_INTERFACE_DESCRIPTOR();
+ WINUSB_PIPE_INFORMATION pipeInfo = new WINUSB_PIPE_INFORMATION();
+
+ if (WinUsb_QueryInterfaceSettings(m_WinUsbHandle, 0, ref ifaceDescriptor))
+ {
+ for (Int32 i = 0; i < ifaceDescriptor.bNumEndpoints; i++)
+ {
+ WinUsb_QueryPipe(m_WinUsbHandle, 0, System.Convert.ToByte(i), ref pipeInfo);
+
+ if (((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeBulk) & UsbEndpointDirectionIn(pipeInfo.PipeId)))
+ {
+ m_BulkIn = pipeInfo.PipeId;
+ WinUsb_FlushPipe(m_WinUsbHandle, m_BulkIn);
+ }
+ else if (((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeBulk) & UsbEndpointDirectionOut(pipeInfo.PipeId)))
+ {
+ m_BulkOut = pipeInfo.PipeId;
+ WinUsb_FlushPipe(m_WinUsbHandle, m_BulkOut);
+ }
+ else if ((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) & UsbEndpointDirectionIn(pipeInfo.PipeId))
+ {
+ m_IntIn = pipeInfo.PipeId;
+ WinUsb_FlushPipe(m_WinUsbHandle, m_IntIn);
+ }
+ else if ((pipeInfo.PipeType == USBD_PIPE_TYPE.UsbdPipeTypeInterrupt) & UsbEndpointDirectionOut(pipeInfo.PipeId))
+ {
+ m_IntOut = pipeInfo.PipeId;
+ WinUsb_FlushPipe(m_WinUsbHandle, m_IntOut);
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message);
+ throw;
+ }
+ }
+
+ protected virtual Boolean RestartDevice(String InstanceId)
+ {
+ IntPtr deviceInfoSet = IntPtr.Zero;
+
+ try
+ {
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA();
+
+ deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData);
+ deviceInfoSet = SetupDiGetClassDevs(ref m_Class, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ if (SetupDiOpenDeviceInfo(deviceInfoSet, InstanceId, IntPtr.Zero, 0, ref deviceInterfaceData))
+ {
+ SP_PROPCHANGE_PARAMS props = new SP_PROPCHANGE_PARAMS();
+
+ props.ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
+ props.ClassInstallHeader.cbSize = Marshal.SizeOf(props.ClassInstallHeader);
+ props.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+
+ props.Scope = DICS_FLAG_GLOBAL;
+ props.StateChange = DICS_PROPCHANGE;
+ props.HwProfile = 0x00;
+
+ if (SetupDiSetClassInstallParams(deviceInfoSet, ref deviceInterfaceData, ref props, Marshal.SizeOf(props)))
+ {
+ return SetupDiChangeState(deviceInfoSet, ref deviceInterfaceData);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0} {1}", ex.HelpLink, ex.Message);
+ throw;
+ }
+ finally
+ {
+ if (deviceInfoSet != IntPtr.Zero)
+ {
+ SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ }
+ }
+
+ return false;
+ }
+ #endregion
+
+ #region Interop Definitions
+ [DllImport("setupapi.dll", SetLastError = true)]
+ protected static extern Int32 SetupDiCreateDeviceInfoList(ref System.Guid ClassGuid, Int32 hwndParent);
+
+ [DllImport("setupapi.dll", SetLastError = true)]
+ protected static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
+
+ [DllImport("setupapi.dll", SetLastError = true)]
+ protected static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, ref SP_DEVICE_INTERFACE_DATA DeviceInfoData);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ protected static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, Int32 Flags);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ protected static extern Boolean UnregisterDeviceNotification(IntPtr Handle);
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, UInt32 hTemplateFile);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_Initialize(SafeFileHandle DeviceHandle, ref IntPtr InterfaceHandle);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_QueryInterfaceSettings(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, ref USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_QueryPipe(IntPtr InterfaceHandle, Byte AlternateInterfaceNumber, Byte PipeIndex, ref WINUSB_PIPE_INFORMATION PipeInformation);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_AbortPipe(IntPtr InterfaceHandle, Byte PipeID);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_FlushPipe(IntPtr InterfaceHandle, Byte PipeID);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_ReadPipe(IntPtr InterfaceHandle, Byte PipeID, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_WritePipe(IntPtr InterfaceHandle, Byte PipeID, Byte[] Buffer, Int32 BufferLength, ref Int32 LengthTransferred, IntPtr Overlapped);
+
+ [DllImport("winusb.dll", SetLastError = true)]
+ protected static extern Boolean WinUsb_Free(IntPtr InterfaceHandle);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ public static extern IntPtr RegisterServiceCtrlHandlerEx(String ServiceName, ServiceControlHandlerEx Callback, IntPtr Context);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ protected static extern Boolean DeviceIoControl(SafeFileHandle DeviceHandle, Int32 IoControlCode, Byte[] InBuffer, Int32 InBufferSize, Byte[] OutBuffer, Int32 OutBufferSize, ref Int32 BytesReturned, IntPtr Overlapped);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern Int32 CM_Get_Device_ID(Int32 dnDevInst, IntPtr Buffer, Int32 BufferLen, Int32 ulFlags);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern Boolean SetupDiOpenDeviceInfo(IntPtr DeviceInfoSet, String DeviceInstanceId, IntPtr hwndParent, Int32 Flags, ref SP_DEVICE_INTERFACE_DATA DeviceInfoData);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern Boolean SetupDiChangeState(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ protected static extern Boolean SetupDiSetClassInstallParams(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, ref SP_PROPCHANGE_PARAMS ClassInstallParams, Int32 ClassInstallParamsSize);
+ #endregion
+ }
+}
diff --git a/DS4Windows/DS4Control/X360BusDevice.cs b/DS4Windows/DS4Control/X360BusDevice.cs
new file mode 100644
index 0000000..ebc3f49
--- /dev/null
+++ b/DS4Windows/DS4Control/X360BusDevice.cs
@@ -0,0 +1,294 @@
+using System;
+using System.Collections.Generic;
+
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Win32.SafeHandles;
+
+namespace DS4Windows
+{
+ [SuppressUnmanagedCodeSecurity]
+ public class X360BusDevice : ScpDevice
+ {
+ private const String DS3_BUS_CLASS_GUID = "{F679F562-3164-42CE-A4DB-E7DDBE723909}";
+ private const int CONTROLLER_OFFSET = 1; // Device 0 is the virtual USB hub itself, and we leave devices 1-10 available for other software (like the Scarlet.Crush DualShock driver itself)
+ private const int inputResolution = 127 - (-128);
+ private const float reciprocalInputResolution = 1 / (float)inputResolution;
+ private const int outputResolution = 32767 - (-32768);
+
+ private int firstController = 1;
+ // Device 0 is the virtual USB hub itself, and we can leave more available for other software (like the Scarlet.Crush DualShock driver)
+ public int FirstController
+ {
+ get { return firstController; }
+ set { firstController = value > 0 ? value : 1; }
+ }
+
+ protected Int32 Scale(Int32 Value, Boolean Flip)
+ {
+ unchecked
+ {
+ Value -= 0x80;
+
+ //float temp = (Value - (-128)) / (float)inputResolution;
+ float temp = (Value - (-128)) * reciprocalInputResolution;
+ if (Flip) temp = (temp - 0.5f) * -1.0f + 0.5f;
+
+ return (Int32)(temp * outputResolution + (-32768));
+ }
+ }
+
+
+ public X360BusDevice()
+ : base(DS3_BUS_CLASS_GUID)
+ {
+ }
+
+ /* public override Boolean Open(int Instance = 0)
+ {
+ if (base.Open(Instance))
+ {
+ }
+
+ return true;
+ } */
+
+ public override Boolean Open(String DevicePath)
+ {
+ m_Path = DevicePath;
+ m_WinUsbHandle = (IntPtr)INVALID_HANDLE_VALUE;
+
+ if (GetDeviceHandle(m_Path))
+ {
+ m_IsActive = true;
+ }
+
+ return true;
+ }
+
+ public override Boolean Start()
+ {
+ if (IsActive)
+ {
+ }
+
+ return true;
+ }
+
+ public override Boolean Stop()
+ {
+ if (IsActive)
+ {
+ //Unplug(0);
+ }
+
+ return base.Stop();
+ }
+
+ public override Boolean Close()
+ {
+ if (IsActive)
+ {
+ Unplug(0);
+ }
+
+ return base.Close();
+ }
+
+
+ public void Parse(DS4State state, Byte[] Output, int device)
+ {
+ Output[0] = 0x1C;
+ Output[4] = (Byte)(device + firstController);
+ Output[9] = 0x14;
+
+ for (int i = 10; i < 28; i++)
+ {
+ Output[i] = 0;
+ }
+
+ unchecked
+ {
+ if (state.Share) Output[10] |= (Byte)(1 << 5); // Back
+ if (state.L3) Output[10] |= (Byte)(1 << 6); // Left Thumb
+ if (state.R3) Output[10] |= (Byte)(1 << 7); // Right Thumb
+ if (state.Options) Output[10] |= (Byte)(1 << 4); // Start
+
+ if (state.DpadUp) Output[10] |= (Byte)(1 << 0); // Up
+ if (state.DpadRight) Output[10] |= (Byte)(1 << 3); // Down
+ if (state.DpadDown) Output[10] |= (Byte)(1 << 1); // Right
+ if (state.DpadLeft) Output[10] |= (Byte)(1 << 2); // Left
+
+ if (state.L1) Output[11] |= (Byte)(1 << 0); // Left Shoulder
+ if (state.R1) Output[11] |= (Byte)(1 << 1); // Right Shoulder
+
+ if (state.Triangle) Output[11] |= (Byte)(1 << 7); // Y
+ if (state.Circle) Output[11] |= (Byte)(1 << 5); // B
+ if (state.Cross) Output[11] |= (Byte)(1 << 4); // A
+ if (state.Square) Output[11] |= (Byte)(1 << 6); // X
+
+ if (state.PS) Output[11] |= (Byte)(1 << 2); // Guide
+
+ SASteeringWheelEmulationAxisType steeringWheelMappedAxis = Global.GetSASteeringWheelEmulationAxis(device);
+ Int32 ThumbLX;
+ Int32 ThumbLY;
+ Int32 ThumbRX;
+ Int32 ThumbRY;
+
+ Output[12] = state.L2; // Left Trigger
+ Output[13] = state.R2; // Right Trigger
+
+ switch(steeringWheelMappedAxis)
+ {
+ case SASteeringWheelEmulationAxisType.None:
+ ThumbLX = Scale(state.LX, false);
+ ThumbLY = Scale(state.LY, true);
+ ThumbRX = Scale(state.RX, false);
+ ThumbRY = Scale(state.RY, true);
+ break;
+
+ case SASteeringWheelEmulationAxisType.LX:
+ ThumbLX = state.SASteeringWheelEmulationUnit;
+ ThumbLY = Scale(state.LY, true);
+ ThumbRX = Scale(state.RX, false);
+ ThumbRY = Scale(state.RY, true);
+ break;
+
+ case SASteeringWheelEmulationAxisType.LY:
+ ThumbLX = Scale(state.LX, false);
+ ThumbLY = state.SASteeringWheelEmulationUnit;
+ ThumbRX = Scale(state.RX, false);
+ ThumbRY = Scale(state.RY, true);
+ break;
+
+ case SASteeringWheelEmulationAxisType.RX:
+ ThumbLX = Scale(state.LX, false);
+ ThumbLY = Scale(state.LY, true);
+ ThumbRX = state.SASteeringWheelEmulationUnit;
+ ThumbRY = Scale(state.RY, true);
+ break;
+
+ case SASteeringWheelEmulationAxisType.RY:
+ ThumbLX = Scale(state.LX, false);
+ ThumbLY = Scale(state.LY, true);
+ ThumbRX = Scale(state.RX, false);
+ ThumbRY = state.SASteeringWheelEmulationUnit;
+ break;
+
+ case SASteeringWheelEmulationAxisType.L2R2:
+ Output[12] = Output[13] = 0;
+ if (state.SASteeringWheelEmulationUnit >= 0) Output[12] = (Byte)state.SASteeringWheelEmulationUnit;
+ else Output[13] = (Byte)state.SASteeringWheelEmulationUnit;
+ goto case SASteeringWheelEmulationAxisType.None;
+
+ case SASteeringWheelEmulationAxisType.VJoy1X:
+ case SASteeringWheelEmulationAxisType.VJoy2X:
+ DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_X);
+ goto case SASteeringWheelEmulationAxisType.None;
+
+ case SASteeringWheelEmulationAxisType.VJoy1Y:
+ case SASteeringWheelEmulationAxisType.VJoy2Y:
+ DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_Y);
+ goto case SASteeringWheelEmulationAxisType.None;
+
+ case SASteeringWheelEmulationAxisType.VJoy1Z:
+ case SASteeringWheelEmulationAxisType.VJoy2Z:
+ DS4Windows.VJoyFeeder.vJoyFeeder.FeedAxisValue(state.SASteeringWheelEmulationUnit, ((((uint)steeringWheelMappedAxis) - ((uint)SASteeringWheelEmulationAxisType.VJoy1X)) / 3) + 1, DS4Windows.VJoyFeeder.HID_USAGES.HID_USAGE_Z);
+ goto case SASteeringWheelEmulationAxisType.None;
+
+ default:
+ // Should never come here but just in case use the NONE case as default handler....
+ goto case SASteeringWheelEmulationAxisType.None;
+ }
+
+ Output[14] = (Byte)((ThumbLX >> 0) & 0xFF); // LX
+ Output[15] = (Byte)((ThumbLX >> 8) & 0xFF);
+ Output[16] = (Byte)((ThumbLY >> 0) & 0xFF); // LY
+ Output[17] = (Byte)((ThumbLY >> 8) & 0xFF);
+ Output[18] = (Byte)((ThumbRX >> 0) & 0xFF); // RX
+ Output[19] = (Byte)((ThumbRX >> 8) & 0xFF);
+ Output[20] = (Byte)((ThumbRY >> 0) & 0xFF); // RY
+ Output[21] = (Byte)((ThumbRY >> 8) & 0xFF);
+ }
+ }
+
+ public Boolean Plugin(Int32 Serial)
+ {
+ if (IsActive)
+ {
+ Int32 Transfered = 0;
+ Byte[] Buffer = new Byte[16];
+
+ Buffer[0] = 0x10;
+ Buffer[1] = 0x00;
+ Buffer[2] = 0x00;
+ Buffer[3] = 0x00;
+
+ Serial += firstController;
+ Buffer[4] = (Byte)((Serial >> 0) & 0xFF);
+ Buffer[5] = (Byte)((Serial >> 8) & 0xFF);
+ Buffer[6] = (Byte)((Serial >> 16) & 0xFF);
+ Buffer[7] = (Byte)((Serial >> 24) & 0xFF);
+
+ return DeviceIoControl(m_FileHandle, 0x2A4000, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero);
+ }
+
+ return false;
+ }
+
+ public Boolean Unplug(Int32 Serial)
+ {
+ if (IsActive)
+ {
+ Int32 Transfered = 0;
+ Byte[] Buffer = new Byte[16];
+
+ Buffer[0] = 0x10;
+ Buffer[1] = 0x00;
+ Buffer[2] = 0x00;
+ Buffer[3] = 0x00;
+
+ Serial += firstController;
+ Buffer[4] = (Byte)((Serial >> 0) & 0xFF);
+ Buffer[5] = (Byte)((Serial >> 8) & 0xFF);
+ Buffer[6] = (Byte)((Serial >> 16) & 0xFF);
+ Buffer[7] = (Byte)((Serial >> 24) & 0xFF);
+
+ return DeviceIoControl(m_FileHandle, 0x2A4004, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero);
+ }
+
+ return false;
+ }
+
+ public Boolean UnplugAll() //not yet implemented, not sure if will
+ {
+ if (IsActive)
+ {
+ Int32 Transfered = 0;
+ Byte[] Buffer = new Byte[16];
+
+ Buffer[0] = 0x10;
+ Buffer[1] = 0x00;
+ Buffer[2] = 0x00;
+ Buffer[3] = 0x00;
+
+ return DeviceIoControl(m_FileHandle, 0x2A4004, Buffer, Buffer.Length, null, 0, ref Transfered, IntPtr.Zero);
+ }
+
+ return false;
+ }
+
+
+ public Boolean Report(Byte[] Input, Byte[] Output)
+ {
+ if (IsActive)
+ {
+ Int32 Transfered = 0;
+
+ return DeviceIoControl(m_FileHandle, 0x2A400C, Input, Input.Length, Output, Output.Length, ref Transfered, IntPtr.Zero) && Transfered > 0;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/DS4Windows/DS4Control/Xbox360ScpOutDevice.cs b/DS4Windows/DS4Control/Xbox360ScpOutDevice.cs
new file mode 100644
index 0000000..dfd59dd
--- /dev/null
+++ b/DS4Windows/DS4Control/Xbox360ScpOutDevice.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DS4Windows
+{
+ class Xbox360ScpOutDevice : OutputDevice
+ {
+ private const int inputResolution = 127 - (-128);
+ private const float reciprocalInputResolution = 1 / (float)inputResolution;
+ private const int outputResolution = 32767 - (-32768);
+ public const string devType = "X360";
+
+ private byte[] report = new byte[28];
+ private byte[] rumble = new byte[8];
+
+ private X360BusDevice x360Bus;
+ private int slotIdx = 0;
+
+ public delegate void Xbox360FeedbackReceivedEventHandler(Xbox360ScpOutDevice sender, byte large, byte small, int idx);
+ public event Xbox360FeedbackReceivedEventHandler FeedbackReceived;
+
+ public Xbox360ScpOutDevice(X360BusDevice client, int idx)
+ {
+ this.x360Bus = client;
+ slotIdx = idx;
+ }
+
+ public override void Connect()
+ {
+ x360Bus.Plugin(slotIdx);
+ }
+
+ public override void ConvertandSendReport(DS4State state, int device)
+ {
+ x360Bus.Parse(state, report, slotIdx);
+ if (x360Bus.Report(report, rumble))
+ {
+ byte Big = rumble[3];
+ byte Small = rumble[4];
+
+ if (rumble[1] == 0x08)
+ {
+ FeedbackReceived?.Invoke(this, Big, Small, slotIdx);
+ }
+ }
+ }
+
+ public override void Disconnect()
+ {
+ FeedbackReceived = null;
+ x360Bus.Unplug(slotIdx);
+ }
+
+ public override string GetDeviceType() => devType;
+ }
+}
diff --git a/DS4Windows/DS4WinWPF.csproj b/DS4Windows/DS4WinWPF.csproj
index ea1b1a0..ff21a65 100644
--- a/DS4Windows/DS4WinWPF.csproj
+++ b/DS4Windows/DS4WinWPF.csproj
@@ -106,12 +106,6 @@
..\packages\TaskScheduler.2.8.17\lib\net452\Microsoft.Win32.TaskScheduler.dll
False
-
- .\libs\x64\Nefarius.ViGEm.Client\Nefarius.ViGEm.Client.dll
-
-
- .\libs\x86\Nefarius.ViGEm.Client\Nefarius.ViGEm.Client.dll
-
..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
False
@@ -172,7 +166,6 @@
-
@@ -185,10 +178,12 @@
+
-
+
+
About.xaml