880 lines
30 KiB
C
880 lines
30 KiB
C
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <basetyps.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <wtypes.h>
|
|
#include <wtypes.h>
|
|
#include "hidsdi.h"
|
|
#include "hid.h"
|
|
|
|
#define INSTRUCTIONS "\nCommands:\n" \
|
|
"\t?,h Display this message\n" \
|
|
"\t<N> Enter device number \n" \
|
|
"\tL LOOP read \n" \
|
|
"\tx exit\n"
|
|
|
|
#define PROMPT "Command!>"
|
|
void PrintDeviceinfo(PHID_DEVICE HidDevices, LONG ulCount);
|
|
|
|
int __cdecl main(int argc, char **argv)
|
|
{
|
|
PHID_DEVICE HidDevices, pWalk;
|
|
LONG ulCount;
|
|
BOOL bReturn, bDone, bOK;
|
|
int uiLoop;
|
|
PHID_DEVICE pDevice;
|
|
PHID_DATA pData;
|
|
unsigned uLoop;
|
|
char sz[256], cCode;
|
|
int i;
|
|
DWORD dwDelay=100;
|
|
|
|
bDone = FALSE;
|
|
bReturn=FindKnownHidDevices(&HidDevices,&ulCount);
|
|
printf("\n");
|
|
if(argc > 1)
|
|
dwDelay = atoi(argv[1]);
|
|
if(!bReturn)
|
|
{
|
|
printf("Error FindKnownHidDevices returned FALSE\n");
|
|
exit(0);
|
|
}
|
|
|
|
pDevice = HidDevices;
|
|
if(!pDevice){
|
|
printf("Hid Devices are not availabel\n");
|
|
exit(0);
|
|
}
|
|
PrintDeviceinfo(HidDevices, ulCount);
|
|
|
|
printf (INSTRUCTIONS);
|
|
|
|
while (!bDone) {
|
|
printf (PROMPT);
|
|
if (gets (sz) == NULL) {
|
|
sz[0] = 'x';
|
|
sz[1] = '\0';
|
|
}
|
|
cCode = sz[0]; // if user types a blank before the command, too bad
|
|
|
|
switch (cCode) {
|
|
case 'h':
|
|
case '?':
|
|
printf (INSTRUCTIONS);
|
|
break;
|
|
case '0': case '1': case '2': case '3':
|
|
case '4': case '5': case '6' : case '7':
|
|
case '8': case '9':{
|
|
if( cCode - '0' >= ulCount ) {
|
|
printf("Error invalid input try again\n");
|
|
continue;
|
|
}
|
|
pDevice = HidDevices + cCode - '0' ;
|
|
Read(pDevice);
|
|
pData=pDevice->InputData;
|
|
|
|
for(uLoop=0;uLoop<pDevice->InputDataLength;uLoop++)
|
|
{
|
|
ReportToString(pData);
|
|
pData++;
|
|
} /*end for*/
|
|
|
|
break;
|
|
}
|
|
case 'L': // loop read
|
|
printf ("Loop read device %d\n", pDevice->HidDevice);
|
|
Sleep(1000);
|
|
for (i = 0; i < 1000; i++) {
|
|
if(!Read(pDevice))
|
|
// printf("Read returned false\n");
|
|
pData=pDevice->InputData;
|
|
printf("-------------------------------------------\n");
|
|
for(uLoop=0;uLoop<pDevice->InputDataLength;uLoop++)
|
|
{
|
|
ReportToString(pData);
|
|
pData++;
|
|
} /*end for*/
|
|
Sleep(dwDelay);
|
|
}
|
|
break;
|
|
|
|
case 'x': // done
|
|
bDone = TRUE;
|
|
break;
|
|
|
|
default:
|
|
printf ("Huh? >%s<\n", sz);
|
|
printf (INSTRUCTIONS);
|
|
break;
|
|
}
|
|
} // end of while
|
|
pWalk= HidDevices;
|
|
for(uiLoop=0;uiLoop<ulCount;uiLoop++,pWalk++)
|
|
CloseHandle(pWalk->HidDevice);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
PrintDeviceinfo(
|
|
PHID_DEVICE HidDevices,
|
|
LONG ulCount
|
|
)
|
|
{
|
|
PHID_DEVICE pWalk;
|
|
LONG uiLoop, i, num;
|
|
PHIDP_VALUE_CAPS pValue;
|
|
PHIDP_BUTTON_CAPS pButton;
|
|
|
|
pWalk=HidDevices;
|
|
for(uiLoop=0;uiLoop<ulCount;uiLoop++, pWalk++)
|
|
{
|
|
if(pWalk->Caps.UsagePage == HID_USAGE_PAGE_GENERIC) {
|
|
switch(pWalk->Caps.Usage){
|
|
case HID_USAGE_GENERIC_POINTER:
|
|
printf("Device (%d) Pointer", uiLoop);break;
|
|
case HID_USAGE_GENERIC_MOUSE:
|
|
printf("Device (%d) Mouse", uiLoop);break;
|
|
case HID_USAGE_GENERIC_PEN:
|
|
printf("Device (%d) PEN", uiLoop);break;
|
|
case HID_USAGE_GENERIC_JOYSTICK:
|
|
printf("Device (%d) Joystick", uiLoop);break;
|
|
case HID_USAGE_GENERIC_GAMEPAD:
|
|
printf("Device (%d) GamePad", uiLoop);break;
|
|
case HID_USAGE_GENERIC_KEYBOARD :
|
|
printf("Device (%d) Keyboard", uiLoop);break;
|
|
case HID_USAGE_GENERIC_KEYPAD :
|
|
printf("Device (%d) Keypad", uiLoop);break;
|
|
case HID_USAGE_GENERIC_STYLUS2:
|
|
printf("Device (%d) Stylus2", uiLoop);break;
|
|
case HID_USAGE_GENERIC_PUCK :
|
|
printf("Device (%d) Pointer", uiLoop);break;
|
|
case HID_USAGE_GENERIC_SYSTEM_CTL :
|
|
printf("Device (%d) System Control", uiLoop);break;
|
|
default: goto PRN;
|
|
}// end of switch
|
|
}
|
|
else {
|
|
PRN: printf("Device (%d) UsagePage:0%x Usage:0%x",
|
|
uiLoop,pWalk->Caps.UsagePage,pWalk->Caps.Usage);
|
|
}
|
|
//pValue = pWalk->InputValueCaps;
|
|
|
|
if(pWalk->Caps.NumberInputButtonCaps){
|
|
pButton = pWalk->InputButtonCaps;
|
|
for(num=0,i=0;i<pWalk->Caps.NumberInputButtonCaps;i++,pButton++)
|
|
{
|
|
num += (pButton->Range.UsageMax -
|
|
pButton->Range.UsageMin + 1);
|
|
}
|
|
printf("\tNumInpBut(%d):%d",pWalk->Caps.NumberInputButtonCaps, num);
|
|
}
|
|
if(pWalk->Caps.NumberInputValueCaps){
|
|
printf("\tInpValCaps:%d",pWalk->Caps.NumberInputValueCaps);
|
|
}
|
|
|
|
if(pWalk->Caps.NumberOutputButtonCaps){
|
|
pButton = pWalk->OutputButtonCaps;
|
|
for(num=0,i=0;i<pWalk->Caps.NumberOutputButtonCaps;i++,pButton++)
|
|
{
|
|
num += (pButton->Range.UsageMax -
|
|
pButton->Range.UsageMin + 1);
|
|
}
|
|
printf("\tNumOutBut(%d):%d",pWalk->Caps.NumberOutputButtonCaps, num);
|
|
}
|
|
if(pWalk->Caps.NumberOutputValueCaps){
|
|
printf("\tOutButCaps:%d\n",pWalk->Caps.NumberOutputValueCaps);
|
|
}
|
|
|
|
if(pWalk->Caps.NumberFeatureButtonCaps){
|
|
pButton = pWalk->FeatureButtonCaps;
|
|
for(num=0,i=0;i<pWalk->Caps.NumberFeatureButtonCaps;i++,pButton++)
|
|
{
|
|
num += (pButton->Range.UsageMax -
|
|
pButton->Range.UsageMin + 1);
|
|
}
|
|
printf("\tNumFeatBut(%d):%d",pWalk->Caps.NumberFeatureButtonCaps, num);
|
|
}
|
|
if(pWalk->Caps.NumberFeatureValueCaps){
|
|
printf("\tFeatButCaps:%d\n",pWalk->Caps.NumberFeatureValueCaps);
|
|
}
|
|
printf("\n");
|
|
} /*end for*/
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
FindKnownHidDevices (
|
|
OUT PHID_DEVICE * HidDevices, // A array of struct _HID_DEVICE
|
|
OUT PULONG NumberDevices // the length of this array.
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Do the required PnP things in order to find, the all the HID devices in
|
|
the system at this time.
|
|
--*/
|
|
{
|
|
HDEVINFO hardwareDeviceInfo;
|
|
SP_DEVICE_INTERFACE_DATA deviceInfoData;
|
|
ULONG i;
|
|
BOOL done;
|
|
PHID_DEVICE hidDeviceInst;
|
|
GUID hidGuid;
|
|
|
|
HidD_GetHidGuid (&hidGuid);
|
|
|
|
*HidDevices = NULL;
|
|
*NumberDevices = 0;
|
|
|
|
//
|
|
// Open a handle to the plug and play dev node.
|
|
//
|
|
hardwareDeviceInfo = SetupDiGetClassDevs (
|
|
&hidGuid,
|
|
NULL, // Define no enumerator (global)
|
|
NULL, // Define no
|
|
(DIGCF_PRESENT | // Only Devices present
|
|
DIGCF_DEVICEINTERFACE)); // Function class devices.
|
|
|
|
//
|
|
// Take a wild guess to start
|
|
//
|
|
*NumberDevices = 4;
|
|
done = FALSE;
|
|
deviceInfoData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
|
|
|
|
i=0;
|
|
while (!done) {
|
|
*NumberDevices *= 2;
|
|
|
|
if (*HidDevices) {
|
|
*HidDevices =
|
|
realloc (*HidDevices, (*NumberDevices * sizeof (HID_DEVICE)));
|
|
} else {
|
|
*HidDevices = calloc (*NumberDevices, sizeof (HID_DEVICE));
|
|
}
|
|
|
|
if (NULL == *HidDevices) {
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
return FALSE;
|
|
}
|
|
|
|
hidDeviceInst = *HidDevices + i;
|
|
|
|
for (; i < *NumberDevices; i++, hidDeviceInst++) {
|
|
if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
|
|
0, // No care about specific PDOs
|
|
&hidGuid,
|
|
i,
|
|
&deviceInfoData)) {
|
|
|
|
OpenHidDevice (hardwareDeviceInfo, &deviceInfoData, hidDeviceInst);
|
|
|
|
} else {
|
|
if (ERROR_NO_MORE_ITEMS == GetLastError()) {
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*NumberDevices = i;
|
|
|
|
SetupDiDestroyDeviceInfoList (hardwareDeviceInfo);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ReportToString(
|
|
PHID_DATA pData
|
|
)
|
|
{
|
|
PUSAGE pUsage;
|
|
ULONG i;
|
|
|
|
if (pData->IsButtonData && pData->UsagePage == HID_USAGE_PAGE_BUTTON )
|
|
{
|
|
printf (" Buttons :");
|
|
for (i=0, pUsage = pData->ButtonData.Usages;
|
|
i < pData->ButtonData.MaxUsageLength;
|
|
i++, pUsage++) {
|
|
if (0 == *pUsage) {
|
|
break; // A usage of zero is a non button.
|
|
}
|
|
printf (" 0x%x", *pUsage);
|
|
}
|
|
printf("\n");
|
|
}
|
|
else
|
|
{
|
|
switch(pData->UsagePage) {
|
|
case HID_USAGE_PAGE_GENERIC :
|
|
case HID_USAGE_PAGE_VEHICLE :
|
|
switch(pData->ValueData.Usage) {
|
|
case HID_USAGE_VEHICLE_THROTTLE:
|
|
printf(" THROTTLE(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_VEHICLE_RUDDER:
|
|
printf(" RUDDER(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_X:
|
|
printf(" X(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_Y:
|
|
printf(" Y(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_Z:
|
|
printf(" Z(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_RX:
|
|
printf(" RX(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_RY:
|
|
printf(" RY(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_RZ:
|
|
printf(" RZ(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_SLIDER:
|
|
printf(" SLIDDER(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_DIAL:
|
|
printf(" DIAL(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_WHEEL:
|
|
printf(" WHEEL(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
|
|
case HID_USAGE_GENERIC_HATSWITCH:
|
|
printf(" HATSWITCH(%4d):%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
default:
|
|
goto END;
|
|
break;
|
|
}// end of switch
|
|
break;
|
|
case HID_USAGE_PAGE_KEYBOARD:
|
|
switch(pData->ValueData.Usage) {
|
|
case HID_USAGE_GENERIC_KEYBOARD:
|
|
printf(" KEYBOARD(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
case HID_USAGE_GENERIC_KEYPAD:
|
|
printf(" KEYPAD(%4d) :%4d\n",
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
break;
|
|
default:
|
|
goto END;
|
|
break;
|
|
}// end of switch
|
|
|
|
default:
|
|
END: printf ("Usage Page: 0x%x, Usage: 0x%x, Scaled: %d Value:%d\n",
|
|
pData->UsagePage,
|
|
pData->ValueData.Usage,
|
|
pData->ValueData.ScaledValue,
|
|
pData->ValueData.Value);
|
|
}//end of switch
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Read (
|
|
PHID_DEVICE HidDevice
|
|
)
|
|
/*++
|
|
RoutineDescription:
|
|
Given a struct _HID_DEVICE, obtain a read report and unpack the values
|
|
into to InputData array.
|
|
--*/
|
|
{
|
|
DWORD bytesRead;
|
|
|
|
if (!ReadFile (HidDevice->HidDevice,
|
|
HidDevice->InputReportBuffer,
|
|
HidDevice->Caps.InputReportByteLength,
|
|
&bytesRead,
|
|
NULL)) { // No overlapped structure. HidClass buffers for us.
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERT (bytesRead == hidDevice->Caps.InputReportByteLength);
|
|
|
|
return UnpackReport (HidDevice->InputReportBuffer,
|
|
HidDevice->Caps.InputReportByteLength,
|
|
HidP_Input,
|
|
HidDevice->InputData,
|
|
HidDevice->InputDataLength,
|
|
HidDevice->Ppd);
|
|
}
|
|
|
|
BOOL
|
|
UnpackReport (
|
|
IN PCHAR ReportBuffer,
|
|
IN USHORT ReportBufferLength,
|
|
IN HIDP_REPORT_TYPE ReportType,
|
|
IN OUT PHID_DATA Data,
|
|
IN ULONG DataLength,
|
|
IN PHIDP_PREPARSED_DATA Ppd
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
--*/
|
|
{
|
|
ULONG numUsages; // Number of usages returned from GetUsages.
|
|
ULONG i;
|
|
|
|
for (i = 0; i < DataLength; i++, Data++) {
|
|
if (Data->IsButtonData) {
|
|
numUsages = Data->ButtonData.MaxUsageLength;
|
|
Data->Status = HidP_GetUsages (
|
|
ReportType,
|
|
Data->UsagePage,
|
|
0, // All collections
|
|
Data->ButtonData.Usages,
|
|
&numUsages,
|
|
Ppd,
|
|
ReportBuffer,
|
|
ReportBufferLength);
|
|
//
|
|
// Get usages writes the list of usages into the buffer
|
|
// Data->ButtonData.Usages newUsage is set to the number of usages
|
|
// written into this array.
|
|
// We assume that there will not be a usage of zero.
|
|
// (None have been defined to date.)
|
|
// So lets assume that a zero indicates an end of the list of usages.
|
|
//
|
|
|
|
if (numUsages < Data->ButtonData.MaxUsageLength) {
|
|
Data->ButtonData.Usages[numUsages] = 0;
|
|
}
|
|
|
|
} else {
|
|
Data->Status = HidP_GetUsageValue (
|
|
ReportType,
|
|
Data->UsagePage,
|
|
0, // All Collections.
|
|
Data->ValueData.Usage,
|
|
&Data->ValueData.Value,
|
|
Ppd,
|
|
ReportBuffer,
|
|
ReportBufferLength);
|
|
|
|
Data->Status = HidP_GetScaledUsageValue (
|
|
ReportType,
|
|
Data->UsagePage,
|
|
0, // All Collections.
|
|
Data->ValueData.Usage,
|
|
&Data->ValueData.ScaledValue,
|
|
Ppd,
|
|
ReportBuffer,
|
|
ReportBufferLength);
|
|
}
|
|
}
|
|
return (HIDP_STATUS_SUCCESS == Data->Status);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
OpenHidDevice (
|
|
IN HDEVINFO HardwareDeviceInfo,
|
|
IN PSP_DEVICE_INTERFACE_DATA DeviceInfoData,
|
|
IN OUT PHID_DEVICE HidDevice
|
|
)
|
|
/*++
|
|
RoutineDescription:
|
|
Given the HardwareDeviceInfo, representing a handle to the plug and
|
|
play information, and deviceInfoData, representing a specific hid device,
|
|
open that device and fill in all the relivant information in the given
|
|
HID_DEVICE structure.
|
|
|
|
return if the open and initialization was successfull or not.
|
|
|
|
--*/
|
|
{
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
|
|
ULONG predictedLength = 0;
|
|
ULONG requiredLength = 0;
|
|
ULONG i;
|
|
ULONG numValues;
|
|
USHORT numCaps;
|
|
PHIDP_BUTTON_CAPS buttonCaps;
|
|
PHIDP_VALUE_CAPS valueCaps;
|
|
PHID_DATA data;
|
|
USAGE usage;
|
|
static ULONG NumberDevices = 0;
|
|
|
|
//
|
|
// allocate a function class device data structure to receive the
|
|
// goods about this particular device.
|
|
//
|
|
SetupDiGetDeviceInterfaceDetail (
|
|
HardwareDeviceInfo,
|
|
DeviceInfoData,
|
|
NULL, // probing so no output buffer yet
|
|
0, // probing so output buffer length of zero
|
|
&requiredLength,
|
|
NULL); // not interested in the specific dev-node
|
|
|
|
|
|
predictedLength = requiredLength;
|
|
|
|
functionClassDeviceData = malloc (predictedLength);
|
|
functionClassDeviceData->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
|
|
//
|
|
// Retrieve the information from Plug and Play.
|
|
//
|
|
if (! SetupDiGetDeviceInterfaceDetail (
|
|
HardwareDeviceInfo,
|
|
DeviceInfoData,
|
|
functionClassDeviceData,
|
|
predictedLength,
|
|
&requiredLength,
|
|
NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//printf("\nDevicePath of %d HID device: %s\n", NumberDevices,
|
|
// functionClassDeviceData->DevicePath);
|
|
HidDevice->HidDevice = CreateFile (
|
|
functionClassDeviceData->DevicePath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0, // FILE_SHARE_READ | FILE_SHARE_WRITE
|
|
NULL, // no SECURITY_ATTRIBUTES structure
|
|
OPEN_EXISTING, // No special create flags
|
|
0, // No special attributes
|
|
NULL); // No template file
|
|
|
|
if (INVALID_HANDLE_VALUE == HidDevice->HidDevice) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!HidD_GetPreparsedData (HidDevice->HidDevice, &HidDevice->Ppd)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!HidP_GetCaps (HidDevice->Ppd, &HidDevice->Caps)) {
|
|
HidD_FreePreparsedData (HidDevice->Ppd);
|
|
return FALSE;
|
|
}
|
|
|
|
NumberDevices++;
|
|
//
|
|
// At this point the client has a choise. It may chose to look at the
|
|
// Usage and Page of the top level collection found in the HIDP_CAPS
|
|
// structure. In this way it could just use the usages it knows about.
|
|
// If either HidP_GetUsages or HidP_GetUsageValue return an error then
|
|
// that particular usage does not exist in the report.
|
|
// This is most likely the preferred method as the application can only
|
|
// use usages of which it already knows.
|
|
// In this case the app need not even call GetButtonCaps or GetValueCaps.
|
|
//
|
|
// In this example, however, we look for all of the usages in the device.
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// setup Input Data buffers.
|
|
//
|
|
|
|
//
|
|
// Allocate memory to hold on input report
|
|
//
|
|
|
|
HidDevice->InputReportBuffer = (PCHAR)
|
|
calloc (HidDevice->Caps.InputReportByteLength, sizeof (CHAR));
|
|
|
|
|
|
//
|
|
// Allocate memory to hold the button and value capabilities.
|
|
// NumberXXCaps is in terms of array elements.
|
|
//
|
|
HidDevice->InputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
|
|
calloc (HidDevice->Caps.NumberInputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
|
|
HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
|
|
calloc (HidDevice->Caps.NumberInputValueCaps, sizeof (HIDP_VALUE_CAPS));
|
|
|
|
//
|
|
// Have the HidP_X functions fill in the capability structure arrays.
|
|
//
|
|
numCaps = HidDevice->Caps.NumberInputButtonCaps;
|
|
HidP_GetButtonCaps (HidP_Input,
|
|
buttonCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numCaps = HidDevice->Caps.NumberInputValueCaps;
|
|
HidP_GetValueCaps (HidP_Input,
|
|
valueCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
|
|
//
|
|
// Depending on the device, some value caps structures may represent more
|
|
// than one value. (A range). In the interest of being verbose, over
|
|
// efficient we will expand these so that we have one and only one
|
|
// struct _HID_DATA for each value.
|
|
//
|
|
// To do this we need to count up the total number of values are listed
|
|
// in the value caps structure. For each element in the array we test
|
|
// for range if it is a range then UsageMax and UsageMin describe the
|
|
// usages for this range INCLUSIVE.
|
|
//
|
|
numValues = 0;
|
|
for (i = 0; i < HidDevice->Caps.NumberInputValueCaps; i++, valueCaps++) {
|
|
if (valueCaps->IsRange) {
|
|
numValues += valueCaps->Range.UsageMax - valueCaps->Range.UsageMin + 1;
|
|
} else {
|
|
numValues++;
|
|
}
|
|
}
|
|
valueCaps = HidDevice->InputValueCaps;
|
|
|
|
|
|
//
|
|
// Allocate a buffer to hold the struct _HID_DATA structures.
|
|
// One element for each set of buttons, and one element for each value
|
|
// found.
|
|
//
|
|
HidDevice->InputDataLength = HidDevice->Caps.NumberInputButtonCaps
|
|
+ numValues;
|
|
HidDevice->InputData = data = (PHID_DATA)
|
|
calloc (HidDevice->InputDataLength, sizeof (HID_DATA));
|
|
|
|
|
|
//
|
|
// Fill in the button data
|
|
//
|
|
for (i = 0;
|
|
i < HidDevice->Caps.NumberInputButtonCaps;
|
|
i++, data++, buttonCaps++) {
|
|
|
|
data->IsButtonData = TRUE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = buttonCaps->UsagePage;
|
|
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
|
|
HidP_Input,
|
|
buttonCaps->UsagePage,
|
|
HidDevice->Ppd);
|
|
data->ButtonData.Usages = (PUSAGE)
|
|
calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
|
|
}
|
|
|
|
//
|
|
// Fill in the value data
|
|
//
|
|
for (i = 0; i < numValues; i++, valueCaps++) {
|
|
if (valueCaps->IsRange) {
|
|
for (usage = valueCaps->Range.UsageMin;
|
|
usage <= valueCaps->Range.UsageMax;
|
|
usage++) {
|
|
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = usage;
|
|
data++;
|
|
}
|
|
} else {
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = valueCaps->NotRange.Usage;
|
|
data++;
|
|
}
|
|
}
|
|
//return TRUE; // no need to get other info
|
|
//
|
|
// setup Output Data buffers.
|
|
//
|
|
HidDevice->OutputReportBuffer = (PCHAR)
|
|
calloc (HidDevice->Caps.OutputReportByteLength, sizeof (CHAR));
|
|
|
|
HidDevice->OutputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
|
|
calloc (HidDevice->Caps.NumberOutputButtonCaps, sizeof (HIDP_BUTTON_CAPS));
|
|
HidDevice->OutputValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
|
|
calloc (HidDevice->Caps.NumberOutputValueCaps, sizeof (HIDP_VALUE_CAPS));
|
|
|
|
numCaps = HidDevice->Caps.NumberOutputButtonCaps;
|
|
HidP_GetButtonCaps (HidP_Output,
|
|
buttonCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numCaps = HidDevice->Caps.NumberOutputValueCaps;
|
|
HidP_GetValueCaps (HidP_Output,
|
|
valueCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
|
|
numValues = 0;
|
|
for (i = 0; i < HidDevice->Caps.NumberOutputValueCaps; i++, valueCaps++) {
|
|
if (valueCaps->IsRange) {
|
|
numValues += valueCaps->Range.UsageMax
|
|
- valueCaps->Range.UsageMin + 1;
|
|
} else {
|
|
numValues++;
|
|
}
|
|
}
|
|
valueCaps = HidDevice->OutputValueCaps;
|
|
|
|
HidDevice->OutputDataLength = HidDevice->Caps.NumberOutputButtonCaps
|
|
+ numValues;
|
|
HidDevice->OutputData = data = (PHID_DATA)
|
|
calloc (HidDevice->OutputDataLength, sizeof (HID_DATA));
|
|
|
|
for (i = 0;
|
|
i < HidDevice->Caps.NumberOutputButtonCaps;
|
|
i++, data++, buttonCaps++) {
|
|
|
|
data->IsButtonData = TRUE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = buttonCaps->UsagePage;
|
|
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
|
|
HidP_Output,
|
|
buttonCaps->UsagePage,
|
|
HidDevice->Ppd);
|
|
data->ButtonData.Usages = (PUSAGE)
|
|
calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
|
|
}
|
|
|
|
for (i = 0; i < numValues; i++, valueCaps++) {
|
|
if (valueCaps->IsRange) {
|
|
for (usage = valueCaps->Range.UsageMin;
|
|
usage <= valueCaps->Range.UsageMax;
|
|
usage++) {
|
|
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = usage;
|
|
data++;
|
|
}
|
|
} else {
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = valueCaps->NotRange.Usage;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
//
|
|
// setup Feature Data buffers.
|
|
//
|
|
|
|
HidDevice->FeatureReportBuffer = (PCHAR)
|
|
calloc (HidDevice->Caps.FeatureReportByteLength, sizeof (CHAR));
|
|
|
|
HidDevice->FeatureButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS)
|
|
calloc (HidDevice->Caps.NumberFeatureButtonCaps, sizeof (HIDP_BUTTON_CAPS));
|
|
HidDevice->FeatureValueCaps = valueCaps = (PHIDP_VALUE_CAPS)
|
|
calloc (HidDevice->Caps.NumberFeatureValueCaps, sizeof (HIDP_VALUE_CAPS));
|
|
|
|
numCaps = HidDevice->Caps.NumberFeatureButtonCaps;
|
|
HidP_GetButtonCaps (HidP_Feature,
|
|
buttonCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
numCaps = HidDevice->Caps.NumberFeatureValueCaps;
|
|
HidP_GetValueCaps (HidP_Feature,
|
|
valueCaps,
|
|
&numCaps,
|
|
HidDevice->Ppd);
|
|
|
|
|
|
numValues = 0;
|
|
for (i = 0; i < HidDevice->Caps.NumberFeatureValueCaps; i++, valueCaps++) {
|
|
if (valueCaps->IsRange) {
|
|
numValues += valueCaps->Range.UsageMax
|
|
- valueCaps->Range.UsageMin + 1;
|
|
} else {
|
|
numValues++;
|
|
}
|
|
}
|
|
valueCaps = HidDevice->FeatureValueCaps;
|
|
|
|
HidDevice->FeatureDataLength = HidDevice->Caps.NumberFeatureButtonCaps
|
|
+ numValues;
|
|
HidDevice->FeatureData = data = (PHID_DATA)
|
|
calloc (HidDevice->FeatureDataLength, sizeof (HID_DATA));
|
|
|
|
for (i = 0;
|
|
i < HidDevice->Caps.NumberFeatureButtonCaps;
|
|
i++, data++, buttonCaps++) {
|
|
|
|
data->IsButtonData = TRUE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = buttonCaps->UsagePage;
|
|
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength (
|
|
HidP_Feature,
|
|
buttonCaps->UsagePage,
|
|
HidDevice->Ppd);
|
|
data->ButtonData.Usages = (PUSAGE)
|
|
calloc (data->ButtonData.MaxUsageLength, sizeof (USAGE));
|
|
}
|
|
|
|
for (i = 0; i < numValues; i++, valueCaps++) {
|
|
if (valueCaps->IsRange) {
|
|
for (usage = valueCaps->Range.UsageMin;
|
|
usage <= valueCaps->Range.UsageMax;
|
|
usage++) {
|
|
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = usage;
|
|
data++;
|
|
}
|
|
} else {
|
|
data->IsButtonData = FALSE;
|
|
data->Status = HIDP_STATUS_SUCCESS;
|
|
data->UsagePage = valueCaps->UsagePage;
|
|
data->ValueData.Usage = valueCaps->NotRange.Usage;
|
|
data++;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|