ShowButtonCaps('Input button capabilities', HidP_Input, HidCaps.NumberInputButtonCaps, HidPreparsedData);

  ShowButtonCaps('Output button capabilities', HidP_Output, HidCaps.NumberOutputButtonCaps, HidPreparsedData);

 }

 return found;

}

Why Get Button and Value Capabilities?

Some programs cannot just rely on the HIDP_CAPS UsagePage and Usage fields. For example, in the future, some fancy device may use these fields to say that it is a 'speech interface'. A 'speech interface' might still be able to generate key presses (e.g., when a user says a word). Its detailed capabilities would show that it could indeed present data that is of interest.

Each control in a HID device is seen by Windows as being either a button or a value. Anything that has a HID usage is defined as being a button. Controls that take on any other values are called values.

Each of the keys on a keyboard has a HID usage. All keyboard keys are in usage page 7. Within that usage page, most of the usages from 0 to 255 have key definitions. However, most Western keyboards produce usage codes in two ranges. Usages 0 to 101 contain most standard keys, while usages 224 to 231 represent the modifier keys such as Shift, Ctrl, Alt, etc. To be extra careful, check that the HID device generates usages in these two ranges.

Similarly to double check that the HID device has the correct LEDs check that its output report contains buttons in usage page 8, for LEDs. Within this usage page, usage 1 corresponds to NumLock, usage 2 with CapsLock, and usage 3 with ScrollLock.

Getting Button Capabilities

The HIDP_CAPS structure has fields that tell you how many button and value capabilities there are for each type of report. For example, NumberInputButtonCaps tells you how many button capabilities there are for input reports.

GetCapabilities uses the ShowButtonCaps routine shown in Listing 23.2 to show what button capabilities there are for different types of report. The NumCaps parameter is passed the number of button capabilities that are expected for the specified type of report.

ShowButtonCaps first allocates an array of HIDP_BUTTON_CAPS structures called ButtonCaps. The call to HidP_GetButtonCaps fills in this array. Afterwards, ShowButtonCaps simply goes through each element in ButtonCaps and prints out the usages that can be returned. The HIDP_BUTTON_CAPS UsagePage field gives the usage page of all the buttons referred to in this structure. ReportId specifies the report in which these buttons are. If the IsRange BOOLEAN is TRUE, the Range.UsageMin and Range.UsageMax fields are valid. Otherwise, the Not Range. Usage field holds the only valid usage.

Each HIDP_BUTTON_CAPS structure has similar fields for the string descriptors and physical designators associated with controls. Finally, various link fields specify in which collection the buttons are. See the previous chapter for a description of collections.

Listing 23.2 Getting buttons capabilities

void ShowButtonCaps(char* Msg, HIDP_REPORT_TYPE ReportType, USHORT NumCaps, PHIDP_PREPARSED_DATA HidPreparsedData) {

 if (NumCaps==0) return;

 printf(' %s ', Msg);

 HIDP_BUTTON_CAPS* ButtonCaps = new HIDP_BUTTON_CAPS[NumCaps];

 if( ButtonCaps==NULL) return;

 NTSTATUS status = HidP_GetButtonCaps(ReportType, ButtonCaps, &NumCaps, HidPreparsedData);

 if (status==HIDP_STATUS_SUCCESS) {

  for (USHORT i=0; i<NumCaps; i++) {

   printf('ButtonCaps[%d].UsagePage %d ', i, ButtonCaps[i].UsagePage);

   if (ButtonCaps[i].IsRange) printf('.Usages %d..%d ', ButtonCaps[i].Range.UsageMin, ButtonCaps[i].Range.UsageMax);

   else printf('.Usage %d ', ButtonCaps[i].NotRange.Usage);

  }

 }

 delete ButtonCaps;

}

Here is an excerpt from the output produced by the ShowButtonCaps routine. It confirms that, in this case, the HID device has the desired controls. It could be fairly laborious if you had to check that all the right buttons were available, as the button capabilities could arrive in any order.

Input button capabilities

ButtonCaps[0].UsagePage 7

             .Usages 224..231

ButtonCaps[1].UsagePage 7

             .Usages 0..101

Output button capabilities

ButtonCaps[0].UsagePage 8

             .Usages 1..3

Use HidP_GetSpecificButtonCaps if you need to look for buttons in a different collection or search for a controls with a specific usage page or usage. This might be a better way of determining whether the controls you are interested in are supported.

Getting Value Capabilities

You can retrieve details of what control values are supported in a very similar way. Use HidP_GetValueCaps to get a list of all values in the top-level collection. Alternatively, HidP_GetSpecificValueCaps is used to look for values in a different collection, or search for controls with a specific usage page or usage. The information is stored in an array of HIDP_VALUE_CAPS structures.

Getting Collection Capabilities

The HidP_GetLinkCollectionNodes function is used to obtain details of all the collections in a top-level collection. It fills in an array of HIDP_LINK_COLLECTION_NODE structures. See the DDK for full details of how this array specifies the arrangement of collections within the top-level collection.

Reading Input Reports

Reading input reports from a HID device is straightforward. Listing 23.3 shows how this is done in the HidUsbUser main routine. It keeps reading input reports until the Esc key is pressed on the HID keyboard. See Listing 23.6 for some example output from this routine.

First, allocate and zero a buffer to receive a report, with the size given in the HIDP_CAPS structure. A keyboard input report is always eight bytes long. However, the InputReportByteLength field in HIDP_CAPS is one longer than this, as the first byte is used to indicate the report ID. For keyboard reports, this first byte will be zero, as report IDs are not used.

Use ReadFile to read the next available input report. If the device can return two different input reports then this call may obtain either of them. Suppose these two reports have different lengths. For the smaller input report, the returned count of bytes transferred will be less than the buffer size you passed.

Listing 23.3 Reading keyboard input reports

DWORD TxdBytes;

char* InputReport = new char[InputReportLen];

assert(InputReport!=NULL);

// Loop until Esc pressed on keyboard

do {

 if (!ReadFile( hHidKbd, InputReport, InputReportLen, &TxdBytes, NULL)) {

  printf('XXX Could not read value %d ', GetLastError());

  break;

 } else if (TxdBytes==InputReportLen) {

  printf(' Input report %d:', InputReport[0]);

  for(USHORT i=1; i<InputReportLen; i++) printf(' %02X', InputReport[i]);

  printf(' ');

  DecodeInputUsages(InputReport, InputReportLen, HidPreparsedData);

 } else {

  printf('XXX Wrong number of bytes read: %d ', TxdBytes);

  break;

 }

} while (InputReport[3]!=0x29);

delete InputReport;

What Buttons Were Set in My Report?

You could just look directly at the received buffer and work out what it means. However, the correct HID way to analyze reports is get the HID parsing routines to tell you what usages were set in the report. DecodeInputUsages, shown in Listing 23.4, does just this job. Indeed, it goes further by telling you what changes have occurred since the last input report. It prints out the usages that have just been 'made' and the ones have just been 'broken'.

The HidP_GetButtonsEx function analyses an input report buffer and reports which button usages were set in the report. The output is an array of USAGE_AND_PAGE

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату