Beispiel #1
0
        /// <summary>
        /// Provide a description for the given capabilities.
        /// Notably describes axis on a gamepad/joystick.
        /// </summary>
        /// <param name="caps"></param>
        /// <returns></returns>
        public static string InputValueCapabilityDescription(HIDP_VALUE_CAPS caps)
        {
            if (!caps.IsRange && Enum.IsDefined(typeof(UsagePage), caps.UsagePage))
            {
                Type usageType = Utils.UsageType((UsagePage)caps.UsagePage);
                if (usageType == null)
                {
                    return("Input Value: " + Enum.GetName(typeof(UsagePage), caps.UsagePage) + " Usage 0x" + caps.NotRange.Usage.ToString("X2"));
                }

                string name = Enum.GetName(usageType, caps.NotRange.Usage);
                if (name == null)
                {
                    // Could not find that usage in our enum.
                    // Provide a relevant warning instead.
                    name = "Usage 0x" + caps.NotRange.Usage.ToString("X2") + " not defined in " + usageType.Name;
                }
                else
                {
                    // Prepend our usage type name
                    name = usageType.Name + "." + name;
                }

                return("Input Value: " + name);
            }

            return(null);
        }
Beispiel #2
0
        /// <summary>
        /// Provide the state of the dpad or hat switch if any.
        /// If no dpad is found we return 'at rest'.
        /// </summary>
        /// <returns></returns>
        public DirectionPadState GetDirectionPadState()
        {
            int index = GetValueCapabilitiesIndex((ushort)Hid.UsagePage.GenericDesktopControls, (ushort)GenericDesktop.HatSwitch);

            if (index < 0)
            {
                //No hat switch found
                return(DirectionPadState.Rest);
            }

            HIDP_VALUE_CAPS caps = Device.InputValueCapabilities[index];

            if (caps.IsRange)
            {
                //Defensive
                return(DirectionPadState.Rest);
            }

            uint dpadUsageValue = UsageValues[caps];

            if (dpadUsageValue < caps.LogicalMin || dpadUsageValue > caps.LogicalMax)
            {
                //Out of range means at rest
                return(DirectionPadState.Rest);
            }

            //Normalize value to start at zero
            //TODO: more error check here?
            DirectionPadState res = (DirectionPadState)((int)dpadUsageValue - caps.LogicalMin);

            return(res);
        }
Beispiel #3
0
        public Axis(HIDP_VALUE_CAPS aCaps)
        {
            if (aCaps.IsRange)
            {
                throw new ArgumentException("Range input values are not axis");
            }

            if (!Enum.IsDefined(typeof(UsagePage), aCaps.UsagePage))
            {
                throw new ArgumentException("Unknown axis usage page");
            }

            Type usageType = Utils.UsageType((UsagePage)aCaps.UsagePage);

            if (usageType == null)
            {
                throw new ArgumentException("Unknown axis usage type");
            }

            // Build our axis id which is combined of usage page and usage
            Id = IdFromValueCaps(aCaps);
            //
            Name     = Enum.GetName(usageType, aCaps.NotRange.Usage);
            FullName = Enum.GetName(typeof(UsagePage), aCaps.UsagePage) + "." + Name;

            Capabilities = aCaps;
        }
Beispiel #4
0
        public static string GetLinkName(this HIDP_VALUE_CAPS caps)
        {
            if (!caps.HasLink())
            {
                return("");
            }
            var pageType = Utils.UsageType((UsagePage)caps.LinkUsagePage);

            return(Enum.GetName(pageType, caps.LinkUsage) + $"({pageType.Name})[{caps.LinkCollection}]");
        }
Beispiel #5
0
        /// <summary>
        /// Utility method to check if the given input value is an axis
        /// </summary>
        /// <param name="aCaps"></param>
        /// <returns></returns>
        public static bool IsAxis(HIDP_VALUE_CAPS aCaps)
        {
            if (!aCaps.IsRange && Enum.IsDefined(typeof(UsagePage), aCaps.UsagePage))
            {
                Type usageType = Utils.UsageType((UsagePage)aCaps.UsagePage);
                if (usageType == null)
                {
                    return(false);
                }

                return(true);
            }

            return(false);
        }
Beispiel #6
0
 public static int GetLinkIndex(this HIDP_VALUE_CAPS caps) => caps.LinkCollection;
Beispiel #7
0
 public static bool HasLink(this HIDP_VALUE_CAPS caps) => caps.LinkUsage != 0;
Beispiel #8
0
        public static float ConvertUnit(this HIDP_VALUE_CAPS caps, uint value_logical, bool friendly = true)
        {
            var t = getUnitTuple(caps.Units, caps.UnitsExp, friendly);

            return(t.Item1 * ((float)caps.PhysicalMin + (caps.PhysicalMax - caps.PhysicalMin) * (value_logical - caps.LogicalMin) / (caps.LogicalMax - caps.LogicalMin)));
        }
Beispiel #9
0
 public static string GetUnit(this HIDP_VALUE_CAPS caps, bool friendly = true)
 {
     return(getUnitTuple(caps.Units, caps.UnitsExp, friendly).Item2);
 }
