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.Diagnostics;
|
||||
using static DS4Windows.Global;
|
||||
using Nefarius.ViGEm.Client;
|
||||
//using Nefarius.ViGEm.Client;
|
||||
|
||||
namespace DS4Windows
|
||||
{
|
||||
public class ControlService
|
||||
{
|
||||
public ViGEmClient vigemTestClient = null;
|
||||
public X360BusDevice x360Bus = null;
|
||||
//public ViGEmClient vigemTestClient = null;
|
||||
public const int DS4_CONTROLLER_COUNT = 4;
|
||||
public DS4Device[] DS4Controllers = new DS4Device[DS4_CONTROLLER_COUNT];
|
||||
public Mouse[] touchPad = new Mouse[DS4_CONTROLLER_COUNT];
|
||||
@ -357,7 +358,8 @@ namespace DS4Windows
|
||||
|
||||
private void startViGEm()
|
||||
{
|
||||
tempThread = new Thread(() => { try { vigemTestClient = new ViGEmClient(); } catch { } });
|
||||
tempThread = new Thread(() => { try { x360Bus = new X360BusDevice(); } catch { } });
|
||||
//tempThread = new Thread(() => { try { vigemTestClient = new ViGEmClient(); } catch { } });
|
||||
tempThread.Priority = ThreadPriority.AboveNormal;
|
||||
tempThread.IsBackground = true;
|
||||
tempThread.Start();
|
||||
@ -371,11 +373,18 @@ namespace DS4Windows
|
||||
|
||||
private void stopViGEm()
|
||||
{
|
||||
if (vigemTestClient != null)
|
||||
if (x360Bus != null)
|
||||
{
|
||||
vigemTestClient.Dispose();
|
||||
vigemTestClient = null;
|
||||
x360Bus.UnplugAll();
|
||||
x360Bus.Stop();
|
||||
x360Bus = null;
|
||||
}
|
||||
|
||||
//if (vigemTestClient != null)
|
||||
//{
|
||||
// vigemTestClient.Dispose();
|
||||
// vigemTestClient = null;
|
||||
//}
|
||||
}
|
||||
|
||||
public void PluginOutDev(int index, DS4Device device)
|
||||
@ -389,94 +398,98 @@ namespace DS4Windows
|
||||
activeOutDevType[index] = OutContType.X360;
|
||||
|
||||
//Xbox360OutDevice tempXbox = new Xbox360OutDevice(vigemTestClient);
|
||||
Xbox360OutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, vigemTestClient)
|
||||
as Xbox360OutDevice;
|
||||
Xbox360ScpOutDevice tempXbox = outputslotMan.AllocateController(OutContType.X360, x360Bus, index)
|
||||
as Xbox360ScpOutDevice;
|
||||
//outputDevices[index] = tempXbox;
|
||||
int devIndex = index;
|
||||
Nefarius.ViGEm.Client.Targets.Xbox360FeedbackReceivedEventHandler p = (sender, args) =>
|
||||
tempXbox.FeedbackReceived += (sender, small, large, slotIdx) =>
|
||||
{
|
||||
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
|
||||
SetDevRumble(device, large, small, devIndex);
|
||||
};
|
||||
tempXbox.cont.FeedbackReceived += p;
|
||||
tempXbox.forceFeedbackCall = p;
|
||||
//Nefarius.ViGEm.Client.Targets.Xbox360FeedbackReceivedEventHandler p = (sender, args) =>
|
||||
// {
|
||||
// SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
|
||||
// };
|
||||
//tempXbox.cont.FeedbackReceived += p;
|
||||
//tempXbox.forceFeedbackCall = p;
|
||||
|
||||
outputslotMan.DeferredPlugin(tempXbox, index, outputDevices);
|
||||
//tempXbox.Connect();
|
||||
//LogDebug("X360 Controller #" + (index + 1) + " connected");
|
||||
}
|
||||
else if (contType == OutContType.DS4)
|
||||
{
|
||||
LogDebug("Plugging in DS4 Controller for input #" + (index + 1));
|
||||
activeOutDevType[index] = OutContType.DS4;
|
||||
//DS4OutDevice tempDS4 = new DS4OutDevice(vigemTestClient);
|
||||
DS4OutDevice tempDS4 = outputslotMan.AllocateController(OutContType.DS4, vigemTestClient)
|
||||
as DS4OutDevice;
|
||||
//outputDevices[index] = tempDS4;
|
||||
int devIndex = index;
|
||||
Nefarius.ViGEm.Client.Targets.DualShock4FeedbackReceivedEventHandler p = (sender, args) =>
|
||||
{
|
||||
//bool useRumble = false; bool useLight = false;
|
||||
byte largeMotor = args.LargeMotor;
|
||||
byte smallMotor = args.SmallMotor;
|
||||
SetDevRumble(device, largeMotor, smallMotor, devIndex);
|
||||
//DS4Color color = new DS4Color(args.LightbarColor.Red,
|
||||
// args.LightbarColor.Green,
|
||||
// args.LightbarColor.Blue);
|
||||
///*Console.WriteLine("IN EVENT");
|
||||
//Console.WriteLine("Rumble ({0}, {1}) | Light ({2}, {3}, {4}) {5}",
|
||||
// largeMotor, smallMotor, color.red, color.green, color.blue, DateTime.Now.ToLongTimeString());
|
||||
// */
|
||||
//if (largeMotor != 0 || smallMotor != 0)
|
||||
//else if (contType == OutContType.DS4)
|
||||
//{
|
||||
// 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)
|
||||
//{
|
||||
// useLight = true;
|
||||
//}
|
||||
// // //if (color.red != 0 || color.green != 0 || color.blue != 0)
|
||||
// // //{
|
||||
// // // useLight = true;
|
||||
// // //}
|
||||
|
||||
//if (!useRumble && !useLight)
|
||||
//{
|
||||
// //Console.WriteLine("Fallback");
|
||||
// if (device.LeftHeavySlowRumble != 0 || device.RightLightFastRumble != 0)
|
||||
// {
|
||||
// useRumble = true;
|
||||
// }
|
||||
// /*else if (device.LightBarColor.red != 0 ||
|
||||
// device.LightBarColor.green != 0 ||
|
||||
// device.LightBarColor.blue != 0)
|
||||
// {
|
||||
// useLight = true;
|
||||
// }
|
||||
// */
|
||||
//}
|
||||
// // //if (!useRumble && !useLight)
|
||||
// // //{
|
||||
// // // //Console.WriteLine("Fallback");
|
||||
// // // if (device.LeftHeavySlowRumble != 0 || device.RightLightFastRumble != 0)
|
||||
// // // {
|
||||
// // // useRumble = true;
|
||||
// // // }
|
||||
// // // /*else if (device.LightBarColor.red != 0 ||
|
||||
// // // device.LightBarColor.green != 0 ||
|
||||
// // // device.LightBarColor.blue != 0)
|
||||
// // // {
|
||||
// // // useLight = true;
|
||||
// // // }
|
||||
// // // */
|
||||
// // //}
|
||||
|
||||
//if (useRumble)
|
||||
//{
|
||||
// //Console.WriteLine("Perform rumble");
|
||||
// SetDevRumble(device, largeMotor, smallMotor, devIndex);
|
||||
// // //if (useRumble)
|
||||
// // //{
|
||||
// // // //Console.WriteLine("Perform rumble");
|
||||
// // // SetDevRumble(device, largeMotor, smallMotor, devIndex);
|
||||
// // //}
|
||||
|
||||
// // //if (useLight)
|
||||
// // //{
|
||||
// // // //Console.WriteLine("Change lightbar color");
|
||||
// // // DS4HapticState haptics = new DS4HapticState
|
||||
// // // {
|
||||
// // // LightBarColor = color,
|
||||
// // // };
|
||||
// // // device.SetHapticState(ref haptics);
|
||||
// // //}
|
||||
|
||||
// // //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;
|
||||
@ -506,8 +519,8 @@ namespace DS4Windows
|
||||
public bool Start(bool showlog = true)
|
||||
{
|
||||
startViGEm();
|
||||
if (vigemTestClient != null)
|
||||
//if (x360Bus.Open() && x360Bus.Start())
|
||||
//if (vigemTestClient != null)
|
||||
if (x360Bus.Open() && x360Bus.Start())
|
||||
{
|
||||
if (showlog)
|
||||
LogDebug(DS4WinWPF.Properties.Resources.Starting);
|
||||
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Nefarius.ViGEm.Client;
|
||||
//using Nefarius.ViGEm.Client;
|
||||
|
||||
namespace DS4Windows
|
||||
{
|
||||
@ -20,16 +20,32 @@ namespace DS4Windows
|
||||
|
||||
public bool RunningQueue { get => runningQueue; }
|
||||
|
||||
public OutputDevice AllocateController(OutContType contType, ViGEmClient client)
|
||||
//public OutputDevice AllocateController(OutContType contType, ViGEmClient client)
|
||||
//{
|
||||
// OutputDevice outputDevice = null;
|
||||
// switch(contType)
|
||||
// {
|
||||
// case OutContType.X360:
|
||||
// outputDevice = new Xbox360OutDevice(client);
|
||||
// break;
|
||||
// case OutContType.DS4:
|
||||
// outputDevice = new DS4OutDevice(client);
|
||||
// break;
|
||||
// case OutContType.None:
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// return outputDevice;
|
||||
//}
|
||||
|
||||
public OutputDevice AllocateController(OutContType contType, X360BusDevice client, int idx)
|
||||
{
|
||||
OutputDevice outputDevice = null;
|
||||
switch (contType)
|
||||
{
|
||||
case OutContType.X360:
|
||||
outputDevice = new Xbox360OutDevice(client);
|
||||
break;
|
||||
case OutContType.DS4:
|
||||
outputDevice = new DS4OutDevice(client);
|
||||
outputDevice = new Xbox360ScpOutDevice(client, idx);
|
||||
break;
|
||||
case OutContType.None:
|
||||
default:
|
||||
|
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>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
</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">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
@ -172,7 +166,6 @@
|
||||
<Compile Include="DS4Control\ControllerSlotManager.cs" />
|
||||
<Compile Include="DS4Control\ControlService.cs" />
|
||||
<Compile Include="DS4Control\DS4LightBar.cs" />
|
||||
<Compile Include="DS4Control\DS4OutDevice.cs" />
|
||||
<Compile Include="DS4Control\DS4StateFieldMapping.cs" />
|
||||
<Compile Include="DS4Control\InputMethods.cs" />
|
||||
<Compile Include="DS4Control\ITouchpadBehaviour.cs" />
|
||||
@ -185,10 +178,12 @@
|
||||
<Compile Include="DS4Control\OutputSlotManager.cs" />
|
||||
<Compile Include="DS4Control\ProfilePropGroups.cs" />
|
||||
<Compile Include="DS4Control\Program.cs" />
|
||||
<Compile Include="DS4Control\ScpDevice.cs" />
|
||||
<Compile Include="DS4Control\ScpUtil.cs" />
|
||||
<Compile Include="DS4Control\UdpServer.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">
|
||||
<DependentUpon>About.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
Loading…
Reference in New Issue
Block a user