Exemplo n.º 1
0
            void GetReportCaps(NativeMethods.HIDP_REPORT_TYPE reportType, ushort buttonCount, ushort valueCount, ushort reportLength)
            {
                var caps = new ReportCaps(); ushort count;
                var buttons = new NativeMethods.HIDP_DATA_CAPS[buttonCount];
                var values  = new NativeMethods.HIDP_DATA_CAPS[valueCount];

                count = buttonCount;
                if (count > 0)
                {
                    if (NativeMethods.HidP_GetButtonCaps(reportType, buttons, ref count, _preparsed) != NativeMethods.HIDP_STATUS_SUCCESS || count != buttonCount)
                    {
                        throw new NotImplementedException();
                    }
                }

                count = valueCount;
                if (count > 0)
                {
                    if (NativeMethods.HidP_GetValueCaps(reportType, values, ref count, _preparsed) != NativeMethods.HIDP_STATUS_SUCCESS || count != valueCount)
                    {
                        throw new NotImplementedException();
                    }
                }

                caps.Items = buttons.Select(b => new ItemCaps()
                {
                    Button = true, Item = b
                })
                             .Concat(values.Select(v => new ItemCaps()
                {
                    Button = false, Item = v
                }))
                             .ToArray();
                caps.ReportLength       = reportLength;
                _types[(int)reportType] = caps;
            }
Exemplo n.º 2
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);
                }
            }