Skip to content

Commit

Permalink
Made it possible to add the controllers after the application has sta…
Browse files Browse the repository at this point in the history
…rted
  • Loading branch information
André Ferreira committed Nov 12, 2016
1 parent 65e5c31 commit 1dcfe8d
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 71 deletions.
140 changes: 75 additions & 65 deletions mi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Xiaomi_gamepad> Gamepads { get; set; } = new List<Xiaomi_gamepad>();

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());
Expand Down Expand Up @@ -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;
}
}
Expand Down
10 changes: 5 additions & 5 deletions mi/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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("")]
Expand All @@ -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")]
4 changes: 3 additions & 1 deletion mi/Xiaomi_gamepad.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit 1dcfe8d

Please sign in to comment.