XInput_Scp/pnp.cpp (593 lines of code) (raw):
#include "StdAfx.h"
BOOLEAN FindKnownHidDevices(OUT PHID_DEVICE* HidDevices, OUT PULONG NumberDevices)
{
HDEVINFO hardwareDeviceInfo;
SP_DEVICE_INTERFACE_DATA deviceInfoData;
ULONG i = 0;
BOOLEAN done;
PHID_DEVICE hidDeviceInst;
GUID hidGuid;
PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData = NULL;
ULONG predictedLength = 0;
ULONG requiredLength = 0;
PHID_DEVICE newHidDevices;
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.
if (hardwareDeviceInfo == INVALID_HANDLE_VALUE)
{
return FALSE;
}
//
// Take a wild guess to start
//
*NumberDevices = 4;
done = FALSE;
deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
while (!done)
{
*NumberDevices *= 2;
if (*HidDevices)
{
newHidDevices = (PHID_DEVICE) realloc(*HidDevices, (*NumberDevices * sizeof(HID_DEVICE)));
if (newHidDevices == NULL)
{
free(*HidDevices);
}
*HidDevices = newHidDevices;
}
else
{
*HidDevices = (PHID_DEVICE) calloc(*NumberDevices, sizeof(HID_DEVICE));
}
if (*HidDevices == NULL)
{
SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
return FALSE;
}
hidDeviceInst = *HidDevices + i;
for (; i < *NumberDevices; i++, hidDeviceInst++)
{
if (SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,
0, // No care about specific PDOs
&hidGuid,
i,
&deviceInfoData))
{
//
// 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 = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(predictedLength);
if (functionClassDeviceData)
{
functionClassDeviceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
ZeroMemory(functionClassDeviceData->DevicePath, sizeof(functionClassDeviceData->DevicePath));
}
else
{
SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
return FALSE;
}
//
// Retrieve the information from Plug and Play.
//
if (! SetupDiGetDeviceInterfaceDetail(
hardwareDeviceInfo,
&deviceInfoData,
functionClassDeviceData,
predictedLength,
&requiredLength,
NULL))
{
SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
free(functionClassDeviceData);
return FALSE;
}
//
// Open device with just generic query abilities to begin with
//
if (! OpenHidDevice(functionClassDeviceData->DevicePath,
FALSE, // ReadAccess - none
FALSE, // WriteAccess - none
FALSE, // Overlapped - no
FALSE, // Exclusive - no
hidDeviceInst))
{
SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
free(functionClassDeviceData);
return FALSE;
}
}
else
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
{
done = TRUE;
break;
}
}
}
}
*NumberDevices = i;
SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
free(functionClassDeviceData);
return TRUE;
}
BOOLEAN OpenHidDevice(IN LPTSTR DevicePath, IN BOOL HasReadAccess, IN BOOL HasWriteAccess, IN BOOL IsOverlapped, IN BOOL IsExclusive, __inout PHID_DEVICE HidDevice)
{
DWORD accessFlags = 0;
DWORD sharingFlags = 0;
INT iDevicePathSize;
if (DevicePath == NULL)
{
return FALSE;
}
iDevicePathSize = (INT) (_tcslen(DevicePath) + 1) * sizeof(TCHAR);
HidDevice->DevicePath = (PTCHAR) malloc(iDevicePathSize);
if (HidDevice->DevicePath == NULL)
{
return FALSE;
}
StringCbCopy(HidDevice->DevicePath, iDevicePathSize, DevicePath);
if (HasReadAccess ) accessFlags |= GENERIC_READ;
if (HasWriteAccess) accessFlags |= GENERIC_WRITE;
if (!IsExclusive ) sharingFlags = FILE_SHARE_READ | FILE_SHARE_WRITE;
HidDevice->HidDevice = CreateFile(DevicePath, accessFlags, sharingFlags, NULL, OPEN_EXISTING, 0, NULL);
if (HidDevice->HidDevice == INVALID_HANDLE_VALUE)
{
free(HidDevice->DevicePath);
HidDevice->DevicePath = NULL;
return FALSE;
}
HidDevice->OpenedForRead = HasReadAccess;
HidDevice->OpenedForWrite = HasWriteAccess;
HidDevice->OpenedOverlapped = IsOverlapped;
HidDevice->OpenedExclusive = IsExclusive;
if (!HidD_GetPreparsedData(HidDevice->HidDevice, &HidDevice->Ppd))
{
free(HidDevice->DevicePath);
HidDevice->DevicePath = NULL;
CloseHandle(HidDevice->HidDevice);
HidDevice->HidDevice = INVALID_HANDLE_VALUE;
return FALSE;
}
if (!HidD_GetAttributes(HidDevice->HidDevice, &HidDevice->Attributes))
{
free(HidDevice->DevicePath);
HidDevice->DevicePath = NULL;
CloseHandle(HidDevice->HidDevice);
HidDevice->HidDevice = INVALID_HANDLE_VALUE;
HidD_FreePreparsedData(HidDevice->Ppd);
HidDevice->Ppd = NULL;
return FALSE;
}
if (!HidP_GetCaps(HidDevice->Ppd, &HidDevice->Caps))
{
free(HidDevice->DevicePath);
HidDevice->DevicePath = NULL;
CloseHandle(HidDevice->HidDevice);
HidDevice->HidDevice = INVALID_HANDLE_VALUE;
HidD_FreePreparsedData(HidDevice->Ppd);
HidDevice->Ppd = NULL;
return FALSE;
}
if (!FillDeviceInfo(HidDevice))
{
CloseHidDevice(HidDevice);
return FALSE;
}
if (IsOverlapped)
{
CloseHandle(HidDevice->HidDevice);
HidDevice->HidDevice = CreateFile(DevicePath, accessFlags, sharingFlags, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (HidDevice->HidDevice == INVALID_HANDLE_VALUE)
{
CloseHidDevice(HidDevice);
return FALSE;
}
}
return TRUE;
}
BOOLEAN FillDeviceInfo(IN PHID_DEVICE HidDevice)
{
ULONG numValues;
USHORT numCaps;
PHIDP_BUTTON_CAPS buttonCaps;
PHIDP_VALUE_CAPS valueCaps;
PHID_DATA data;
ULONG i;
USAGE usage;
UINT dataIdx;
ULONG newFeatureDataLength;
ULONG tmpSum;
HidDevice->InputReportBuffer = (PCHAR) calloc(HidDevice->Caps.InputReportByteLength, sizeof(CHAR));
HidDevice->InputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS) calloc(HidDevice->Caps.NumberInputButtonCaps, sizeof(HIDP_BUTTON_CAPS));
if (buttonCaps == NULL)
{
return FALSE;
}
HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS) calloc(HidDevice->Caps.NumberInputValueCaps, sizeof(HIDP_VALUE_CAPS));
if (valueCaps == NULL)
{
return FALSE;
}
numCaps = HidDevice->Caps.NumberInputButtonCaps;
if(numCaps > 0)
{
if(HidP_GetButtonCaps(HidP_Input, buttonCaps, &numCaps, HidDevice->Ppd) != HIDP_STATUS_SUCCESS)
{
return FALSE;
}
}
numCaps = HidDevice->Caps.NumberInputValueCaps;
if(numCaps > 0)
{
if(HidP_GetValueCaps(HidP_Input, valueCaps, &numCaps, HidDevice->Ppd) != HIDP_STATUS_SUCCESS)
{
return FALSE;
}
}
numValues = 0;
for (i = 0; i < HidDevice->Caps.NumberInputValueCaps; i++, valueCaps++)
{
if (valueCaps->IsRange)
{
numValues += valueCaps->Range.UsageMax - valueCaps->Range.UsageMin + 1;
if(valueCaps->Range.UsageMin >= valueCaps->Range.UsageMax + (HidDevice->Caps).NumberInputButtonCaps)
{
return FALSE;
}
}
else
{
numValues++;
}
}
valueCaps = HidDevice->InputValueCaps;
HidDevice->InputDataLength = HidDevice->Caps.NumberInputButtonCaps + numValues;
HidDevice->InputData = data = (PHID_DATA) calloc(HidDevice->InputDataLength, sizeof(HID_DATA));
if (data == NULL)
{
return FALSE;
}
dataIdx = 0;
for (i = 0; i < HidDevice->Caps.NumberInputButtonCaps; i++, data++, buttonCaps++, dataIdx++)
{
data->IsButtonData = TRUE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = buttonCaps->UsagePage;
if (buttonCaps->IsRange)
{
data->ButtonData.UsageMin = buttonCaps->Range.UsageMin;
data->ButtonData.UsageMax = buttonCaps->Range.UsageMax;
}
else
{
data->ButtonData.UsageMin = data->ButtonData.UsageMax = buttonCaps->NotRange.Usage;
}
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength(HidP_Input, buttonCaps->UsagePage, HidDevice->Ppd);
data->ButtonData.Usages = (PUSAGE) calloc(data->ButtonData.MaxUsageLength, sizeof(USAGE));
data->ReportID = buttonCaps->ReportID;
}
for (i = 0; i < HidDevice->Caps.NumberInputValueCaps ; i++, valueCaps++)
{
if (valueCaps->IsRange)
{
for (usage = valueCaps->Range.UsageMin; usage <= valueCaps->Range.UsageMax; usage++)
{
if(dataIdx >= HidDevice->InputDataLength)
{
return FALSE;
}
data->IsButtonData = FALSE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = valueCaps->UsagePage;
data->ValueData.Usage = usage;
data->ReportID = valueCaps->ReportID;
data++; dataIdx++;
}
}
else
{
if(dataIdx >= HidDevice->InputDataLength)
{
return FALSE;
}
data->IsButtonData = FALSE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = valueCaps->UsagePage;
data->ValueData.Usage = valueCaps->NotRange.Usage;
data->ReportID = valueCaps->ReportID;
data++; dataIdx++;
}
}
HidDevice->OutputReportBuffer = (PCHAR) calloc(HidDevice->Caps.OutputReportByteLength, sizeof(CHAR));
HidDevice->OutputButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS) calloc(HidDevice->Caps.NumberOutputButtonCaps, sizeof(HIDP_BUTTON_CAPS));
if (buttonCaps == NULL)
{
return FALSE;
}
HidDevice->OutputValueCaps = valueCaps = (PHIDP_VALUE_CAPS) calloc(HidDevice->Caps.NumberOutputValueCaps, sizeof(HIDP_VALUE_CAPS));
if (valueCaps == NULL)
{
return FALSE;
}
numCaps = HidDevice->Caps.NumberOutputButtonCaps;
if(numCaps > 0)
{
if(HidP_GetButtonCaps(HidP_Output, buttonCaps, &numCaps, HidDevice->Ppd) != HIDP_STATUS_SUCCESS)
{
return FALSE;
}
}
numCaps = HidDevice->Caps.NumberOutputValueCaps;
if(numCaps > 0)
{
if(HidP_GetValueCaps(HidP_Output, valueCaps, &numCaps, HidDevice->Ppd) != HIDP_STATUS_SUCCESS)
{
return FALSE;
}
}
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));
if (data == NULL)
{
return FALSE;
}
for (i = 0; i < HidDevice->Caps.NumberOutputButtonCaps; i++, data++, buttonCaps++)
{
if (i >= HidDevice->OutputDataLength)
{
return FALSE;
}
if(FAILED(ULongAdd(HidDevice->Caps.NumberOutputButtonCaps, valueCaps->Range.UsageMax, &tmpSum)))
{
return FALSE;
}
if(valueCaps->Range.UsageMin == tmpSum)
{
return FALSE;
}
data->IsButtonData = TRUE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = buttonCaps->UsagePage;
if (buttonCaps->IsRange)
{
data->ButtonData.UsageMin = buttonCaps->Range.UsageMin;
data->ButtonData.UsageMax = buttonCaps->Range.UsageMax;
}
else
{
data->ButtonData.UsageMin = data->ButtonData.UsageMax = buttonCaps->NotRange.Usage;
}
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength(HidP_Output, buttonCaps->UsagePage, HidDevice->Ppd);
data->ButtonData.Usages = (PUSAGE) calloc(data->ButtonData.MaxUsageLength, sizeof(USAGE));
data->ReportID = buttonCaps->ReportID;
}
for (i = 0; i < HidDevice->Caps.NumberOutputValueCaps ; 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->ReportID = valueCaps->ReportID;
data++;
}
}
else
{
data->IsButtonData = FALSE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = valueCaps->UsagePage;
data->ValueData.Usage = valueCaps->NotRange.Usage;
data->ReportID = valueCaps->ReportID;
data++;
}
}
HidDevice->FeatureReportBuffer = (PCHAR) calloc(HidDevice->Caps.FeatureReportByteLength, sizeof(CHAR));
HidDevice->FeatureButtonCaps = buttonCaps = (PHIDP_BUTTON_CAPS) calloc(HidDevice->Caps.NumberFeatureButtonCaps, sizeof(HIDP_BUTTON_CAPS));
if (buttonCaps == NULL)
{
return FALSE;
}
HidDevice->FeatureValueCaps = valueCaps = (PHIDP_VALUE_CAPS) calloc(HidDevice->Caps.NumberFeatureValueCaps, sizeof(HIDP_VALUE_CAPS));
if (valueCaps == NULL)
{
return FALSE;
}
numCaps = HidDevice->Caps.NumberFeatureButtonCaps;
if(numCaps > 0)
{
if(HidP_GetButtonCaps(HidP_Feature, buttonCaps, &numCaps, HidDevice->Ppd) != HIDP_STATUS_SUCCESS)
{
return FALSE;
}
}
numCaps = HidDevice->Caps.NumberFeatureValueCaps;
if(numCaps > 0)
{
if(HidP_GetValueCaps(HidP_Feature, valueCaps, &numCaps, HidDevice->Ppd) != HIDP_STATUS_SUCCESS)
{
return FALSE;
}
}
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;
if(FAILED(ULongAdd(HidDevice->Caps.NumberFeatureButtonCaps, numValues, &newFeatureDataLength)))
{
return FALSE;
}
HidDevice->FeatureDataLength = newFeatureDataLength;
HidDevice->FeatureData = data = (PHID_DATA) calloc(HidDevice->FeatureDataLength, sizeof(HID_DATA));
if (data == NULL)
{
return FALSE;
}
dataIdx = 0;
for (i = 0; i < HidDevice->Caps.NumberFeatureButtonCaps; i++, data++, buttonCaps++, dataIdx++)
{
data->IsButtonData = TRUE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = buttonCaps->UsagePage;
if (buttonCaps->IsRange)
{
data->ButtonData.UsageMin = buttonCaps->Range.UsageMin;
data->ButtonData.UsageMax = buttonCaps->Range.UsageMax;
}
else
{
data->ButtonData.UsageMin = data->ButtonData.UsageMax = buttonCaps->NotRange.Usage;
}
data->ButtonData.MaxUsageLength = HidP_MaxUsageListLength(HidP_Feature, buttonCaps->UsagePage, HidDevice->Ppd);
data->ButtonData.Usages = (PUSAGE) calloc(data->ButtonData.MaxUsageLength, sizeof(USAGE));
data->ReportID = buttonCaps->ReportID;
}
for (i = 0; i < HidDevice->Caps.NumberFeatureValueCaps ; i++, valueCaps++)
{
if (valueCaps->IsRange)
{
for (usage = valueCaps->Range.UsageMin; usage <= valueCaps->Range.UsageMax; usage++)
{
if(dataIdx >= HidDevice->FeatureDataLength)
{
return FALSE;
}
data->IsButtonData = FALSE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = valueCaps->UsagePage;
data->ValueData.Usage = usage;
data->ReportID = valueCaps->ReportID;
data++; dataIdx++;
}
}
else
{
if(dataIdx >= HidDevice->FeatureDataLength)
{
return FALSE;
}
data->IsButtonData = FALSE;
data->Status = HIDP_STATUS_SUCCESS;
data->UsagePage = valueCaps->UsagePage;
data->ValueData.Usage = valueCaps->NotRange.Usage;
data->ReportID = valueCaps->ReportID;
data++; dataIdx++;
}
}
return TRUE;
}
VOID CloseHidDevices(IN PHID_DEVICE HidDevices, IN ULONG NumberDevices)
{
for (ULONG Index = 0; Index < NumberDevices; Index++)
{
CloseHidDevice(&HidDevices[Index]);
}
}
VOID CloseHidDevice(IN PHID_DEVICE HidDevice)
{
if (HidDevice->DevicePath != NULL)
{
free(HidDevice->DevicePath);
HidDevice->DevicePath = NULL;
}
if (HidDevice->HidDevice != INVALID_HANDLE_VALUE)
{
CloseHandle(HidDevice->HidDevice);
HidDevice->HidDevice = INVALID_HANDLE_VALUE;
}
if (HidDevice->Ppd != NULL)
{
HidD_FreePreparsedData(HidDevice->Ppd);
HidDevice->Ppd = NULL;
}
if (HidDevice->InputReportBuffer != NULL)
{
free(HidDevice->InputReportBuffer);
HidDevice->InputReportBuffer = NULL;
}
if (HidDevice->InputData != NULL)
{
free(HidDevice->InputData);
HidDevice->InputData = NULL;
}
if (HidDevice->InputButtonCaps != NULL)
{
free(HidDevice->InputButtonCaps);
HidDevice->InputButtonCaps = NULL;
}
if (HidDevice->InputValueCaps != NULL)
{
free(HidDevice->InputValueCaps);
HidDevice->InputValueCaps = NULL;
}
if (HidDevice->OutputReportBuffer != NULL)
{
free(HidDevice->OutputReportBuffer);
HidDevice->OutputReportBuffer = NULL;
}
if (HidDevice->OutputData != NULL)
{
free(HidDevice->OutputData);
HidDevice->OutputData = NULL;
}
if (HidDevice->OutputButtonCaps != NULL)
{
free(HidDevice->OutputButtonCaps);
HidDevice->OutputButtonCaps = NULL;
}
if (HidDevice->OutputValueCaps != NULL)
{
free(HidDevice->OutputValueCaps);
HidDevice->OutputValueCaps = NULL;
}
if (HidDevice->FeatureReportBuffer != NULL)
{
free(HidDevice->FeatureReportBuffer);
HidDevice->FeatureReportBuffer = NULL;
}
if (HidDevice->FeatureData != NULL)
{
free(HidDevice->FeatureData);
HidDevice->FeatureData = NULL;
}
if (HidDevice->FeatureButtonCaps != NULL)
{
free(HidDevice->FeatureButtonCaps);
HidDevice->FeatureButtonCaps = NULL;
}
if (HidDevice->FeatureValueCaps != NULL)
{
free(HidDevice->FeatureValueCaps);
HidDevice->FeatureValueCaps = NULL;
}
return;
}