Chromium Code Reviews| Index: device/hid/hid_report_descriptor.h |
| diff --git a/device/hid/hid_report_descriptor.h b/device/hid/hid_report_descriptor.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..2d06b08641e54d844328f3ecde099b60dc311ba8 |
| --- /dev/null |
| +++ b/device/hid/hid_report_descriptor.h |
| @@ -0,0 +1,803 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef DEVICE_HID_HID_REPORT_DESCRIPTOR_H_ |
| +#define DEVICE_HID_HID_REPORT_DESCRIPTOR_H_ |
| + |
| +#include <sstream> |
| +#include <vector> |
| + |
| +#include "base/basictypes.h" |
| +#include "device/hid/hid_usage_and_page.h" |
| + |
| +namespace device { |
| + |
| +// An element of a HID report descriptor. |
| +class HidReportDescriptorItem { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
I think this is large enough that it deserves its
jracle (use Gerrit)
2014/04/16 16:39:19
Sure, done.
|
| + |
| +#pragma pack(push, 1) |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please do not use packed structs to map onto a dat
jracle (use Gerrit)
2014/04/16 16:39:19
Got your point, I will refactor in next patch set.
|
| + |
| + public: |
| + enum Type { |
| + kTypeMain = 0, |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please move Type into the next public block since
|
| + kTypeGlobal = 1, |
| + kTypeLocal = 2, |
| + kTypeReserved = 3 |
| + }; |
| + |
| + private: |
| + // Tags |
| + |
| + enum MainTag { |
| + kMainTagDefault = 0x00, // 0000 |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
As these are only used internally, please move the
|
| + kMainTagInput = 0x08, // 1000 |
| + kMainTagOutput = 0x09, // 1001 |
| + kMainTagFeature = 0x0B, // 1011 |
| + kMainTagCollection = 0x0A, // 1010 |
| + kMainTagEndCollection = 0x0C // 1100 |
| + }; |
| + |
| + enum GlobalTag { |
| + kGlobalTagUsagePage = 0x00, // 0000 |
| + kGlobalTagLogicalMinimum = 0x01, // 0001 |
| + kGlobalTagLogicalMaximum = 0x02, // 0010 |
| + kGlobalTagPhysicalMinimum = 0x03, // 0011 |
| + kGlobalTagPhysicalMaximum = 0x04, // 0100 |
| + kGlobalTagUnitExponent = 0x05, // 0101 |
| + kGlobalTagUnit = 0x06, // 0110 |
| + kGlobalTagReportSize = 0x07, // 0111 |
| + kGlobalTagReportId = 0x08, // 1000 |
| + kGlobalTagReportCount = 0x09, // 1001 |
| + kGlobalTagPush = 0x0A, // 1010 |
| + kGlobalTagPop = 0x0B // 1011 |
| + }; |
| + |
| + enum LocalTag { |
| + kLocalTagUsage = 0x00, // 0000 |
| + kLocalTagUsageMinimum = 0x01, // 0001 |
| + kLocalTagUsageMaximum = 0x02, // 0010 |
| + kLocalTagDesignatorIndex = 0x03, // 0011 |
| + kLocalTagDesignatorMinimum = 0x04, // 0100 |
| + kLocalTagDesignatorMaximum = 0x05, // 0101 |
| + kLocalTagStringIndex = 0x07, // 0111 |
| + kLocalTagStringMinimum = 0x08, // 1000 |
| + kLocalTagStringMaximum = 0x09, // 1001 |
| + kLocalTagDelimiter = 0x0A // 1010 |
| + }; |
| + |
| + enum ReservedTag { |
| + kReservedTagLong = 0xF // 1111 |
| + }; |
| + |
| + public: |
| + enum Tag { |
| + kTagDefault = kMainTagDefault << 2 | kTypeMain, |
| + kTagInput = kMainTagInput << 2 | kTypeMain, |
| + kTagOutput = kMainTagOutput << 2 | kTypeMain, |
| + kTagFeature = kMainTagFeature << 2 | kTypeMain, |
| + kTagCollection = kMainTagCollection << 2 | kTypeMain, |
| + kTagEndCollection = kMainTagEndCollection << 2 | kTypeMain, |
| + kTagUsagePage = kGlobalTagUsagePage << 2 | kTypeGlobal, |
| + kTagLogicalMinimum = kGlobalTagLogicalMinimum << 2 | kTypeGlobal, |
| + kTagLogicalMaximum = kGlobalTagLogicalMaximum << 2 | kTypeGlobal, |
| + kTagPhysicalMinimum = kGlobalTagPhysicalMinimum << 2 | kTypeGlobal, |
| + kTagPhysicalMaximum = kGlobalTagPhysicalMaximum << 2 | kTypeGlobal, |
| + kTagUnitExponent = kGlobalTagUnitExponent << 2 | kTypeGlobal, |
| + kTagUnit = kGlobalTagUnit << 2 | kTypeGlobal, |
| + kTagReportSize = kGlobalTagReportSize << 2 | kTypeGlobal, |
| + kTagReportId = kGlobalTagReportId << 2 | kTypeGlobal, |
| + kTagReportCount = kGlobalTagReportCount << 2 | kTypeGlobal, |
| + kTagPush = kGlobalTagPush << 2 | kTypeGlobal, |
| + kTagPop = kGlobalTagPop << 2 | kTypeGlobal, |
| + kTagUsage = kLocalTagUsage << 2 | kTypeLocal, |
| + kTagUsageMinimum = kLocalTagUsageMinimum << 2 | kTypeLocal, |
| + kTagUsageMaximum = kLocalTagUsageMaximum << 2 | kTypeLocal, |
| + kTagDesignatorIndex = kLocalTagDesignatorIndex << 2 | kTypeLocal, |
| + kTagDesignatorMinimum = kLocalTagDesignatorMinimum << 2 | kTypeLocal, |
| + kTagDesignatorMaximum = kLocalTagDesignatorMaximum << 2 | kTypeLocal, |
| + kTagStringIndex = kLocalTagStringIndex << 2 | kTypeLocal, |
| + kTagStringMinimum = kLocalTagStringMinimum << 2 | kTypeLocal, |
| + kTagStringMaximum = kLocalTagStringMaximum << 2 | kTypeLocal, |
| + kTagDelimiter = kLocalTagDelimiter << 2 | kTypeLocal, |
| + kTagLong = kReservedTagLong << 2 | kTypeReserved |
| + }; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Tag& tag) { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please do not inline this, and in fact it doesn't
jracle (use Gerrit)
2014/04/16 16:39:19
Done
|
| + switch (tag) { |
| + case kTagDefault: |
| + os << "Default"; |
| + break; |
| + case kTagInput: |
| + os << "Input"; |
| + break; |
| + case kTagOutput: |
| + os << "Output"; |
| + break; |
| + case kTagFeature: |
| + os << "Feature"; |
| + break; |
| + case kTagCollection: |
| + os << "Collection"; |
| + break; |
| + case kTagEndCollection: |
| + os << "End Collection"; |
| + break; |
| + case kTagUsagePage: |
| + os << "Usage Page"; |
| + break; |
| + case kTagLogicalMinimum: |
| + os << "Logical Minimum"; |
| + break; |
| + case kTagLogicalMaximum: |
| + os << "Logical Maximum"; |
| + break; |
| + case kTagPhysicalMinimum: |
| + os << "Physical Minimum"; |
| + break; |
| + case kTagPhysicalMaximum: |
| + os << "Physical Maximum"; |
| + break; |
| + case kTagUnitExponent: |
| + os << "Unit Exponent"; |
| + break; |
| + case kTagUnit: |
| + os << "Unit"; |
| + break; |
| + case kTagReportSize: |
| + os << "Report Size"; |
| + break; |
| + case kTagReportId: |
| + os << "Report ID"; |
| + break; |
| + case kTagReportCount: |
| + os << "Report Count"; |
| + break; |
| + case kTagPush: |
| + os << "Push"; |
| + break; |
| + case kTagPop: |
| + os << "Pop"; |
| + break; |
| + case kTagUsage: |
| + os << "Usage"; |
| + break; |
| + case kTagUsageMinimum: |
| + os << "Usage Minimum"; |
| + break; |
| + case kTagUsageMaximum: |
| + os << "Usage Maximum"; |
| + break; |
| + case kTagDesignatorIndex: |
| + os << "Designator Index"; |
| + break; |
| + case kTagDesignatorMinimum: |
| + os << "Designator Minimum"; |
| + break; |
| + case kTagDesignatorMaximum: |
| + os << "Designator Maximum"; |
| + break; |
| + case kTagStringIndex: |
| + os << "String Index"; |
| + break; |
| + case kTagStringMinimum: |
| + os << "String Minimum"; |
| + break; |
| + case kTagStringMaximum: |
| + os << "String Maximum"; |
| + break; |
| + case kTagDelimiter: |
| + os << "Delimeter"; |
| + break; |
| + case kTagLong: |
| + os << "Long"; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + return os; |
| + }; |
| + |
| + public: |
| + // Headers |
| + |
| + struct Header { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
I'm jumping around this CL a lot as I get a better
jracle (use Gerrit)
2014/04/16 16:39:19
Got it, no point to show those details. Confusing.
|
| + uint8_t size : 2; |
| + uint8_t type : 2; |
| + uint8_t tag : 4; |
| + }; |
| + |
| + struct LongHeader { |
| + Header short_header; |
| + uint8_t data_size; |
| + uint8_t long_item_tag; |
| + }; |
| + |
| + // Data |
| + |
| + // (Short) Main items |
| + |
| + struct Default { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Default what? A more descriptive name may be in or
jracle (use Gerrit)
2014/04/16 16:39:19
Oops. Not meaningful.
|
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Default& data) { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
See the comment in Input_Output_Feature about movi
jracle (use Gerrit)
2014/04/16 16:39:19
Indeed.
|
| + return os; |
| + } |
| + }; |
| + |
| + struct Input_Output_Feature { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
InputOutputFeature, please
|
| + uint8_t data_or_constant : 1; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Same as previous comments. I know it's a lot of fi
|
| + uint8_t array_or_variable : 1; |
| + uint8_t absolute_or_relative : 1; |
| + uint8_t wrap : 1; |
| + uint8_t linear : 1; |
| + uint8_t preferred : 1; |
| + uint8_t null : 1; |
| + uint8_t reserved_1 : 1; |
| + uint8_t bit_field_or_buffer : 1; |
| + uint8_t reserved_2 : 1; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const Input_Output_Feature& data) { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please do not inline this. In fact once again, thi
|
| + if (data.data_or_constant) |
| + os << "Con"; |
| + else |
| + os << "Dat"; |
| + if (data.array_or_variable) |
| + os << "|Arr"; |
| + else |
| + os << "|Var"; |
| + if (data.absolute_or_relative) |
| + os << "|Abs"; |
| + else |
| + os << "|Rel"; |
| + if (data.wrap) |
| + os << "|Wrp"; |
| + else |
| + os << "|NoWrp"; |
| + if (data.linear) |
| + os << "|NoLin"; |
| + else |
| + os << "|Lin"; |
| + if (data.preferred) |
| + os << "|NoPrf"; |
| + else |
| + os << "|Prf"; |
| + if (data.null) |
| + os << "|Null"; |
| + else |
| + os << "|NoNull"; |
| + if (data.bit_field_or_buffer) |
| + os << "|Buff"; |
| + else |
| + os << "|BitF"; |
| + return os; |
| + } |
| + }; |
| + |
| + struct Collection { |
| + |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Whitespace
|
| + enum CollectionType { |
| + kCollectionTypePhysical, |
| + kCollectionTypeApplication, |
| + kCollectionTypeLogical, |
| + kCollectionTypeReport, |
| + kCollectionTypeNamedArray, |
| + kCollectionTypeUsageSwitch, |
| + kCollectionTypeUsageModifier, |
| + kCollectionTypeReserved, |
| + kCollectionTypeVendor |
| + }; |
| + |
| + uint8_t value; |
| + |
| + CollectionType collectionType() const { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please do not inline this. Same goes for the rest
|
| + switch (value) { |
| + case 0x00: |
| + return kCollectionTypePhysical; |
| + case 0x01: |
| + return kCollectionTypePhysical; |
| + case 0x02: |
| + return kCollectionTypePhysical; |
| + case 0x03: |
| + return kCollectionTypePhysical; |
| + case 0x04: |
| + return kCollectionTypePhysical; |
| + case 0x05: |
| + return kCollectionTypePhysical; |
| + case 0x06: |
| + return kCollectionTypePhysical; |
| + default: |
| + break; |
| + } |
| + |
| + if (0x80 < value && value < 0xFF) |
| + return kCollectionTypeVendor; |
| + |
| + return kCollectionTypeReserved; |
| + } |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Collection& data) { |
| + switch (data.collectionType()) { |
| + case kCollectionTypePhysical: |
| + os << "Physical"; |
| + break; |
| + case kCollectionTypeApplication: |
| + os << "Application"; |
| + break; |
| + case kCollectionTypeLogical: |
| + os << "Logical"; |
| + break; |
| + case kCollectionTypeReport: |
| + os << "Report"; |
| + break; |
| + case kCollectionTypeNamedArray: |
| + os << "Named Array"; |
| + break; |
| + case kCollectionTypeUsageSwitch: |
| + os << "Usage Switch"; |
| + break; |
| + case kCollectionTypeUsageModifier: |
| + os << "Usage Modifier"; |
| + break; |
| + case kCollectionTypeReserved: |
| + os << "Reserved"; |
| + break; |
| + case kCollectionTypeVendor: |
| + os << "Vendor"; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + return os; |
| + } |
| + }; |
| + |
| + struct EndCollection { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const EndCollection& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + // (Short) Global Items |
| + |
| + struct UsagePage { |
| + uint16_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const UsagePage& data) { |
| + HidUsageAndPage::Page page = (HidUsageAndPage::Page)data.value; |
| + os << page; |
| + return os; |
| + } |
| + }; |
| + |
| + struct LogicalMinimum { |
| + int32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const LogicalMinimum& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct LogicalMaximum { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
There's a lot of code duplication going on here an
|
| + int32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const LogicalMaximum& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct PhysicalMinimum { |
| + int32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const PhysicalMinimum& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct PhysicalMaximum { |
| + int32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const PhysicalMaximum& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct UnitExponent { |
| + uint32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const UnitExponent& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct Unit { |
| + uint32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Unit& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct ReportSize { |
| + uint32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const ReportSize& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct ReportId { |
| + uint32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const ReportId& data) { |
| + os << "0x" << std::hex << std::uppercase << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct ReportCount { |
| + uint32_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const ReportCount& data) { |
| + os << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct Push { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Push& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct Pop { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Pop& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + // (Short) Local Items |
| + |
| + struct Usage { |
| + uint16_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Usage& data) { |
| + os << "0x" << std::hex << std::uppercase << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct UsageMinimum { |
| + uint16_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const UsageMinimum& data) { |
| + os << "0x" << std::hex << std::uppercase << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct UsageMaximum { |
| + uint16_t value; |
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const UsageMaximum& data) { |
| + os << "0x" << std::hex << std::uppercase << data.value; |
| + return os; |
| + } |
| + }; |
| + |
| + struct DesignatorIndex { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const DesignatorIndex& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct DesignatorMinimum { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const DesignatorMinimum& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct DesignatorMaximum { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const DesignatorMaximum& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct StringIndex { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const StringIndex& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct StringMinimum { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const StringMinimum& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct StringMaximum { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const StringMaximum& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + struct Delimiter { |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, const Delimiter& data) { |
| + return os; |
| + } |
| + }; |
| + |
| + // (Long) Reserved items |
| + // nothing for now |
| + |
| + // Data union |
| + |
| + struct Data { |
| + union u { |
| + // (Short) Main items |
| + Default none; |
| + Input_Output_Feature input; |
| + Input_Output_Feature output; |
| + Input_Output_Feature feature; |
| + Collection collection; |
| + EndCollection end_collection; |
| + // (Short) Global items |
| + UsagePage usage_page; |
| + LogicalMinimum logical_minimum; |
| + LogicalMaximum logical_maximum; |
| + PhysicalMinimum physical_minimum; |
| + PhysicalMaximum physical_maximum; |
| + UnitExponent unit_exponent; |
| + Unit unit; |
| + ReportSize report_size; |
| + ReportId report_id; |
| + ReportCount report_count; |
| + Push push; |
| + Pop pop; |
| + // (Short) Local items |
| + Usage usage; |
| + UsageMinimum usage_minimum; |
| + UsageMaximum usage_maximum; |
| + DesignatorIndex designator_index; |
| + DesignatorMinimum designator_minimum; |
| + DesignatorMaximum designator_maximum; |
| + StringIndex string_index; |
| + StringMinimum string_minimum; |
| + StringMaximum string_maximum; |
| + Delimiter delimiter; |
| + // (Long) Reserved items |
| + // nothing for now |
| + }; |
| + }; |
| + |
| +#pragma pack(pop) |
| + |
| + HidReportDescriptorItem(const uint8_t* bytes, |
| + HidReportDescriptorItem* previous = NULL); |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please, no default argument values. Please specify
jracle (use Gerrit)
2014/04/16 16:39:19
Done
|
| + ~HidReportDescriptorItem(); |
| + |
| + HidReportDescriptorItem* previous() const { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please make it clear that neither this item nor th
|
| + return previous_; |
| + }; |
| + HidReportDescriptorItem* next() const { |
| + return next_; |
| + }; |
| + HidReportDescriptorItem* parent() const { |
| + return parent_; |
| + }; |
| + size_t depth() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
GetDepth() please. Lowercase names are for trivial
|
| + |
| + bool isLong() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
IsLong() please.
|
| + size_t headerSize() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
GetHeaderSize() please.
|
| + size_t payloadSize() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
GetPayloadSize() please.
|
| + size_t size() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
GetSize()
Also because none of these are trivial
|
| + |
| + Header* header() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
This (and longHeader) make me extremely uncomforta
jracle (use Gerrit)
2014/04/16 16:39:19
Now private in next patch-set, and accessed by val
|
| + LongHeader* longHeader() const; |
| + |
| + Tag tag() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
GetTag() please.
|
| + Data* data() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Since Data is a POD type, and you can change it so
jracle (use Gerrit)
2014/04/16 16:39:19
Data is actually known only for short items.
It ha
|
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const HidReportDescriptorItem& item) { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please see base/strings/stringprintf.h for the bas
jracle (use Gerrit)
2014/04/16 16:39:19
This I didn't catch yet, can you handle it in a ne
|
| + Tag tg = item.tag(); |
| + Data* dt = item.data(); |
| + |
| + std::ostringstream sstr; |
| + sstr << tg; |
| + sstr << " ("; |
| + |
| + long pos = sstr.tellp(); |
| + switch (tg) { |
| + case kTagDefault: |
| + sstr << *(Default*)dt; |
| + break; |
| + case kTagInput: |
| + case kTagOutput: |
| + case kTagFeature: |
| + sstr << *(Input_Output_Feature*)dt; |
| + break; |
| + case kTagCollection: |
| + sstr << *(Collection*)dt; |
| + break; |
| + case kTagEndCollection: |
| + sstr << *(EndCollection*)dt; |
| + break; |
| + case kTagUsagePage: |
| + sstr << *(UsagePage*)dt; |
| + break; |
| + case kTagLogicalMinimum: |
| + sstr << *(LogicalMinimum*)dt; |
| + break; |
| + case kTagLogicalMaximum: |
| + sstr << *(LogicalMaximum*)dt; |
| + break; |
| + case kTagPhysicalMinimum: |
| + sstr << *(PhysicalMinimum*)dt; |
| + break; |
| + case kTagPhysicalMaximum: |
| + sstr << *(PhysicalMaximum*)dt; |
| + break; |
| + case kTagUnitExponent: |
| + sstr << *(UnitExponent*)dt; |
| + break; |
| + case kTagUnit: |
| + sstr << *(Unit*)dt; |
| + break; |
| + case kTagReportSize: |
| + sstr << *(ReportSize*)dt; |
| + break; |
| + case kTagReportId: |
| + sstr << *(ReportId*)dt; |
| + break; |
| + case kTagReportCount: |
| + sstr << *(ReportCount*)dt; |
| + break; |
| + case kTagPush: |
| + sstr << *(Push*)dt; |
| + break; |
| + case kTagPop: |
| + sstr << *(Pop*)dt; |
| + break; |
| + case kTagUsage: |
| + sstr << *(Usage*)dt; |
| + break; |
| + case kTagUsageMinimum: |
| + sstr << *(UsageMinimum*)dt; |
| + break; |
| + case kTagUsageMaximum: |
| + sstr << *(UsageMaximum*)dt; |
| + break; |
| + case kTagDesignatorIndex: |
| + sstr << *(DesignatorIndex*)dt; |
| + break; |
| + case kTagDesignatorMinimum: |
| + sstr << *(DesignatorMinimum*)dt; |
| + break; |
| + case kTagDesignatorMaximum: |
| + sstr << *(DesignatorMaximum*)dt; |
| + break; |
| + case kTagStringIndex: |
| + sstr << *(StringIndex*)dt; |
| + break; |
| + case kTagStringMinimum: |
| + sstr << *(StringMinimum*)dt; |
| + break; |
| + case kTagStringMaximum: |
| + sstr << *(StringMaximum*)dt; |
| + break; |
| + case kTagDelimiter: |
| + sstr << *(Delimiter*)dt; |
| + break; |
| + case kTagLong: |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| + |
| + if (pos == sstr.tellp()) { |
| + std::string str = sstr.str(); |
| + str.erase(str.end() - 2, str.end()); |
| + os << str; |
| + } else { |
| + os << sstr.str() << ")"; |
| + } |
| + |
| + return os; |
| + } |
| + |
| + const uint8_t* bytes_; |
| + HidReportDescriptorItem* previous_; |
| + HidReportDescriptorItem* next_; |
| + HidReportDescriptorItem* parent_; |
| +}; |
| + |
| +// HID report descriptor. |
| +// See section 6.2.2 of HID specifications (v1.11). |
| +class HidReportDescriptor { |
| + |
| + private: |
| + static const char kIndentChar; |
| + |
| + public: |
| + HidReportDescriptor(const uint8_t* bytes, size_t size); |
| + ~HidReportDescriptor(); |
| + |
| + const std::vector<HidReportDescriptorItem*>& items() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
items is a trivial accessor; please feel free to i
jracle (use Gerrit)
2014/04/16 16:39:19
OK
|
| + std::vector<HidUsageAndPage> topLevelCollections() const; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
GetTopLevelCollections() please. This is not a tri
jracle (use Gerrit)
2014/04/16 16:39:19
OK
|
| + |
| + private: |
| + friend std::ostream& operator<<(std::ostream& os, |
| + const HidReportDescriptor& descriptor) { |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please do not inline this definition. In fact it d
|
| + for (std::vector<HidReportDescriptorItem*>::const_iterator items_iter = |
| + descriptor.items_.begin(); |
| + items_iter != descriptor.items_.end(); |
| + ++items_iter) { |
| + HidReportDescriptorItem* item = *items_iter; |
| + size_t indentLevel = item->depth(); |
| + for (size_t i = 0; i < indentLevel; i++) |
| + os << kIndentChar; |
| + os << *item << std::endl; |
| + } |
| + return os; |
| + } |
| + |
| + const uint8_t* bytes_; |
| + size_t size_; |
| + std::vector<HidReportDescriptorItem*> items_; |
|
Ken Rockot(use gerrit already)
2014/04/15 21:18:37
Please use linked_ptr here
std::vector<linked_ptr
jracle (use Gerrit)
2014/04/16 16:39:19
Indeed
|
| +}; |
| + |
| +} // namespace device |
| + |
| +#endif // DEVICE_HID_HID_REPORT_DESCRIPTOR_H_ |