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.
7 #include "device/hid/hid_report_descriptor.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 using namespace testing
;
17 std::ostream
& operator<<(std::ostream
& os
,
18 const HidUsageAndPage::Page
& usage_page
) {
20 case HidUsageAndPage::kPageUndefined
:
23 case HidUsageAndPage::kPageGenericDesktop
:
24 os
<< "Generic Desktop";
26 case HidUsageAndPage::kPageSimulation
:
29 case HidUsageAndPage::kPageVirtualReality
:
30 os
<< "Virtual Reality";
32 case HidUsageAndPage::kPageSport
:
35 case HidUsageAndPage::kPageGame
:
38 case HidUsageAndPage::kPageKeyboard
:
41 case HidUsageAndPage::kPageLed
:
44 case HidUsageAndPage::kPageButton
:
47 case HidUsageAndPage::kPageOrdinal
:
50 case HidUsageAndPage::kPageTelephony
:
53 case HidUsageAndPage::kPageConsumer
:
56 case HidUsageAndPage::kPageDigitizer
:
59 case HidUsageAndPage::kPagePidPage
:
62 case HidUsageAndPage::kPageUnicode
:
65 case HidUsageAndPage::kPageAlphanumericDisplay
:
66 os
<< "Alphanumeric Display";
68 case HidUsageAndPage::kPageMedicalInstruments
:
69 os
<< "Medical Instruments";
71 case HidUsageAndPage::kPageMonitor0
:
74 case HidUsageAndPage::kPageMonitor1
:
77 case HidUsageAndPage::kPageMonitor2
:
80 case HidUsageAndPage::kPageMonitor3
:
83 case HidUsageAndPage::kPagePower0
:
86 case HidUsageAndPage::kPagePower1
:
89 case HidUsageAndPage::kPagePower2
:
92 case HidUsageAndPage::kPagePower3
:
95 case HidUsageAndPage::kPageBarCodeScanner
:
96 os
<< "Bar Code Scanner";
98 case HidUsageAndPage::kPageScale
:
101 case HidUsageAndPage::kPageMagneticStripeReader
:
102 os
<< "Magnetic Stripe Reader";
104 case HidUsageAndPage::kPageReservedPointOfSale
:
105 os
<< "Reserved Point Of Sale";
107 case HidUsageAndPage::kPageCameraControl
:
108 os
<< "Camera Control";
110 case HidUsageAndPage::kPageArcade
:
113 case HidUsageAndPage::kPageVendor
:
116 case HidUsageAndPage::kPageMediaCenter
:
117 os
<< "Media Center";
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
;
133 std::ostream
& operator<<(std::ostream
& os
,
134 const HidReportDescriptorItem::Tag
& tag
) {
136 case HidReportDescriptorItem::kTagDefault
:
139 case HidReportDescriptorItem::kTagInput
:
142 case HidReportDescriptorItem::kTagOutput
:
145 case HidReportDescriptorItem::kTagFeature
:
148 case HidReportDescriptorItem::kTagCollection
:
151 case HidReportDescriptorItem::kTagEndCollection
:
152 os
<< "End Collection";
154 case HidReportDescriptorItem::kTagUsagePage
:
157 case HidReportDescriptorItem::kTagLogicalMinimum
:
158 os
<< "Logical Minimum";
160 case HidReportDescriptorItem::kTagLogicalMaximum
:
161 os
<< "Logical Maximum";
163 case HidReportDescriptorItem::kTagPhysicalMinimum
:
164 os
<< "Physical Minimum";
166 case HidReportDescriptorItem::kTagPhysicalMaximum
:
167 os
<< "Physical Maximum";
169 case HidReportDescriptorItem::kTagUnitExponent
:
170 os
<< "Unit Exponent";
172 case HidReportDescriptorItem::kTagUnit
:
175 case HidReportDescriptorItem::kTagReportSize
:
178 case HidReportDescriptorItem::kTagReportId
:
181 case HidReportDescriptorItem::kTagReportCount
:
182 os
<< "Report Count";
184 case HidReportDescriptorItem::kTagPush
:
187 case HidReportDescriptorItem::kTagPop
:
190 case HidReportDescriptorItem::kTagUsage
:
193 case HidReportDescriptorItem::kTagUsageMinimum
:
194 os
<< "Usage Minimum";
196 case HidReportDescriptorItem::kTagUsageMaximum
:
197 os
<< "Usage Maximum";
199 case HidReportDescriptorItem::kTagDesignatorIndex
:
200 os
<< "Designator Index";
202 case HidReportDescriptorItem::kTagDesignatorMinimum
:
203 os
<< "Designator Minimum";
205 case HidReportDescriptorItem::kTagDesignatorMaximum
:
206 os
<< "Designator Maximum";
208 case HidReportDescriptorItem::kTagStringIndex
:
209 os
<< "String Index";
211 case HidReportDescriptorItem::kTagStringMinimum
:
212 os
<< "String Minimum";
214 case HidReportDescriptorItem::kTagStringMaximum
:
215 os
<< "String Maximum";
217 case HidReportDescriptorItem::kTagDelimiter
:
220 case HidReportDescriptorItem::kTagLong
:
231 std::ostream
& operator<<(std::ostream
& os
,
232 const HidReportDescriptorItem::ReportInfo
& data
) {
233 if (data
.data_or_constant
)
237 if (data
.array_or_variable
)
241 if (data
.absolute_or_relative
)
261 if (data
.bit_field_or_buffer
)
268 std::ostream
& operator<<(std::ostream
& os
,
269 const HidReportDescriptorItem::CollectionType
& type
) {
271 case HidReportDescriptorItem::kCollectionTypePhysical
:
274 case HidReportDescriptorItem::kCollectionTypeApplication
:
277 case HidReportDescriptorItem::kCollectionTypeLogical
:
280 case HidReportDescriptorItem::kCollectionTypeReport
:
283 case HidReportDescriptorItem::kCollectionTypeNamedArray
:
286 case HidReportDescriptorItem::kCollectionTypeUsageSwitch
:
287 os
<< "Usage Switch";
289 case HidReportDescriptorItem::kCollectionTypeUsageModifier
:
290 os
<< "Usage Modifier";
292 case HidReportDescriptorItem::kCollectionTypeReserved
:
295 case HidReportDescriptorItem::kCollectionTypeVendor
:
305 std::ostream
& operator<<(std::ostream
& os
,
306 const HidReportDescriptorItem
& item
) {
307 HidReportDescriptorItem::Tag item_tag
= item
.tag();
308 uint32_t data
= item
.GetShortData();
310 std::ostringstream sstr
;
314 long pos
= sstr
.tellp();
316 case HidReportDescriptorItem::kTagDefault
:
317 case HidReportDescriptorItem::kTagEndCollection
:
318 case HidReportDescriptorItem::kTagPush
:
319 case HidReportDescriptorItem::kTagPop
:
320 case HidReportDescriptorItem::kTagLong
:
323 case HidReportDescriptorItem::kTagCollection
:
324 sstr
<< HidReportDescriptorItem::GetCollectionTypeFromValue(data
);
327 case HidReportDescriptorItem::kTagInput
:
328 case HidReportDescriptorItem::kTagOutput
:
329 case HidReportDescriptorItem::kTagFeature
:
330 sstr
<< (HidReportDescriptorItem::ReportInfo
&)data
;
333 case HidReportDescriptorItem::kTagUsagePage
:
334 sstr
<< (HidUsageAndPage::Page
)data
;
337 case HidReportDescriptorItem::kTagUsage
:
338 case HidReportDescriptorItem::kTagReportId
:
339 sstr
<< "0x" << std::hex
<< std::uppercase
<< data
;
346 if (pos
== sstr
.tellp()) {
347 std::string str
= sstr
.str();
348 str
.erase(str
.end() - 2, str
.end());
351 os
<< sstr
.str() << ")";
357 const char kIndentStep
[] = " ";
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();
365 linked_ptr
<HidReportDescriptorItem
> item
= *items_iter
;
366 size_t indentLevel
= item
->GetDepth();
367 for (size_t i
= 0; i
< indentLevel
; i
++)
369 os
<< *item
.get() << std::endl
;
374 // See 'E.6 Report Descriptor (Keyboard)'
375 // in HID specifications (v1.11)
376 const uint8_t kKeyboard
[] = {
377 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29,
378 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02,
379 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x05, 0x75, 0x01, 0x05,
380 0x08, 0x19, 0x01, 0x29, 0x05, 0x91, 0x02, 0x95, 0x01, 0x75, 0x03,
381 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05,
382 0x07, 0x19, 0x00, 0x29, 0x65, 0x81, 0x00, 0xC0};
384 // See 'E.10 Report Descriptor (Mouse)'
385 // in HID specifications (v1.11)
386 const uint8_t kMouse
[] = {0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1,
387 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00,
388 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95,
389 0x01, 0x75, 0x05, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30,
390 0x09, 0x31, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95,
391 0x02, 0x81, 0x06, 0xC0, 0xC0};
393 const uint8_t kLogitechUnifyingReceiver
[] = {
394 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x75, 0x08,
395 0x95, 0x06, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x01, 0x81, 0x00,
396 0x09, 0x01, 0x91, 0x00, 0xC0, 0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1,
397 0x01, 0x85, 0x11, 0x75, 0x08, 0x95, 0x13, 0x15, 0x00, 0x26, 0xFF,
398 0x00, 0x09, 0x02, 0x81, 0x00, 0x09, 0x02, 0x91, 0x00, 0xC0, 0x06,
399 0x00, 0xFF, 0x09, 0x04, 0xA1, 0x01, 0x85, 0x20, 0x75, 0x08, 0x95,
400 0x0E, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x09, 0x41, 0x81, 0x00, 0x09,
401 0x41, 0x91, 0x00, 0x85, 0x21, 0x95, 0x1F, 0x15, 0x00, 0x26, 0xFF,
402 0x00, 0x09, 0x42, 0x81, 0x00, 0x09, 0x42, 0x91, 0x00, 0xC0};
406 class HidReportDescriptorTest
: public testing::Test
{
409 virtual void SetUp() OVERRIDE
{ descriptor_
= NULL
; }
411 virtual void TearDown() OVERRIDE
{
418 void ParseDescriptor(const std::string
& expected
,
419 const uint8_t* bytes
,
421 descriptor_
= new HidReportDescriptor(bytes
, size
);
423 std::stringstream actual
;
424 actual
<< *descriptor_
;
426 std::cout
<< "HID report descriptor:" << std::endl
;
427 std::cout
<< actual
.str();
429 // TODO(jracle@logitech.com): refactor string comparison in favor of
430 // testing individual fields.
431 ASSERT_EQ(expected
, actual
.str());
434 void GetTopLevelCollections(const std::vector
<HidUsageAndPage
>& expected
,
435 const uint8_t* bytes
,
437 descriptor_
= new HidReportDescriptor(bytes
, size
);
439 std::vector
<HidUsageAndPage
> actual
;
440 descriptor_
->GetTopLevelCollections(&actual
);
442 std::cout
<< "HID top-level collections:" << std::endl
;
443 for (std::vector
<HidUsageAndPage
>::const_iterator iter
= actual
.begin();
444 iter
!= actual
.end();
446 std::cout
<< *iter
<< std::endl
;
449 ASSERT_THAT(actual
, ContainerEq(expected
));
453 HidReportDescriptor
* descriptor_
;
456 TEST_F(HidReportDescriptorTest
, ParseDescriptor_Keyboard
) {
457 const char expected
[] = {
458 "Usage Page (Generic Desktop)\n"
460 "Collection (Physical)\n"
461 " Usage Page (Keyboard)\n"
462 " Usage Minimum (224)\n"
463 " Usage Maximum (231)\n"
464 " Logical Minimum (0)\n"
465 " Logical Maximum (1)\n"
467 " Report Count (8)\n"
468 " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
469 " Report Count (1)\n"
471 " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
472 " Report Count (5)\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"
480 " Output (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
481 " Report Count (6)\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"
491 ParseDescriptor(std::string(expected
), kKeyboard
, sizeof(kKeyboard
));
494 TEST_F(HidReportDescriptorTest
, TopLevelCollections_Keyboard
) {
495 HidUsageAndPage expected
[] = {
496 HidUsageAndPage(0x06, HidUsageAndPage::kPageGenericDesktop
)};
498 GetTopLevelCollections(std::vector
<HidUsageAndPage
>(
499 expected
, expected
+ ARRAYSIZE_UNSAFE(expected
)),
504 TEST_F(HidReportDescriptorTest
, ParseDescriptor_Mouse
) {
505 const char expected
[] = {
506 "Usage Page (Generic Desktop)\n"
508 "Collection (Physical)\n"
510 " Collection (Physical)\n"
511 " Usage Page (Button)\n"
512 " Usage Minimum (1)\n"
513 " Usage Maximum (3)\n"
514 " Logical Minimum (0)\n"
515 " Logical Maximum (1)\n"
516 " Report Count (3)\n"
518 " Input (Dat|Arr|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
519 " Report Count (1)\n"
521 " Input (Con|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
522 " Usage Page (Generic Desktop)\n"
525 " Logical Minimum (129)\n"
526 " Logical Maximum (127)\n"
528 " Report Count (2)\n"
529 " Input (Dat|Arr|Abs|NoWrp|Lin|Prf|NoNull|BitF)\n"
533 ParseDescriptor(std::string(expected
), kMouse
, sizeof(kMouse
));
536 TEST_F(HidReportDescriptorTest
, TopLevelCollections_Mouse
) {
537 HidUsageAndPage expected
[] = {
538 HidUsageAndPage(0x02, HidUsageAndPage::kPageGenericDesktop
)};
540 GetTopLevelCollections(std::vector
<HidUsageAndPage
>(
541 expected
, expected
+ ARRAYSIZE_UNSAFE(expected
)),
546 TEST_F(HidReportDescriptorTest
, ParseDescriptor_LogitechUnifyingReceiver
) {
547 const char expected
[] = {
548 "Usage Page (Vendor)\n"
550 "Collection (Physical)\n"
551 " Report ID (0x10)\n"
553 " Report Count (6)\n"
554 " Logical Minimum (0)\n"
555 " Logical Maximum (255)\n"
557 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
559 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
561 "Usage Page (Vendor)\n"
563 "Collection (Physical)\n"
564 " Report ID (0x11)\n"
566 " Report Count (19)\n"
567 " Logical Minimum (0)\n"
568 " Logical Maximum (255)\n"
570 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
572 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
574 "Usage Page (Vendor)\n"
576 "Collection (Physical)\n"
577 " Report ID (0x20)\n"
579 " Report Count (14)\n"
580 " Logical Minimum (0)\n"
581 " Logical Maximum (255)\n"
583 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\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"
591 " Input (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
593 " Output (Dat|Var|Rel|NoWrp|Lin|Prf|NoNull|BitF)\n"
596 ParseDescriptor(std::string(expected
),
597 kLogitechUnifyingReceiver
,
598 sizeof(kLogitechUnifyingReceiver
));
601 TEST_F(HidReportDescriptorTest
, TopLevelCollections_LogitechUnifyingReceiver
) {
602 HidUsageAndPage expected
[] = {
603 HidUsageAndPage(0x01, HidUsageAndPage::kPageVendor
),
604 HidUsageAndPage(0x02, HidUsageAndPage::kPageVendor
),
605 HidUsageAndPage(0x04, HidUsageAndPage::kPageVendor
), };
607 GetTopLevelCollections(std::vector
<HidUsageAndPage
>(
608 expected
, expected
+ ARRAYSIZE_UNSAFE(expected
)),
609 kLogitechUnifyingReceiver
,
610 sizeof(kLogitechUnifyingReceiver
));
613 } // namespace device