Пример #1
0
        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);
        }
Пример #2
0
        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);
        }