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) { PS4Controller.Enabled = 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; PS4Controller.Inputs = inputReport; #region f**k boi status for (int i = 0; i < inputReport.Length; i++) { //Console.Write(inputReport[i] + ", "); } //Console.WriteLine(); #endregion //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); } }
private void performEAll4Input() { 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, 0, 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[5]; cState.LY = inputReport[6]; cState.RX = inputReport[7]; cState.RY = inputReport[8]; cState.LT = inputReport[11]; cState.RT = inputReport[12]; cState.A = ((byte)inputReport[1] & Convert.ToByte(1)) != 0; cState.B = ((byte)inputReport[1] & Convert.ToByte(2)) != 0; cState.X = ((byte)inputReport[1] & Convert.ToByte(8)) != 0; cState.Y = ((byte)inputReport[1] & Convert.ToByte(16)) != 0; switch (inputReport[4]) { 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; default: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break; } cState.RS = ((byte)inputReport[2] & Convert.ToByte(64)) != 0; var leftStick = ((byte)inputReport[2] & Convert.ToByte(32)) != 0; cState.LS = leftStick; var menu = ((byte)inputReport[2] & Convert.ToByte(8)) != 0; var back = ((byte)inputReport[2] & Convert.ToByte(4)) != 0; cState.Start = menu; cState.Back = back; cState.LB = ((byte)inputReport[1] & Convert.ToByte(64)) != 0; cState.RB = ((byte)inputReport[1] & Convert.ToByte(128)) != 0; cState.Guide = menu && leftStick; // 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); } }
private void performDs4Input() { firstActive = DateTime.UtcNow; NativeMethods.HidD_SetNumInputBuffers(hDevice.safeReadHandle.DangerousGetHandle(), 2); //List<long> latencyList = new List<long>(51); // Set capacity at max + 1 to avoid any list resizing Queue <long> latencyQueue = new Queue <long>(51); // Set capacity at max + 1 to avoid any resizing int tempLatencyCount = 0; long oldtime = 0; string currerror = string.Empty; long curtime = 0; Stopwatch sw = new Stopwatch(); sw.Start(); timeoutEvent = false; int maxBatteryValue = 0; int tempBattery = 0; while (!exitInputThread) { oldCharging = charging; currerror = string.Empty; curtime = sw.ElapsedMilliseconds; this.lastTimeElapsed = curtime - oldtime; //latencyList.Add(this.lastTimeElapsed); latencyQueue.Enqueue(this.lastTimeElapsed); tempLatencyCount++; oldtime = curtime; if (tempLatencyCount > 50) { //latencyList.RemoveAt(0); latencyQueue.Dequeue(); tempLatencyCount--; } //Latency = latencyList.Average(); //latencyList.Average(); Latency = latencyQueue.Average(); if (conType == ConnectionType.BT) { //HidDevice.ReadStatus res = hDevice.ReadFile(btInputReport); //HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(btInputReport, READ_STREAM_TIMEOUT); HidDevice.ReadStatus res = hDevice.ReadWithFileStream(btInputReport); timeoutEvent = false; //HidDevice.ReadStatus res = hDevice.ReadFileOverlapped(btInputReport, READ_STREAM_TIMEOUT); if (res == HidDevice.ReadStatus.Success) { Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length); } else { if (res == HidDevice.ReadStatus.WaitTimedOut) { Log.LogToGui(Mac.ToString() + " disconnected due to timeout", true); } else { int winError = Marshal.GetLastWin32Error(); Console.WriteLine(Mac.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + winError); //Log.LogToGui(Mac.ToString() + " disconnected due to read failure: " + winError, true); } sendOutputReport(true); // Kick Windows into noticing the disconnection. StopOutputUpdate(); isDisconnecting = true; uiContext.Send(new SendOrPostCallback(delegate(object state4) { Removal?.Invoke(this, EventArgs.Empty); }), null); //System.Threading.Tasks.Task.Factory.StartNew(() => { Removal?.Invoke(this, EventArgs.Empty); }); //Removal?.Invoke(this, EventArgs.Empty); timeoutExecuted = true; return; } } else { //HidDevice.ReadStatus res = hDevice.ReadFile(inputReport); //Array.Clear(inputReport, 0, inputReport.Length); //HidDevice.ReadStatus res = hDevice.ReadAsyncWithFileStream(inputReport, READ_STREAM_TIMEOUT); HidDevice.ReadStatus res = hDevice.ReadWithFileStream(inputReport); //HidDevice.ReadStatus res = hDevice.ReadFileOverlapped(inputReport, READ_STREAM_TIMEOUT); if (res != HidDevice.ReadStatus.Success) { if (res == HidDevice.ReadStatus.WaitTimedOut) { Log.LogToGui(Mac.ToString() + " disconnected due to timeout", true); } else { int winError = Marshal.GetLastWin32Error(); Console.WriteLine(Mac.ToString() + " " + System.DateTime.UtcNow.ToString("o") + "> disconnect due to read failure: " + winError); //Log.LogToGui(Mac.ToString() + " disconnected due to read failure: " + winError, true); } StopOutputUpdate(); isDisconnecting = true; uiContext.Send(new SendOrPostCallback(delegate(object state4) { Removal?.Invoke(this, EventArgs.Empty); }), null); //System.Threading.Tasks.Task.Factory.StartNew(() => { Removal?.Invoke(this, EventArgs.Empty); }); //Removal?.Invoke(this, EventArgs.Empty); timeoutExecuted = true; return; } else { //Array.Copy(inputReport2, 0, inputReport, 0, inputReport.Length); } } if (conType == ConnectionType.BT && btInputReport[0] != 0x11) { //Received incorrect report, skip it continue; } DateTime utcNow = 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 = (inputReport[5] & (1 << 7)) != 0; cState.Circle = (inputReport[5] & (1 << 6)) != 0; cState.Cross = (inputReport[5] & (1 << 5)) != 0; cState.Square = (inputReport[5] & (1 << 4)) != 0; // First 4 bits denote dpad state. Clock representation // with 8 meaning centered and 0 meaning DpadUp. byte dpad_state = (byte)(inputReport[5] & 0x0F); 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: default: cState.DpadUp = false; cState.DpadDown = false; cState.DpadLeft = false; cState.DpadRight = false; break; } cState.R3 = (inputReport[6] & (1 << 7)) != 0; cState.L3 = (inputReport[6] & (1 << 6)) != 0; cState.Options = (inputReport[6] & (1 << 5)) != 0; cState.Share = (inputReport[6] & (1 << 4)) != 0; cState.R1 = (inputReport[6] & (1 << 1)) != 0; cState.L1 = (inputReport[6] & (1 << 0)) != 0; cState.PS = (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; maxBatteryValue = charging ? BATTERY_MAX_USB : BATTERY_MAX; tempBattery = (inputReport[30] & 0x0f) * 100 / maxBatteryValue; battery = Math.Min((byte)tempBattery, (byte)100); cState.Battery = (byte)battery; //System.Diagnostics.Debug.WriteLine("CURRENT BATTERY: " + (inputReport[30] & 0x0f) + " | " + tempBattery + " | " + 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 { // Only care if one touch packet is detected. Other touch packets // don't seem to contain relevant data. ds4drv does not use them either. for (int touches = Math.Max((int)(inputReport[-1 + DS4Touchpad.TOUCHPAD_DATA_OFFSET - 1]), 1), touchOffset = 0; touches > 0; touches--, touchOffset += 9) //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 (conType == ConnectionType.SONYWA) { bool controllerSynced = inputReport[31] == 0; if (controllerSynced != synced) { synced = controllerSynced; SyncChange?.Invoke(this, EventArgs.Empty); } } bool ds4Idle = cState.FrameCounter == pState.FrameCounter; if (!ds4Idle) { isRemoved = false; } if (conType == ConnectionType.USB) { lastActive = utcNow; } else { bool shouldDisconnect = false; int idleTime = idleTimeout; if (!isRemoved && idleTime > 0) { bool idleInput = isDS4Idle(); if (idleInput) { DateTime timeout = lastActive + TimeSpan.FromSeconds(idleTime); if (!charging) { shouldDisconnect = utcNow >= timeout; } } else { lastActive = utcNow; } } else { lastActive = utcNow; } if (shouldDisconnect) { Log.LogToGui(Mac.ToString() + " disconnecting due to idle disconnect", false); if (conType == ConnectionType.BT) { if (DisconnectBT(true)) { timeoutExecuted = true; return; // all done } } else if (conType == ConnectionType.SONYWA) { DisconnectDongle(); } } } if (oldCharging != charging && conType == ConnectionType.BT) { if (Global.getQuickCharge() && charging) { DisconnectBT(true); timeoutExecuted = true; return; } } if (Report != null) { Report(this, EventArgs.Empty); } bool syncWriteReport = true; if (conType == ConnectionType.BT) { syncWriteReport = false; } sendOutputReport(syncWriteReport); if (!string.IsNullOrEmpty(currerror)) { error = currerror; } else if (!string.IsNullOrEmpty(error)) { error = string.Empty; } cState.CopyTo(pState); lock (eventQueueLock) { Action tempAct = null; for (int actInd = 0, actLen = eventQueue.Count; actInd < actLen; actInd++) //foreach (Action tempAct in eventQueue) { tempAct = eventQueue.Dequeue(); tempAct.Invoke(); } //eventQueue.Clear(); } } timeoutExecuted = true; }
private void InputListener() { //if (settings.getSetting("Low latency mode")) // inputReport = new byte[10]; byte[] accel = new byte[6]; byte[] gyro = new byte[6]; Thread.Sleep(500); sendHaptic(); bool isResponding = true; lastReport.Start(); while (isResponding) { if (!isDeviceResponding(hDevice)) { Dispose(); } if (DeviceConnectionType == ConnectionTypes.BT) { HidDevice.ReadStatus readStatus = hDevice.ReadFile(btInputReport); if (readStatus == HidDevice.ReadStatus.Success) { Array.Copy(btInputReport, 2, inputReport, 0, inputReport.Length); } else { isResponding = false; } } else if (DeviceConnectionType == ConnectionTypes.USB) { HidDevice.ReadStatus readStatus = hDevice.ReadFile(inputReport); if (readStatus != HidDevice.ReadStatus.Success) { isResponding = false; } } if (isResponding) { lastReport.Restart(); } deviceClass.LSx.Value = SafeStickValue(inputReport[1] - 127) / 127f; deviceClass.LSy.Value = SafeStickValue(inputReport[2] - 127) / 127f; deviceClass.RSx.Value = SafeStickValue(inputReport[3] - 127) / 127f; deviceClass.RSy.Value = SafeStickValue(inputReport[4] - 127) / 127f; deviceClass.L2.Value = inputReport[8] / 255f; deviceClass.R2.Value = inputReport[9] / 255f; deviceClass.Triangle.Value = ((byte)inputReport[5] & (1 << 7)) != 0; deviceClass.Circle.Value = ((byte)inputReport[5] & (1 << 6)) != 0; deviceClass.Cross.Value = ((byte)inputReport[5] & (1 << 5)) != 0; deviceClass.Square.Value = ((byte)inputReport[5] & (1 << 4)) != 0; bool RDpadUp = ((byte)inputReport[5] & (1 << 3)) != 0; bool RDpadDown = ((byte)inputReport[5] & (1 << 2)) != 0; bool RDpadLeft = ((byte)inputReport[5] & (1 << 1)) != 0; bool RDpadRight = ((byte)inputReport[5] & (1 << 0)) != 0; byte dpad_state = 0; dpad_state = (byte)( ((RDpadRight ? 1 : 0) << 0) | ((RDpadLeft ? 1 : 0) << 1) | ((RDpadDown ? 1 : 0) << 2) | ((RDpadUp ? 1 : 0) << 3)); switch (dpad_state) { case 0: deviceClass.DUp.Value = true; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = false; break; case 1: deviceClass.DUp.Value = true; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = true; break; case 2: deviceClass.DUp.Value = false; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = true; break; case 3: deviceClass.DUp.Value = false; deviceClass.DDown.Value = true; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = true; break; case 4: deviceClass.DUp.Value = false; deviceClass.DDown.Value = true; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = false; break; case 5: deviceClass.DUp.Value = false; deviceClass.DDown.Value = true; deviceClass.DLeft.Value = true; deviceClass.DRight.Value = false; break; case 6: deviceClass.DUp.Value = false; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = true; deviceClass.DRight.Value = false; break; case 7: deviceClass.DUp.Value = true; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = true; deviceClass.DRight.Value = false; break; case 8: deviceClass.DUp.Value = false; deviceClass.DDown.Value = false; deviceClass.DLeft.Value = false; deviceClass.DRight.Value = false; break; } deviceClass.R3.Value = ((byte)inputReport[6] & (1 << 7)) != 0; deviceClass.L3.Value = ((byte)inputReport[6] & (1 << 6)) != 0; deviceClass.Options.Value = ((byte)inputReport[6] & (1 << 5)) != 0; deviceClass.Share.Value = ((byte)inputReport[6] & (1 << 4)) != 0; deviceClass.R1.Value = ((byte)inputReport[6] & (1 << 1)) != 0; deviceClass.L1.Value = ((byte)inputReport[6] & (1 << 0)) != 0; deviceClass.PS.Value = ((byte)inputReport[7] & (1 << 0)) != 0; deviceClass.TouchpadButton.Value = (inputReport[7] & (1 << 2 - 1)) != 0; Array.Copy(inputReport, 14, accel, 0, 6); Array.Copy(inputReport, 20, gyro, 0, 6); bool charging = (inputReport[30] & 0x10) != 0; float battery = (inputReport[30] & 0x0f) / 10; if (!charging) { battery += 10; } battery = Math.Max(battery, 0f); battery = Math.Min(battery, 1f); deviceClass.Charging.Value = charging; deviceClass.Battery.Value = battery; deviceClass.AccelX.Value = (Int16)((UInt16)(accel[0] << 8) | accel[1]) / 65535f; deviceClass.AccelY.Value = (Int16)((UInt16)(accel[2] << 8) | accel[3]) / 65535f; deviceClass.AccelZ.Value = (Int16)((UInt16)(accel[4] << 8) | accel[5]) / 65535f; deviceClass.GyroX.Value = (Int16)((UInt16)(gyro[0] << 8) | gyro[1]) / 65535f; deviceClass.GyroY.Value = (Int16)((UInt16)(gyro[2] << 8) | gyro[3]) / 65535f; deviceClass.GyroZ.Value = (Int16)((UInt16)(gyro[4] << 8) | gyro[5]) / 65535f; for (int touches = inputReport[-1 + TOUCHPAD_DATA_OFFSET - 1], touchOffset = 0; touches > 0; touches--, touchOffset += 9) { //TouchPacketCounter = inputReport[-1 + TOUCHPAD_DATA_OFFSET + touchOffset]; deviceClass.TouchpadTouchOne.Value = (inputReport[0 + TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // >= 1 touch detected //Touch1Identifier = (byte)(inputReport[0 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f); deviceClass.TouchpadTouchTwo.Value = (inputReport[4 + TOUCHPAD_DATA_OFFSET + touchOffset] >> 7) != 0 ? false : true; // 2 touches detected //Touch2Identifier = (byte)(inputReport[4 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7f); byte touchID1 = (byte)(inputReport[0 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7F); byte touchID2 = (byte)(inputReport[4 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0x7F); deviceClass.TouchpadTouchOneX.Value = (inputReport[1 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255)) / 1920f; deviceClass.TouchpadTouchOneY.Value = (((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF0) >> 4) + (inputReport[3 + TOUCHPAD_DATA_OFFSET + touchOffset] * 16)) / 950f; deviceClass.TouchpadTouchTwoX.Value = (inputReport[5 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[6 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255)) / 1920f; deviceClass.TouchpadTouchTwoY.Value = (((inputReport[6 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF0) >> 4) + (inputReport[7 + TOUCHPAD_DATA_OFFSET + touchOffset] * 16)) / 950f; //if (cState.Touch1) //{ // cState.TouchLeft = (inputReport[1 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + TOUCHPAD_DATA_OFFSET + touchOffset] & 0xF) * 255) >= 1920 * 2 / 5) ? false : true; // cState.TouchRight = (inputReport[1 + TOUCHPAD_DATA_OFFSET + touchOffset] + ((inputReport[2 + 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); } //Console.WriteLine((((byte)255 << 8) | (byte)255)); } Dispose(); }