2014-03-28 02:50:40 +01:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
|
|
|
|
using System.Diagnostics;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
using System.Linq;
|
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Security.Principal;
|
2015-02-08 22:51:52 +01:00
|
|
|
|
|
|
|
|
|
namespace DS4Windows
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
|
|
|
|
public class DS4Devices
|
|
|
|
|
{
|
|
|
|
|
private static Dictionary<string, DS4Device> Devices = new Dictionary<string, DS4Device>();
|
2014-03-29 06:29:08 +01:00
|
|
|
|
private static HashSet<String> DevicePaths = new HashSet<String>();
|
2014-03-28 02:50:40 +01:00
|
|
|
|
public static bool isExclusiveMode = false;
|
|
|
|
|
|
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
|
|
|
|
private static string devicePathToInstanceId(string devicePath)
|
|
|
|
|
{
|
|
|
|
|
string deviceInstanceId = devicePath;
|
|
|
|
|
deviceInstanceId = deviceInstanceId.Remove(0, deviceInstanceId.LastIndexOf('\\') + 1);
|
|
|
|
|
deviceInstanceId = deviceInstanceId.Remove(deviceInstanceId.LastIndexOf('{'));
|
|
|
|
|
deviceInstanceId = deviceInstanceId.Replace('#', '\\');
|
|
|
|
|
if (deviceInstanceId.EndsWith("\\"))
|
|
|
|
|
{
|
|
|
|
|
deviceInstanceId = deviceInstanceId.Remove(deviceInstanceId.Length - 1);
|
|
|
|
|
}
|
|
|
|
|
return deviceInstanceId;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-28 02:50:40 +01:00
|
|
|
|
//enumerates ds4 controllers in the system
|
|
|
|
|
public static void findControllers()
|
|
|
|
|
{
|
|
|
|
|
lock (Devices)
|
|
|
|
|
{
|
2016-10-05 18:18:59 +02:00
|
|
|
|
int[] pid = { 0xBA0, 0x5C4, 0x09CC };
|
2014-03-28 02:50:40 +01:00
|
|
|
|
IEnumerable<HidDevice> hDevices = HidDevices.Enumerate(0x054C, pid);
|
2014-03-29 06:29:08 +01:00
|
|
|
|
// Sort Bluetooth first in case USB is also connected on the same controller.
|
|
|
|
|
hDevices = hDevices.OrderBy<HidDevice, ConnectionType>((HidDevice d) => { return DS4Device.HidConnectionType(d); });
|
2014-03-28 02:50:40 +01:00
|
|
|
|
|
|
|
|
|
foreach (HidDevice hDevice in hDevices)
|
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
if (DevicePaths.Contains(hDevice.DevicePath))
|
|
|
|
|
continue; // BT/USB endpoint already open once
|
2014-03-28 02:50:40 +01:00
|
|
|
|
if (!hDevice.IsOpen)
|
2014-03-29 06:29:08 +01:00
|
|
|
|
{
|
2014-03-28 02:50:40 +01:00
|
|
|
|
hDevice.OpenDevice(isExclusiveMode);
|
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
|
|
|
|
if (!hDevice.IsOpen && isExclusiveMode)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
|
|
|
|
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
|
|
|
|
bool elevated = principal.IsInRole(WindowsBuiltInRole.Administrator);
|
|
|
|
|
|
|
|
|
|
if (!elevated)
|
|
|
|
|
{
|
|
|
|
|
// Launches an elevated child process to re-enable device
|
|
|
|
|
string exeName = Process.GetCurrentProcess().MainModule.FileName;
|
|
|
|
|
ProcessStartInfo startInfo = new ProcessStartInfo(exeName);
|
|
|
|
|
startInfo.Verb = "runas";
|
|
|
|
|
startInfo.Arguments = "re-enabledevice " + devicePathToInstanceId(hDevice.DevicePath);
|
|
|
|
|
Process child = Process.Start(startInfo);
|
|
|
|
|
if (!child.WaitForExit(5000))
|
|
|
|
|
{
|
|
|
|
|
child.Kill();
|
|
|
|
|
}
|
|
|
|
|
else if (child.ExitCode == 0)
|
|
|
|
|
{
|
|
|
|
|
hDevice.OpenDevice(isExclusiveMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
reEnableDevice(devicePathToInstanceId(hDevice.DevicePath));
|
|
|
|
|
hDevice.OpenDevice(isExclusiveMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception) { }
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-29 06:29:08 +01:00
|
|
|
|
// TODO in exclusive mode, try to hold both open when both are connected
|
|
|
|
|
if (isExclusiveMode && !hDevice.IsOpen)
|
|
|
|
|
hDevice.OpenDevice(false);
|
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
if (hDevice.IsOpen)
|
|
|
|
|
{
|
|
|
|
|
if (Devices.ContainsKey(hDevice.readSerial()))
|
2014-03-29 06:29:08 +01:00
|
|
|
|
continue; // happens when the BT endpoint already is open and the USB is plugged into the same host
|
2014-03-28 02:50:40 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DS4Device ds4Device = new DS4Device(hDevice);
|
|
|
|
|
ds4Device.Removal += On_Removal;
|
|
|
|
|
Devices.Add(ds4Device.MacAddress, ds4Device);
|
2014-03-29 06:29:08 +01:00
|
|
|
|
DevicePaths.Add(hDevice.DevicePath);
|
|
|
|
|
ds4Device.StartUpdate();
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//allows to get DS4Device by specifying unique MAC address
|
|
|
|
|
//format for MAC address is XX:XX:XX:XX:XX:XX
|
|
|
|
|
public static DS4Device getDS4Controller(string mac)
|
2014-03-29 06:29:08 +01:00
|
|
|
|
{
|
|
|
|
|
lock (Devices)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
DS4Device device = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
Devices.TryGetValue(mac, out device);
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentNullException) { }
|
|
|
|
|
return device;
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//returns DS4 controllers that were found and are running
|
|
|
|
|
public static IEnumerable<DS4Device> getDS4Controllers()
|
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
lock (Devices)
|
|
|
|
|
{
|
|
|
|
|
DS4Device[] controllers = new DS4Device[Devices.Count];
|
|
|
|
|
Devices.Values.CopyTo(controllers, 0);
|
|
|
|
|
return controllers;
|
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void stopControllers()
|
2014-03-29 06:29:08 +01:00
|
|
|
|
{
|
|
|
|
|
lock (Devices)
|
2014-03-28 02:50:40 +01:00
|
|
|
|
{
|
2014-03-29 06:29:08 +01:00
|
|
|
|
IEnumerable<DS4Device> devices = getDS4Controllers();
|
|
|
|
|
foreach (DS4Device device in devices)
|
|
|
|
|
{
|
|
|
|
|
device.StopUpdate();
|
|
|
|
|
device.HidDevice.CloseDevice();
|
|
|
|
|
}
|
|
|
|
|
Devices.Clear();
|
|
|
|
|
DevicePaths.Clear();
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//called when devices is diconnected, timed out or has input reading failure
|
|
|
|
|
public static void On_Removal(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
lock (Devices)
|
|
|
|
|
{
|
|
|
|
|
DS4Device device = (DS4Device)sender;
|
|
|
|
|
device.HidDevice.CloseDevice();
|
|
|
|
|
Devices.Remove(device.MacAddress);
|
2014-03-29 06:29:08 +01:00
|
|
|
|
DevicePaths.Remove(device.HidDevice.DevicePath);
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
|
|
|
|
|
|
|
|
|
public static void reEnableDevice(string deviceInstanceId)
|
|
|
|
|
{
|
|
|
|
|
bool success;
|
|
|
|
|
Guid hidGuid = new Guid();
|
|
|
|
|
NativeMethods.HidD_GetHidGuid(ref hidGuid);
|
|
|
|
|
IntPtr deviceInfoSet = NativeMethods.SetupDiGetClassDevs(ref hidGuid, deviceInstanceId, 0, NativeMethods.DIGCF_PRESENT | NativeMethods.DIGCF_DEVICEINTERFACE);
|
|
|
|
|
NativeMethods.SP_DEVINFO_DATA deviceInfoData = new NativeMethods.SP_DEVINFO_DATA();
|
|
|
|
|
deviceInfoData.cbSize = Marshal.SizeOf(deviceInfoData);
|
|
|
|
|
success = NativeMethods.SetupDiEnumDeviceInfo(deviceInfoSet, 0, ref deviceInfoData);
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Error getting device info data, error code = " + Marshal.GetLastWin32Error());
|
|
|
|
|
}
|
|
|
|
|
success = NativeMethods.SetupDiEnumDeviceInfo(deviceInfoSet, 1, ref deviceInfoData); // Checks that we have a unique device
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Can't find unique device");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NativeMethods.SP_PROPCHANGE_PARAMS propChangeParams = new NativeMethods.SP_PROPCHANGE_PARAMS();
|
|
|
|
|
propChangeParams.classInstallHeader.cbSize = Marshal.SizeOf(propChangeParams.classInstallHeader);
|
|
|
|
|
propChangeParams.classInstallHeader.installFunction = NativeMethods.DIF_PROPERTYCHANGE;
|
|
|
|
|
propChangeParams.stateChange = NativeMethods.DICS_DISABLE;
|
|
|
|
|
propChangeParams.scope = NativeMethods.DICS_FLAG_GLOBAL;
|
|
|
|
|
propChangeParams.hwProfile = 0;
|
|
|
|
|
success = NativeMethods.SetupDiSetClassInstallParams(deviceInfoSet, ref deviceInfoData, ref propChangeParams, Marshal.SizeOf(propChangeParams));
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Error setting class install params, error code = " + Marshal.GetLastWin32Error());
|
|
|
|
|
}
|
|
|
|
|
success = NativeMethods.SetupDiCallClassInstaller(NativeMethods.DIF_PROPERTYCHANGE, deviceInfoSet, ref deviceInfoData);
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Error disabling device, error code = " + Marshal.GetLastWin32Error());
|
|
|
|
|
}
|
|
|
|
|
propChangeParams.stateChange = NativeMethods.DICS_ENABLE;
|
|
|
|
|
success = NativeMethods.SetupDiSetClassInstallParams(deviceInfoSet, ref deviceInfoData, ref propChangeParams, Marshal.SizeOf(propChangeParams));
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Error setting class install params, error code = " + Marshal.GetLastWin32Error());
|
|
|
|
|
}
|
|
|
|
|
success = NativeMethods.SetupDiCallClassInstaller(NativeMethods.DIF_PROPERTYCHANGE, deviceInfoSet, ref deviceInfoData);
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Error enabling device, error code = " + Marshal.GetLastWin32Error());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet);
|
|
|
|
|
}
|
2014-03-28 02:50:40 +01:00
|
|
|
|
}
|
|
|
|
|
}
|