From 1dcfe8db65973229f8e833754fd6920595b34377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ferreira?= Date: Sat, 12 Nov 2016 15:01:57 +0000 Subject: [PATCH] Made it possible to add the controllers after the application has started --- mi/Program.cs | 140 ++++++++++++++++++---------------- mi/Properties/AssemblyInfo.cs | 10 +-- mi/Xiaomi_gamepad.cs | 4 +- 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/mi/Program.cs b/mi/Program.cs index 45a3cb2..4b49bfd 100755 --- a/mi/Program.cs +++ b/mi/Program.cs @@ -50,104 +50,114 @@ static void Main(string[] args) SetConsoleCtrlHandler(handler, true); Thread.Sleep(400); + var controllersManager = new Thread(() => ManageControllers(scpBus)); + controllersManager.Start(); - Xiaomi_gamepad[] gamepads = new Xiaomi_gamepad[4]; - int index = 1; - var compatibleDevices = HidDevices.Enumerate(0x2717, 0x3144).ToList(); - foreach (var deviceInstance in compatibleDevices) + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + var ni = new NotifyIcon(); + + + try { - Console.WriteLine(deviceInstance); - HidDevice Device = deviceInstance; - try + using (var pi = new ProcessIcon()) { - Device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.Exclusive); + pi.Display(); + Application.Run(); } - catch + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, "Program Terminated Unexpectedly", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + scpBus.UnplugAll(); + } + + private static void ManageControllers(ScpBus scpBus) + { + var nrConnected = 0; + while (true) + { + var compatibleDevices = HidDevices.Enumerate(0x2717, 0x3144).ToList(); + var existingDevices = Gamepads.Select(g => g.Device).ToList(); + var newDevices = compatibleDevices.Where(d => !existingDevices.Contains(d)); + foreach (var deviceInstance in newDevices) { - Console.WriteLine("Could not open gamepad in exclusive mode. Try reconnecting the device."); - var instanceId = devicePathToInstanceId(deviceInstance.DevicePath); - if (TryReEnableDevice(instanceId)) + Console.WriteLine(deviceInstance); + var device = deviceInstance; + try { - try + device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.Exclusive); + } + catch + { + Console.WriteLine("Could not open gamepad in exclusive mode. Try reconnecting the device."); + var instanceId = devicePathToInstanceId(deviceInstance.DevicePath); + if (TryReEnableDevice(instanceId)) { - Device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.Exclusive); - Console.WriteLine("Opened in exclusive mode."); + try + { + device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.Exclusive); + Console.WriteLine("Opened in exclusive mode."); + } + catch + { + device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.ShareRead | ShareMode.ShareWrite); + Console.WriteLine("Opened in shared mode."); + } } - catch + else { - Device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.ShareRead | ShareMode.ShareWrite); + device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.ShareRead | ShareMode.ShareWrite); Console.WriteLine("Opened in shared mode."); } } - else + + byte[] vibration = { 0x20, 0x00, 0x00 }; + if (device.WriteFeatureData(vibration) == false) { - Device.OpenDevice(DeviceMode.Overlapped, DeviceMode.Overlapped, ShareMode.ShareRead | ShareMode.ShareWrite); - Console.WriteLine("Opened in shared mode."); + Console.WriteLine("Could not write to gamepad (is it closed?), skipping"); + device.CloseDevice(); + continue; } - } - - byte[] Vibration = { 0x20, 0x00, 0x00 }; - if (Device.WriteFeatureData(Vibration) == false) - { - Console.WriteLine("Could not write to gamepad (is it closed?), skipping"); - Device.CloseDevice(); - continue; - } - byte[] serialNumber; - byte[] product; - Device.ReadSerialNumber(out serialNumber); - Device.ReadProduct(out product); + byte[] serialNumber; + byte[] product; + device.ReadSerialNumber(out serialNumber); + device.ReadProduct(out product); - gamepads[index - 1] = new Xiaomi_gamepad(Device, scpBus, index); - ++index; - - if (index >= 5) + Gamepads.Add(new Xiaomi_gamepad(device, scpBus, Gamepads.Count + 1)); + } + if (Gamepads.Count != nrConnected) { - break; + Console.WriteLine("{0} controllers connected", Gamepads.Count); } - } - - Console.WriteLine("{0} controllers connected", index - 1); - - - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - var ni = new NotifyIcon(); - - - try - { - // Show the system tray icon. - using (var pi = new ProcessIcon()) + nrConnected = Gamepads.Count; + if (nrConnected == 4) { - pi.Display(); - - // Make sure the application runs! - Application.Run(); + Thread.Sleep(10000); + continue; } + Thread.Sleep(5000); } - catch (Exception ex) - { - MessageBox.Show(ex.Message, "Program Terminated Unexpectedly", - MessageBoxButtons.OK, MessageBoxIcon.Error); - } - scpBus.UnplugAll(); } + public static List Gamepads { get; set; } = new List(); + private static bool TryReEnableDevice(string deviceInstanceId) { try { - bool success; Guid hidGuid = new Guid(); HidLibrary.NativeMethods.HidD_GetHidGuid(ref hidGuid); IntPtr deviceInfoSet = HidLibrary.NativeMethods.SetupDiGetClassDevs(ref hidGuid, deviceInstanceId, 0, HidLibrary.NativeMethods.DIGCF_PRESENT | HidLibrary.NativeMethods.DIGCF_DEVICEINTERFACE); HidLibrary.NativeMethods.SP_DEVINFO_DATA deviceInfoData = new HidLibrary.NativeMethods.SP_DEVINFO_DATA(); deviceInfoData.cbSize = Marshal.SizeOf(deviceInfoData); - success = HidLibrary.NativeMethods.SetupDiEnumDeviceInfo(deviceInfoSet, 0, ref deviceInfoData); + var success = HidLibrary.NativeMethods.SetupDiEnumDeviceInfo(deviceInfoSet, 0, ref deviceInfoData); if (!success) { Console.WriteLine("Error getting device info data, error code = " + Marshal.GetLastWin32Error()); @@ -202,7 +212,7 @@ private static bool TryReEnableDevice(string deviceInstanceId) } catch { - Console.WriteLine("Can't reenable device"); + Console.WriteLine("Can't re-enable device"); return false; } } diff --git a/mi/Properties/AssemblyInfo.cs b/mi/Properties/AssemblyInfo.cs index 14b6481..64a3f61 100644 --- a/mi/Properties/AssemblyInfo.cs +++ b/mi/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("mi")] -[assembly: AssemblyDescription("Adds a virtual xbox360 controller controlled by the mi controller")] +[assembly: AssemblyTitle("Mi controller interface application")] +[assembly: AssemblyDescription("Adds a virtual xbox360 gamepad managed by the mi controller")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("mi")] +[assembly: AssemblyProduct("Emulator")] [assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.2.0.0")] +[assembly: AssemblyFileVersion("1.2.0.0")] diff --git a/mi/Xiaomi_gamepad.cs b/mi/Xiaomi_gamepad.cs index 24d25f8..ef2a935 100644 --- a/mi/Xiaomi_gamepad.cs +++ b/mi/Xiaomi_gamepad.cs @@ -7,12 +7,14 @@ namespace mi { public class Xiaomi_gamepad { + public HidDevice Device { get; set; } private byte[] Vibration = { 0x20, 0x00, 0x00 }; private Mutex rumble_mutex = new Mutex(); //private byte[] enableAccelerometer = { 0x31, 0x01, 0x08 }; - public Xiaomi_gamepad(HidDevice Device, ScpBus scpBus, int index) + public Xiaomi_gamepad(HidDevice device, ScpBus scpBus, int index) { + Device = device; Device.WriteFeatureData(Vibration); Thread rThread = new Thread(() => rumble_thread(Device));