Use ScpVBus for X360 emulation rather than ViGEmBus

Test branch
This commit is contained in:
Travis Nickles 2020-04-15 16:25:54 -05:00
parent 31aa0a1aac
commit 19344c40b0
6 changed files with 1168 additions and 98 deletions

View File

@ -5,13 +5,14 @@ using System.Threading.Tasks;
using System.Threading; using System.Threading;
using System.Diagnostics; using System.Diagnostics;
using static DS4Windows.Global; using static DS4Windows.Global;
using Nefarius.ViGEm.Client; //using Nefarius.ViGEm.Client;
namespace DS4Windows namespace DS4Windows
{ {
public class ControlService public class ControlService
{ {
public ViGEmClient vigemTestClient = null; public X360BusDevice x360Bus = null;
//public ViGEmClient vigemTestClient = null;
public const int DS4_CONTROLLER_COUNT = 4; public const int DS4_CONTROLLER_COUNT = 4;
public DS4Device[] DS4Controllers = new DS4Device[DS4_CONTROLLER_COUNT]; public DS4Device[] DS4Controllers = new DS4Device[DS4_CONTROLLER_COUNT];
public Mouse[] touchPad = new Mouse[DS4_CONTROLLER_COUNT]; public Mouse[] touchPad = new Mouse[DS4_CONTROLLER_COUNT];
@ -357,7 +358,8 @@ namespace DS4Windows
private void startViGEm() 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.Priority = ThreadPriority.AboveNormal;
tempThread.IsBackground = true; tempThread.IsBackground = true;
tempThread.Start(); tempThread.Start();
@ -371,11 +373,18 @@ namespace DS4Windows
private void stopViGEm() private void stopViGEm()
{ {
if (vigemTestClient != null) if (x360Bus != null)
{ {
vigemTestClient.Dispose(); x360Bus.UnplugAll();
vigemTestClient = null; x360Bus.Stop();
x360Bus = null;
} }
//if (vigemTestClient != null)
//{
// vigemTestClient.Dispose();
// vigemTestClient = null;
//}
} }
public void PluginOutDev(int index, DS4Device device) public void PluginOutDev(int index, DS4Device device)
@ -389,94 +398,98 @@ namespace DS4Windows
activeOutDevType[index] = OutContType.X360; activeOutDevType[index] = OutContType.X360;
//Xbox360OutDevice tempXbox = new Xbox360OutDevice(vigemTestClient); //Xbox360OutDevice tempXbox = new Xbox360OutDevice(vigemTestClient);
Xbox360OutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, vigemTestClient) Xbox360ScpOutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, x360Bus, index)
as Xbox360OutDevice; as Xbox360ScpOutDevice;
//outputDevices[index] = tempXbox; //outputDevices[index] = tempXbox;
int devIndex = index; int devIndex = index;
Nefarius.ViGEm.Client.Targets.Xbox360FeedbackReceivedEventHandler p = (sender, args) => tempXbox.FeedbackReceived += (sender, small, large, slotIdx) =>
{ {
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex); SetDevRumble(device, large, small, devIndex);
}; };
tempXbox.cont.FeedbackReceived += p; //Nefarius.ViGEm.Client.Targets.Xbox360FeedbackReceivedEventHandler p = (sender, args) =>
tempXbox.forceFeedbackCall = p; // {
// SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
// };
//tempXbox.cont.FeedbackReceived += p;
//tempXbox.forceFeedbackCall = p;
outputslotMan.DeferredPlugin(tempXbox, index, outputDevices); outputslotMan.DeferredPlugin(tempXbox, index, outputDevices);
//tempXbox.Connect(); //tempXbox.Connect();
//LogDebug("X360 Controller #" + (index + 1) + " connected"); //LogDebug("X360 Controller #" + (index + 1) + " connected");
} }
else if (contType == OutContType.DS4) //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; // 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) // // //if (color.red != 0 || color.green != 0 || color.blue != 0)
//{ // // //{
// useLight = true; // // // useLight = true;
//} // // //}
//if (!useRumble && !useLight) // // //if (!useRumble && !useLight)
//{ // // //{
// //Console.WriteLine("Fallback"); // // // //Console.WriteLine("Fallback");
// if (device.LeftHeavySlowRumble != 0 || device.RightLightFastRumble != 0) // // // if (device.LeftHeavySlowRumble != 0 || device.RightLightFastRumble != 0)
// { // // // {
// useRumble = true; // // // useRumble = true;
// } // // // }
// /*else if (device.LightBarColor.red != 0 || // // // /*else if (device.LightBarColor.red != 0 ||
// device.LightBarColor.green != 0 || // // // device.LightBarColor.green != 0 ||
// device.LightBarColor.blue != 0) // // // device.LightBarColor.blue != 0)
// { // // // {
// useLight = true; // // // useLight = true;
// } // // // }
// */ // // // */
//} // // //}
//if (useRumble) // // //if (useRumble)
//{ // // //{
// //Console.WriteLine("Perform rumble"); // // // //Console.WriteLine("Perform rumble");
// SetDevRumble(device, largeMotor, smallMotor, devIndex); // // // SetDevRumble(device, largeMotor, smallMotor, devIndex);
// // //}
// // //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;
// outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
// //tempDS4.Connect();
// //LogDebug("DS4 Controller #" + (index + 1) + " connected");
//} //}
//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;
outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
//tempDS4.Connect();
//LogDebug("DS4 Controller #" + (index + 1) + " connected");
}
} }
useDInputOnly[index] = false; useDInputOnly[index] = false;
@ -506,8 +519,8 @@ namespace DS4Windows
public bool Start(bool showlog = true) public bool Start(bool showlog = true)
{ {
startViGEm(); startViGEm();
if (vigemTestClient != null) //if (vigemTestClient != null)
//if (x360Bus.Open() && x360Bus.Start()) if (x360Bus.Open() && x360Bus.Start())
{ {
if (showlog) if (showlog)
LogDebug(DS4WinWPF.Properties.Resources.Starting); LogDebug(DS4WinWPF.Properties.Resources.Starting);

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Nefarius.ViGEm.Client; //using Nefarius.ViGEm.Client;
namespace DS4Windows namespace DS4Windows
{ {
@ -20,16 +20,32 @@ namespace DS4Windows
public bool RunningQueue { get => runningQueue; } 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; OutputDevice outputDevice = null;
switch (contType) switch (contType)
{ {
case OutContType.X360: case OutContType.X360:
outputDevice = new Xbox360OutDevice(client); outputDevice = new Xbox360ScpOutDevice(client, idx);
break;
case OutContType.DS4:
outputDevice = new DS4OutDevice(client);
break; break;
case OutContType.None: case OutContType.None:
default: default:

View File

@ -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
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -106,12 +106,6 @@
<HintPath>..\packages\TaskScheduler.2.8.17\lib\net452\Microsoft.Win32.TaskScheduler.dll</HintPath> <HintPath>..\packages\TaskScheduler.2.8.17\lib\net452\Microsoft.Win32.TaskScheduler.dll</HintPath>
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
</Reference> </Reference>
<Reference Include="Nefarius.ViGEm.Client" Condition="'$(Platform)' == 'x64'&#xD;&#xA;">
<HintPath>.\libs\x64\Nefarius.ViGEm.Client\Nefarius.ViGEm.Client.dll</HintPath>
</Reference>
<Reference Include="Nefarius.ViGEm.Client" Condition="'$(Platform)' == 'x86'&#xD;&#xA;">
<HintPath>.\libs\x86\Nefarius.ViGEm.Client\Nefarius.ViGEm.Client.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
@ -172,7 +166,6 @@
<Compile Include="DS4Control\ControllerSlotManager.cs" /> <Compile Include="DS4Control\ControllerSlotManager.cs" />
<Compile Include="DS4Control\ControlService.cs" /> <Compile Include="DS4Control\ControlService.cs" />
<Compile Include="DS4Control\DS4LightBar.cs" /> <Compile Include="DS4Control\DS4LightBar.cs" />
<Compile Include="DS4Control\DS4OutDevice.cs" />
<Compile Include="DS4Control\DS4StateFieldMapping.cs" /> <Compile Include="DS4Control\DS4StateFieldMapping.cs" />
<Compile Include="DS4Control\InputMethods.cs" /> <Compile Include="DS4Control\InputMethods.cs" />
<Compile Include="DS4Control\ITouchpadBehaviour.cs" /> <Compile Include="DS4Control\ITouchpadBehaviour.cs" />
@ -185,10 +178,12 @@
<Compile Include="DS4Control\OutputSlotManager.cs" /> <Compile Include="DS4Control\OutputSlotManager.cs" />
<Compile Include="DS4Control\ProfilePropGroups.cs" /> <Compile Include="DS4Control\ProfilePropGroups.cs" />
<Compile Include="DS4Control\Program.cs" /> <Compile Include="DS4Control\Program.cs" />
<Compile Include="DS4Control\ScpDevice.cs" />
<Compile Include="DS4Control\ScpUtil.cs" /> <Compile Include="DS4Control\ScpUtil.cs" />
<Compile Include="DS4Control\UdpServer.cs" /> <Compile Include="DS4Control\UdpServer.cs" />
<Compile Include="DS4Control\Util.cs" /> <Compile Include="DS4Control\Util.cs" />
<Compile Include="DS4Control\Xbox360OutDevice.cs" /> <Compile Include="DS4Control\X360BusDevice.cs" />
<Compile Include="DS4Control\Xbox360ScpOutDevice.cs" />
<Compile Include="DS4Forms\About.xaml.cs"> <Compile Include="DS4Forms\About.xaml.cs">
<DependentUpon>About.xaml</DependentUpon> <DependentUpon>About.xaml</DependentUpon>
</Compile> </Compile>