Inheritance: IDisposable
Example #1
0
        // Enumerates ds4 controllers in the system
        public static void findControllers()
        {
            lock (Devices)
            {
                IEnumerable <HidDevice> hDevices = HidDevices.EnumerateDS4(knownDevices);
                // Sort Bluetooth first in case USB is also connected on the same controller.
                hDevices = hDevices.OrderBy <HidDevice, ConnectionType>((HidDevice d) => { return(DS4Device.HidConnectionType(d)); });

                List <HidDevice> tempList = hDevices.ToList();
                purgeHiddenExclusiveDevices();
                tempList.AddRange(DisabledDevices);
                int    devCount     = tempList.Count();
                string devicePlural = "device" + (devCount == 0 || devCount > 1 ? "s" : "");
                //Log.LogToGui("Found " + devCount + " possible " + devicePlural + ". Examining " + devicePlural + ".", false);

                for (int i = 0; i < devCount; i++)
                //foreach (HidDevice hDevice in hDevices)
                {
                    HidDevice hDevice = tempList[i];
                    if (hDevice.Description == "HID-compliant vendor-defined device")
                    {
                        continue; // ignore the Nacon Revolution Pro programming interface
                    }
                    else if (DevicePaths.Contains(hDevice.DevicePath))
                    {
                        continue; // BT/USB endpoint already open once
                    }
                    if (!hDevice.IsOpen)
                    {
                        hDevice.OpenDevice(isExclusiveMode);
                        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(30000))
                                    {
                                        child.Kill();
                                    }
                                    else if (child.ExitCode == 0)
                                    {
                                        hDevice.OpenDevice(isExclusiveMode);
                                    }
                                }
                                else
                                {
                                    reEnableDevice(devicePathToInstanceId(hDevice.DevicePath));
                                    hDevice.OpenDevice(isExclusiveMode);
                                }
                            }
                            catch (Exception) { }
                        }

                        // TODO in exclusive mode, try to hold both open when both are connected
                        if (isExclusiveMode && !hDevice.IsOpen)
                        {
                            hDevice.OpenDevice(false);
                        }
                    }

                    if (hDevice.IsOpen)
                    {
                        string serial      = hDevice.readSerial();
                        bool   validSerial = !serial.Equals(DS4Device.blankSerial);
                        if (validSerial && deviceSerials.Contains(serial))
                        {
                            // happens when the BT endpoint already is open and the USB is plugged into the same host
                            if (isExclusiveMode && hDevice.IsExclusive &&
                                !DisabledDevices.Contains(hDevice))
                            {
                                // Grab reference to exclusively opened HidDevice so device
                                // stays hidden to other processes
                                DisabledDevices.Add(hDevice);
                                //DevicePaths.Add(hDevice.DevicePath);
                            }

                            continue;
                        }
                        else
                        {
                            DS4Device ds4Device = new DS4Device(hDevice);
                            //ds4Device.Removal += On_Removal;
                            if (!ds4Device.ExitOutputThread)
                            {
                                Devices.Add(hDevice.DevicePath, ds4Device);
                                DevicePaths.Add(hDevice.DevicePath);
                                deviceSerials.Add(serial);
                            }
                        }
                    }
                }
            }
        }
