public string readSerial() { if (serial != null) { return(serial); } // Some devices don't have MAC address (especially gamepads with USB only suports in PC). If the serial number reading fails // then use dummy zero MAC address, because there is a good chance the gamepad stll works in DS4Windows app (the code would throw // an index out of bounds exception anyway without IF-THEN-ELSE checks after trying to read a serial number). if (Capabilities.InputReportByteLength == 64) { byte[] buffer = new byte[16]; buffer[0] = 18; if (readFeatureData(buffer)) { serial = String.Format("{0:X02}:{1:X02}:{2:X02}:{3:X02}:{4:X02}:{5:X02}", buffer[6], buffer[5], buffer[4], buffer[3], buffer[2], buffer[1]); } } else { byte[] buffer = new byte[126]; #if WIN64 ulong bufferLen = 126; #else uint bufferLen = 126; #endif if (NativeMethods.HidD_GetSerialNumberString(safeReadHandle.DangerousGetHandle(), buffer, bufferLen)) { string MACAddr = System.Text.Encoding.Unicode.GetString(buffer).Replace("\0", string.Empty).ToUpper(); MACAddr = $"{MACAddr[0]}{MACAddr[1]}:{MACAddr[2]}{MACAddr[3]}:{MACAddr[4]}{MACAddr[5]}:{MACAddr[6]}{MACAddr[7]}:{MACAddr[8]}{MACAddr[9]}:{MACAddr[10]}{MACAddr[11]}"; serial = MACAddr; } } // If serial# reading failed then generate a dummy MAC address based on HID device path (WinOS generated runtime unique value based on connected usb port and hub or BT channel). // The device path remains the same as long the gamepad is always connected to the same usb/BT port, but may be different in other usb ports. Therefore this value is unique // as long the same device is always connected to the same usb port. if (serial == null) { string MACAddr = string.Empty; AppLogger.LogToGui($"WARNING: Failed to read serial# from a gamepad ({this._deviceAttributes.VendorHexId}/{this._deviceAttributes.ProductHexId}). Generating MAC address from a device path. From now on you should connect this gamepad always into the same USB port or BT pairing host to keep the same device path.", true); try { // Substring: \\?\hid#vid_054c&pid_09cc&mi_03#7&1f882A25&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030} -> \\?\hid#vid_054c&pid_09cc&mi_03#7&1f882A25&0&0001# int endPos = this.DevicePath.LastIndexOf('{'); if (endPos < 0) { endPos = this.DevicePath.Length; } // String array: \\?\hid#vid_054c&pid_09cc&mi_03#7&1f882A25&0&0001# -> [0]=\\?\hidvid_054c, [1]=pid_09cc, [2]=mi_037, [3]=1f882A25, [4]=0, [5]=0001 string[] devPathItems = this.DevicePath.Substring(0, endPos).Replace("#", "").Replace("-", "").Replace("{", "").Replace("}", "").Split('&'); if (devPathItems.Length >= 3) { MACAddr = devPathItems[devPathItems.Length - 3].ToUpper() // 1f882A25 + devPathItems[devPathItems.Length - 2].ToUpper() // 0 + devPathItems[devPathItems.Length - 1].TrimStart('0').ToUpper(); // 0001 -> 1 } else if (devPathItems.Length >= 1) { // Device and usb hub and port identifiers missing in devicePath string. Fallback to use vendor and product ID values and // take a number from the last part of the devicePath. Hopefully the last part is a usb port number as it usually should be. MACAddr = this._deviceAttributes.VendorId.ToString("X4") + this._deviceAttributes.ProductId.ToString("X4") + devPathItems[devPathItems.Length - 1].TrimStart('0').ToUpper(); } if (!string.IsNullOrEmpty(MACAddr)) { MACAddr = MACAddr.PadRight(12, '0'); serial = $"{MACAddr[0]}{MACAddr[1]}:{MACAddr[2]}{MACAddr[3]}:{MACAddr[4]}{MACAddr[5]}:{MACAddr[6]}{MACAddr[7]}:{MACAddr[8]}{MACAddr[9]}:{MACAddr[10]}{MACAddr[11]}"; } else { // Hmm... Shold never come here. Strange format in devicePath because all identifier items of devicePath string are missing. serial = BLANK_SERIAL; } } catch (Exception e) { AppLogger.LogToGui($"ERROR: Failed to generate runtime MAC address from device path {this.DevicePath}. {e.Message}", true); serial = BLANK_SERIAL; } } return(serial); }
public bool InitBezierCurve(double x1, double y1, double x2, double y2, AxisType gamepadAxisType) { bool bRetValue = true; if (arrayBezierLUT == null) { arrayBezierLUT = new byte[256]; } // Axis type and max range per axis axisType = gamepadAxisType; switch (gamepadAxisType) { case AxisType.LSRS: axisMaxDouble = 127; // DS4 LS/RS axis has a "center position" at 128. Left turn has 0..127 positions and right turn 128..255 positions axisCenterPosDouble = 128; break; case AxisType.L2R2: axisMaxDouble = 255; // L2R2 analog trigger range 0..255 axisCenterPosDouble = 0; break; default: axisMaxDouble = 128; // SixAxis x/z/y range 0..128 axisCenterPosDouble = 0; break; } // If x1 = 99.0 then this is probably just a dummy bezier curve value if (x1 == 99.0) { mX1 = 99.0; mY1 = y1; mX2 = x2; mY2 = y2; switch (y1) { case 91.0: return(InitEnhancedPrecision_91()); case 92.0: return(InitQuadric_92()); case 93.0: return(InitCubic_93()); case 94.0: return(InitEaseoutQuad_94()); case 95.0: return(InitEaseoutCubic_95()); } } if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) { // throw new Exception("INVALID VALUE. BezierCurve X1 and X2 should be in [0, 1] range"); AppLogger.LogToGui($"WARNING. Invalid custom bezier curve \"{x1}, {y1}, {x2}, {y2}\" in {gamepadAxisType} axis. x1 and x2 should be in 0..1 range. Using linear curve.", true); mX1 = mY1 = mX2 = mY2 = 0; bRetValue = false; } else { mX1 = x1; mY1 = y1; mX2 = x2; mY2 = y2; } // If this is linear definition then init the lookup table with 1-on-1 mapping if (x1 == 0 && y1 == 0 && ((x2 == 0 && y2 == 0) || (x2 == 1 && y2 == 1))) { for (int idx = 0; idx <= 255; idx++) { arrayBezierLUT[idx] = (byte)idx; } return(bRetValue); } try { arraySampleValues = new double[BezierCurve.kSplineTableSize]; for (int idx = 0; idx < BezierCurve.kSplineTableSize; idx++) { arraySampleValues[idx] = CalcBezier(idx * BezierCurve.kSampleStepSize, mX1, mX2); } // Pre-populate lookup result table for GetBezierEasing function (performance optimization) for (byte idx = 0; idx <= (byte)axisMaxDouble; idx++) { arrayBezierLUT[idx + (byte)axisCenterPosDouble] = (byte)(Global.Clamp(0, Math.Round(CalcBezier(getTForX(idx / axisMaxDouble), mY1, mY2) * axisMaxDouble), axisMaxDouble) + axisCenterPosDouble); // Invert curve from a right side of the center position (128) to the left tilted stick axis (or from up tilt to down tilt) if (gamepadAxisType == AxisType.LSRS) { arrayBezierLUT[127 - idx] = (byte)(255 - arrayBezierLUT[idx + (byte)axisCenterPosDouble]); } // If the axisMaxDouble is 255 then we need this to break the look (byte is unsigned 0..255, so the FOR loop never reaches 256 idx value. C# would throw an overflow exceptio) if (idx == axisMaxDouble) { break; } } } finally { arraySampleValues = null; } return(bRetValue); }