OLD | NEW |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <sstream> | 5 #include <sstream> |
6 | 6 |
7 #include "device/hid/hid_report_descriptor.h" | 7 #include "device/hid/hid_report_descriptor.h" |
8 #include "testing/gmock/include/gmock/gmock.h" | 8 #include "testing/gmock/include/gmock/gmock.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 | 10 |
11 using namespace testing; | 11 using namespace testing; |
12 | 12 |
13 namespace device { | 13 namespace device { |
14 | 14 |
15 namespace { | 15 namespace { |
16 | 16 |
17 // Digitizer descriptor from HID descriptor tool | 17 std::ostream& operator<<(std::ostream& os, |
18 // http://www.usb.org/developers/hidpage/dt2_4.zip | 18 const HidUsageAndPage::Page& usage_page) { |
19 const uint8_t kDigitizer[] = { | 19 switch (usage_page) { |
20 0x05, 0x0d, // Usage Page (Digitizer) | 20 case HidUsageAndPage::kPageUndefined: |
21 0x09, 0x01, // Usage (0x1) | 21 os << "Undefined"; |
22 0xa1, 0x01, // Collection (Application) | 22 break; |
23 0x85, 0x01, // Report ID (0x1) | 23 case HidUsageAndPage::kPageGenericDesktop: |
24 0x09, 0x21, // Usage (0x21) | 24 os << "Generic Desktop"; |
25 0xa1, 0x00, // Collection (Physical) | 25 break; |
26 0x05, 0x01, // Usage Page (Generic Desktop) | 26 case HidUsageAndPage::kPageSimulation: |
27 0x09, 0x30, // Usage (0x30) | 27 os << "Simulation"; |
28 0x09, 0x31, // Usage (0x31) | 28 break; |
29 0x75, 0x10, // Report Size (16) | 29 case HidUsageAndPage::kPageVirtualReality: |
30 0x95, 0x02, // Report Count (2) | 30 os << "Virtual Reality"; |
31 0x15, 0x00, // Logical Minimum (0) | 31 break; |
32 0x26, 0xe0, 0x2e, // Logical Maximum (12000) | 32 case HidUsageAndPage::kPageSport: |
33 0x35, 0x00, // Physical Minimum (0) | 33 os << "Sport"; |
34 0x45, 0x0c, // Physical Maximum (12) | 34 break; |
35 0x65, 0x13, // Unit (19) | 35 case HidUsageAndPage::kPageGame: |
36 0x55, 0x00, // Unit Exponent (0) | 36 os << "Game"; |
37 0xa4, // Push | 37 break; |
38 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 38 case HidUsageAndPage::kPageKeyboard: |
39 0x05, 0x0d, // Usage Page (Digitizer) | 39 os << "Keyboard"; |
40 0x09, 0x32, // Usage (0x32) | 40 break; |
41 0x09, 0x44, // Usage (0x44) | 41 case HidUsageAndPage::kPageLed: |
42 0x09, 0x42, // Usage (0x42) | 42 os << "Led"; |
43 0x15, 0x00, // Logical Minimum (0) | 43 break; |
44 0x25, 0x01, // Logical Maximum (1) | 44 case HidUsageAndPage::kPageButton: |
45 0x35, 0x00, // Physical Minimum (0) | 45 os << "Button"; |
46 0x45, 0x01, // Physical Maximum (1) | 46 break; |
47 0x75, 0x01, // Report Size (1) | 47 case HidUsageAndPage::kPageOrdinal: |
48 0x95, 0x03, // Report Count (3) | 48 os << "Ordinal"; |
49 0x65, 0x00, // Unit (0) | 49 break; |
50 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 50 case HidUsageAndPage::kPageTelephony: |
51 0x95, 0x01, // Report Count (1) | 51 os << "Telephony"; |
52 0x75, 0x05, // Report Size (5) | 52 break; |
53 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 53 case HidUsageAndPage::kPageConsumer: |
54 0xc0, // End Collection | 54 os << "Consumer"; |
55 0x85, 0x02, // Report ID (0x2) | 55 break; |
56 0x09, 0x20, // Usage (0x20) | 56 case HidUsageAndPage::kPageDigitizer: |
57 0xa1, 0x00, // Collection (Physical) | 57 os << "Digitizer"; |
58 0xb4, // Pop | 58 break; |
59 0xa4, // Push | 59 case HidUsageAndPage::kPagePidPage: |
60 0x09, 0x30, // Usage (0x30) | 60 os << "Pid Page"; |
61 0x09, 0x31, // Usage (0x31) | 61 break; |
62 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 62 case HidUsageAndPage::kPageUnicode: |
63 0x05, 0x0d, // Usage Page (Digitizer) | 63 os << "Unicode"; |
64 0x09, 0x32, // Usage (0x32) | 64 break; |
65 0x15, 0x00, // Logical Minimum (0) | 65 case HidUsageAndPage::kPageAlphanumericDisplay: |
66 0x25, 0x01, // Logical Maximum (1) | 66 os << "Alphanumeric Display"; |
67 0x35, 0x00, // Physical Minimum (0) | 67 break; |
68 0x45, 0x01, // Physical Maximum (1) | 68 case HidUsageAndPage::kPageMedicalInstruments: |
69 0x65, 0x00, // Unit (0) | 69 os << "Medical Instruments"; |
70 0x75, 0x01, // Report Size (1) | 70 break; |
71 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 71 case HidUsageAndPage::kPageMonitor0: |
72 0x05, 0x09, // Usage Page (Button) | 72 os << "Monitor 0"; |
73 0x19, 0x00, // Usage Minimum (0) | 73 break; |
74 0x29, 0x10, // Usage Maximum (16) | 74 case HidUsageAndPage::kPageMonitor1: |
75 0x25, 0x10, // Logical Maximum (16) | 75 os << "Monitor 1"; |
76 0x75, 0x05, // Report Size (5) | 76 break; |
77 0x81, 0x40, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|Null|BitF) | 77 case HidUsageAndPage::kPageMonitor2: |
78 0x75, 0x02, // Report Size (2) | 78 os << "Monitor 2"; |
79 0x81, 0x01, // Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 79 break; |
80 0xc0, // End Collection | 80 case HidUsageAndPage::kPageMonitor3: |
81 0x85, 0x03, // Report ID (0x3) | 81 os << "Monitor 3"; |
82 0x05, 0x0d, // Usage Page (Digitizer) | 82 break; |
83 0x09, 0x20, // Usage (0x20) | 83 case HidUsageAndPage::kPagePower0: |
84 0xa1, 0x00, // Collection (Physical) | 84 os << "Power 0"; |
85 0xb4, // Pop | 85 break; |
86 0x09, 0x30, // Usage (0x30) | 86 case HidUsageAndPage::kPagePower1: |
87 0x09, 0x31, // Usage (0x31) | 87 os << "Power 1"; |
88 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 88 break; |
89 0x05, 0x0d, // Usage Page (Digitizer) | 89 case HidUsageAndPage::kPagePower2: |
90 0x09, 0x32, // Usage (0x32) | 90 os << "Power 2"; |
91 0x09, 0x44, // Usage (0x44) | 91 break; |
92 0x75, 0x01, // Report Size (1) | 92 case HidUsageAndPage::kPagePower3: |
93 0x15, 0x00, // Logical Minimum (0) | 93 os << "Power 3"; |
94 0x25, 0x01, // Logical Maximum (1) | 94 break; |
95 0x35, 0x00, // Physical Minimum (0) | 95 case HidUsageAndPage::kPageBarCodeScanner: |
96 0x45, 0x01, // Physical Maximum (1) | 96 os << "Bar Code Scanner"; |
97 0x65, 0x00, // Unit (0) | 97 break; |
98 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 98 case HidUsageAndPage::kPageScale: |
99 0x95, 0x06, // Report Count (6) | 99 os << "Scale"; |
100 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 100 break; |
101 0x09, 0x30, // Usage (0x30) | 101 case HidUsageAndPage::kPageMagneticStripeReader: |
102 0x15, 0x00, // Logical Minimum (0) | 102 os << "Magnetic Stripe Reader"; |
103 0x25, 0x7f, // Logical Maximum (127) | 103 break; |
104 0x35, 0x00, // Physical Minimum (0) | 104 case HidUsageAndPage::kPageReservedPointOfSale: |
105 0x45, 0x2d, // Physical Maximum (45) | 105 os << "Reserved Point Of Sale"; |
106 0x67, 0x11, 0xe1, // Unit (57617) | 106 break; |
107 0x00, 0x00, // Default | 107 case HidUsageAndPage::kPageCameraControl: |
108 0x55, 0x04, // Unit Exponent (4) | 108 os << "Camera Control"; |
109 0x75, 0x08, // Report Size (8) | 109 break; |
110 0x95, 0x01, // Report Count (1) | 110 case HidUsageAndPage::kPageArcade: |
111 0x81, 0x12, // Input (Dat|Arr|Rel|NoWrp|NoLin|Prf|NoNull|BitF) | 111 os << "Arcade"; |
112 0xc0, // End Collection | 112 break; |
113 0xc0 // End Collection | 113 case HidUsageAndPage::kPageVendor: |
114 }; | 114 os << "Vendor"; |
115 | 115 break; |
116 // Keyboard descriptor from HID descriptor tool | 116 case HidUsageAndPage::kPageMediaCenter: |
117 // http://www.usb.org/developers/hidpage/dt2_4.zip | 117 os << "Media Center"; |
| 118 break; |
| 119 default: |
| 120 NOTREACHED(); |
| 121 break; |
| 122 } |
| 123 return os; |
| 124 } |
| 125 |
| 126 std::ostream& operator<<(std::ostream& os, |
| 127 const HidUsageAndPage& usage_and_page) { |
| 128 os << "Usage Page: " << usage_and_page.usage_page << ", Usage: " |
| 129 << "0x" << std::hex << std::uppercase << usage_and_page.usage; |
| 130 return os; |
| 131 } |
| 132 |
| 133 std::ostream& operator<<(std::ostream& os, |
| 134 const HidReportDescriptorItem::Tag& tag) { |
| 135 switch (tag) { |
| 136 case HidReportDescriptorItem::kTagDefault: |
| 137 os << "Default"; |
| 138 break; |
| 139 case HidReportDescriptorItem::kTagInput: |
| 140 os << "Input"; |
| 141 break; |
| 142 case HidReportDescriptorItem::kTagOutput: |
| 143 os << "Output"; |
| 144 break; |
| 145 case HidReportDescriptorItem::kTagFeature: |
| 146 os << "Feature"; |
| 147 break; |
| 148 case HidReportDescriptorItem::kTagCollection: |
| 149 os << "Collection"; |
| 150 break; |
| 151 case HidReportDescriptorItem::kTagEndCollection: |
| 152 os << "End Collection"; |
| 153 break; |
| 154 case HidReportDescriptorItem::kTagUsagePage: |
| 155 os << "Usage Page"; |
| 156 break; |
| 157 case HidReportDescriptorItem::kTagLogicalMinimum: |
| 158 os << "Logical Minimum"; |
| 159 break; |
| 160 case HidReportDescriptorItem::kTagLogicalMaximum: |
| 161 os << "Logical Maximum"; |
| 162 break; |
| 163 case HidReportDescriptorItem::kTagPhysicalMinimum: |
| 164 os << "Physical Minimum"; |
| 165 break; |
| 166 case HidReportDescriptorItem::kTagPhysicalMaximum: |
| 167 os << "Physical Maximum"; |
| 168 break; |
| 169 case HidReportDescriptorItem::kTagUnitExponent: |
| 170 os << "Unit Exponent"; |
| 171 break; |
| 172 case HidReportDescriptorItem::kTagUnit: |
| 173 os << "Unit"; |
| 174 break; |
| 175 case HidReportDescriptorItem::kTagReportSize: |
| 176 os << "Report Size"; |
| 177 break; |
| 178 case HidReportDescriptorItem::kTagReportId: |
| 179 os << "Report ID"; |
| 180 break; |
| 181 case HidReportDescriptorItem::kTagReportCount: |
| 182 os << "Report Count"; |
| 183 break; |
| 184 case HidReportDescriptorItem::kTagPush: |
| 185 os << "Push"; |
| 186 break; |
| 187 case HidReportDescriptorItem::kTagPop: |
| 188 os << "Pop"; |
| 189 break; |
| 190 case HidReportDescriptorItem::kTagUsage: |
| 191 os << "Usage"; |
| 192 break; |
| 193 case HidReportDescriptorItem::kTagUsageMinimum: |
| 194 os << "Usage Minimum"; |
| 195 break; |
| 196 case HidReportDescriptorItem::kTagUsageMaximum: |
| 197 os << "Usage Maximum"; |
| 198 break; |
| 199 case HidReportDescriptorItem::kTagDesignatorIndex: |
| 200 os << "Designator Index"; |
| 201 break; |
| 202 case HidReportDescriptorItem::kTagDesignatorMinimum: |
| 203 os << "Designator Minimum"; |
| 204 break; |
| 205 case HidReportDescriptorItem::kTagDesignatorMaximum: |
| 206 os << "Designator Maximum"; |
| 207 break; |
| 208 case HidReportDescriptorItem::kTagStringIndex: |
| 209 os << "String Index"; |
| 210 break; |
| 211 case HidReportDescriptorItem::kTagStringMinimum: |
| 212 os << "String Minimum"; |
| 213 break; |
| 214 case HidReportDescriptorItem::kTagStringMaximum: |
| 215 os << "String Maximum"; |
| 216 break; |
| 217 case HidReportDescriptorItem::kTagDelimiter: |
| 218 os << "Delimeter"; |
| 219 break; |
| 220 case HidReportDescriptorItem::kTagLong: |
| 221 os << "Long"; |
| 222 break; |
| 223 default: |
| 224 NOTREACHED(); |
| 225 break; |
| 226 } |
| 227 |
| 228 return os; |
| 229 } |
| 230 |
| 231 std::ostream& operator<<(std::ostream& os, |
| 232 const HidReportDescriptorItem::ReportInfo& data) { |
| 233 if (data.data_or_constant) |
| 234 os << "Con"; |
| 235 else |
| 236 os << "Dat"; |
| 237 if (data.array_or_variable) |
| 238 os << "|Arr"; |
| 239 else |
| 240 os << "|Var"; |
| 241 if (data.absolute_or_relative) |
| 242 os << "|Abs"; |
| 243 else |
| 244 os << "|Rel"; |
| 245 if (data.wrap) |
| 246 os << "|Wrp"; |
| 247 else |
| 248 os << "|NoWrp"; |
| 249 if (data.linear) |
| 250 os << "|NoLin"; |
| 251 else |
| 252 os << "|Lin"; |
| 253 if (data.preferred) |
| 254 os << "|NoPrf"; |
| 255 else |
| 256 os << "|Prf"; |
| 257 if (data.null) |
| 258 os << "|Null"; |
| 259 else |
| 260 os << "|NoNull"; |
| 261 if (data.bit_field_or_buffer) |
| 262 os << "|Buff"; |
| 263 else |
| 264 os << "|BitF"; |
| 265 return os; |
| 266 } |
| 267 |
| 268 std::ostream& operator<<(std::ostream& os, |
| 269 const HidReportDescriptorItem::CollectionType& type) { |
| 270 switch (type) { |
| 271 case HidReportDescriptorItem::kCollectionTypePhysical: |
| 272 os << "Physical"; |
| 273 break; |
| 274 case HidReportDescriptorItem::kCollectionTypeApplication: |
| 275 os << "Application"; |
| 276 break; |
| 277 case HidReportDescriptorItem::kCollectionTypeLogical: |
| 278 os << "Logical"; |
| 279 break; |
| 280 case HidReportDescriptorItem::kCollectionTypeReport: |
| 281 os << "Report"; |
| 282 break; |
| 283 case HidReportDescriptorItem::kCollectionTypeNamedArray: |
| 284 os << "Named Array"; |
| 285 break; |
| 286 case HidReportDescriptorItem::kCollectionTypeUsageSwitch: |
| 287 os << "Usage Switch"; |
| 288 break; |
| 289 case HidReportDescriptorItem::kCollectionTypeUsageModifier: |
| 290 os << "Usage Modifier"; |
| 291 break; |
| 292 case HidReportDescriptorItem::kCollectionTypeReserved: |
| 293 os << "Reserved"; |
| 294 break; |
| 295 case HidReportDescriptorItem::kCollectionTypeVendor: |
| 296 os << "Vendor"; |
| 297 break; |
| 298 default: |
| 299 NOTREACHED(); |
| 300 break; |
| 301 } |
| 302 return os; |
| 303 } |
| 304 |
| 305 std::ostream& operator<<(std::ostream& os, |
| 306 const HidReportDescriptorItem& item) { |
| 307 HidReportDescriptorItem::Tag item_tag = item.tag(); |
| 308 uint32_t data = item.GetShortData(); |
| 309 |
| 310 std::ostringstream sstr; |
| 311 sstr << item_tag; |
| 312 sstr << " ("; |
| 313 |
| 314 long pos = sstr.tellp(); |
| 315 switch (item_tag) { |
| 316 case HidReportDescriptorItem::kTagDefault: |
| 317 case HidReportDescriptorItem::kTagEndCollection: |
| 318 case HidReportDescriptorItem::kTagPush: |
| 319 case HidReportDescriptorItem::kTagPop: |
| 320 case HidReportDescriptorItem::kTagLong: |
| 321 break; |
| 322 |
| 323 case HidReportDescriptorItem::kTagCollection: |
| 324 sstr << HidReportDescriptorItem::GetCollectionTypeFromValue(data); |
| 325 break; |
| 326 |
| 327 case HidReportDescriptorItem::kTagInput: |
| 328 case HidReportDescriptorItem::kTagOutput: |
| 329 case HidReportDescriptorItem::kTagFeature: |
| 330 sstr << (HidReportDescriptorItem::ReportInfo&)data; |
| 331 break; |
| 332 |
| 333 case HidReportDescriptorItem::kTagUsagePage: |
| 334 sstr << (HidUsageAndPage::Page)data; |
| 335 break; |
| 336 |
| 337 case HidReportDescriptorItem::kTagUsage: |
| 338 case HidReportDescriptorItem::kTagReportId: |
| 339 sstr << "0x" << std::hex << std::uppercase << data; |
| 340 break; |
| 341 |
| 342 default: |
| 343 sstr << data; |
| 344 break; |
| 345 } |
| 346 if (pos == sstr.tellp()) { |
| 347 std::string str = sstr.str(); |
| 348 str.erase(str.end() - 2, str.end()); |
| 349 os << str; |
| 350 } else { |
| 351 os << sstr.str() << ")"; |
| 352 } |
| 353 |
| 354 return os; |
| 355 } |
| 356 |
| 357 const char kIndentStep[] = " "; |
| 358 |
| 359 std::ostream& operator<<(std::ostream& os, |
| 360 const HidReportDescriptor& descriptor) { |
| 361 for (std::vector<linked_ptr<HidReportDescriptorItem> >::const_iterator |
| 362 items_iter = descriptor.items().begin(); |
| 363 items_iter != descriptor.items().end(); |
| 364 ++items_iter) { |
| 365 linked_ptr<HidReportDescriptorItem> item = *items_iter; |
| 366 size_t indentLevel = item->GetDepth(); |
| 367 for (size_t i = 0; i < indentLevel; i++) |
| 368 os << kIndentStep; |
| 369 os << *item.get() << std::endl; |
| 370 } |
| 371 return os; |
| 372 } |
| 373 |
| 374 // See 'E.6 Report Descriptor (Keyboard)' |
| 375 // in HID specifications (v1.11) |
118 const uint8_t kKeyboard[] = { | 376 const uint8_t kKeyboard[] = { |
119 0x05, 0x01, // Usage Page (Generic Desktop) | 377 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, |
120 0x09, 0x06, // Usage (0x6) | 378 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, |
121 0xa1, 0x01, // Collection (Application) | 379 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05, |
122 0x05, 0x07, // Usage Page (Keyboard) | 380 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, |
123 0x19, 0xe0, // Usage Minimum (224) | 381 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, |
124 0x29, 0xe7, // Usage Maximum (231) | 382 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0}; |
125 0x15, 0x00, // Logical Minimum (0) | 383 |
126 0x25, 0x01, // Logical Maximum (1) | 384 // See 'E.10 Report Descriptor (Mouse)' |
127 0x75, 0x01, // Report Size (1) | 385 // in HID specifications (v1.11) |
128 0x95, 0x08, // Report Count (8) | 386 const uint8_t kMouse[] = {0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, |
129 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 387 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00, |
130 0x95, 0x01, // Report Count (1) | 388 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, |
131 0x75, 0x08, // Report Size (8) | 389 0x01, 0x75, 0x05, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30, |
132 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | 390 0x09, 0x31, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, |
133 0x95, 0x05, // Report Count (5) | 391 0x02, 0x81, 0x06, 0xC0, 0xC0}; |
134 0x75, 0x01, // Report Size (1) | 392 |
135 0x05, 0x08, // Usage Page (Led) | |
136 0x19, 0x01, // Usage Minimum (1) | |
137 0x29, 0x05, // Usage Maximum (5) | |
138 0x91, 0x02, // Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
139 0x95, 0x01, // Report Count (1) | |
140 0x75, 0x03, // Report Size (3) | |
141 0x91, 0x03, // Output (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
142 0x95, 0x06, // Report Count (6) | |
143 0x75, 0x08, // Report Size (8) | |
144 0x15, 0x00, // Logical Minimum (0) | |
145 0x25, 0x65, // Logical Maximum (101) | |
146 0x05, 0x07, // Usage Page (Keyboard) | |
147 0x19, 0x00, // Usage Minimum (0) | |
148 0x29, 0x65, // Usage Maximum (101) | |
149 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
150 0xc0 // End Collection | |
151 }; | |
152 | |
153 // Monitor descriptor from HID descriptor tool | |
154 // http://www.usb.org/developers/hidpage/dt2_4.zip | |
155 const uint8_t kMonitor[] = { | |
156 0x05, 0x80, // Usage Page (Monitor 0) | |
157 0x09, 0x01, // Usage (0x1) | |
158 0xa1, 0x01, // Collection (Application) | |
159 0x85, 0x01, // Report ID (0x1) | |
160 0x15, 0x00, // Logical Minimum (0) | |
161 0x26, 0xff, 0x00, // Logical Maximum (255) | |
162 0x75, 0x08, // Report Size (8) | |
163 0x95, 0x80, // Report Count (128) | |
164 0x09, 0x02, // Usage (0x2) | |
165 0xb2, 0x02, 0x01, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff) | |
166 0x85, 0x02, // Report ID (0x2) | |
167 0x95, 0xf3, // Report Count (243) | |
168 0x09, 0x03, // Usage (0x3) | |
169 0xb2, 0x02, 0x01, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|Buff) | |
170 0x85, 0x03, // Report ID (0x3) | |
171 0x05, 0x82, // Usage Page (Monitor 2) | |
172 0x95, 0x01, // Report Count (1) | |
173 0x75, 0x10, // Report Size (16) | |
174 0x26, 0xc8, 0x00, // Logical Maximum (200) | |
175 0x09, 0x10, // Usage (0x10) | |
176 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
177 0x85, 0x04, // Report ID (0x4) | |
178 0x25, 0x64, // Logical Maximum (100) | |
179 0x09, 0x12, // Usage (0x12) | |
180 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
181 0x95, 0x06, // Report Count (6) | |
182 0x26, 0xff, 0x00, // Logical Maximum (255) | |
183 0x09, 0x16, // Usage (0x16) | |
184 0x09, 0x18, // Usage (0x18) | |
185 0x09, 0x1a, // Usage (0x1A) | |
186 0x09, 0x6c, // Usage (0x6C) | |
187 0x09, 0x6e, // Usage (0x6E) | |
188 0x09, 0x70, // Usage (0x70) | |
189 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
190 0x85, 0x05, // Report ID (0x5) | |
191 0x25, 0x7f, // Logical Maximum (127) | |
192 0x09, 0x20, // Usage (0x20) | |
193 0x09, 0x22, // Usage (0x22) | |
194 0x09, 0x30, // Usage (0x30) | |
195 0x09, 0x32, // Usage (0x32) | |
196 0x09, 0x42, // Usage (0x42) | |
197 0x09, 0x44, // Usage (0x44) | |
198 0xb1, 0x02, // Feature (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
199 0xc0 // End Collection | |
200 }; | |
201 | |
202 // Mouse descriptor from HID descriptor tool | |
203 // http://www.usb.org/developers/hidpage/dt2_4.zip | |
204 const uint8_t kMouse[] = { | |
205 0x05, 0x01, // Usage Page (Generic Desktop) | |
206 0x09, 0x02, // Usage (0x2) | |
207 0xa1, 0x01, // Collection (Application) | |
208 0x09, 0x01, // Usage (0x1) | |
209 0xa1, 0x00, // Collection (Physical) | |
210 0x05, 0x09, // Usage Page (Button) | |
211 0x19, 0x01, // Usage Minimum (1) | |
212 0x29, 0x03, // Usage Maximum (3) | |
213 0x15, 0x00, // Logical Minimum (0) | |
214 0x25, 0x01, // Logical Maximum (1) | |
215 0x95, 0x03, // Report Count (3) | |
216 0x75, 0x01, // Report Size (1) | |
217 0x81, 0x02, // Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
218 0x95, 0x01, // Report Count (1) | |
219 0x75, 0x05, // Report Size (5) | |
220 0x81, 0x03, // Input (Con|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
221 0x05, 0x01, // Usage Page (Generic Desktop) | |
222 0x09, 0x30, // Usage (0x30) | |
223 0x09, 0x31, // Usage (0x31) | |
224 0x15, 0x81, // Logical Minimum (129) | |
225 0x25, 0x7f, // Logical Maximum (127) | |
226 0x75, 0x08, // Report Size (8) | |
227 0x95, 0x02, // Report Count (2) | |
228 0x81, 0x06, // Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF) | |
229 0xc0, // End Collection | |
230 0xc0 // End Collection | |
231 }; | |
232 | |
233 // Logitech Unifying receiver descriptor | |
234 const uint8_t kLogitechUnifyingReceiver[] = { | 393 const uint8_t kLogitechUnifyingReceiver[] = { |
235 0x06, 0x00, 0xFF, // Usage Page (Vendor) | 394 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x75, 0x08, |
236 0x09, 0x01, // Usage (0x1) | 395 0x95, 0x06, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x01, 0x81, 0x00, |
237 0xA1, 0x01, // Collection (Application) | 396 0x09, 0x01, 0x91, 0x00, 0xC0, 0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1, |
238 0x85, 0x10, // Report ID (0x10) | 397 0x01, 0x85, 0x11, 0x75, 0x08, 0x95, 0x13, 0x15, 0x00, 0x26, 0xFF, |
239 0x75, 0x08, // Report Size (8) | 398 0x00, 0x09, 0x02, 0x81, 0x00, 0x09, 0x02, 0x91, 0x00, 0xC0, 0x06, |
240 0x95, 0x06, // Report Count (6) | 399 0x00, 0xFF, 0x09, 0x04, 0xA1, 0x01, 0x85, 0x20, 0x75, 0x08, 0x95, |
241 0x15, 0x00, // Logical Minimum (0) | 400 0x0E, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x41, 0x81, 0x00, 0x09, |
242 0x26, 0xFF, 0x00, // Logical Maximum (255) | 401 0x41, 0x91, 0x00, 0x85, 0x21, 0x95, 0x1F, 0x15, 0x00, 0x26, 0xFF, |
243 0x09, 0x01, // Usage (0x1) | 402 0x00, 0x09, 0x42, 0x81, 0x00, 0x09, 0x42, 0x91, 0x00, 0xC0}; |
244 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
245 0x09, 0x01, // Usage (0x1) | |
246 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
247 0xC0, // End Collection | |
248 0x06, 0x00, 0xFF, // Usage Page (Vendor) | |
249 0x09, 0x02, // Usage (0x2) | |
250 0xA1, 0x01, // Collection (Application) | |
251 0x85, 0x11, // Report ID (0x11) | |
252 0x75, 0x08, // Report Size (8) | |
253 0x95, 0x13, // Report Count (19) | |
254 0x15, 0x00, // Logical Minimum (0) | |
255 0x26, 0xFF, 0x00, // Logical Maximum (255) | |
256 0x09, 0x02, // Usage (0x2) | |
257 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
258 0x09, 0x02, // Usage (0x2) | |
259 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
260 0xC0, // End Collection | |
261 0x06, 0x00, 0xFF, // Usage Page (Vendor) | |
262 0x09, 0x04, // Usage (0x4) | |
263 0xA1, 0x01, // Collection (Application) | |
264 0x85, 0x20, // Report ID (0x20) | |
265 0x75, 0x08, // Report Size (8) | |
266 0x95, 0x0E, // Report Count (14) | |
267 0x15, 0x00, // Logical Minimum (0) | |
268 0x26, 0xFF, 0x00, // Logical Maximum (255) | |
269 0x09, 0x41, // Usage (0x41) | |
270 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
271 0x09, 0x41, // Usage (0x41) | |
272 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
273 0x85, 0x21, // Report ID (0x21) | |
274 0x95, 0x1F, // Report Count (31) | |
275 0x15, 0x00, // Logical Minimum (0) | |
276 0x26, 0xFF, 0x00, // Logical Maximum (255) | |
277 0x09, 0x42, // Usage (0x42) | |
278 0x81, 0x00, // Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
279 0x09, 0x42, // Usage (0x42) | |
280 0x91, 0x00, // Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF) | |
281 0xC0 // End Collection | |
282 }; | |
283 | 403 |
284 } // namespace | 404 } // namespace |
285 | 405 |
286 class HidReportDescriptorTest : public testing::Test { | 406 class HidReportDescriptorTest : public testing::Test { |
287 | 407 |
288 protected: | 408 protected: |
289 virtual void SetUp() OVERRIDE { descriptor_ = NULL; } | 409 virtual void SetUp() OVERRIDE { descriptor_ = NULL; } |
290 | 410 |
291 virtual void TearDown() OVERRIDE { | 411 virtual void TearDown() OVERRIDE { |
292 if (descriptor_) { | 412 if (descriptor_) { |
293 delete descriptor_; | 413 delete descriptor_; |
294 } | 414 } |
295 } | 415 } |
296 | 416 |
297 public: | 417 public: |
298 void ValidateDetails( | 418 void ParseDescriptor(const std::string& expected, |
299 const std::vector<HidCollectionInfo>& expected_collections, | 419 const uint8_t* bytes, |
300 const int expected_max_input_report_size, | 420 size_t size) { |
301 const int expected_max_output_report_size, | |
302 const int expected_max_feature_report_size, | |
303 const uint8_t* bytes, | |
304 size_t size) { | |
305 descriptor_ = new HidReportDescriptor(bytes, size); | 421 descriptor_ = new HidReportDescriptor(bytes, size); |
306 | 422 |
307 std::vector<HidCollectionInfo> actual_collections; | 423 std::stringstream actual; |
308 int actual_max_input_report_size; | 424 actual << *descriptor_; |
309 int actual_max_output_report_size; | |
310 int actual_max_feature_report_size; | |
311 descriptor_->GetDetails(&actual_collections, | |
312 &actual_max_input_report_size, | |
313 &actual_max_output_report_size, | |
314 &actual_max_feature_report_size); | |
315 | 425 |
316 ASSERT_EQ(expected_collections.size(), actual_collections.size()); | 426 std::cout << "HID report descriptor:" << std::endl; |
| 427 std::cout << actual.str(); |
317 | 428 |
318 std::vector<HidCollectionInfo>::const_iterator actual_collections_iter = | 429 // TODO(jracle@logitech.com): refactor string comparison in favor of |
319 actual_collections.begin(); | 430 // testing individual fields. |
320 std::vector<HidCollectionInfo>::const_iterator expected_collections_iter = | 431 ASSERT_EQ(expected, actual.str()); |
321 expected_collections.begin(); | 432 } |
322 | 433 |
323 while (expected_collections_iter != expected_collections.end() && | 434 void GetTopLevelCollections(const std::vector<HidUsageAndPage>& expected, |
324 actual_collections_iter != actual_collections.end()) { | 435 const uint8_t* bytes, |
325 HidCollectionInfo expected_collection = *expected_collections_iter; | 436 size_t size) { |
326 HidCollectionInfo actual_collection = *actual_collections_iter; | 437 descriptor_ = new HidReportDescriptor(bytes, size); |
327 | 438 |
328 ASSERT_EQ(expected_collection.usage.usage_page, | 439 std::vector<HidUsageAndPage> actual; |
329 actual_collection.usage.usage_page); | 440 descriptor_->GetTopLevelCollections(&actual); |
330 ASSERT_EQ(expected_collection.usage.usage, actual_collection.usage.usage); | |
331 ASSERT_THAT(actual_collection.report_ids, | |
332 ContainerEq(expected_collection.report_ids)); | |
333 | 441 |
334 expected_collections_iter++; | 442 std::cout << "HID top-level collections:" << std::endl; |
335 actual_collections_iter++; | 443 for (std::vector<HidUsageAndPage>::const_iterator iter = actual.begin(); |
| 444 iter != actual.end(); |
| 445 ++iter) { |
| 446 std::cout << *iter << std::endl; |
336 } | 447 } |
337 | 448 |
338 ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size); | 449 ASSERT_THAT(actual, ContainerEq(expected)); |
339 ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size); | |
340 ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size); | |
341 } | 450 } |
342 | 451 |
343 private: | 452 private: |
344 HidReportDescriptor* descriptor_; | 453 HidReportDescriptor* descriptor_; |
345 }; | 454 }; |
346 | 455 |
347 TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) { | 456 TEST_F(HidReportDescriptorTest, ParseDescriptor_Keyboard) { |
348 HidCollectionInfo digitizer; | 457 const char expected[] = { |
349 digitizer.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageDigitizer); | 458 "Usage Page (Generic Desktop)\n" |
350 digitizer.report_ids.insert(1); | 459 "Usage (0x6)\n" |
351 digitizer.report_ids.insert(2); | 460 "Collection (Physical)\n" |
352 digitizer.report_ids.insert(3); | 461 " Usage Page (Keyboard)\n" |
353 HidCollectionInfo expected[] = {digitizer}; | 462 " Usage Minimum (224)\n" |
354 ValidateDetails(std::vector<HidCollectionInfo>( | 463 " Usage Maximum (231)\n" |
355 expected, expected + ARRAYSIZE_UNSAFE(expected)), | 464 " Logical Minimum (0)\n" |
356 7, | 465 " Logical Maximum (1)\n" |
357 0, | 466 " Report Size (1)\n" |
358 0, | 467 " Report Count (8)\n" |
359 kDigitizer, | 468 " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
360 sizeof(kDigitizer)); | 469 " Report Count (1)\n" |
| 470 " Report Size (8)\n" |
| 471 " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 472 " Report Count (5)\n" |
| 473 " Report Size (1)\n" |
| 474 " Usage Page (Led)\n" |
| 475 " Usage Minimum (1)\n" |
| 476 " Usage Maximum (5)\n" |
| 477 " Output (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 478 " Report Count (1)\n" |
| 479 " Report Size (3)\n" |
| 480 " Output (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 481 " Report Count (6)\n" |
| 482 " Report Size (8)\n" |
| 483 " Logical Minimum (0)\n" |
| 484 " Logical Maximum (101)\n" |
| 485 " Usage Page (Keyboard)\n" |
| 486 " Usage Minimum (0)\n" |
| 487 " Usage Maximum (101)\n" |
| 488 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 489 "End Collection\n"}; |
| 490 |
| 491 ParseDescriptor(std::string(expected), kKeyboard, sizeof(kKeyboard)); |
361 } | 492 } |
362 | 493 |
363 TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) { | 494 TEST_F(HidReportDescriptorTest, TopLevelCollections_Keyboard) { |
364 HidCollectionInfo keyboard; | 495 HidUsageAndPage expected[] = { |
365 keyboard.usage = HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop); | 496 HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop)}; |
366 HidCollectionInfo expected[] = {keyboard}; | 497 |
367 ValidateDetails(std::vector<HidCollectionInfo>( | 498 GetTopLevelCollections(std::vector<HidUsageAndPage>( |
368 expected, expected + ARRAYSIZE_UNSAFE(expected)), | 499 expected, expected + ARRAYSIZE_UNSAFE(expected)), |
369 8, | 500 kKeyboard, |
370 1, | 501 sizeof(kKeyboard)); |
371 0, | |
372 kKeyboard, | |
373 sizeof(kKeyboard)); | |
374 } | 502 } |
375 | 503 |
376 TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) { | 504 TEST_F(HidReportDescriptorTest, ParseDescriptor_Mouse) { |
377 HidCollectionInfo monitor; | 505 const char expected[] = { |
378 monitor.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageMonitor0); | 506 "Usage Page (Generic Desktop)\n" |
379 monitor.report_ids.insert(1); | 507 "Usage (0x2)\n" |
380 monitor.report_ids.insert(2); | 508 "Collection (Physical)\n" |
381 monitor.report_ids.insert(3); | 509 " Usage (0x1)\n" |
382 monitor.report_ids.insert(4); | 510 " Collection (Physical)\n" |
383 monitor.report_ids.insert(5); | 511 " Usage Page (Button)\n" |
384 HidCollectionInfo expected[] = {monitor}; | 512 " Usage Minimum (1)\n" |
385 ValidateDetails(std::vector<HidCollectionInfo>( | 513 " Usage Maximum (3)\n" |
386 expected, expected + ARRAYSIZE_UNSAFE(expected)), | 514 " Logical Minimum (0)\n" |
387 0, | 515 " Logical Maximum (1)\n" |
388 0, | 516 " Report Count (3)\n" |
389 244, | 517 " Report Size (1)\n" |
390 kMonitor, | 518 " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
391 sizeof(kMonitor)); | 519 " Report Count (1)\n" |
| 520 " Report Size (5)\n" |
| 521 " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 522 " Usage Page (Generic Desktop)\n" |
| 523 " Usage (0x30)\n" |
| 524 " Usage (0x31)\n" |
| 525 " Logical Minimum (129)\n" |
| 526 " Logical Maximum (127)\n" |
| 527 " Report Size (8)\n" |
| 528 " Report Count (2)\n" |
| 529 " Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 530 " End Collection\n" |
| 531 "End Collection\n"}; |
| 532 |
| 533 ParseDescriptor(std::string(expected), kMouse, sizeof(kMouse)); |
392 } | 534 } |
393 | 535 |
394 TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) { | 536 TEST_F(HidReportDescriptorTest, TopLevelCollections_Mouse) { |
395 HidCollectionInfo mouse; | 537 HidUsageAndPage expected[] = { |
396 mouse.usage = HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop); | 538 HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop)}; |
397 HidCollectionInfo expected[] = {mouse}; | 539 |
398 ValidateDetails(std::vector<HidCollectionInfo>( | 540 GetTopLevelCollections(std::vector<HidUsageAndPage>( |
399 expected, expected + ARRAYSIZE_UNSAFE(expected)), | 541 expected, expected + ARRAYSIZE_UNSAFE(expected)), |
400 3, | 542 kMouse, |
401 0, | 543 sizeof(kMouse)); |
402 0, | |
403 kMouse, | |
404 sizeof(kMouse)); | |
405 } | 544 } |
406 | 545 |
407 TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) { | 546 TEST_F(HidReportDescriptorTest, ParseDescriptor_LogitechUnifyingReceiver) { |
408 HidCollectionInfo hidpp_short; | 547 const char expected[] = { |
409 hidpp_short.usage = HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor); | 548 "Usage Page (Vendor)\n" |
410 hidpp_short.report_ids.insert(0x10); | 549 "Usage (0x1)\n" |
411 HidCollectionInfo hidpp_long; | 550 "Collection (Physical)\n" |
412 hidpp_long.usage = HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor); | 551 " Report ID (0x10)\n" |
413 hidpp_long.report_ids.insert(0x11); | 552 " Report Size (8)\n" |
414 HidCollectionInfo hidpp_dj; | 553 " Report Count (6)\n" |
415 hidpp_dj.usage = HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor); | 554 " Logical Minimum (0)\n" |
416 hidpp_dj.report_ids.insert(0x20); | 555 " Logical Maximum (255)\n" |
417 hidpp_dj.report_ids.insert(0x21); | 556 " Usage (0x1)\n" |
| 557 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 558 " Usage (0x1)\n" |
| 559 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 560 "End Collection\n" |
| 561 "Usage Page (Vendor)\n" |
| 562 "Usage (0x2)\n" |
| 563 "Collection (Physical)\n" |
| 564 " Report ID (0x11)\n" |
| 565 " Report Size (8)\n" |
| 566 " Report Count (19)\n" |
| 567 " Logical Minimum (0)\n" |
| 568 " Logical Maximum (255)\n" |
| 569 " Usage (0x2)\n" |
| 570 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 571 " Usage (0x2)\n" |
| 572 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 573 "End Collection\n" |
| 574 "Usage Page (Vendor)\n" |
| 575 "Usage (0x4)\n" |
| 576 "Collection (Physical)\n" |
| 577 " Report ID (0x20)\n" |
| 578 " Report Size (8)\n" |
| 579 " Report Count (14)\n" |
| 580 " Logical Minimum (0)\n" |
| 581 " Logical Maximum (255)\n" |
| 582 " Usage (0x41)\n" |
| 583 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 584 " Usage (0x41)\n" |
| 585 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 586 " Report ID (0x21)\n" |
| 587 " Report Count (31)\n" |
| 588 " Logical Minimum (0)\n" |
| 589 " Logical Maximum (255)\n" |
| 590 " Usage (0x42)\n" |
| 591 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 592 " Usage (0x42)\n" |
| 593 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n" |
| 594 "End Collection\n"}; |
418 | 595 |
419 HidCollectionInfo expected[] = {hidpp_short, hidpp_long, hidpp_dj}; | 596 ParseDescriptor(std::string(expected), |
420 ValidateDetails(std::vector<HidCollectionInfo>( | |
421 expected, expected + ARRAYSIZE_UNSAFE(expected)), | |
422 32, | |
423 32, | |
424 0, | |
425 kLogitechUnifyingReceiver, | 597 kLogitechUnifyingReceiver, |
426 sizeof(kLogitechUnifyingReceiver)); | 598 sizeof(kLogitechUnifyingReceiver)); |
427 } | 599 } |
428 | 600 |
| 601 TEST_F(HidReportDescriptorTest, TopLevelCollections_LogitechUnifyingReceiver) { |
| 602 HidUsageAndPage expected[] = { |
| 603 HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor), |
| 604 HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor), |
| 605 HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor), }; |
| 606 |
| 607 GetTopLevelCollections(std::vector<HidUsageAndPage>( |
| 608 expected, expected + ARRAYSIZE_UNSAFE(expected)), |
| 609 kLogitechUnifyingReceiver, |
| 610 sizeof(kLogitechUnifyingReceiver)); |
| 611 } |
| 612 |
429 } // namespace device | 613 } // namespace device |
OLD | NEW |