mirror of
https://github.com/cemu-project/DS4Windows.git
synced 2024-11-25 18:46:58 +01:00
Use ScpVBus for X360 emulation rather than ViGEmBus
Test branch
This commit is contained in:
parent
31aa0a1aac
commit
19344c40b0
@ -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));
|
// LogDebug("Plugging in DS4 Controller for input #" + (index + 1));
|
||||||
activeOutDevType[index] = OutContType.DS4;
|
// activeOutDevType[index] = OutContType.DS4;
|
||||||
//DS4OutDevice tempDS4 = new DS4OutDevice(vigemTestClient);
|
// //DS4OutDevice tempDS4 = new DS4OutDevice(vigemTestClient);
|
||||||
DS4OutDevice tempDS4 = outputslotMan.AllocateController(OutContType.DS4, vigemTestClient)
|
// DS4OutDevice tempDS4 = outputslotMan.AllocateController(OutContType.DS4, vigemTestClient)
|
||||||
as DS4OutDevice;
|
// as DS4OutDevice;
|
||||||
//outputDevices[index] = tempDS4;
|
// //outputDevices[index] = tempDS4;
|
||||||
int devIndex = index;
|
// int devIndex = index;
|
||||||
Nefarius.ViGEm.Client.Targets.DualShock4FeedbackReceivedEventHandler p = (sender, args) =>
|
// //Nefarius.ViGEm.Client.Targets.DualShock4FeedbackReceivedEventHandler p = (sender, args) =>
|
||||||
{
|
// // {
|
||||||
//bool useRumble = false; bool useLight = false;
|
// // //bool useRumble = false; bool useLight = false;
|
||||||
byte largeMotor = args.LargeMotor;
|
// // byte largeMotor = args.LargeMotor;
|
||||||
byte smallMotor = args.SmallMotor;
|
// // byte smallMotor = args.SmallMotor;
|
||||||
SetDevRumble(device, largeMotor, smallMotor, devIndex);
|
// // SetDevRumble(device, largeMotor, smallMotor, devIndex);
|
||||||
//DS4Color color = new DS4Color(args.LightbarColor.Red,
|
// // //DS4Color color = new DS4Color(args.LightbarColor.Red,
|
||||||
// args.LightbarColor.Green,
|
// // // args.LightbarColor.Green,
|
||||||
// args.LightbarColor.Blue);
|
// // // args.LightbarColor.Blue);
|
||||||
///*Console.WriteLine("IN EVENT");
|
// // ///*Console.WriteLine("IN EVENT");
|
||||||
//Console.WriteLine("Rumble ({0}, {1}) | Light ({2}, {3}, {4}) {5}",
|
// // //Console.WriteLine("Rumble ({0}, {1}) | Light ({2}, {3}, {4}) {5}",
|
||||||
// largeMotor, smallMotor, color.red, color.green, color.blue, DateTime.Now.ToLongTimeString());
|
// // // largeMotor, smallMotor, color.red, color.green, color.blue, DateTime.Now.ToLongTimeString());
|
||||||
// */
|
// // // */
|
||||||
//if (largeMotor != 0 || smallMotor != 0)
|
// // //if (largeMotor != 0 || smallMotor != 0)
|
||||||
//{
|
// // //{
|
||||||
// useRumble = true;
|
// // // 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)
|
// // //if (useLight)
|
||||||
//{
|
// // //{
|
||||||
// //Console.WriteLine("Change lightbar color");
|
// // // //Console.WriteLine("Change lightbar color");
|
||||||
// DS4HapticState haptics = new DS4HapticState
|
// // // DS4HapticState haptics = new DS4HapticState
|
||||||
// {
|
// // // {
|
||||||
// LightBarColor = color,
|
// // // LightBarColor = color,
|
||||||
// };
|
// // // };
|
||||||
// device.SetHapticState(ref haptics);
|
// // // device.SetHapticState(ref haptics);
|
||||||
//}
|
// // //}
|
||||||
|
|
||||||
//Console.WriteLine();
|
// // //Console.WriteLine();
|
||||||
};
|
// //};
|
||||||
tempDS4.cont.FeedbackReceived += p;
|
// //tempDS4.cont.FeedbackReceived += p;
|
||||||
tempDS4.forceFeedbackCall = p;
|
// //tempDS4.forceFeedbackCall = p;
|
||||||
|
|
||||||
outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
|
// outputslotMan.DeferredPlugin(tempDS4, index, outputDevices);
|
||||||
//tempDS4.Connect();
|
// //tempDS4.Connect();
|
||||||
//LogDebug("DS4 Controller #" + (index + 1) + " connected");
|
// //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);
|
||||||
|
@ -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:
|
||||||
|
693
DS4Windows/DS4Control/ScpDevice.cs
Normal file
693
DS4Windows/DS4Control/ScpDevice.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
294
DS4Windows/DS4Control/X360BusDevice.cs
Normal file
294
DS4Windows/DS4Control/X360BusDevice.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
DS4Windows/DS4Control/Xbox360ScpOutDevice.cs
Normal file
59
DS4Windows/DS4Control/Xbox360ScpOutDevice.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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'
">
|
|
||||||
<HintPath>.\libs\x64\Nefarius.ViGEm.Client\Nefarius.ViGEm.Client.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Nefarius.ViGEm.Client" Condition="'$(Platform)' == 'x86'
">
|
|
||||||
<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>
|
||||||
|
Loading…
Reference in New Issue
Block a user