Beispiel #10
0
 public static bool HasUnit(this HIDP_VALUE_CAPS caps) => caps.Units != 0;
Beispiel #11
0
        public static string GetName(this HIDP_VALUE_CAPS caps)
        {
            var pageType = Utils.UsageType((UsagePage)caps.UsagePage);

            return(Enum.GetName(pageType, caps.NotRange.Usage) + $"({pageType.Name})");
        }
Beispiel #12
0
        public static TouchpadContact[] ParseInput(IntPtr lParam)
        {
            // Get RAWINPUT.
            uint rawInputSize       = 0;
            uint rawInputHeaderSize = (uint)Marshal.SizeOf <RAWINPUTHEADER>();

            if (GetRawInputData(
                    lParam,
                    RID_INPUT,
                    IntPtr.Zero,
                    ref rawInputSize,
                    rawInputHeaderSize) != 0)
            {
                return(null);
            }

            RAWINPUT rawInput;

            byte[] rawHidRawData;

            IntPtr rawInputPointer = IntPtr.Zero;

            try
            {
                rawInputPointer = Marshal.AllocHGlobal((int)rawInputSize);

                if (GetRawInputData(
                        lParam,
                        RID_INPUT,
                        rawInputPointer,
                        ref rawInputSize,
                        rawInputHeaderSize) != rawInputSize)
                {
                    return(null);
                }

                rawInput = Marshal.PtrToStructure <RAWINPUT>(rawInputPointer);

                var rawInputData = new byte[rawInputSize];
                Marshal.Copy(rawInputPointer, rawInputData, 0, rawInputData.Length);

                rawHidRawData = new byte[rawInput.Hid.dwSizeHid * rawInput.Hid.dwCount];
                int rawInputOffset = (int)rawInputSize - rawHidRawData.Length;
                Buffer.BlockCopy(rawInputData, rawInputOffset, rawHidRawData, 0, rawHidRawData.Length);
            }
            finally
            {
                Marshal.FreeHGlobal(rawInputPointer);
            }

            // Parse RAWINPUT.
            IntPtr preparsedDataPointer = IntPtr.Zero;
            IntPtr rawHidRawDataPointer = IntPtr.Zero;

            try
            {
                uint preparsedDataSize = 0;

                if (GetRawInputDeviceInfo(
                        rawInput.Header.hDevice,
                        RIDI_PREPARSEDDATA,
                        IntPtr.Zero,
                        ref preparsedDataSize) != 0)
                {
                    return(null);
                }

                preparsedDataPointer = Marshal.AllocHGlobal((int)preparsedDataSize);

                if (GetRawInputDeviceInfo(
                        rawInput.Header.hDevice,
                        RIDI_PREPARSEDDATA,
                        preparsedDataPointer,
                        ref preparsedDataSize) != preparsedDataSize)
                {
                    return(null);
                }

                if (HidP_GetCaps(
                        preparsedDataPointer,
                        out HIDP_CAPS caps) != HIDP_STATUS_SUCCESS)
                {
                    return(null);
                }

                ushort valueCapsLength = caps.NumberInputValueCaps;
                var    valueCaps       = new HIDP_VALUE_CAPS[valueCapsLength];

                if (HidP_GetValueCaps(
                        HIDP_REPORT_TYPE.HidP_Input,
                        valueCaps,
                        ref valueCapsLength,
                        preparsedDataPointer) != HIDP_STATUS_SUCCESS)
                {
                    return(null);
                }

                rawHidRawDataPointer = Marshal.AllocHGlobal(rawHidRawData.Length);
                Marshal.Copy(rawHidRawData, 0, rawHidRawDataPointer, rawHidRawData.Length);

                uint scanTime     = 0;
                uint contactCount = 0;
                TouchpadContactCreator creator  = new();
                List <TouchpadContact> contacts = new();

                foreach (var valueCap in valueCaps.OrderBy(x => x.LinkCollection))
                {
                    if (HidP_GetUsageValue(
                            HIDP_REPORT_TYPE.HidP_Input,
                            valueCap.UsagePage,
                            valueCap.LinkCollection,
                            valueCap.Usage,
                            out uint value,
                            preparsedDataPointer,
                            rawHidRawDataPointer,
                            (uint)rawHidRawData.Length) != HIDP_STATUS_SUCCESS)
                    {
                        continue;
                    }

                    // Usage Page and ID in Windows Precision Touchpad input reports
                    // https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-precision-touchpad-required-hid-top-level-collections#windows-precision-touchpad-input-reports
                    switch (valueCap.LinkCollection)
                    {
                    case 0:
                        switch (valueCap.UsagePage, valueCap.Usage)
                        {
                        case (0x0D, 0x56):                                         // Scan Time
                            scanTime = value;
                            break;

                        case (0x0D, 0x54):                                         // Contact Count
                            contactCount = value;
                            break;
                        }
                        break;
Beispiel #13
0
 public static int IdFromValueCaps(HIDP_VALUE_CAPS aCaps)
 {
     return(IdFromUsage(aCaps.UsagePage, aCaps.NotRange.Usage));
 }