void ParseMain(MainItemTag tag, uint value)
        {
            LocalIndexes indexes = null;

            switch (tag)
            {
            case MainItemTag.Collection:
                ReportCollection collection = new ReportCollection();
                collection.Parent = CurrentCollection;
                collection.Type   = (CollectionType)value;
                CurrentCollection = collection;
                indexes           = collection.Indexes;
                break;

            case MainItemTag.EndCollection:
                CurrentCollection = CurrentCollection.Parent;
                break;

            case MainItemTag.Input:
            case MainItemTag.Output:
            case MainItemTag.Feature:
                ParseDataMain(tag, value, out indexes);
                break;
            }

            if (indexes != null)
            {
                ParseMainIndexes(indexes);
            }
        }
Exemplo n.º 2
0
 public void AddMainItem(MainItemTag mainItemTag, uint dataValue)
 {
     _items.Add(new EncodedItem()
     {
         ItemType = ItemType.Main, TagForMain = mainItemTag, DataValue = dataValue
     });
 }
        void ParseDataMain(MainItemTag tag, uint value, out LocalIndexes indexes)
        {
            ReportSegment segment = new ReportSegment();

            segment.Flags        = (DataMainItemFlags)value;
            segment.Parent       = CurrentCollection;
            segment.ElementCount = (int)GetGlobalItemValue(GlobalItemTag.ReportCount);
            segment.ElementSize  = (int)GetGlobalItemValue(GlobalItemTag.ReportSize);
            segment.Unit         = new Units.Unit(GetGlobalItemValue(GlobalItemTag.Unit));
            segment.UnitExponent = Units.Unit.DecodeExponent(GetGlobalItemValue(GlobalItemTag.UnitExponent));
            indexes = segment.Indexes;

            EncodedItem logicalMinItem = GetGlobalItem(GlobalItemTag.LogicalMinimum);
            EncodedItem logicalMaxItem = GetGlobalItem(GlobalItemTag.LogicalMaximum);

            segment.LogicalIsSigned =
                (logicalMinItem != null && logicalMinItem.DataValueMayBeNegative) ||
                (logicalMaxItem != null && logicalMaxItem.DataValueMayBeNegative);
            int logicalMinimum  = logicalMinItem == null ? 0 : segment.LogicalIsSigned ? logicalMinItem.DataValueSigned : (int)logicalMinItem.DataValue;
            int logicalMaximum  = logicalMaxItem == null ? 0 : segment.LogicalIsSigned ? logicalMaxItem.DataValueSigned : (int)logicalMaxItem.DataValue;
            int physicalMinimum = (int)GetGlobalItemValue(GlobalItemTag.PhysicalMinimum);
            int physicalMaximum = (int)GetGlobalItemValue(GlobalItemTag.PhysicalMaximum);

            if (!IsGlobalItemSet(GlobalItemTag.PhysicalMinimum) ||
                !IsGlobalItemSet(GlobalItemTag.PhysicalMaximum) ||
                (physicalMinimum == 0 && physicalMaximum == 0))
            {
                physicalMinimum = logicalMinimum;
                physicalMaximum = logicalMaximum;
            }

            segment.LogicalMinimum  = logicalMinimum;
            segment.LogicalMaximum  = logicalMaximum;
            segment.PhysicalMinimum = physicalMinimum;
            segment.PhysicalMaximum = physicalMaximum;

            Report     report;
            ReportType reportType
                = tag == MainItemTag.Output ? ReportType.Output
                : tag == MainItemTag.Feature ? ReportType.Feature
                : ReportType.Input;
            uint reportID = GetGlobalItemValue(GlobalItemTag.ReportID);

            if (!TryGetReport(reportType, (byte)reportID, out report))
            {
                report = new Report()
                {
                    ID   = (byte)reportID,
                    Type = reportType
                };
                Reports.Add(report);
            }
            segment.Report = report;
        }
        void ParseMain(MainItemTag tag, uint value)
        {
            switch (tag)
            {
            case MainItemTag.Collection:
                ParseMainCollection(value); break;

            case MainItemTag.EndCollection:
                ParseMainCollectionEnd(); break;

            case MainItemTag.Input:
            case MainItemTag.Output:
            case MainItemTag.Feature:
                ParseMainData(tag, value); break;
            }
        }
