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
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7
8 #include <limits>
9 #include <sstream>
10 #include <unordered_map>
11 #include <utility>
12
13 #include "base/macros.h"
14 #include "services/device/hid/test_report_descriptors.h"
15 #include "services/device/public/cpp/hid/hid_report_descriptor.h"
16 #include "services/device/public/cpp/hid/hid_usage_and_page.h"
17 #include "services/device/public/mojom/hid.mojom.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace device {
22
23 namespace {
24 using HidReport = std::vector<std::unique_ptr<HidReportItem>>;
25 using HidReportMap = std::unordered_map<uint8_t, HidReport>;
26 using HidCollectionVector = std::vector<std::unique_ptr<HidCollection>>;
27
28 // HID unit values.
29 const uint32_t kUnitCandela = 0x010000e1;
30 const uint32_t kUnitDegrees = 0x14;
31 const uint32_t kUnitInch = 0x13;
32 const uint32_t kUnitNewton = 0xe111;
33 const uint32_t kUnitSecond = 0x1001;
34
35 // Report info bitfield values. The bits are:
36 // bit 0: Data (0) | Constant (1)
37 // bit 1: Array (0) | Variable (1)
38 // bit 2: Absolute (0) | Relative (1)
39 // bit 3: No Wrap (0) | Wrap (1)
40 // bit 4: Linear (0) | Non-Linear (1)
41 // bit 5: Preferred State (0) | No Preferred State (1)
42 // bit 6: No Null Value (0) | Has Null Value (1)
43 // bit 7: Non-Volatile (0) | Volatile (1)
44 // bit 8: Bit Field (0) | Buffered Bytes (1)
45 const uint16_t kNonNullableArray = 0x0000;
46 const uint16_t kConstantArray = 0x0001;
47 const uint16_t kAbsoluteVariable = 0x0002;
48 const uint16_t kConstant = 0x0003;
49 const uint16_t kRelativeVariable = 0x0006;
50 const uint16_t kNonLinearVariable = 0x0012;
51 const uint16_t kNullableArray = 0x0040;
52 const uint16_t kNullableAbsoluteVariable = 0x0042;
53 const uint16_t kVolatileConstant = 0x0083;
54 const uint16_t kBufferedBytes = 0x0102;
55
56 // Vendor usage pages.
57 const uint16_t kPageVendor02 = mojom::kPageVendor + 0x02;
58 const uint16_t kPageVendor05 = mojom::kPageVendor + 0x05;
59 const uint16_t kPageVendor80 = mojom::kPageVendor + 0x80;
60
61 // Bit-width and mask for the usage ID field in a 32-bit usage value.
62 const size_t kUsageIdSizeBits = sizeof(uint16_t) * 8;
63 const uint32_t kUsageIdMask = std::numeric_limits<uint16_t>::max();
64
65 // Combined usage page and usage ID values. The usage page occupies the high 16
66 // bits, the usage ID occupies the low 16 bits.
67 const uint32_t kUsageButton = (mojom::kPageButton << kUsageIdSizeBits);
68 const uint32_t kUsageConsumer = (mojom::kPageConsumer << kUsageIdSizeBits);
69 const uint32_t kUsageConsumerACBack = kUsageConsumer | 0x0224;
70 const uint32_t kUsageConsumerACHome = kUsageConsumer | 0x0223;
71 const uint32_t kUsageConsumerControl = kUsageConsumer | 0x01;
72 const uint32_t kUsageConsumerModeStep = kUsageConsumer | 0x82;
73 const uint32_t kUsageDigitizer = (mojom::kPageDigitizer << kUsageIdSizeBits);
74 const uint32_t kUsageDigitizerDigitizer = kUsageDigitizer | 0x01;
75 const uint32_t kUsageDigitizerBarrelSwitch = kUsageDigitizer | 0x44;
76 const uint32_t kUsageDigitizerInRange = kUsageDigitizer | 0x32;
77 const uint32_t kUsageDigitizerPuck = kUsageDigitizer | 0x21;
78 const uint32_t kUsageDigitizerStylus = kUsageDigitizer | 0x20;
79 const uint32_t kUsageDigitizerTipPressure = kUsageDigitizer | 0x30;
80 const uint32_t kUsageDigitizerTipSwitch = kUsageDigitizer | 0x42;
81 const uint32_t kUsageGenericDesktop =
82 (mojom::kPageGenericDesktop << kUsageIdSizeBits);
83 const uint32_t kUsageGenericDesktopDial =
84 kUsageGenericDesktop | mojom::kGenericDesktopDial;
85 const uint32_t kUsageGenericDesktopGamePad =
86 kUsageGenericDesktop | mojom::kGenericDesktopGamePad;
87 const uint32_t kUsageGenericDesktopHatSwitch =
88 kUsageGenericDesktop | mojom::kGenericDesktopHatSwitch;
89 const uint32_t kUsageGenericDesktopJoystick =
90 kUsageGenericDesktop | mojom::kGenericDesktopJoystick;
91 const uint32_t kUsageGenericDesktopKeyboard =
92 kUsageGenericDesktop | mojom::kGenericDesktopKeyboard;
93 const uint32_t kUsageGenericDesktopMouse =
94 kUsageGenericDesktop | mojom::kGenericDesktopMouse;
95 const uint32_t kUsageGenericDesktopPointer =
96 kUsageGenericDesktop | mojom::kGenericDesktopPointer;
97 const uint32_t kUsageGenericDesktopRx =
98 kUsageGenericDesktop | mojom::kGenericDesktopRx;
99 const uint32_t kUsageGenericDesktopRy =
100 kUsageGenericDesktop | mojom::kGenericDesktopRy;
101 const uint32_t kUsageGenericDesktopRz =
102 kUsageGenericDesktop | mojom::kGenericDesktopRz;
103 const uint32_t kUsageGenericDesktopSystemControl =
104 kUsageGenericDesktop | mojom::kGenericDesktopSystemControl;
105 const uint32_t kUsageGenericDesktopSystemMainMenu =
106 kUsageGenericDesktop | mojom::kGenericDesktopSystemMainMenu;
107 const uint32_t kUsageGenericDesktopVbrx =
108 kUsageGenericDesktop | mojom::kGenericDesktopVbrx;
109 const uint32_t kUsageGenericDesktopVbry =
110 kUsageGenericDesktop | mojom::kGenericDesktopVbry;
111 const uint32_t kUsageGenericDesktopVbrz =
112 kUsageGenericDesktop | mojom::kGenericDesktopVbrz;
113 const uint32_t kUsageGenericDesktopVx =
114 kUsageGenericDesktop | mojom::kGenericDesktopVx;
115 const uint32_t kUsageGenericDesktopVy =
116 kUsageGenericDesktop | mojom::kGenericDesktopVy;
117 const uint32_t kUsageGenericDesktopVz =
118 kUsageGenericDesktop | mojom::kGenericDesktopVz;
119 const uint32_t kUsageGenericDesktopWheel =
120 kUsageGenericDesktop | mojom::kGenericDesktopWheel;
121 const uint32_t kUsageGenericDesktopX =
122 kUsageGenericDesktop | mojom::kGenericDesktopX;
123 const uint32_t kUsageGenericDesktopY =
124 kUsageGenericDesktop | mojom::kGenericDesktopY;
125 const uint32_t kUsageGenericDesktopZ =
126 kUsageGenericDesktop | mojom::kGenericDesktopZ;
127 const uint32_t kUsageGenericDeviceBatteryStrength =
128 (mojom::kPageGenericDevice << kUsageIdSizeBits) | 0x20;
129 const uint32_t kUsageKeyboard = (mojom::kPageKeyboard << kUsageIdSizeBits);
130 const uint32_t kUsageKeyboardApplication = kUsageKeyboard | 0x65;
131 const uint32_t kUsageKeyboardLeftControl = kUsageKeyboard | 0xe0;
132 const uint32_t kUsageKeyboardRightGui = kUsageKeyboard | 0xe7;
133 const uint32_t kUsageLedNumLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x01;
134 const uint32_t kUsageLedCapsLock = (mojom::kPageLed << kUsageIdSizeBits) | 0x02;
135 const uint32_t kUsageLedScrollLock =
136 (mojom::kPageLed << kUsageIdSizeBits) | 0x03;
137 const uint32_t kUsageLedCompose = (mojom::kPageLed << kUsageIdSizeBits) | 0x04;
138 const uint32_t kUsageLedKana = (mojom::kPageLed << kUsageIdSizeBits) | 0x05;
139 const uint32_t kUsageMonitorControl =
140 (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x01;
141 const uint32_t kUsageMonitorEdidInfo =
142 (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x02;
143 const uint32_t kUsageMonitorVdifInfo =
144 (mojom::kPageMonitor0 << kUsageIdSizeBits) | 0x03;
145 const uint32_t kUsageMonitorBrightness =
146 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x10;
147 const uint32_t kUsageMonitorContrast =
148 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x12;
149 const uint32_t kUsageMonitorRedVideoGain =
150 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x16;
151 const uint32_t kUsageMonitorGreenVideoGain =
152 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x18;
153 const uint32_t kUsageMonitorBlueVideoGain =
154 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x1a;
155 const uint32_t kUsageMonitorHorizontalPosition =
156 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x20;
157 const uint32_t kUsageMonitorHorizontalSize =
158 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x22;
159 const uint32_t kUsageMonitorVerticalPosition =
160 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x30;
161 const uint32_t kUsageMonitorVerticalSize =
162 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x32;
163 const uint32_t kUsageMonitorTrapezoidalDistortion =
164 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x42;
165 const uint32_t kUsageMonitorTilt =
166 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x44;
167 const uint32_t kUsageMonitorRedVideoBlackLevel =
168 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6c;
169 const uint32_t kUsageMonitorGreenVideoBlackLevel =
170 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x6e;
171 const uint32_t kUsageMonitorBlueVideoBlackLevel =
172 (mojom::kPageMonitor2 << kUsageIdSizeBits) | 0x70;
173 const uint32_t kUsagePidSetEffectReport =
174 (mojom::kPagePidPage << kUsageIdSizeBits) | 0x21;
175 const uint32_t kUsagePidDuration =
176 (mojom::kPagePidPage << kUsageIdSizeBits) | 0x50;
177 const uint32_t kUsagePidMagnitude =
178 (mojom::kPagePidPage << kUsageIdSizeBits) | 0x70;
179 const uint32_t kUsagePidLoopCount =
180 (mojom::kPagePidPage << kUsageIdSizeBits) | 0x7c;
181 const uint32_t kUsagePidDCEnableActuators =
182 (mojom::kPagePidPage << kUsageIdSizeBits) | 0x97;
183 const uint32_t kUsagePidStartDelay =
184 (mojom::kPagePidPage << kUsageIdSizeBits) | 0xa7;
185 const uint32_t kUsageSimulationAccelerator =
186 (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc4;
187 const uint32_t kUsageSimulationBrake =
188 (mojom::kPageSimulation << kUsageIdSizeBits) | 0xc5;
189 const uint32_t kUsageVendor = mojom::kPageVendor << kUsageIdSizeBits;
190 const uint32_t kUsageVendor02 = kPageVendor02 << kUsageIdSizeBits;
191 const uint32_t kUsageVendor05 = kPageVendor05 << kUsageIdSizeBits;
192 const uint32_t kUsageVendor80 = kPageVendor80 << kUsageIdSizeBits;
193
194 // Report item tags.
195 const HidReportDescriptorItem::Tag kInput = HidReportDescriptorItem::kTagInput;
196 const HidReportDescriptorItem::Tag kOutput =
197 HidReportDescriptorItem::kTagOutput;
198 const HidReportDescriptorItem::Tag kFeature =
199 HidReportDescriptorItem::kTagFeature;
200 const uint32_t kCollectionTypeApplication =
201 mojom::kHIDCollectionTypeApplication;
202 const uint32_t kCollectionTypeLogical = mojom::kHIDCollectionTypeLogical;
203 const uint32_t kCollectionTypePhysical = mojom::kHIDCollectionTypePhysical;
204
205 } // namespace
206
207 class HidReportDescriptorTest : public testing::Test {
208 protected:
209 using HidUsageAndPage = mojom::HidUsageAndPage;
210 using HidCollectionInfo = mojom::HidCollectionInfo;
211 using HidCollectionInfoPtr = mojom::HidCollectionInfoPtr;
212
TearDown()213 void TearDown() override {
214 descriptor_ = nullptr;
215 expected_collection_infos_.clear();
216 expected_collections_.clear();
217 report_id_ = 0;
218 globals_ = HidItemStateTable::HidGlobalItemState();
219 }
220
221 public:
222 // Add a top-level collection to |expected_collection_infos_|.
AddTopCollectionInfo(HidCollectionInfoPtr collection_info)223 void AddTopCollectionInfo(HidCollectionInfoPtr collection_info) {
224 expected_collection_infos_.push_back(std::move(collection_info));
225 }
226
227 // Create a new collection and append it to |expected_collections_|.
AddTopCollection(uint32_t usage,uint32_t collection_type)228 HidCollection* AddTopCollection(uint32_t usage, uint32_t collection_type) {
229 uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
230 usage = usage & kUsageIdMask;
231 expected_collections_.push_back(std::make_unique<HidCollection>(
232 nullptr, usage_page, usage, static_cast<uint32_t>(collection_type)));
233 return expected_collections_.back().get();
234 }
235
236 // Create a new collection as a child of |parent|.
AddChild(HidCollection * parent,uint32_t usage,uint32_t collection_type)237 HidCollection* AddChild(HidCollection* parent,
238 uint32_t usage,
239 uint32_t collection_type) {
240 uint16_t usage_page = (usage >> kUsageIdSizeBits) & kUsageIdMask;
241 usage = usage & kUsageIdMask;
242 parent->AddChildForTesting(std::make_unique<HidCollection>(
243 parent, usage_page, usage, static_cast<uint32_t>(collection_type)));
244 return parent->GetChildren().back().get();
245 }
246
247 // Set the |report_id|. Subsequent report items will be appended to the report
248 // with this ID.
SetReportId(uint8_t report_id)249 void SetReportId(uint8_t report_id) { report_id_ = report_id; }
250
251 // Set the |unit| and |unit_exponent|. Subsequent report items will inherit
252 // these values.
SetUnitAndUnitExponent(uint32_t unit,uint32_t unit_exponent)253 void SetUnitAndUnitExponent(uint32_t unit, uint32_t unit_exponent) {
254 globals_.unit = unit;
255 globals_.unit_exponent = unit_exponent;
256 }
257
258 // Set the logical and physical minimums and maximums. Subsequent report items
259 // will inherit these values.
SetLogicalAndPhysicalBounds(uint32_t logical_minimum,uint32_t logical_maximum,uint32_t physical_minimum,uint32_t physical_maximum)260 void SetLogicalAndPhysicalBounds(uint32_t logical_minimum,
261 uint32_t logical_maximum,
262 uint32_t physical_minimum,
263 uint32_t physical_maximum) {
264 globals_.logical_minimum = int32_t{logical_minimum};
265 globals_.logical_maximum = int32_t{logical_maximum};
266 globals_.physical_minimum = int32_t{physical_minimum};
267 globals_.physical_maximum = int32_t{physical_maximum};
268 }
269
270 // Set the |report_size| in bits, and the |report_count|. Subsequent report
271 // items will inherit these values.
SetReportSizeAndCount(uint32_t report_size,uint32_t report_count)272 void SetReportSizeAndCount(uint32_t report_size, uint32_t report_count) {
273 globals_.report_size = report_size;
274 globals_.report_count = report_count;
275 }
276
277 // Add a report item with a size and count but no usage value.
AddReportConstant(HidCollection * collection,HidReportDescriptorItem::Tag tag,uint32_t report_info)278 void AddReportConstant(HidCollection* collection,
279 HidReportDescriptorItem::Tag tag,
280 uint32_t report_info) {
281 HidItemStateTable state;
282 state.global_stack.push_back(globals_);
283 state.report_id = report_id_;
284 for (const HidCollection* c = collection; c; c = c->GetParent())
285 const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
286 }
287
288 // Add a report item for one or more usages with the same size. The size of
289 // |usage_ids| is not required to be the same as the report count.
AddReportItem(HidCollection * collection,HidReportDescriptorItem::Tag tag,uint32_t report_info,const std::vector<uint32_t> & usage_ids)290 void AddReportItem(HidCollection* collection,
291 HidReportDescriptorItem::Tag tag,
292 uint32_t report_info,
293 const std::vector<uint32_t>& usage_ids) {
294 HidItemStateTable state;
295 state.global_stack.push_back(globals_);
296 state.report_id = report_id_;
297 state.local.usages = usage_ids;
298 for (const HidCollection* c = collection; c; c = c->GetParent())
299 const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
300 }
301
302 // Add a report item for a range of usages. The item may be a variable or an
303 // array.
AddReportItemRange(HidCollection * collection,HidReportDescriptorItem::Tag tag,uint32_t report_info,uint32_t usage_minimum,uint32_t usage_maximum)304 void AddReportItemRange(HidCollection* collection,
305 HidReportDescriptorItem::Tag tag,
306 uint32_t report_info,
307 uint32_t usage_minimum,
308 uint32_t usage_maximum) {
309 HidItemStateTable state;
310 state.global_stack.push_back(globals_);
311 state.report_id = report_id_;
312 state.local.usage_minimum = usage_minimum;
313 state.local.usage_maximum = usage_maximum;
314 for (const HidCollection* c = collection; c; c = c->GetParent())
315 const_cast<HidCollection*>(c)->AddReportItem(tag, report_info, state);
316 }
317
ValidateDetails(const bool expected_has_report_id,const size_t expected_max_input_report_size,const size_t expected_max_output_report_size,const size_t expected_max_feature_report_size,const uint8_t * bytes,size_t size)318 void ValidateDetails(
319 const bool expected_has_report_id,
320 const size_t expected_max_input_report_size,
321 const size_t expected_max_output_report_size,
322 const size_t expected_max_feature_report_size,
323 const uint8_t* bytes,
324 size_t size) {
325 descriptor_ = std::make_unique<HidReportDescriptor>(
326 std::vector<uint8_t>(bytes, bytes + size));
327 std::vector<HidCollectionInfoPtr> actual_collection_infos;
328 bool actual_has_report_id;
329 size_t actual_max_input_report_size;
330 size_t actual_max_output_report_size;
331 size_t actual_max_feature_report_size;
332 descriptor_->GetDetails(&actual_collection_infos, &actual_has_report_id,
333 &actual_max_input_report_size,
334 &actual_max_output_report_size,
335 &actual_max_feature_report_size);
336
337 ASSERT_EQ(expected_collection_infos_.size(),
338 actual_collection_infos.size());
339 auto actual_info_iter = actual_collection_infos.begin();
340 auto expected_info_iter = expected_collection_infos_.begin();
341 while (expected_info_iter != expected_collection_infos_.end() &&
342 actual_info_iter != actual_collection_infos.end()) {
343 const HidCollectionInfoPtr& expected_info = *expected_info_iter;
344 const HidCollectionInfoPtr& actual_info = *actual_info_iter;
345 ASSERT_EQ(expected_info->usage->usage_page,
346 actual_info->usage->usage_page);
347 ASSERT_EQ(expected_info->usage->usage, actual_info->usage->usage);
348 ASSERT_THAT(actual_info->report_ids,
349 testing::ContainerEq(expected_info->report_ids));
350 ++expected_info_iter;
351 ++actual_info_iter;
352 }
353 ASSERT_EQ(expected_has_report_id, actual_has_report_id);
354 ASSERT_EQ(expected_max_input_report_size, actual_max_input_report_size);
355 ASSERT_EQ(expected_max_output_report_size, actual_max_output_report_size);
356 ASSERT_EQ(expected_max_feature_report_size, actual_max_feature_report_size);
357 }
358
ValidateReportItem(const HidReportItem & expected,const HidReportItem & actual)359 static void ValidateReportItem(const HidReportItem& expected,
360 const HidReportItem& actual) {
361 uint32_t expected_report_info =
362 *reinterpret_cast<const uint32_t*>(&expected.GetReportInfo());
363 uint32_t actual_report_info =
364 *reinterpret_cast<const uint32_t*>(&actual.GetReportInfo());
365 ASSERT_EQ(expected.GetTag(), actual.GetTag());
366 ASSERT_EQ(expected_report_info, actual_report_info);
367 ASSERT_EQ(expected.GetReportId(), actual.GetReportId());
368 ASSERT_THAT(actual.GetUsages(), testing::ContainerEq(expected.GetUsages()));
369 ASSERT_EQ(expected.GetUsageMinimum(), actual.GetUsageMinimum());
370 ASSERT_EQ(expected.GetUsageMaximum(), actual.GetUsageMaximum());
371 ASSERT_EQ(expected.GetDesignatorMinimum(), actual.GetDesignatorMinimum());
372 ASSERT_EQ(expected.GetDesignatorMaximum(), actual.GetDesignatorMaximum());
373 ASSERT_EQ(expected.GetStringMinimum(), actual.GetStringMinimum());
374 ASSERT_EQ(expected.GetStringMaximum(), actual.GetStringMaximum());
375 ASSERT_EQ(expected.GetLogicalMinimum(), actual.GetLogicalMinimum());
376 ASSERT_EQ(expected.GetLogicalMaximum(), actual.GetLogicalMaximum());
377 ASSERT_EQ(expected.GetPhysicalMinimum(), actual.GetPhysicalMinimum());
378 ASSERT_EQ(expected.GetPhysicalMaximum(), actual.GetPhysicalMaximum());
379 ASSERT_EQ(expected.GetUnitExponent(), actual.GetUnitExponent());
380 ASSERT_EQ(expected.GetUnit(), actual.GetUnit());
381 ASSERT_EQ(expected.GetReportSize(), actual.GetReportSize());
382 ASSERT_EQ(expected.GetReportCount(), actual.GetReportCount());
383 }
384
ValidateReportMap(const HidReportMap & expected_reports,const HidReportMap & actual_reports)385 static void ValidateReportMap(const HidReportMap& expected_reports,
386 const HidReportMap& actual_reports) {
387 for (const auto& expected_entry : expected_reports) {
388 auto find_it = actual_reports.find(expected_entry.first);
389 ASSERT_NE(find_it, actual_reports.end());
390 const auto& expected_report = expected_entry.second;
391 const auto& actual_report = find_it->second;
392 ASSERT_EQ(expected_report.size(), actual_report.size());
393 auto expected_item_iter = expected_report.begin();
394 auto actual_item_iter = actual_report.begin();
395 while (expected_item_iter != expected_report.end() &&
396 actual_item_iter != actual_report.end()) {
397 ValidateReportItem(**expected_item_iter, **actual_item_iter);
398 ++expected_item_iter;
399 ++actual_item_iter;
400 }
401 }
402 ASSERT_EQ(expected_reports.size(), actual_reports.size());
403 }
404
ValidateLinkCollection(const HidCollection * expected_collection,const HidCollection * actual_collection)405 static void ValidateLinkCollection(const HidCollection* expected_collection,
406 const HidCollection* actual_collection) {
407 ASSERT_EQ(expected_collection->GetUsagePage(),
408 actual_collection->GetUsagePage());
409 ASSERT_EQ(expected_collection->GetUsage(), actual_collection->GetUsage());
410 ASSERT_EQ(expected_collection->GetCollectionType(),
411 actual_collection->GetCollectionType());
412 ValidateReportMap(expected_collection->GetInputReports(),
413 actual_collection->GetInputReports());
414 ValidateReportMap(expected_collection->GetOutputReports(),
415 actual_collection->GetOutputReports());
416 ValidateReportMap(expected_collection->GetFeatureReports(),
417 actual_collection->GetFeatureReports());
418 const auto& expected_children = expected_collection->GetChildren();
419 const auto& actual_children = actual_collection->GetChildren();
420 auto expected_child_iter = expected_children.begin();
421 auto actual_child_iter = actual_children.begin();
422 while (expected_child_iter != expected_children.end() &&
423 actual_child_iter != actual_children.end()) {
424 const HidCollection* expected_child = expected_child_iter->get();
425 const HidCollection* actual_child = actual_child_iter->get();
426 ASSERT_EQ(actual_child->GetParent(), actual_collection);
427 ValidateLinkCollection(expected_child, actual_child);
428 ++expected_child_iter;
429 ++actual_child_iter;
430 }
431 ASSERT_EQ(expected_children.size(), actual_children.size());
432 }
433
ValidateCollections(const uint8_t * bytes,size_t size)434 void ValidateCollections(const uint8_t* bytes, size_t size) {
435 descriptor_ = std::make_unique<HidReportDescriptor>(
436 std::vector<uint8_t>(bytes, bytes + size));
437 const auto& actual_collections = descriptor_->collections();
438 auto actual_collection_iter = actual_collections.begin();
439 auto expected_collection_iter = expected_collections_.begin();
440 while (expected_collection_iter != expected_collections_.end() &&
441 actual_collection_iter != actual_collections.end()) {
442 ValidateLinkCollection(expected_collection_iter->get(),
443 actual_collection_iter->get());
444 ++expected_collection_iter;
445 ++actual_collection_iter;
446 }
447 ASSERT_EQ(expected_collections_.size(), actual_collections.size());
448 }
449
450 private:
451 std::unique_ptr<HidReportDescriptor> descriptor_;
452 std::vector<HidCollectionInfoPtr> expected_collection_infos_;
453 HidCollectionVector expected_collections_;
454 uint8_t report_id_ = 0;
455 HidItemStateTable::HidGlobalItemState globals_;
456 };
457
TEST_F(HidReportDescriptorTest,ValidateDetails_Digitizer)458 TEST_F(HidReportDescriptorTest, ValidateDetails_Digitizer) {
459 auto digitizer = HidCollectionInfo::New();
460 digitizer->usage = HidUsageAndPage::New(0x01, mojom::kPageDigitizer);
461 ASSERT_EQ(IsProtected(*digitizer->usage), false);
462 digitizer->report_ids = {0x01, 0x02, 0x03};
463 AddTopCollectionInfo(std::move(digitizer));
464 ValidateDetails(true, 6, 0, 0, kDigitizer, kDigitizerSize);
465 }
466
TEST_F(HidReportDescriptorTest,ValidateCollections_Digitizer)467 TEST_F(HidReportDescriptorTest, ValidateCollections_Digitizer) {
468 auto* top =
469 AddTopCollection(kUsageDigitizerDigitizer, kCollectionTypeApplication);
470 auto* puck = AddChild(top, kUsageDigitizerPuck, kCollectionTypePhysical);
471 SetReportId(0x01);
472 SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
473 SetUnitAndUnitExponent(kUnitInch, 0);
474 SetReportSizeAndCount(16, 2);
475 AddReportItem(puck, kInput, kAbsoluteVariable,
476 {kUsageGenericDesktopX, kUsageGenericDesktopY});
477 SetLogicalAndPhysicalBounds(0, 1, 0, 1);
478 SetUnitAndUnitExponent(0, 0);
479 SetReportSizeAndCount(1, 3);
480 AddReportItem(puck, kInput, kAbsoluteVariable,
481 {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch,
482 kUsageDigitizerTipSwitch});
483 SetReportSizeAndCount(5, 1);
484 AddReportConstant(puck, kInput, kConstant);
485 SetReportId(0x02);
486 auto* stylus_up =
487 AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
488 SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
489 SetUnitAndUnitExponent(kUnitInch, 0);
490 SetReportSizeAndCount(16, 2);
491 AddReportItem(stylus_up, kInput, kAbsoluteVariable,
492 {kUsageGenericDesktopX, kUsageGenericDesktopY});
493 SetLogicalAndPhysicalBounds(0, 1, 0, 1);
494 SetUnitAndUnitExponent(0, 0);
495 SetReportSizeAndCount(1, 2);
496 AddReportItem(stylus_up, kInput, kAbsoluteVariable, {kUsageDigitizerInRange});
497 SetLogicalAndPhysicalBounds(0, 16, 0, 1);
498 SetReportSizeAndCount(5, 2);
499 AddReportItemRange(stylus_up, kInput, kNullableArray, kUsageButton,
500 kUsageButton + 16);
501 SetReportSizeAndCount(2, 2);
502 AddReportConstant(stylus_up, kInput, kConstantArray);
503 SetReportId(0x03);
504 auto* stylus_down =
505 AddChild(top, kUsageDigitizerStylus, kCollectionTypePhysical);
506 SetLogicalAndPhysicalBounds(0, 12000, 0, 12);
507 SetUnitAndUnitExponent(kUnitInch, 0);
508 SetReportSizeAndCount(16, 2);
509 AddReportItem(stylus_down, kInput, kAbsoluteVariable,
510 {kUsageGenericDesktopX, kUsageGenericDesktopY});
511 SetLogicalAndPhysicalBounds(0, 1, 0, 1);
512 SetUnitAndUnitExponent(0, 0);
513 SetReportSizeAndCount(1, 2);
514 AddReportItem(stylus_down, kInput, kAbsoluteVariable,
515 {kUsageDigitizerInRange, kUsageDigitizerBarrelSwitch});
516 SetReportSizeAndCount(1, 6);
517 AddReportConstant(stylus_down, kInput, kConstant);
518 SetLogicalAndPhysicalBounds(0, 127, 0, 45);
519 SetUnitAndUnitExponent(kUnitNewton, 4);
520 SetReportSizeAndCount(8, 1);
521 AddReportItem(stylus_down, kInput, kNonLinearVariable,
522 {kUsageDigitizerTipPressure});
523 ValidateCollections(kDigitizer, kDigitizerSize);
524 }
525
TEST_F(HidReportDescriptorTest,ValidateDetails_Keyboard)526 TEST_F(HidReportDescriptorTest, ValidateDetails_Keyboard) {
527 auto keyboard = HidCollectionInfo::New();
528 keyboard->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
529 mojom::kPageGenericDesktop);
530 ASSERT_EQ(IsProtected(*keyboard->usage), true);
531 AddTopCollectionInfo(std::move(keyboard));
532 ValidateDetails(false, 8, 1, 0, kKeyboard, kKeyboardSize);
533 }
534
TEST_F(HidReportDescriptorTest,ValidateCollections_Keyboard)535 TEST_F(HidReportDescriptorTest, ValidateCollections_Keyboard) {
536 auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
537 kCollectionTypeApplication);
538 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
539 SetReportSizeAndCount(1, 8);
540 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
541 kUsageKeyboardRightGui);
542 SetReportSizeAndCount(8, 1);
543 AddReportConstant(top, kInput, kConstant);
544 SetReportSizeAndCount(1, 5);
545 AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
546 kUsageLedKana);
547 SetReportSizeAndCount(3, 1);
548 AddReportConstant(top, kOutput, kConstant);
549 SetLogicalAndPhysicalBounds(0, 101, 0, 0);
550 SetReportSizeAndCount(8, 6);
551 AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
552 kUsageKeyboardApplication);
553 ValidateCollections(kKeyboard, kKeyboardSize);
554 }
555
TEST_F(HidReportDescriptorTest,ValidateDetails_Monitor)556 TEST_F(HidReportDescriptorTest, ValidateDetails_Monitor) {
557 auto monitor = HidCollectionInfo::New();
558 monitor->usage = HidUsageAndPage::New(0x01, mojom::kPageMonitor0);
559 ASSERT_EQ(IsProtected(*monitor->usage), false);
560 monitor->report_ids = {0x01, 0x02, 0x03, 0x04, 0x05};
561 AddTopCollectionInfo(std::move(monitor));
562 ValidateDetails(true, 0, 0, 243, kMonitor, kMonitorSize);
563 }
564
TEST_F(HidReportDescriptorTest,ValidateCollections_Monitor)565 TEST_F(HidReportDescriptorTest, ValidateCollections_Monitor) {
566 auto* top =
567 AddTopCollection(kUsageMonitorControl, kCollectionTypeApplication);
568 SetReportId(0x01);
569 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
570 SetReportSizeAndCount(8, 128);
571 AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorEdidInfo});
572 SetReportId(0x02);
573 SetReportSizeAndCount(8, 243);
574 AddReportItem(top, kFeature, kBufferedBytes, {kUsageMonitorVdifInfo});
575 SetReportId(0x03);
576 SetUnitAndUnitExponent(kUnitCandela, 0x0e);
577 SetReportSizeAndCount(16, 1);
578 SetLogicalAndPhysicalBounds(0, 200, 0, 0);
579 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorBrightness});
580 SetReportId(0x04);
581 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
582 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageMonitorContrast});
583 SetReportSizeAndCount(16, 6);
584 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
585 AddReportItem(
586 top, kFeature, kAbsoluteVariable,
587 {kUsageMonitorRedVideoGain, kUsageMonitorGreenVideoGain,
588 kUsageMonitorBlueVideoGain, kUsageMonitorRedVideoBlackLevel,
589 kUsageMonitorGreenVideoBlackLevel, kUsageMonitorBlueVideoBlackLevel});
590 SetReportId(0x05);
591 SetLogicalAndPhysicalBounds(0, 127, 0, 0);
592 AddReportItem(top, kFeature, kAbsoluteVariable,
593 {kUsageMonitorHorizontalPosition, kUsageMonitorHorizontalSize,
594 kUsageMonitorVerticalPosition, kUsageMonitorVerticalSize,
595 kUsageMonitorTrapezoidalDistortion, kUsageMonitorTilt});
596 ValidateCollections(kMonitor, kMonitorSize);
597 }
598
TEST_F(HidReportDescriptorTest,ValidateDetails_Mouse)599 TEST_F(HidReportDescriptorTest, ValidateDetails_Mouse) {
600 auto mouse = HidCollectionInfo::New();
601 mouse->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
602 mojom::kPageGenericDesktop);
603 ASSERT_EQ(IsProtected(*mouse->usage), true);
604 AddTopCollectionInfo(std::move(mouse));
605 ValidateDetails(false, 3, 0, 0, kMouse, kMouseSize);
606 }
607
TEST_F(HidReportDescriptorTest,ValidateCollections_Mouse)608 TEST_F(HidReportDescriptorTest, ValidateCollections_Mouse) {
609 auto* top =
610 AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
611 auto* physical =
612 AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
613 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
614 SetReportSizeAndCount(1, 3);
615 AddReportItemRange(physical, kInput, kAbsoluteVariable, kUsageButton + 1,
616 kUsageButton + 3);
617 SetReportSizeAndCount(5, 1);
618 AddReportConstant(physical, kInput, kConstant);
619 SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
620 SetReportSizeAndCount(8, 2);
621 AddReportItem(physical, kInput, kRelativeVariable,
622 {kUsageGenericDesktopX, kUsageGenericDesktopY});
623 ValidateCollections(kMouse, kMouseSize);
624 }
625
TEST_F(HidReportDescriptorTest,ValidateDetails_LogitechUnifyingReceiver)626 TEST_F(HidReportDescriptorTest, ValidateDetails_LogitechUnifyingReceiver) {
627 auto hidpp_short = HidCollectionInfo::New();
628 hidpp_short->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
629 ASSERT_EQ(IsProtected(*hidpp_short->usage), false);
630 hidpp_short->report_ids = {0x10};
631 auto hidpp_long = HidCollectionInfo::New();
632 hidpp_long->usage = HidUsageAndPage::New(0x02, mojom::kPageVendor);
633 ASSERT_EQ(IsProtected(*hidpp_long->usage), false);
634 hidpp_long->report_ids = {0x11};
635 auto hidpp_dj = HidCollectionInfo::New();
636 hidpp_dj->usage = HidUsageAndPage::New(0x04, mojom::kPageVendor);
637 ASSERT_EQ(IsProtected(*hidpp_dj->usage), false);
638 hidpp_dj->report_ids = {0x20, 0x21};
639 AddTopCollectionInfo(std::move(hidpp_short));
640 AddTopCollectionInfo(std::move(hidpp_long));
641 AddTopCollectionInfo(std::move(hidpp_dj));
642 ValidateDetails(true, 31, 31, 0, kLogitechUnifyingReceiver,
643 kLogitechUnifyingReceiverSize);
644 }
645
TEST_F(HidReportDescriptorTest,ValidateCollections_LogitechUnifyingReceiver)646 TEST_F(HidReportDescriptorTest, ValidateCollections_LogitechUnifyingReceiver) {
647 auto* short_collection =
648 AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
649 SetReportId(0x10);
650 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
651 SetReportSizeAndCount(8, 6);
652 AddReportItem(short_collection, kInput, kNonNullableArray,
653 {kUsageVendor + 0x01});
654 AddReportItem(short_collection, kOutput, kNonNullableArray,
655 {kUsageVendor + 0x01});
656 auto* long_collection =
657 AddTopCollection(kUsageVendor + 0x02, kCollectionTypeApplication);
658 SetReportId(0x11);
659 SetReportSizeAndCount(8, 19);
660 AddReportItem(long_collection, kInput, kNonNullableArray,
661 {kUsageVendor + 0x02});
662 AddReportItem(long_collection, kOutput, kNonNullableArray,
663 {kUsageVendor + 0x02});
664 auto* dj_collection =
665 AddTopCollection(kUsageVendor + 0x04, kCollectionTypeApplication);
666 SetReportId(0x20);
667 SetReportSizeAndCount(8, 14);
668 AddReportItem(dj_collection, kInput, kNonNullableArray,
669 {kUsageVendor + 0x41});
670 AddReportItem(dj_collection, kOutput, kNonNullableArray,
671 {kUsageVendor + 0x41});
672 SetReportId(0x21);
673 SetReportSizeAndCount(8, 31);
674 AddReportItem(dj_collection, kInput, kNonNullableArray,
675 {kUsageVendor + 0x42});
676 AddReportItem(dj_collection, kOutput, kNonNullableArray,
677 {kUsageVendor + 0x42});
678 ValidateCollections(kLogitechUnifyingReceiver, kLogitechUnifyingReceiverSize);
679 }
680
TEST_F(HidReportDescriptorTest,ValidateDetails_SonyDualshock3)681 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock3) {
682 auto top_info = HidCollectionInfo::New();
683 top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
684 mojom::kPageGenericDesktop);
685 ASSERT_EQ(IsProtected(*top_info->usage), false);
686 top_info->report_ids = {0x01, 0x02, 0xee, 0xef};
687 AddTopCollectionInfo(std::move(top_info));
688 ValidateDetails(true, 48, 48, 48, kSonyDualshock3, kSonyDualshock3Size);
689 }
690
TEST_F(HidReportDescriptorTest,ValidateCollections_SonyDualshock3)691 TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock3) {
692 auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
693 kCollectionTypeApplication);
694 auto* joystick = AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
695 SetReportId(0x01);
696 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
697 SetReportSizeAndCount(8, 1);
698 AddReportConstant(joystick, kInput, kConstant);
699 SetLogicalAndPhysicalBounds(0, 1, 0, 1);
700 SetReportSizeAndCount(1, 19);
701 AddReportItemRange(joystick, kInput, kAbsoluteVariable, kUsageButton + 1,
702 kUsageButton + 19);
703 SetReportSizeAndCount(1, 13);
704 AddReportConstant(joystick, kInput, kConstant);
705 auto* stick_axes =
706 AddChild(joystick, kUsageGenericDesktopPointer, kCollectionTypePhysical);
707 SetLogicalAndPhysicalBounds(0, 255, 0, 255);
708 SetReportSizeAndCount(8, 4);
709 AddReportItem(stick_axes, kInput, kAbsoluteVariable,
710 {kUsageGenericDesktopX, kUsageGenericDesktopY,
711 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
712 SetReportSizeAndCount(8, 39);
713 AddReportItem(joystick, kInput, kAbsoluteVariable,
714 {kUsageGenericDesktopPointer});
715 SetReportSizeAndCount(8, 48);
716 AddReportItem(joystick, kOutput, kAbsoluteVariable,
717 {kUsageGenericDesktopPointer});
718 AddReportItem(joystick, kFeature, kAbsoluteVariable,
719 {kUsageGenericDesktopPointer});
720 auto* report_02_collection =
721 AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
722 SetReportId(0x02);
723 AddReportItem(report_02_collection, kFeature, kAbsoluteVariable,
724 {kUsageGenericDesktopPointer});
725 auto* report_ee_collection =
726 AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
727 SetReportId(0xee);
728 AddReportItem(report_ee_collection, kFeature, kAbsoluteVariable,
729 {kUsageGenericDesktopPointer});
730 auto* report_ef_collection =
731 AddChild(top, kUsageGenericDesktop, kCollectionTypeLogical);
732 SetReportId(0xef);
733 AddReportItem(report_ef_collection, kFeature, kAbsoluteVariable,
734 {kUsageGenericDesktopPointer});
735 ValidateCollections(kSonyDualshock3, kSonyDualshock3Size);
736 }
737
TEST_F(HidReportDescriptorTest,ValidateDetails_SonyDualshock4)738 TEST_F(HidReportDescriptorTest, ValidateDetails_SonyDualshock4) {
739 auto top_info = HidCollectionInfo::New();
740 top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
741 mojom::kPageGenericDesktop);
742 ASSERT_EQ(IsProtected(*top_info->usage), false);
743 top_info->report_ids = {0x01, 0x05, 0x04, 0x02, 0x08, 0x10, 0x11, 0x12, 0x13,
744 0x14, 0x15, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
745 0x87, 0x88, 0x89, 0x90, 0x91, 0x92, 0x93, 0xa0, 0xa1,
746 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xf0, 0xf1, 0xf2, 0xa7,
747 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0};
748 AddTopCollectionInfo(std::move(top_info));
749 ValidateDetails(true, 63, 31, 63, kSonyDualshock4, kSonyDualshock4Size);
750 }
751
TEST_F(HidReportDescriptorTest,ValidateCollections_SonyDualshock4)752 TEST_F(HidReportDescriptorTest, ValidateCollections_SonyDualshock4) {
753 auto* top =
754 AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
755 SetReportId(0x01);
756 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
757 SetReportSizeAndCount(8, 4);
758 AddReportItem(top, kInput, kAbsoluteVariable,
759 {kUsageGenericDesktopX, kUsageGenericDesktopY,
760 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
761 SetLogicalAndPhysicalBounds(0, 7, 0, 315);
762 SetUnitAndUnitExponent(kUnitDegrees, 0);
763 SetReportSizeAndCount(4, 1);
764 AddReportItem(top, kInput, kNullableAbsoluteVariable,
765 {kUsageGenericDesktopHatSwitch});
766 SetLogicalAndPhysicalBounds(0, 1, 0, 315);
767 SetUnitAndUnitExponent(0, 0);
768 SetReportSizeAndCount(1, 14);
769 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
770 kUsageButton + 14);
771 SetLogicalAndPhysicalBounds(0, 127, 0, 315);
772 SetReportSizeAndCount(6, 1);
773 AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x20});
774 SetLogicalAndPhysicalBounds(0, 255, 0, 315);
775 SetReportSizeAndCount(8, 2);
776 AddReportItem(top, kInput, kAbsoluteVariable,
777 {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
778 SetReportSizeAndCount(8, 54);
779 AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x21});
780 SetReportId(0x05);
781 SetReportSizeAndCount(8, 31);
782 AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x22});
783 SetReportId(0x04);
784 SetReportSizeAndCount(8, 36);
785 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x23});
786 SetReportId(0x02);
787 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x24});
788 SetReportId(0x08);
789 SetReportSizeAndCount(8, 3);
790 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x25});
791 SetReportId(0x10);
792 SetReportSizeAndCount(8, 4);
793 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x26});
794 SetReportId(0x11);
795 SetReportSizeAndCount(8, 2);
796 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x27});
797 SetReportId(0x12);
798 SetReportSizeAndCount(8, 15);
799 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x21});
800 SetReportId(0x13);
801 SetReportSizeAndCount(8, 22);
802 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor02 + 0x22});
803 SetReportId(0x14);
804 SetReportSizeAndCount(8, 16);
805 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x20});
806 SetReportId(0x15);
807 SetReportSizeAndCount(8, 44);
808 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor05 + 0x21});
809 SetReportId(0x80);
810 SetReportSizeAndCount(8, 6);
811 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x20});
812 SetReportId(0x81);
813 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x21});
814 SetReportId(0x82);
815 SetReportSizeAndCount(8, 5);
816 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x22});
817 SetReportId(0x83);
818 SetReportSizeAndCount(8, 1);
819 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x23});
820 SetReportId(0x84);
821 SetReportSizeAndCount(8, 4);
822 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x24});
823 SetReportId(0x85);
824 SetReportSizeAndCount(8, 6);
825 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x25});
826 SetReportId(0x86);
827 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x26});
828 SetReportId(0x87);
829 SetReportSizeAndCount(8, 35);
830 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x27});
831 SetReportId(0x88);
832 SetReportSizeAndCount(8, 34);
833 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x28});
834 SetReportId(0x89);
835 SetReportSizeAndCount(8, 2);
836 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x29});
837 SetReportId(0x90);
838 SetReportSizeAndCount(8, 5);
839 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x30});
840 SetReportId(0x91);
841 SetReportSizeAndCount(8, 3);
842 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x31});
843 SetReportId(0x92);
844 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x32});
845 SetReportId(0x93);
846 SetReportSizeAndCount(8, 12);
847 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x33});
848 SetReportId(0xa0);
849 SetReportSizeAndCount(8, 6);
850 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x40});
851 SetReportId(0xa1);
852 SetReportSizeAndCount(8, 1);
853 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x41});
854 SetReportId(0xa2);
855 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x42});
856 SetReportId(0xa3);
857 SetReportSizeAndCount(8, 48);
858 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x43});
859 SetReportId(0xa4);
860 SetReportSizeAndCount(8, 13);
861 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x44});
862 SetReportId(0xa5);
863 SetReportSizeAndCount(8, 21);
864 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x45});
865 SetReportId(0xa6);
866 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x46});
867 SetReportId(0xf0);
868 SetReportSizeAndCount(8, 63);
869 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x47});
870 SetReportId(0xf1);
871 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x48});
872 SetReportId(0xf2);
873 SetReportSizeAndCount(8, 15);
874 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x49});
875 SetReportId(0xa7);
876 SetReportSizeAndCount(8, 1);
877 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4a});
878 SetReportId(0xa8);
879 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4b});
880 SetReportId(0xa9);
881 SetReportSizeAndCount(8, 8);
882 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4c});
883 SetReportId(0xaa);
884 SetReportSizeAndCount(8, 1);
885 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4e});
886 SetReportId(0xab);
887 SetReportSizeAndCount(8, 57);
888 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x4f});
889 SetReportId(0xac);
890 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x50});
891 SetReportId(0xad);
892 SetReportSizeAndCount(8, 11);
893 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x51});
894 SetReportId(0xae);
895 SetReportSizeAndCount(8, 1);
896 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x52});
897 SetReportId(0xaf);
898 SetReportSizeAndCount(8, 2);
899 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x53});
900 SetReportId(0xb0);
901 SetReportSizeAndCount(8, 63);
902 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor80 + 0x54});
903 ValidateCollections(kSonyDualshock4, kSonyDualshock4Size);
904 }
905
TEST_F(HidReportDescriptorTest,ValidateDetails_XboxWirelessController)906 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxWirelessController) {
907 auto top_info = HidCollectionInfo::New();
908 top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
909 mojom::kPageGenericDesktop);
910 ASSERT_EQ(IsProtected(*top_info->usage), false);
911 top_info->report_ids = {0x01, 0x02, 0x03, 0x04};
912 AddTopCollectionInfo(std::move(top_info));
913 ValidateDetails(true, 15, 8, 0, kMicrosoftXboxWirelessController,
914 kMicrosoftXboxWirelessControllerSize);
915 }
916
TEST_F(HidReportDescriptorTest,ValidateCollections_XboxWirelessController)917 TEST_F(HidReportDescriptorTest, ValidateCollections_XboxWirelessController) {
918 auto* top =
919 AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
920 SetReportId(0x01);
921 auto* left_stick =
922 AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
923 SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
924 SetReportSizeAndCount(16, 2);
925 AddReportItem(left_stick, kInput, kAbsoluteVariable,
926 {kUsageGenericDesktopX, kUsageGenericDesktopY});
927 auto* right_stick =
928 AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
929 SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
930 AddReportItem(right_stick, kInput, kAbsoluteVariable,
931 {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
932 SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
933 SetReportSizeAndCount(10, 1);
934 AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopZ});
935 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
936 SetReportSizeAndCount(6, 1);
937 AddReportConstant(top, kInput, kConstant);
938 SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
939 SetReportSizeAndCount(10, 1);
940 AddReportItem(top, kInput, kAbsoluteVariable, {kUsageGenericDesktopRz});
941 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
942 SetReportSizeAndCount(6, 1);
943 AddReportConstant(top, kInput, kConstant);
944 SetLogicalAndPhysicalBounds(1, 8, 0, 315);
945 SetUnitAndUnitExponent(kUnitDegrees, 0);
946 SetReportSizeAndCount(4, 1);
947 AddReportItem(top, kInput, kNullableAbsoluteVariable,
948 {kUsageGenericDesktopHatSwitch});
949 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
950 SetUnitAndUnitExponent(0, 0);
951 AddReportConstant(top, kInput, kConstant);
952 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
953 SetReportSizeAndCount(1, 10);
954 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
955 kUsageButton + 10);
956 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
957 SetReportSizeAndCount(6, 1);
958 AddReportConstant(top, kInput, kConstant);
959 SetReportId(0x02);
960 auto* mode_collection =
961 AddChild(top, kUsageGenericDesktopSystemControl, kCollectionTypePhysical);
962 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
963 SetReportSizeAndCount(1, 1);
964 AddReportItem(mode_collection, kInput, kAbsoluteVariable,
965 {kUsageGenericDesktopSystemMainMenu});
966 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
967 SetReportSizeAndCount(7, 1);
968 AddReportConstant(mode_collection, kInput, kConstant);
969 SetReportId(0x03);
970 auto* pid_collection =
971 AddChild(top, kUsagePidSetEffectReport, kCollectionTypeLogical);
972 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
973 SetReportSizeAndCount(4, 1);
974 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
975 {kUsagePidDCEnableActuators});
976 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
977 AddReportConstant(pid_collection, kOutput, kConstant);
978 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
979 SetReportSizeAndCount(8, 4);
980 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
981 {kUsagePidMagnitude});
982 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
983 SetUnitAndUnitExponent(kUnitSecond, 0x0e);
984 SetReportSizeAndCount(8, 1);
985 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
986 {kUsagePidDuration});
987 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
988 {kUsagePidStartDelay});
989 SetUnitAndUnitExponent(0, 0);
990 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
991 {kUsagePidLoopCount});
992 SetReportId(0x04);
993 AddReportItem(top, kInput, kAbsoluteVariable,
994 {kUsageGenericDeviceBatteryStrength});
995 ValidateCollections(kMicrosoftXboxWirelessController,
996 kMicrosoftXboxWirelessControllerSize);
997 }
998
TEST_F(HidReportDescriptorTest,ValidateDetails_NintendoSwitchProController)999 TEST_F(HidReportDescriptorTest, ValidateDetails_NintendoSwitchProController) {
1000 auto top_info = HidCollectionInfo::New();
1001 top_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
1002 mojom::kPageGenericDesktop);
1003 ASSERT_EQ(IsProtected(*top_info->usage), false);
1004 top_info->report_ids = {0x30, 0x21, 0x81, 0x01, 0x10, 0x80, 0x82};
1005 AddTopCollectionInfo(std::move(top_info));
1006 ValidateDetails(true, 63, 63, 0, kNintendoSwitchProController,
1007 kNintendoSwitchProControllerSize);
1008 }
1009
TEST_F(HidReportDescriptorTest,ValidateCollections_NintendoSwitchProController)1010 TEST_F(HidReportDescriptorTest,
1011 ValidateCollections_NintendoSwitchProController) {
1012 auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
1013 kCollectionTypeApplication);
1014 SetReportId(0x30);
1015 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1016 SetUnitAndUnitExponent(0, 0);
1017 SetReportSizeAndCount(1, 10);
1018 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
1019 kUsageButton + 10);
1020 SetReportSizeAndCount(1, 4);
1021 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 11,
1022 kUsageButton + 14);
1023 SetReportSizeAndCount(1, 2);
1024 AddReportConstant(top, kInput, kConstant);
1025 auto* stick_axes =
1026 AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1027 SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1028 SetReportSizeAndCount(16, 4);
1029 AddReportItem(stick_axes, kInput, kAbsoluteVariable,
1030 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1031 kUsageGenericDesktopZ, kUsageGenericDesktopRz});
1032 SetLogicalAndPhysicalBounds(0, 7, 0, 315);
1033 SetUnitAndUnitExponent(kUnitDegrees, 0);
1034 SetReportSizeAndCount(4, 1);
1035 AddReportItem(top, kInput, kAbsoluteVariable,
1036 {kUsageGenericDesktopHatSwitch});
1037 SetLogicalAndPhysicalBounds(0, 1, 0, 315);
1038 SetReportSizeAndCount(1, 4);
1039 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 15,
1040 kUsageButton + 18);
1041 SetReportSizeAndCount(8, 52);
1042 AddReportConstant(top, kInput, kConstant);
1043 SetReportId(0x21);
1044 SetReportSizeAndCount(8, 63);
1045 AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x01});
1046 SetReportId(0x81);
1047 AddReportItem(top, kInput, kConstant, {kUsageVendor + 0x02});
1048 SetReportId(0x01);
1049 AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x03});
1050 SetReportId(0x10);
1051 AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x04});
1052 SetReportId(0x80);
1053 AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x05});
1054 SetReportId(0x82);
1055 AddReportItem(top, kOutput, kVolatileConstant, {kUsageVendor + 0x06});
1056 ValidateCollections(kNintendoSwitchProController,
1057 kNintendoSwitchProControllerSize);
1058 }
1059
TEST_F(HidReportDescriptorTest,ValidateDetails_XboxAdaptiveController)1060 TEST_F(HidReportDescriptorTest, ValidateDetails_XboxAdaptiveController) {
1061 auto gamepad_info = HidCollectionInfo::New();
1062 gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
1063 mojom::kPageGenericDesktop);
1064 ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
1065 gamepad_info->report_ids = {0x01, 0x02, 0x03, 0x04, 0x06,
1066 0x07, 0x08, 0x09, 0x0a, 0x0b};
1067 auto keyboard_info = HidCollectionInfo::New();
1068 keyboard_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
1069 mojom::kPageGenericDesktop);
1070 ASSERT_EQ(IsProtected(*keyboard_info->usage), true);
1071 keyboard_info->report_ids = {0x05};
1072 AddTopCollectionInfo(std::move(gamepad_info));
1073 AddTopCollectionInfo(std::move(keyboard_info));
1074 ValidateDetails(true, 54, 8, 64, kMicrosoftXboxAdaptiveController,
1075 kMicrosoftXboxAdaptiveControllerSize);
1076 }
1077
TEST_F(HidReportDescriptorTest,ValidateCollections_XboxAdaptiveController)1078 TEST_F(HidReportDescriptorTest, ValidateCollections_XboxAdaptiveController) {
1079 auto* gamepad =
1080 AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
1081 SetReportId(0x01);
1082 auto* left_stick =
1083 AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1084 SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1085 SetReportSizeAndCount(16, 2);
1086 AddReportItem(left_stick, kInput, kAbsoluteVariable,
1087 {kUsageGenericDesktopX, kUsageGenericDesktopY});
1088 auto* right_stick =
1089 AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1090 AddReportItem(right_stick, kInput, kAbsoluteVariable,
1091 {kUsageGenericDesktopZ, kUsageGenericDesktopRz});
1092 SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1093 SetReportSizeAndCount(10, 1);
1094 AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageSimulationBrake});
1095 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1096 SetReportSizeAndCount(6, 1);
1097 AddReportConstant(gamepad, kInput, kConstant);
1098 SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1099 SetReportSizeAndCount(10, 1);
1100 AddReportItem(gamepad, kInput, kAbsoluteVariable,
1101 {kUsageSimulationAccelerator});
1102 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1103 SetReportSizeAndCount(6, 1);
1104 AddReportConstant(gamepad, kInput, kConstant);
1105 SetLogicalAndPhysicalBounds(1, 8, 0, 315);
1106 SetUnitAndUnitExponent(kUnitDegrees, 0);
1107 SetReportSizeAndCount(4, 1);
1108 AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
1109 {kUsageGenericDesktopHatSwitch});
1110 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1111 SetUnitAndUnitExponent(0, 0);
1112 AddReportConstant(gamepad, kInput, kConstant);
1113 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1114 SetReportSizeAndCount(1, 15);
1115 AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 1,
1116 kUsageButton + 15);
1117 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1118 SetReportSizeAndCount(1, 1);
1119 AddReportConstant(gamepad, kInput, kConstant);
1120 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1121 AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerACBack});
1122 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1123 SetReportSizeAndCount(7, 1);
1124 AddReportConstant(gamepad, kInput, kConstant);
1125 auto* left_stick2 =
1126 AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1127 SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1128 SetReportSizeAndCount(16, 2);
1129 AddReportItem(left_stick2, kInput, kAbsoluteVariable,
1130 {kUsageGenericDesktopVx, kUsageGenericDesktopVy});
1131 auto* right_stick2 =
1132 AddChild(gamepad, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1133 SetLogicalAndPhysicalBounds(0, 0xffff, 0, 0);
1134 AddReportItem(right_stick2, kInput, kAbsoluteVariable,
1135 {kUsageGenericDesktopVbrx, kUsageGenericDesktopVbry});
1136 SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1137 SetReportSizeAndCount(10, 1);
1138 AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVz});
1139 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1140 SetReportSizeAndCount(6, 1);
1141 AddReportConstant(gamepad, kInput, kConstant);
1142 SetLogicalAndPhysicalBounds(0, 1023, 0, 0);
1143 SetReportSizeAndCount(10, 1);
1144 AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageGenericDesktopVbrz});
1145 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1146 SetReportSizeAndCount(6, 1);
1147 AddReportConstant(gamepad, kInput, kConstant);
1148 SetLogicalAndPhysicalBounds(1, 8, 0, 315);
1149 SetUnitAndUnitExponent(kUnitDegrees, 0);
1150 SetReportSizeAndCount(4, 1);
1151 AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
1152 {kUsageGenericDesktopDial});
1153 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1154 SetUnitAndUnitExponent(0, 0);
1155 AddReportConstant(gamepad, kInput, kConstant);
1156 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1157 SetReportSizeAndCount(1, 15);
1158 AddReportItemRange(gamepad, kInput, kAbsoluteVariable, kUsageButton + 16,
1159 kUsageButton + 30);
1160 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1161 SetReportSizeAndCount(1, 1);
1162 AddReportConstant(gamepad, kInput, kConstant);
1163 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1164 AddReportItem(gamepad, kInput, kAbsoluteVariable, {kUsageConsumerModeStep});
1165 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1166 SetReportSizeAndCount(7, 1);
1167 AddReportConstant(gamepad, kInput, kConstant);
1168 auto* consumer_collection =
1169 AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
1170 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1171 SetReportSizeAndCount(4, 1);
1172 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1173 {kUsageConsumer + 0x81});
1174 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1175 AddReportConstant(consumer_collection, kInput, kConstant);
1176 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1177 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1178 {kUsageConsumer + 0x84});
1179 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1180 AddReportConstant(consumer_collection, kInput, kConstant);
1181 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1182 SetReportSizeAndCount(8, 1);
1183 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1184 {kUsageConsumer + 0x85});
1185 SetReportSizeAndCount(4, 1);
1186 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1187 {kUsageConsumer + 0x99});
1188 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1189 AddReportConstant(consumer_collection, kInput, kConstant);
1190 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1191 SetReportSizeAndCount(8, 1);
1192 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1193 {kUsageConsumer + 0x9e});
1194 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1195 {kUsageConsumer + 0xa1});
1196 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1197 {kUsageConsumer + 0xa2});
1198 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1199 {kUsageConsumer + 0xa3});
1200 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1201 {kUsageConsumer + 0xa4});
1202 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1203 {kUsageConsumer + 0xb9});
1204 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1205 {kUsageConsumer + 0xba});
1206 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1207 {kUsageConsumer + 0xbb});
1208 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1209 {kUsageConsumer + 0xbe});
1210 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1211 {kUsageConsumer + 0xc0});
1212 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1213 {kUsageConsumer + 0xc1});
1214 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1215 {kUsageConsumer + 0xc2});
1216 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1217 {kUsageConsumer + 0xc3});
1218 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1219 {kUsageConsumer + 0xc4});
1220 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1221 {kUsageConsumer + 0xc5});
1222 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1223 {kUsageConsumer + 0xc6});
1224 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1225 {kUsageConsumer + 0xc7});
1226 AddReportItem(consumer_collection, kInput, kAbsoluteVariable,
1227 {kUsageConsumer + 0xc8});
1228 SetReportId(0x02);
1229 auto* mode_collection =
1230 AddChild(gamepad, kUsageConsumerControl, kCollectionTypeApplication);
1231 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1232 SetReportSizeAndCount(1, 1);
1233 AddReportItem(mode_collection, kInput, kAbsoluteVariable,
1234 {kUsageConsumerACHome});
1235 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1236 SetReportSizeAndCount(7, 1);
1237 AddReportConstant(mode_collection, kInput, kConstant);
1238 SetReportId(0x03);
1239 auto* pid_collection =
1240 AddChild(gamepad, kUsagePidSetEffectReport, kCollectionTypeLogical);
1241 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1242 SetReportSizeAndCount(4, 1);
1243 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1244 {kUsagePidDCEnableActuators});
1245 SetLogicalAndPhysicalBounds(0, 0, 0, 0);
1246 AddReportConstant(pid_collection, kOutput, kConstant);
1247 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1248 SetReportSizeAndCount(8, 4);
1249 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1250 {kUsagePidMagnitude});
1251 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1252 SetUnitAndUnitExponent(kUnitSecond, 0x0e);
1253 SetReportSizeAndCount(8, 1);
1254 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1255 {kUsagePidDuration});
1256 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1257 {kUsagePidStartDelay});
1258 SetUnitAndUnitExponent(0, 0);
1259 AddReportItem(pid_collection, kOutput, kAbsoluteVariable,
1260 {kUsagePidLoopCount});
1261 SetReportId(0x04);
1262 AddReportItem(gamepad, kInput, kAbsoluteVariable,
1263 {kUsageGenericDeviceBatteryStrength});
1264 SetReportId(0x06);
1265 auto* report_06_collection =
1266 AddChild(gamepad, kUsageVendor + 0x01, kCollectionTypeLogical);
1267 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1268 AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
1269 {kUsageVendor + 0x01});
1270 AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
1271 {kUsageVendor + 0x02});
1272 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1273 AddReportItem(report_06_collection, kFeature, kAbsoluteVariable,
1274 {kUsageVendor + 0x03});
1275 SetReportSizeAndCount(8, 60);
1276 AddReportItem(report_06_collection, kFeature, kBufferedBytes,
1277 {kUsageVendor + 0x04});
1278 SetReportId(0x07);
1279 auto* report_07_collection =
1280 AddChild(gamepad, kUsageVendor + 0x02, kCollectionTypeLogical);
1281 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1282 SetReportSizeAndCount(8, 1);
1283 AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
1284 {kUsageVendor + 0x05});
1285 AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
1286 {kUsageVendor + 0x06});
1287 AddReportItem(report_07_collection, kFeature, kAbsoluteVariable,
1288 {kUsageVendor + 0x07});
1289 SetReportId(0x08);
1290 auto* report_08_collection =
1291 AddChild(gamepad, kUsageVendor + 0x03, kCollectionTypeLogical);
1292 AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
1293 {kUsageVendor + 0x08});
1294 AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
1295 {kUsageVendor + 0x09});
1296 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1297 AddReportItem(report_08_collection, kFeature, kAbsoluteVariable,
1298 {kUsageVendor + 0x0a});
1299 SetReportId(0x09);
1300 auto* report_09_collection =
1301 AddChild(gamepad, kUsageVendor + 0x04, kCollectionTypeApplication);
1302 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1303 AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1304 {kUsageVendor + 0x0b});
1305 AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1306 {kUsageVendor + 0x0c});
1307 AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1308 {kUsageVendor + 0x0d});
1309 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1310 AddReportItem(report_09_collection, kFeature, kAbsoluteVariable,
1311 {kUsageVendor + 0x0e});
1312 SetReportSizeAndCount(8, 60);
1313 AddReportItem(report_09_collection, kFeature, kBufferedBytes,
1314 {kUsageVendor + 0x0f});
1315 SetReportId(0x0a);
1316 auto* report_0a_collection =
1317 AddChild(gamepad, kUsageVendor + 0x05, kCollectionTypeApplication);
1318 SetLogicalAndPhysicalBounds(0, 0x7fffffff, 0, 0);
1319 SetReportSizeAndCount(32, 1);
1320 AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1321 {kUsageVendor + 0x10});
1322 AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1323 {kUsageVendor + 0x11});
1324 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1325 SetReportSizeAndCount(8, 2);
1326 AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1327 {kUsageVendor + 0x12});
1328 SetReportSizeAndCount(8, 1);
1329 AddReportItem(report_0a_collection, kInput, kAbsoluteVariable,
1330 {kUsageVendor + 0x13});
1331 SetReportId(0x0b);
1332 auto* report_0b_collection =
1333 AddChild(gamepad, kUsageVendor + 0x06, kCollectionTypeLogical);
1334 SetLogicalAndPhysicalBounds(0, 100, 0, 0);
1335
1336 AddReportItem(report_0b_collection, kFeature, kAbsoluteVariable,
1337 {kUsageVendor + 0x14});
1338 SetReportId(0x05);
1339 auto* keyboard = AddTopCollection(kUsageGenericDesktopKeyboard,
1340 kCollectionTypeApplication);
1341 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1342 SetReportSizeAndCount(1, 8);
1343 AddReportItemRange(keyboard, kInput, kAbsoluteVariable,
1344 kUsageKeyboardLeftControl, kUsageKeyboardRightGui);
1345 SetReportSizeAndCount(8, 1);
1346 AddReportConstant(keyboard, kInput, kConstant);
1347 SetLogicalAndPhysicalBounds(0, 101, 0, 0);
1348 SetReportSizeAndCount(8, 6);
1349 AddReportItemRange(keyboard, kInput, kNonNullableArray, kUsageKeyboard,
1350 kUsageKeyboardApplication);
1351 ValidateCollections(kMicrosoftXboxAdaptiveController,
1352 kMicrosoftXboxAdaptiveControllerSize);
1353 }
1354
TEST_F(HidReportDescriptorTest,ValidateDetails_NexusPlayerController)1355 TEST_F(HidReportDescriptorTest, ValidateDetails_NexusPlayerController) {
1356 auto gamepad_info = HidCollectionInfo::New();
1357 gamepad_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
1358 mojom::kPageGenericDesktop);
1359 ASSERT_EQ(IsProtected(*gamepad_info->usage), false);
1360 gamepad_info->report_ids = {0x01, 0x02};
1361 auto status_info = HidCollectionInfo::New();
1362 status_info->usage = HidUsageAndPage::New(mojom::kGenericDesktopGamePad,
1363 mojom::kPageGenericDesktop);
1364 ASSERT_EQ(IsProtected(*status_info->usage), false);
1365 status_info->report_ids = {0x03};
1366 AddTopCollectionInfo(std::move(gamepad_info));
1367 AddTopCollectionInfo(std::move(status_info));
1368 ValidateDetails(true, 8, 1, 0, kNexusPlayerController,
1369 kNexusPlayerControllerSize);
1370 }
1371
TEST_F(HidReportDescriptorTest,ValidateCollections_NexusPlayerController)1372 TEST_F(HidReportDescriptorTest, ValidateCollections_NexusPlayerController) {
1373 auto* gamepad =
1374 AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
1375 SetReportId(0x01);
1376 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1377 SetReportSizeAndCount(1, 11);
1378 AddReportItem(
1379 gamepad, kInput, kAbsoluteVariable,
1380 {kUsageButton + 1, kUsageButton + 2, kUsageButton + 4, kUsageButton + 5,
1381 kUsageButton + 7, kUsageButton + 8, kUsageButton + 14, kUsageButton + 15,
1382 kUsageButton + 13, kUsageConsumerACBack, kUsageConsumerACHome});
1383 SetReportSizeAndCount(1, 1);
1384 AddReportConstant(gamepad, kInput, kConstant);
1385 SetLogicalAndPhysicalBounds(0, 7, 0, 315);
1386 SetUnitAndUnitExponent(kUnitDegrees, 0);
1387 SetReportSizeAndCount(4, 1);
1388 AddReportItem(gamepad, kInput, kNullableAbsoluteVariable,
1389 {kUsageGenericDesktopHatSwitch});
1390 SetUnitAndUnitExponent(0, 0);
1391 auto* axes_collection =
1392 AddChild(gamepad, kUsageGenericDesktop, kCollectionTypePhysical);
1393 SetLogicalAndPhysicalBounds(0, 255, 0, 255);
1394 SetReportSizeAndCount(8, 6);
1395 AddReportItem(axes_collection, kInput, kAbsoluteVariable,
1396 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1397 kUsageGenericDesktopZ, kUsageGenericDesktopRz,
1398 kUsageSimulationBrake, kUsageSimulationAccelerator});
1399 SetReportId(0x02);
1400 SetLogicalAndPhysicalBounds(0, 1, 0, 255);
1401 SetReportSizeAndCount(1, 4);
1402 AddReportItem(gamepad, kOutput, kAbsoluteVariable,
1403 {kUsageLedNumLock, kUsageLedCapsLock, kUsageLedScrollLock,
1404 kUsageLedCompose});
1405 SetReportSizeAndCount(4, 1);
1406 AddReportConstant(gamepad, kOutput, kConstant);
1407 SetReportId(0x03);
1408 auto* status =
1409 AddTopCollection(kUsageGenericDesktopGamePad, kCollectionTypeApplication);
1410 SetLogicalAndPhysicalBounds(0, 255, 0, 255);
1411 SetReportSizeAndCount(8, 1);
1412 AddReportItem(status, kInput, kAbsoluteVariable,
1413 {kUsageGenericDeviceBatteryStrength});
1414 SetReportSizeAndCount(8, 6);
1415 AddReportItem(status, kInput, kAbsoluteVariable, {0xffbcbdad});
1416 ValidateCollections(kNexusPlayerController, kNexusPlayerControllerSize);
1417 }
1418
TEST_F(HidReportDescriptorTest,ValidateDetails_SteamControllerKeyboard)1419 TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerKeyboard) {
1420 auto info = HidCollectionInfo::New();
1421 info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
1422 mojom::kPageGenericDesktop);
1423 ASSERT_EQ(IsProtected(*info->usage), true);
1424 AddTopCollectionInfo(std::move(info));
1425 ValidateDetails(false, 8, 1, 0, kSteamControllerKeyboard,
1426 kSteamControllerKeyboardSize);
1427 }
1428
TEST_F(HidReportDescriptorTest,ValidateCollections_SteamControllerKeyboard)1429 TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerKeyboard) {
1430 auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
1431 kCollectionTypeApplication);
1432 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1433 SetReportSizeAndCount(1, 8);
1434 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
1435 kUsageKeyboardRightGui);
1436 SetReportSizeAndCount(8, 1);
1437 AddReportConstant(top, kInput, kConstantArray);
1438 SetReportSizeAndCount(1, 5);
1439 AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageLedNumLock,
1440 kUsageLedKana);
1441 SetReportSizeAndCount(3, 1);
1442 AddReportConstant(top, kOutput, kConstantArray);
1443 SetReportSizeAndCount(8, 6);
1444 SetLogicalAndPhysicalBounds(0, 101, 0, 0);
1445 AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
1446 kUsageKeyboardApplication);
1447 ValidateCollections(kSteamControllerKeyboard, kSteamControllerKeyboardSize);
1448 }
1449
TEST_F(HidReportDescriptorTest,ValidateDetails_SteamControllerMouse)1450 TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerMouse) {
1451 auto info = HidCollectionInfo::New();
1452 info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
1453 mojom::kPageGenericDesktop);
1454 ASSERT_EQ(IsProtected(*info->usage), true);
1455 AddTopCollectionInfo(std::move(info));
1456 ValidateDetails(false, 4, 0, 0, kSteamControllerMouse,
1457 kSteamControllerMouseSize);
1458 }
1459
TEST_F(HidReportDescriptorTest,ValidateCollections_SteamControllerMouse)1460 TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerMouse) {
1461 auto* top =
1462 AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
1463 auto* pointer =
1464 AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1465 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1466 SetReportSizeAndCount(1, 5);
1467 AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
1468 kUsageButton + 5);
1469 SetReportSizeAndCount(3, 1);
1470 AddReportConstant(pointer, kInput, kConstantArray);
1471 SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
1472 SetReportSizeAndCount(8, 3);
1473 AddReportItem(pointer, kInput, kRelativeVariable,
1474 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1475 kUsageGenericDesktopWheel});
1476 ValidateCollections(kSteamControllerMouse, kSteamControllerMouseSize);
1477 }
1478
TEST_F(HidReportDescriptorTest,ValidateDetails_SteamControllerVendor)1479 TEST_F(HidReportDescriptorTest, ValidateDetails_SteamControllerVendor) {
1480 auto info = HidCollectionInfo::New();
1481 info->usage = HidUsageAndPage::New(0x01, mojom::kPageVendor);
1482 ASSERT_EQ(IsProtected(*info->usage), false);
1483 AddTopCollectionInfo(std::move(info));
1484 ValidateDetails(false, 64, 64, 64, kSteamControllerVendor,
1485 kSteamControllerVendorSize);
1486 }
1487
TEST_F(HidReportDescriptorTest,ValidateCollections_SteamControllerVendor)1488 TEST_F(HidReportDescriptorTest, ValidateCollections_SteamControllerVendor) {
1489 auto* top = AddTopCollection(kUsageVendor + 0x01, kCollectionTypeApplication);
1490 SetLogicalAndPhysicalBounds(0, 255, 0, 0);
1491 SetReportSizeAndCount(8, 64);
1492 AddReportItem(top, kInput, kAbsoluteVariable, {kUsageVendor + 0x01});
1493 AddReportItem(top, kOutput, kAbsoluteVariable, {kUsageVendor + 0x01});
1494 AddReportItem(top, kFeature, kAbsoluteVariable, {kUsageVendor + 0x01});
1495 ValidateCollections(kSteamControllerVendor, kSteamControllerVendorSize);
1496 }
1497
TEST_F(HidReportDescriptorTest,ValidateDetails_XSkillsUsbAdapter)1498 TEST_F(HidReportDescriptorTest, ValidateDetails_XSkillsUsbAdapter) {
1499 auto info = HidCollectionInfo::New();
1500 info->usage = HidUsageAndPage::New(mojom::kGenericDesktopJoystick,
1501 mojom::kPageGenericDesktop);
1502 ASSERT_EQ(IsProtected(*info->usage), false);
1503 AddTopCollectionInfo(std::move(info));
1504 ValidateDetails(false, 7, 4, 0, kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
1505 }
1506
TEST_F(HidReportDescriptorTest,ValidateCollections_XSkillsUsbAdapter)1507 TEST_F(HidReportDescriptorTest, ValidateCollections_XSkillsUsbAdapter) {
1508 auto* top = AddTopCollection(kUsageGenericDesktopJoystick,
1509 kCollectionTypeApplication);
1510 SetLogicalAndPhysicalBounds(0, 1, 0, 1);
1511 SetReportSizeAndCount(1, 12);
1512 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageButton + 1,
1513 kUsageButton + 12);
1514 SetReportSizeAndCount(1, 4);
1515 AddReportConstant(top, kInput, kConstant);
1516 SetLogicalAndPhysicalBounds(0, 255, 0, 255);
1517 SetReportSizeAndCount(8, 4);
1518 AddReportItem(top, kInput, kAbsoluteVariable,
1519 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1520 kUsageGenericDesktopRz, kUsageGenericDesktopZ});
1521 SetLogicalAndPhysicalBounds(0, 15, 0, 15);
1522 SetReportSizeAndCount(4, 2);
1523 AddReportItem(top, kInput, kAbsoluteVariable,
1524 {kUsageGenericDesktopRx, kUsageGenericDesktopRy});
1525 SetReportSizeAndCount(8, 4);
1526 AddReportItemRange(top, kOutput, kAbsoluteVariable, kUsageVendor + 0x01,
1527 kUsageVendor + 0x04);
1528 ValidateCollections(kXSkillsUsbAdapter, kXSkillsUsbAdapterSize);
1529 }
1530
TEST_F(HidReportDescriptorTest,ValidateDetails_BelkinNostromoKeyboard)1531 TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoKeyboard) {
1532 auto info = HidCollectionInfo::New();
1533 info->usage = HidUsageAndPage::New(mojom::kGenericDesktopKeyboard,
1534 mojom::kPageGenericDesktop);
1535 ASSERT_EQ(IsProtected(*info->usage), true);
1536 AddTopCollectionInfo(std::move(info));
1537 ValidateDetails(false, 8, 0, 0, kBelkinNostromoKeyboard,
1538 kBelkinNostromoKeyboardSize);
1539 }
1540
TEST_F(HidReportDescriptorTest,ValidateCollections_BelkinNostromoKeyboard)1541 TEST_F(HidReportDescriptorTest, ValidateCollections_BelkinNostromoKeyboard) {
1542 auto* top = AddTopCollection(kUsageGenericDesktopKeyboard,
1543 kCollectionTypeApplication);
1544 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1545 SetReportSizeAndCount(1, 8);
1546 AddReportItemRange(top, kInput, kAbsoluteVariable, kUsageKeyboardLeftControl,
1547 kUsageKeyboardRightGui);
1548 SetReportSizeAndCount(8, 1);
1549 AddReportConstant(top, kInput, kConstantArray);
1550 SetLogicalAndPhysicalBounds(0, 101, 0, 0);
1551 SetReportSizeAndCount(8, 6);
1552 AddReportItemRange(top, kInput, kNonNullableArray, kUsageKeyboard,
1553 kUsageKeyboardApplication);
1554 ValidateCollections(kBelkinNostromoKeyboard, kBelkinNostromoKeyboardSize);
1555 }
1556
TEST_F(HidReportDescriptorTest,ValidateDetails_BelkinNostromoMouseAndExtra)1557 TEST_F(HidReportDescriptorTest, ValidateDetails_BelkinNostromoMouseAndExtra) {
1558 auto info = HidCollectionInfo::New();
1559 info->usage = HidUsageAndPage::New(mojom::kGenericDesktopMouse,
1560 mojom::kPageGenericDesktop);
1561 ASSERT_EQ(IsProtected(*info->usage), true);
1562 AddTopCollectionInfo(std::move(info));
1563 ValidateDetails(false, 4, 1, 0, kBelkinNostromoMouseAndExtra,
1564 kBelkinNostromoMouseAndExtraSize);
1565 }
1566
TEST_F(HidReportDescriptorTest,ValidateCollections_BelkinNostromoMouseAndExtra)1567 TEST_F(HidReportDescriptorTest,
1568 ValidateCollections_BelkinNostromoMouseAndExtra) {
1569 auto* top =
1570 AddTopCollection(kUsageGenericDesktopMouse, kCollectionTypeApplication);
1571 auto* pointer =
1572 AddChild(top, kUsageGenericDesktopPointer, kCollectionTypePhysical);
1573 SetLogicalAndPhysicalBounds(0, 1, 0, 0);
1574 SetReportSizeAndCount(1, 3);
1575 AddReportItemRange(pointer, kInput, kAbsoluteVariable, kUsageButton + 1,
1576 kUsageButton + 3);
1577 SetReportSizeAndCount(5, 1);
1578 AddReportConstant(pointer, kInput, kConstantArray);
1579 SetLogicalAndPhysicalBounds(0x81, 0x7f, 0, 0);
1580 SetReportSizeAndCount(8, 3);
1581 AddReportItem(pointer, kInput, kRelativeVariable,
1582 {kUsageGenericDesktopX, kUsageGenericDesktopY,
1583 kUsageGenericDesktopWheel});
1584 SetLogicalAndPhysicalBounds(0, 1, 0, 1);
1585 SetReportSizeAndCount(1, 3);
1586 AddReportItemRange(pointer, kOutput, kAbsoluteVariable, kUsageLedNumLock,
1587 kUsageLedScrollLock);
1588 SetReportSizeAndCount(5, 1);
1589 AddReportConstant(pointer, kOutput, kConstantArray);
1590 ValidateCollections(kBelkinNostromoMouseAndExtra,
1591 kBelkinNostromoMouseAndExtraSize);
1592 }
1593
TEST_F(HidReportDescriptorTest,InvalidReportSizeIgnored)1594 TEST_F(HidReportDescriptorTest, InvalidReportSizeIgnored) {
1595 // Report size can be at most 32 bits. Make sure a report item with invalid
1596 // size does not affect the maximum report size. The descriptor below
1597 // describes a report with one 64-bit constant field.
1598 static const uint8_t kInvalidReportSizeDescriptor[] = {
1599 0xA0, // Collection
1600 0x95, 0x01, // Report Count (1)
1601 0x75, 0x40, // Report Size (64)
1602 0x90 // Output
1603 };
1604 static const size_t kInvalidReportSizeDescriptorSize =
1605 base::size(kInvalidReportSizeDescriptor);
1606 auto info = HidCollectionInfo::New();
1607 info->usage = HidUsageAndPage::New(0, 0);
1608 AddTopCollectionInfo(std::move(info));
1609 // Maximum report sizes should not be affected by the invalid report item.
1610 ValidateDetails(false, 0, 0, 0, kInvalidReportSizeDescriptor,
1611 kInvalidReportSizeDescriptorSize);
1612
1613 // The report item with invalid size should still be included in the
1614 // collection info.
1615 auto* top = AddTopCollection(0, kCollectionTypePhysical);
1616 SetReportSizeAndCount(64, 1);
1617 AddReportConstant(top, kOutput, kNonNullableArray);
1618 ValidateCollections(kInvalidReportSizeDescriptor,
1619 kInvalidReportSizeDescriptorSize);
1620 }
1621
TEST_F(HidReportDescriptorTest,ReasonablyHugeReportNotIgnored)1622 TEST_F(HidReportDescriptorTest, ReasonablyHugeReportNotIgnored) {
1623 // The descriptor below defines a 2^16-1 byte output report. Larger reports
1624 // are considered unreasonable and are ignored in the max report size
1625 // calculation.
1626 static const uint8_t kReasonablyHugeReportDescriptor[] = {
1627 0xA0, // Collection
1628 0x96, 0xff, 0xff, // Report Count (65535)
1629 0x75, 0x08, // Report Size (8)
1630 0x90 // Output
1631 };
1632 static const size_t kReasonablyHugeReportDescriptorSize =
1633 base::size(kReasonablyHugeReportDescriptor);
1634 auto info = HidCollectionInfo::New();
1635 info->usage = HidUsageAndPage::New(0, 0);
1636 AddTopCollectionInfo(std::move(info));
1637 // Maximum report sizes should include the huge report.
1638 ValidateDetails(false, 0, 65535, 0, kReasonablyHugeReportDescriptor,
1639 kReasonablyHugeReportDescriptorSize);
1640
1641 auto* top = AddTopCollection(0, kCollectionTypePhysical);
1642 SetReportSizeAndCount(8, 65535);
1643 AddReportConstant(top, kOutput, kNonNullableArray);
1644 ValidateCollections(kReasonablyHugeReportDescriptor,
1645 kReasonablyHugeReportDescriptorSize);
1646 }
1647
TEST_F(HidReportDescriptorTest,UnreasonablyHugeReportIgnored)1648 TEST_F(HidReportDescriptorTest, UnreasonablyHugeReportIgnored) {
1649 // The descriptor below defines a 2^16 byte output report. The report is
1650 // larger than the maximum report size considered reasonable and will be
1651 // ignored when computing the max report size.
1652 static const uint8_t kUnreasonablyHugeReportDescriptor[] = {
1653 0xA0, // Collection
1654 0x97, 0x00, 0x00, 0x01, 0x00, // Report Count (65536)
1655 0x75, 0x08, // Report Size (8)
1656 0x90 // Output
1657 };
1658 static const size_t kUnreasonablyHugeReportDescriptorSize =
1659 base::size(kUnreasonablyHugeReportDescriptor);
1660 auto info = HidCollectionInfo::New();
1661 info->usage = HidUsageAndPage::New(0, 0);
1662 AddTopCollectionInfo(std::move(info));
1663 // Maximum report sizes should not be affected by the huge report.
1664 ValidateDetails(false, 0, 0, 0, kUnreasonablyHugeReportDescriptor,
1665 kUnreasonablyHugeReportDescriptorSize);
1666
1667 // The unreasonably huge report item should still be included in the
1668 // collection info.
1669 auto* top = AddTopCollection(0, kCollectionTypePhysical);
1670 SetReportSizeAndCount(8, 65536);
1671 AddReportConstant(top, kOutput, kNonNullableArray);
1672 ValidateCollections(kUnreasonablyHugeReportDescriptor,
1673 kUnreasonablyHugeReportDescriptorSize);
1674 }
1675
TEST_F(HidReportDescriptorTest,HighlyNestedReportLimitsDepth)1676 TEST_F(HidReportDescriptorTest, HighlyNestedReportLimitsDepth) {
1677 // The HID report descriptor parser sets a maximum depth to prevent issues
1678 // with descriptors that define many nested collections. The descriptor below
1679 // nests a single constant inside 51 collections.
1680 static const uint8_t kHighlyNestedReportDescriptor[] = {
1681 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1682 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1683 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1684 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1685 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1686
1687 0x95, 0x01, // Report Count (1)
1688 0x75, 0x08, // Report Size (8)
1689 0x90 // Output
1690 };
1691 static const size_t kHighlyNestedReportDescriptorSize =
1692 base::size(kHighlyNestedReportDescriptor);
1693 auto info = HidCollectionInfo::New();
1694 info->usage = HidUsageAndPage::New(0, 0);
1695 AddTopCollectionInfo(std::move(info));
1696 // The item in the innermost collection should still be reflected in the
1697 // maximum report size.
1698 ValidateDetails(false, 0, 1, 0, kHighlyNestedReportDescriptor,
1699 kHighlyNestedReportDescriptorSize);
1700
1701 // Construct nested collections up to the depth limit. The item from the
1702 // innermost collection should be propagated to all its parents even though
1703 // the depth limit has been reached.
1704 auto* parent = AddTopCollection(0, kCollectionTypePhysical);
1705 for (size_t i = 1; i < 50; ++i)
1706 parent = AddChild(parent, 0, kCollectionTypePhysical);
1707 SetReportSizeAndCount(8, 1);
1708 AddReportConstant(parent, kOutput, kNonNullableArray);
1709 ValidateCollections(kHighlyNestedReportDescriptor,
1710 kHighlyNestedReportDescriptorSize);
1711 }
1712
TEST_F(HidReportDescriptorTest,ExtraEndCollectionIgnored)1713 TEST_F(HidReportDescriptorTest, ExtraEndCollectionIgnored) {
1714 // When the report descriptor parser encounters an End Collection item,
1715 // it should decrement the collection depth only if a matching Collection
1716 // item was previously encountered. If no Collection item was encountered,
1717 // the End Collection item should be ignored.
1718 static const uint8_t kExtraEndCollectionDescriptor[] = {
1719 0xC0, // End Collection
1720
1721 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1722 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1723 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1724 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
1725 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0};
1726 static const size_t kExtraEndCollectionDescriptorSize =
1727 base::size(kExtraEndCollectionDescriptor);
1728
1729 // Construct nested collections up to the depth limit. If the extra End
1730 // Collection item was ignored, the depth limit should have prevented the
1731 // innermost collection from being created.
1732 auto* parent = AddTopCollection(0, kCollectionTypePhysical);
1733 for (size_t i = 1; i < 50; ++i)
1734 parent = AddChild(parent, 0, kCollectionTypePhysical);
1735 ValidateCollections(kExtraEndCollectionDescriptor,
1736 kExtraEndCollectionDescriptorSize);
1737 }
1738
1739 } // namespace device
1740