Example #2
0
        private void performDs4Input()
        {
            firstActive = DateTime.UtcNow;
            System.Timers.Timer readTimeout = new System.Timers.Timer(); // Await 30 seconds for the initial packet, then 3 seconds thereafter.
            readTimeout.Elapsed += delegate { HidDevice.CancelIO(); };
            List <long> Latency = new List <long>();
            long        oldtime = 0;
            Stopwatch   sw      = new Stopwatch();

            sw.Start();
            while (true)
            {
                string currerror = string.Empty;
                Latency.Add(sw.ElapsedMilliseconds - oldtime);
                oldtime = sw.ElapsedMilliseconds;

                if (Latency.Count > 100)
                {
                    Latency.RemoveAt(0);
                }

                this.Latency = Latency.Average();

                if (this.Latency > 10 && !warn && sw.ElapsedMilliseconds > 4000)
                {
                    warn = true;
                    //System.Diagnostics.Trace.WriteLine(System.DateTime.UtcNow.ToString("o") + "> " + "Controller " + /*this.DeviceNum*/ + 1 + " (" + this.MacAddress + ") is experiencing latency issues. Currently at " + Math.Round(this.Latency, 2).ToString() + "ms of recomended maximum 10ms");
                }
                else if (this.Latency <= 10 && warn)
                {
                    warn = false;
                }

                if (readTimeout.Interval != 3000.0)
                {
                    if (readTimeout.Interval != 30000.0)
                    {
                        readTimeout.Interval = 30000.0;
                    }
                    else
                    {
                        readTimeout.Interval = 3000.0;
                    }
                }
                readTimeout.Enabled = true;
                if (conType != ConnectionType.USB)
                {
                    HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport);
                    readTimeout.Enabled = false;
                    if (res == HidDevice.ReadStatus.Success)
                    {
                        Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length);
                    }
                    else
                    {
                        //Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
                        sendOutputReport(true); // Kick Windows into noticing the disconnection.
                        StopOutputUpdate();
                        IsDisconnecting = true;
                        if (Removal != null)
                        {
                            Removal(this, EventArgs.Empty);
                        }
                        return;
                    }
                }
                else
                {
                    HidDevice.ReadStatus res = hDevice.ReadFile(inputReport);
                    readTimeout.Enabled = false;
                    if (res != HidDevice.ReadStatus.Success)
                    {
                        //Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + Marshal.GetLastWin32Error());
                        StopOutputUpdate();
                        IsDisconnecting = true;
                        if (Removal != null)
                        {
                            Removal(this, EventArgs.Empty);
                        }
                        return;
                    }
                }
                if (ConnectionType == ConnectionType.BT && btInputReport[0] != 0x11)
                {
                    //Received incorrect report, skip it
                    continue;
                }
                DateTime utcNow = System.DateTime.UtcNow; // timestamp with UTC in case system time zone changes
                resetHapticState();
                cState.ReportTimeStamp = utcNow;
                cState.LX = inputReport[1];
                cState.LY = inputReport[2];
                cState.RX = inputReport[3];
                cState.RY = inputReport[4];
                cState.L2 = inputReport[8];
                cState.R2 = inputReport[9];

                cState.Triangle  = ((byte)inputReport[5] & (1 << 7)) != 0;
                cState.Circle    = ((byte)inputReport[5] & (1 << 6)) != 0;
                cState.Cross     = ((byte)inputReport[5] & (1 << 5)) != 0;
                cState.Square    = ((byte)inputReport[5] & (1 << 4)) != 0;
                cState.DpadUp    = ((byte)inputReport[5] & (1 << 3)) != 0;
                cState.DpadDown  = ((byte)inputReport[5] & (1 << 2)) != 0;
                cState.DpadLeft  = ((byte)inputReport[5] & (1 << 1)) != 0;
                cState.DpadRight = ((byte)inputReport[5] & (1 << 0)) != 0;

                //Convert dpad into individual On/Off bits instead of a clock representation
                byte dpad_state = 0;

                dpad_state = (byte)(
                    ((cState.DpadRight ? 1 : 0) << 0) |
                    ((cState.DpadLeft ? 1 : 0) << 1) |
                    ((cState.DpadDown ? 1 : 0) << 2) |
                    ((cState.DpadUp ? 1 : 0) << 3));

                switch (dpad_state)
                {
                case 0: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 1: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 2: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 3: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = true; break;

                case 4: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = false; cState.DpadRight = false; break;

                case 5: cState.DpadUp = false; cState.DpadDown = true; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 6: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 7: cState.DpadUp = true; cState.DpadDown = false; cState.DpadLeft = true; cState.DpadRight = false; break;

                case 8: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break;
                }

                cState.R3      = ((byte)inputReport[6] & (1 << 7)) != 0;
                cState.L3      = ((byte)inputReport[6] & (1 << 6)) != 0;
                cState.Options = ((byte)inputReport[6] & (1 << 5)) != 0;
                cState.Share   = ((byte)inputReport[6] & (1 << 4)) != 0;
                cState.R1      = ((byte)inputReport[6] & (1 << 1)) != 0;
                cState.L1      = ((byte)inputReport[6] & (1 << 0)) != 0;

                cState.PS           = ((byte)inputReport[7] & (1 << 0)) != 0;
                cState.TouchButton  = (inputReport[7] & (1 << 2 - 1)) != 0;
                cState.FrameCounter = (byte)(inputReport[7] >> 2);

                // Store Gyro and Accel values
                Array.Copy(inputReport, 14, accel, 0, 6);
                Array.Copy(inputReport, 20, gyro, 0, 6);
                sixAxis.handleSixaxis(gyro, accel, cState);

                try
                {
                    charging       = (inputReport[30] & 0x10) != 0;
                    battery        = (inputReport[30] & 0x0f) * 10;
                    cState.Battery = (byte)battery;
                    if (inputReport[30] != priorInputReport30)
                    {
                        priorInputReport30 = inputReport[30];
                        //Console.WriteLine(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> power subsystem octet: 0x" + inputReport[30].ToString("x02"));
                    }
                }
                catch { currerror = "Index out of bounds: battery"; }
                // XXX DS4State mapping needs fixup, turn touches into an array[4] of structs.  And include the touchpad details there instead.
                try
                {
                    for (int touches = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9)
                    {
                        cState.TouchPacketCounter = inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset];
                        cState.Touch1             = (inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected
                        cState.Touch1Identifier   = (byte)(inputReport[0 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                        cState.Touch2             = (inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // 2 touches detected
                        cState.Touch2Identifier   = (byte)(inputReport[4 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f);
                        cState.TouchLeft          = (inputReport[1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) >= 1920 * 2 / 5) ? false : true;
                        cState.TouchRight         = (inputReport[1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + DS4Touchpad.TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) < 1920 * 2 / 5) ? false : true;
                        // Even when idling there is still a touch packet indicating no touch 1 or 2
                        touchpad.handleTouchpad(inputReport, cState, touchOffset);
                    }
                }
                catch { currerror = "Index out of bounds: touchpad"; }

                /* Debug output of incoming HID data:
                 * if (cState.L2 == 0xff && cState.R2 == 0xff)
                 * {
                 *  Console.Write(MacAddress.ToString() + " " + System.DateTime.UtcNow.ToString("o") + ">");
                 *  for (int i = 0; i < inputReport.Length; i++)
                 *      Console.Write(" " + inputReport[i].ToString("x2"));
                 *  Console.WriteLine();
                 * } */
                if (!isDS4Idle())
                {
                    lastActive = utcNow;
                }
                if (conType == ConnectionType.BT)
                {
                    bool shouldDisconnect = false;
                    if (IdleTimeout > 0)
                    {
                        if (isDS4Idle())
                        {
                            DateTime timeout = lastActive + TimeSpan.FromSeconds(IdleTimeout);
                            if (!Charging)
                            {
                                shouldDisconnect = utcNow >= timeout;
                            }
                        }
                    }
                    if (shouldDisconnect && DisconnectBT())
                    {
                        return; // all done
                    }
                }
                // XXX fix initialization ordering so the null checks all go away
                if (Report != null)
                {
                    Report(this, EventArgs.Empty);
                }
                sendOutputReport(false);
                if (!string.IsNullOrEmpty(error))
                {
                    error = string.Empty;
                }
                if (!string.IsNullOrEmpty(currerror))
                {
                    error = currerror;
                }
                cState.CopyTo(pState);
            }
        }
Example #3
0
 public DS4Device(HidDevice hidDevice)
 {
     hDevice = hidDevice;
     conType = HidConnectionType(hDevice);
     Mac = hDevice.readSerial();
     if (conType == ConnectionType.USB)
     {
         inputReport = new byte[64];
         outputReport = new byte[hDevice.Capabilities.OutputReportByteLength];
         outputReportBuffer = new byte[hDevice.Capabilities.OutputReportByteLength];
     }
     else
     {
         btInputReport = new byte[BT_INPUT_REPORT_LENGTH];
         inputReport = new byte[btInputReport.Length - 2];
         outputReport = new byte[BT_OUTPUT_REPORT_LENGTH];
         outputReportBuffer = new byte[BT_OUTPUT_REPORT_LENGTH];
     }
     touchpad = new DS4Touchpad();
     sixAxis = new DS4SixAxis();
 }
Example #4
0
 public static ConnectionType HidConnectionType(HidDevice hidDevice)
 {
     return(hidDevice.Capabilities.InputReportByteLength == 64 ? ConnectionType.USB : ConnectionType.BT);
 }
Example #5
0
 public static ConnectionType HidConnectionType(HidDevice hidDevice)
 {
     return hidDevice.Capabilities.InputReportByteLength == 64 ? ConnectionType.USB : ConnectionType.BT;
 }