structures (i.e., usage page and usage values).

DecodeInputUsages must first find out the maximum size for this output array using HidP_MaxUsageListLength, so that a suitably sized array can be allocated. Actually, DecodeInputUsages cheats, as I know the maximum size in advance. I use the MaxPreviousUsages constant to declare fixed-size arrays; this avoids allocating and freeing buffers all over the place.

The maximum usage list length for a keyboard report is 14. This is made up of the six keys that the HID Report descriptor says can be pressed simultaneously, and the eight modifier keys, again that the Report descriptor says can be pressed simultaneously. Obviously, it is extremely unlikely that 14 keys can be pressed at the same time.

HidP_GetButtonsEx analyses the input report just received and fills in the array of USAGE_AND_PAGE structures, called Usages. The ValidUsages variable is filled with the number of valid elements in this array. DecodeInputUsages simply prints out the usage page and usage for each of these valid key presses.

The next job, if desired, is to work out what has changed since the last input report. The HidP_UsageListDifference function does this. It is passed the previous usage list and the current usage list as input. It fills in two further arrays, one with a list of usages that have been 'made' (or just arrived), and one with a list of usages that have just 'broken' (or gone away). DecodeInputUsages prints out these two arrays. Note that HidP_UsageListDifference deals with arrays of USAGE values, not USAGE_AND_PAGEs. In DecodeInputUsages all the input usages are in the keyboard usage page, so this is not a problem.

Listing 23.4 Decoding input report usages

const ULONG MaxPreviousUsages = 14;

USAGE_AND_PAGE Usages[MaxPreviousUsages];

USAGE PreviousUsages[MaxPreviousUsages];

void DecodeInputUsages(char* KbdReport, USHORT KbdReportLen, PHIDP_PREPARSED_DATA HidPreparsedData) {

 // Get max number of USAGE_ANQ_PAGEs required for all input reports in

 // top-level collection

 ULONG MaxUsages = HidP_MaxUsageListLength(HidP_Input, 0, HidPreparsedData);

 if (MaxUsages==0 || MaxUsages>MaxPreviousUsages) {

  printf('XXX Invalid HidP_MaxUsageListLength returned %d ', MaxUsages);

  return;

 }

 // Get usages set in given keyboard report

 ULONG ValidUsages = MaxUsages;

 NTSTATUS status = HidP_GetButtonsEx(HidP_Input, 0, Usages, &ValidUsages, HidPreparsedData, KbdReport, KbdReportLen);

 if (status==HIDP_STATUS_SUCCESS) {

  USAGE CurrentUsages[MaxPreviousUsages];

  USAGE BreakUsages[MaxPreviousUsages];

  USAGE MakeUsages[MaxPreviousUsages];

  // Show current usages

  memset(CurrentUsages, 0, sizeof(CurrentUsages));

  printf(' Usages set: ');

  for (ULONG i=0; i<ValidUsages; i++) {

   printf( ' %02X:%02X', Usages[i].UsagePage, Usages[i].Usage);

   CurrentUsages[i] = Usages[i].Usage;

  }

  // Work out differences compared to previous usages

  HidP_UsageListDifference(PreviousUsages, CurrentUsages, BreakUsages, MakeUsages, MaxUsages);

  // Print out usages broken and made

  printf(' (Break: ');

  for (i=0; i<MaxUsages; i++) {

   if (BreakUsages[i]==0) break;

   printf(' %02X', BreakUsages[i]);

  }

  printf(') (Make: ');

  for(i=0; i<MaxUsages; i++) {

   if (MakeUsages[i]==0) break;

   printf(' %02X', MakeUsages[i]);

  }

  printf(') ');

  // Save previous usages

  memcpy(PreviousUsages, CurrentUsages, MaxUsages*sizeof(USAGE));

 }

}

The HidP_GetButtons function can be used if you are only looking for buttons in a particular usage page. Both HidP_GetButtons and HidP_GetButtonsEx have parameters that let you look for buttons in a particular collection.

What Values Were Set in My Report?

Use the HidP_GetUsageValue, HidP_GetScaledUsageValue, or HidP_GetUsageValueArray functions to retrieve control values.

Sending Output Reports

You send HID output reports using the Win32 WriteFile function. While you can build the output buffer by hand, it is safer to use the HID parsing routines to fill in the buffer.

The SetLEDs function shown in Listing 23.5 shows how a single output report is sent to set the state of the HID keyboard LEDs. It has three optional parameters, which must contain the individual LED usages that you want set on. This line in the HidUsbUser main routine shows how to turn the ScrollLock LED on and turn the other LEDs off.

SetLEDs(hHidKbd, OutputReportLen, HidPreparsedData, HID_USAGE_LED_SCROLL_LOCK);

A keyboard output report consists of just one byte. However, as before, the output buffer must have an extra byte at the beginning for the report ID. This is set to zero in this case, as keyboards do not use report IDs. SetLEDs allocates an output buffer and zeroes it.

SetLEDs must now build an array of USAGEs, filled with any of its optional parameters that are non-zero. This array and its length are passed to HidP_SetButtons. HidP_SetButtons builds the output buffer in the correct format. SetLEDs then simply calls WriteFile to send off the output report.

You can call HidP_SetButtons more than once for a single output report. Indeed, you may also want to call one of the set value functions, if the output report must contain values. Set values into an output report using the HidP_SetUsageValue, HidP_SetScaledUsageValue, and HidP_SetUsageValueArray functions.

Be careful if you are using a HID device that has more than one output report. HidP_SetButtons can only build one output report at a time. HidP_SetButtons sets the report ID, if appropriate. If a second call to HidP_SetButtons tries to set a usage that is not in the first report, it fails with a suitable error code. However, if you start afresh with a new output report and repeat the second call to HidP_SetButtons, it should work this time. This whole process makes it particularly laborious to set output usages in a way that is truly independent of the device that is attached.

Listing 23.5 Setting keyboard LEDs using an output HID report

void SetLEDs(HANDLE hHidKbd, USHORT OutputReportLen, PHIDP_PREPARSED_DATA HidPreparsedData,

 USAGE Usage1/*=0*/, USAGE Usage2/*=0*/, USAGE Usage3/*=0*/) {

 // Build Output report from given usage(s)

 char* OutputReport = new char[OutputReportLen];

 assert(OutputReport!=NULL);

 memset(OutputReport, 0, OutputReportLen);

 USAGE UsageList[3];

 UsageList[0] = Usage1;

 UsageList[1] = Usage2;

 UsageList[2] = Usage3;

 ULONG UsageLength = 0;

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

0

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

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