Exemplo n.º 5
0
            void PadReport(MainItemTag mainItemTag, int padToBit, ref int currentBit)
            {
                if (currentBit > padToBit)
                {
                    throw new NotImplementedException();
                }                                                                   // Overlapping...

                // Padding...
                int paddingBitCount = padToBit - currentBit;

                if (paddingBitCount > 0)
                {
                    AddButtonGlobalItems(paddingBitCount);
                    _builder.AddMainItem(mainItemTag, (uint)(DataItemFlags.Constant | DataItemFlags.Variable));
                    currentBit += paddingBitCount;
                }
            }
        void ParseMainData(MainItemTag tag, uint value)
        {
            DataItem dataItem = new DataItem();

            dataItem.Flags        = (DataItemFlags)value;
            dataItem.ParentItem   = State.CurrentCollectionItem;
            dataItem.ElementCount = (int)State.GetGlobalItemValue(GlobalItemTag.ReportCount);
            dataItem.ElementBits  = (int)State.GetGlobalItemValue(GlobalItemTag.ReportSize);
            dataItem.Unit         = new Units.Unit(State.GetGlobalItemValue(GlobalItemTag.Unit));
            dataItem.UnitExponent = Units.Unit.DecodeExponent(State.GetGlobalItemValue(GlobalItemTag.UnitExponent));

            EncodedItem logicalMinItem = State.GetGlobalItem(GlobalItemTag.LogicalMinimum);
            EncodedItem logicalMaxItem = State.GetGlobalItem(GlobalItemTag.LogicalMaximum);

            dataItem.IsLogicalSigned = !dataItem.IsArray && ((logicalMinItem != null ? logicalMinItem.DataValue : 0) > (logicalMaxItem != null ? logicalMaxItem.DataValue : 0));
            int logicalMinimum = logicalMinItem == null ? 0 : dataItem.IsLogicalSigned ? logicalMinItem.DataValueSigned : (int)logicalMinItem.DataValue;
            int logicalMaximum = logicalMaxItem == null ? 0 : dataItem.IsLogicalSigned ? logicalMaxItem.DataValueSigned : (int)logicalMaxItem.DataValue;

            EncodedItem physicalMinItem  = State.GetGlobalItem(GlobalItemTag.PhysicalMinimum);
            EncodedItem physicalMaxItem  = State.GetGlobalItem(GlobalItemTag.PhysicalMaximum);
            bool        isPhysicalSigned = !dataItem.IsArray && ((physicalMinItem != null ? physicalMinItem.DataValue : 0) > (physicalMaxItem != null ? physicalMaxItem.DataValue : 0));
            int         physicalMinimum  = physicalMinItem == null ? 0 : isPhysicalSigned ? physicalMinItem.DataValueSigned : (int)physicalMinItem.DataValue;
            int         physicalMaximum  = physicalMaxItem == null ? 0 : isPhysicalSigned ? physicalMaxItem.DataValueSigned : (int)physicalMaxItem.DataValue;

            if (physicalMinimum == 0 && physicalMaximum == 0)
            {
                physicalMinimum = logicalMinimum; physicalMaximum = logicalMaximum;
            }

            dataItem.LogicalMinimum     = logicalMinimum; dataItem.LogicalMaximum = logicalMaximum;
            dataItem.RawPhysicalMinimum = physicalMinimum; dataItem.RawPhysicalMaximum = physicalMaximum;

            Report     report;
            ReportType reportType
                = tag == MainItemTag.Output ? ReportType.Output
                : tag == MainItemTag.Feature ? ReportType.Feature
                : ReportType.Input;
            uint reportID = State.GetGlobalItemValue(GlobalItemTag.ReportID);

            if (!TryGetReport(reportType, (byte)reportID, out report))
            {
                report = new Report()
                {
                    ReportID = (byte)reportID, ReportType = reportType
                };
                Reports.Add(report);

                var collection = State.CurrentCollectionItem;
                while (collection != null && !(collection is DeviceItem))
                {
                    collection = collection.ParentItem;
                }
                if (collection is DeviceItem)
                {
                    ((DeviceItem)collection).Reports.Add(report);
                }
            }
            report.DataItems.Add(dataItem);

            ParseMainIndexes(dataItem);
        }
        void ParseDataMain(MainItemTag tag, uint value, out LocalIndexes indexes)
        {
            ReportSegment segment = new ReportSegment();
            segment.Flags = (DataMainItemFlags)value;
            segment.Parent = CurrentCollection;
            segment.ElementCount = (int)GetGlobalItemValue(GlobalItemTag.ReportCount);
            segment.ElementSize = (int)GetGlobalItemValue(GlobalItemTag.ReportSize);
            segment.Unit = new Units.Unit(GetGlobalItemValue(GlobalItemTag.Unit));
            segment.UnitExponent = Units.Unit.DecodeExponent(GetGlobalItemValue(GlobalItemTag.UnitExponent));
            indexes = segment.Indexes;

            EncodedItem logicalMinItem = GetGlobalItem(GlobalItemTag.LogicalMinimum);
            EncodedItem logicalMaxItem = GetGlobalItem(GlobalItemTag.LogicalMaximum);
            segment.LogicalIsSigned =
                (logicalMinItem != null && logicalMinItem.DataValueMayBeNegative) ||
                (logicalMaxItem != null && logicalMaxItem.DataValueMayBeNegative);
            int logicalMinimum = logicalMinItem == null ? 0 : segment.LogicalIsSigned ? logicalMinItem.DataValueSigned : (int)logicalMinItem.DataValue;
            int logicalMaximum = logicalMaxItem == null ? 0 : segment.LogicalIsSigned ? logicalMaxItem.DataValueSigned : (int)logicalMaxItem.DataValue;
            int physicalMinimum = (int)GetGlobalItemValue(GlobalItemTag.PhysicalMinimum);
            int physicalMaximum = (int)GetGlobalItemValue(GlobalItemTag.PhysicalMaximum);
            if (!IsGlobalItemSet(GlobalItemTag.PhysicalMinimum) ||
                !IsGlobalItemSet(GlobalItemTag.PhysicalMaximum) ||
                (physicalMinimum == 0 && physicalMaximum == 0))
            {
                physicalMinimum = logicalMinimum; physicalMaximum = logicalMaximum;
            }

            segment.LogicalMinimum = logicalMinimum; segment.LogicalMaximum = logicalMaximum;
            segment.PhysicalMinimum = physicalMinimum; segment.PhysicalMaximum = physicalMaximum;

            Report report;
            ReportType reportType
                = tag == MainItemTag.Output ? ReportType.Output
                : tag == MainItemTag.Feature ? ReportType.Feature
                : ReportType.Input;
            uint reportID = GetGlobalItemValue(GlobalItemTag.ReportID);
            if (!TryGetReport(reportType, (byte)reportID, out report))
            {
                report = new Report() { ID = (byte)reportID, Type = reportType };
                Reports.Add(report);
            }
            segment.Report = report;
        }
        void ParseMain(MainItemTag tag, uint value)
        {
            LocalIndexes indexes = null;

            switch (tag)
            {
                case MainItemTag.Collection:
                    ReportCollection collection = new ReportCollection();
                    collection.Parent = CurrentCollection;
                    collection.Type = (CollectionType)value;
                    CurrentCollection = collection;
                    indexes = collection.Indexes; break;

                case MainItemTag.EndCollection:
                    CurrentCollection = CurrentCollection.Parent; break;

                case MainItemTag.Input:
                case MainItemTag.Output:
                case MainItemTag.Feature:
                    ParseDataMain(tag, value, out indexes); break;
            }

            if (indexes != null) { ParseMainIndexes(indexes); }
        }
Exemplo n.º 9
0
            void EncodeReports(NativeMethods.HIDP_REPORT_TYPE reportType, MainItemTag mainItemTag)
            {
                var types       = _types[(int)reportType];
                var reportBytes = new byte[types.ReportLength];

                var reports = types.Items.GroupBy(y => y.Item.ReportID);

                foreach (var report in reports)
                {
                    var reportID       = report.Key;
                    var reportItemList = report.ToArray();

                    if (reportID != 0)
                    {
                        _builder.AddGlobalItem(GlobalItemTag.ReportID, reportID);
                    }

                    int maxBit = (reportBytes.Length - 1) * 8;

                    // Determine the location of all report items.
                    for (int reportItemIndex = 0; reportItemIndex < reportItemList.Length; reportItemIndex++)
                    {
                        var reportItem = reportItemList[reportItemIndex];

                        var button = reportItem.Button;
                        var item   = reportItem.Item;
                        if (item.IsAlias != 0)
                        {
                            throw new NotImplementedException();
                        }
                        var flags = (DataItemFlags)item.BitField;

                        int dataIndexCount = (item.IsRange != 0) ? item.DataIndexMax - item.DataIndex + 1 : 1;
                        if (button)
                        {
                            reportItem.ReportCount = dataIndexCount;
                            reportItem.ReportSize  = 1;
                        }
                        else
                        {
                            reportItem.ReportCount = item.VALUE_ReportCount;
                            reportItem.ReportSize  = item.VALUE_ReportSize;
                        }

                        InitData(reportBytes, reportID);
                        if (dataIndexCount == reportItem.ReportCount)
                        {
                            // Individual fields...
                            var dataList = new NativeMethods.HIDP_DATA()
                            {
                                DataIndex = item.DataIndex, RawValue = 0xffffffffu
                            }; int dataCount = 1;
                            int    hr        = NativeMethods.HidP_SetData(reportType, ref dataList, ref dataCount, _preparsed, reportBytes, reportBytes.Length);
                            if (hr == NativeMethods.HIDP_STATUS_SUCCESS)
                            {
                                GetDataStartBit(reportBytes, reportItem, maxBit);
                            }
                            else if (hr == NativeMethods.HIDP_STATUS_IS_VALUE_ARRAY)
                            {
                                // TODO
                                reportItem.BitOffset = maxBit;

                                // According to https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/button-capability-arrays#button-usages-in-a-variable-main-item:

                                /*
                                 *  If the number of usages specified for a variable item is less than the number of buttons in the item,
                                 *  the capability array contains only one capability structure that describes one button usage (the last
                                 *  usage specified in the report descriptor for the variable main item). However, see Usage Value Array
                                 *  for information about usage values that have a report count greater than one.
                                 */
                                // How to reconstruct it, then? The following does not work:

                                /*
                                 * var usage = (ushort)item.UsageIndex; int usageCount = 1;
                                 * hr = NativeMethods.HidP_SetUsages(reportType, item.UsagePage, 0, ref usage, ref usageCount, _preparsed, reportBytes, reportBytes.Length);
                                 * if (hr != NativeMethods.HIDP_STATUS_SUCCESS) { throw new NotImplementedException(); }
                                 */
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                        else if (dataIndexCount == 1)
                        {
                            // Array...
                            int bitCount   = reportItem.ReportCount * reportItem.ReportSize;
                            var usageValue = new byte[(bitCount + 7) / 8];
                            for (int i = 0; i < usageValue.Length; i++)
                            {
                                usageValue[i] = 0xff;
                            }
                            int hr = NativeMethods.HidP_SetUsageValueArray(reportType, item.UsagePage, item.LinkCollection, item.UsageIndex, usageValue, (ushort)usageValue.Length, _preparsed, reportBytes, reportBytes.Length);
                            if (hr == NativeMethods.HIDP_STATUS_SUCCESS)
                            {
                                GetDataStartBit(reportBytes, reportItem, maxBit);
                            }
                            else
                            {
                                // TODO need to set the usage value array here instead

                                // but we only want to find the bit offset, let's just do an educated guess
                                if (reportItemIndex == 0)
                                {
                                    reportItem.BitOffset = 0;
                                }
                                else
                                {
                                    var prevItem = reportItemList[reportItemIndex - 1];
                                    reportItem.BitOffset = prevItem.BitOffset + prevItem.ReportCount * prevItem.ReportSize;
                                }
                            }
                        }
                        else
                        {
                            // Not sure...
                            reportItem.BitOffset = maxBit;
                        }
                    }

                    // Write the report descriptors.
                    int currentBit = 0;

                    var reportItems = report.Where(x => x.BitOffset != maxBit).OrderBy(x => x.BitOffset).ToArray();
                    foreach (var reportItem in reportItems)
                    {
                        var button   = reportItem.Button;
                        var item     = reportItem.Item;
                        int startBit = reportItem.BitOffset;
                        int bitCount = reportItem.ReportCount * reportItem.ReportSize;
                        if (currentBit > startBit)
                        {
                            throw new NotImplementedException();
                        }                                                                   // Overlapping...

                        SetCollection(item.LinkCollection);
                        PadReport(mainItemTag, startBit, ref currentBit);

                        // The entry...
                        _builder.AddGlobalItem(GlobalItemTag.UsagePage, item.UsagePage);

                        uint usageMin = item.UsageIndex, usageMax = (item.IsRange != 0) ? item.UsageMax : usageMin;
                        if (item.IsRange != 0)
                        {
                            _builder.AddLocalItem(LocalItemTag.UsageMinimum, usageMin);
                            _builder.AddLocalItem(LocalItemTag.UsageMaximum, usageMax);
                        }
                        else
                        {
                            _builder.AddLocalItem(LocalItemTag.Usage, usageMin);
                        }

                        if (button)
                        {
                            AddButtonGlobalItems(reportItem.ReportCount);
                        }
                        else
                        {
                            _builder.AddGlobalItemSigned(GlobalItemTag.LogicalMinimum, item.VALUE_LogicalMin);
                            _builder.AddGlobalItemSigned(GlobalItemTag.LogicalMaximum, item.VALUE_LogicalMax);
                            _builder.AddGlobalItemSigned(GlobalItemTag.PhysicalMinimum, item.VALUE_PhysicalMin);
                            _builder.AddGlobalItemSigned(GlobalItemTag.PhysicalMaximum, item.VALUE_PhysicalMax);
                            _builder.AddGlobalItem(GlobalItemTag.Unit, item.VALUE_Units);
                            _builder.AddGlobalItem(GlobalItemTag.UnitExponent, item.VALUE_UnitsExp);
                            _builder.AddGlobalItem(GlobalItemTag.ReportSize, (uint)reportItem.ReportSize);
                            _builder.AddGlobalItem(GlobalItemTag.ReportCount, (uint)reportItem.ReportCount);
                        }
                        _builder.AddMainItem(mainItemTag, item.BitField);

                        currentBit += bitCount;
                    }

                    PadReport(mainItemTag, maxBit, ref currentBit);
                }
            }