BOOLEAN FillDeviceInfo( IN PHID_DEVICE HidDevice ) { USHORT numValues; USHORT numCaps; PHIDP_BUTTON_CAPS buttonCaps; PHIDP_VALUE_CAPS valueCaps; PHID_DATA data; ULONG i; USAGE usage; // // 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)); if (NULL == buttonCaps) { return (FALSE); } HidDevice->InputValueCaps = valueCaps = (PHIDP_VALUE_CAPS) calloc (HidDevice->Caps.NumberInputValueCaps, sizeof (HIDP_VALUE_CAPS)); if (NULL == valueCaps) { return(FALSE); } // // 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)); if (NULL == data) { return (FALSE); } // // 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; 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; } // // 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->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++; } } // // 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)); if (NULL == buttonCaps) { return (FALSE); } HidDevice->OutputValueCaps = valueCaps = (PHIDP_VALUE_CAPS) calloc (HidDevice->Caps.NumberOutputValueCaps, sizeof (HIDP_VALUE_CAPS)); if (NULL == valueCaps) { return (FALSE); } 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)); if (NULL == data) { return (FALSE); } for (i = 0; i < HidDevice->Caps.NumberOutputButtonCaps; i++, data++, buttonCaps++) { 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 < 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->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++; } } // // 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)); if (NULL == buttonCaps) { return (FALSE); } HidDevice->FeatureValueCaps = valueCaps = (PHIDP_VALUE_CAPS) calloc (HidDevice->Caps.NumberFeatureValueCaps, sizeof (HIDP_VALUE_CAPS)); if (NULL == valueCaps) { return (FALSE); } 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)); if (NULL == data) { return (FALSE); } for (i = 0; i < HidDevice->Caps.NumberFeatureButtonCaps; i++, data++, buttonCaps++) { 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 < 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->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++; } } return (TRUE); }
bool Controller::registerController(int pDeviceId) { //Required variables to iterate over the device interface DWORD result = 0; LPGUID hidguid = (LPGUID)malloc(sizeof(GUID)); HDEVINFO deviceset; PSP_DEVICE_INTERFACE_DATA deviceInterfaceData = nullptr; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceInfo = nullptr; DWORD buffersize = 0; //malloc check CHECK_NULL(hidguid, SETUP_ERROR); //get hid guid HidD_GetHidGuid(hidguid); //get device list deviceset = SetupDiGetClassDevs(hidguid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (deviceset == INVALID_HANDLE_VALUE) { goto SETUP_ERROR; } int deviceindex = 0; deviceInterfaceData = (PSP_DEVICE_INTERFACE_DATA)malloc(sizeof(SP_DEVICE_INTERFACE_DATA)); //malloc check CHECK_NULL(deviceInterfaceData, SETUP_ERROR); deviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); //iterate through devices while (SetupDiEnumDeviceInterfaces(deviceset, nullptr, hidguid, deviceindex, deviceInterfaceData)) { //this should fail originally in order to get buffer size if (deviceInterfaceInfo != nullptr) { free(deviceInterfaceInfo); deviceInterfaceInfo = 0; } if (SetupDiGetDeviceInterfaceDetail(deviceset, deviceInterfaceData, nullptr, 0, (PDWORD)&buffersize, nullptr) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { goto SETUP_ERROR; } deviceInterfaceInfo = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(buffersize); //malloc check CHECK_NULL(deviceInterfaceInfo, SETUP_ERROR); deviceInterfaceInfo->cbSize = sizeof(*deviceInterfaceInfo); //device info buffer allocated, get details if (!SetupDiGetDeviceInterfaceDetail(deviceset, deviceInterfaceData, deviceInterfaceInfo, buffersize, (PDWORD)&buffersize, nullptr)) { goto SETUP_ERROR; } //you must pass in the device id of the hid client to read from if (deviceindex == pDeviceId) { _controllerHandle = CreateFile( deviceInterfaceInfo->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ); if (_controllerHandle == INVALID_HANDLE_VALUE) { Log(L"Error opening HID Device: Error No: %d", GetLastError()); goto HID_SETUP_FAILURE; } else { //get preparsed data if (HidD_GetPreparsedData(_controllerHandle, &_pPreparsedData) == FALSE) { goto HID_SETUP_FAILURE; } //get device capabilities _pCaps = (PHIDP_CAPS)(malloc(sizeof(HIDP_CAPS))); //malloc check CHECK_NULL(_pCaps, HID_SETUP_FAILURE); _succ = HidP_GetCaps(_pPreparsedData, _pCaps); CHECK_HID(_succ, HID_SETUP_FAILURE); //get button capabilities _pButtonCaps = (PHIDP_BUTTON_CAPS)malloc(sizeof(HIDP_BUTTON_CAPS)* _pCaps->NumberInputButtonCaps); //malloc check CHECK_NULL(_pButtonCaps, HID_SETUP_FAILURE); USHORT numInputButtonCaps = _pCaps->NumberInputButtonCaps; _succ = HidP_GetButtonCaps(HidP_Input, _pButtonCaps, &numInputButtonCaps, _pPreparsedData); CHECK_HID(_succ, HID_SETUP_FAILURE); //prep the button usage data structs _pButtonUsages = (PUSAGE)malloc(sizeof(USAGE)*(_pButtonCaps->Range.DataIndexMax - _pButtonCaps->Range.DataIndexMin + 1)); //malloc check CHECK_NULL(_pButtonUsages, HID_SETUP_FAILURE); ULONG numButtonUsages = _pButtonCaps->Range.UsageMax - _pButtonCaps->Range.UsageMin + 1; //get max data length _pInputReport = (PCHAR)malloc(_pCaps->InputReportByteLength); //malloc check CHECK_NULL(_pInputReport, HID_SETUP_FAILURE); DWORD readbytecount = 0; //get value caps _pValueCaps = (PHIDP_VALUE_CAPS)malloc(sizeof(HIDP_VALUE_CAPS)* _pCaps->NumberInputValueCaps); //malloc check CHECK_NULL(_pValueCaps, HID_SETUP_FAILURE); USHORT numInputValueCaps = _pCaps->NumberInputValueCaps; _succ = HidP_GetValueCaps(HidP_Input, _pValueCaps, &numInputValueCaps, _pPreparsedData); CHECK_HID(_succ, HID_SETUP_FAILURE); goto SETUP_DONE; HID_SETUP_FAILURE: clearHidStructures(); return false; } } deviceindex++; deviceInterfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); } goto SETUP_DONE; SETUP_ERROR: int err = GetLastError(); return false; SETUP_DONE: if (deviceset != INVALID_HANDLE_VALUE && deviceset != nullptr) { SetupDiDestroyDeviceInfoList(deviceset); } if (hidguid != nullptr) { free(hidguid); } if (deviceInterfaceData != nullptr) { free(deviceInterfaceData); } if (deviceInterfaceInfo != nullptr) { free(deviceInterfaceInfo); } return true; }
static void ParseRawInputHID(PRAWINPUT pRawInput) { PHIDP_PREPARSED_DATA pPreparsedData = NULL; HIDP_CAPS Caps; PHIDP_BUTTON_CAPS pButtonCaps = NULL; PHIDP_VALUE_CAPS pValueCaps = NULL; UINT bufferSize; ULONG usageLength, value; TCHAR name[1024] = {0}; UINT nameSize = 1024; RID_DEVICE_INFO devInfo = {0}; std::wstring devName; USHORT capsLength = 0; USAGE usage[MAX_BUTTONS] = {0}; Mappings *mapping = NULL; MapVector::iterator it; GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, name, &nameSize); devName = name; std::transform(devName.begin(), devName.end(), devName.begin(), ::toupper); for(it = mapVector.begin(); it != mapVector.end(); it++) { if((*it).hidPath == devName) { mapping = &(*it); break; } } if(mapping == NULL) return; CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 ); CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)malloc(bufferSize) ); CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 ); CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS ); //pSize = sizeof(devInfo); //GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &devInfo, &pSize); //Unset buttons/axes mapped to this device //ResetData(&mapping->data[0]); //ResetData(&mapping->data[1]); memset(&mapping->data[0], 0xFF, sizeof(wheel_data_t)); memset(&mapping->data[1], 0xFF, sizeof(wheel_data_t)); mapping->data[0].buttons = 0; mapping->data[1].buttons = 0; mapping->data[0].hatswitch = 0x8; mapping->data[1].hatswitch = 0x8; //Get pressed buttons CHECK( pButtonCaps = (PHIDP_BUTTON_CAPS)malloc(sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps) ); //If fails, maybe wheel only has axes capsLength = Caps.NumberInputButtonCaps; HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData); int numberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1; usageLength = numberOfButtons; NTSTATUS stat; if((stat = HidP_GetUsages( HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData, (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid)) == HIDP_STATUS_SUCCESS ) { for(uint32_t i = 0; i < usageLength; i++) { uint16_t btn = mapping->btnMap[usage[i] - pButtonCaps->Range.UsageMin]; for(int j=0; j<2; j++) { PS2WheelTypes wt = (PS2WheelTypes)conf.WheelType[j]; if(PLY_IS_MAPPED(j, btn)) { uint32_t wtbtn = (1 << convert_wt_btn(wt, PLY_GET_VALUE(j, btn))) & 0xFFF; //12bit mask mapping->data[j].buttons |= wtbtn; } } } } /// Get axes' values CHECK( pValueCaps = (PHIDP_VALUE_CAPS)malloc(sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) ); capsLength = Caps.NumberInputValueCaps; if(HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS ) { for(USHORT i = 0; i < capsLength; i++) { if(HidP_GetUsageValue( HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData, (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid ) != HIDP_STATUS_SUCCESS ) { continue; // if here then maybe something is up with HIDP_CAPS.NumberInputValueCaps } //fprintf(stderr, "Min/max %d/%d\t", pValueCaps[i].LogicalMin, pValueCaps[i].LogicalMax); //TODO can be simpler? //Get mapped axis for physical axis uint16_t v = 0; switch(pValueCaps[i].Range.UsageMin) { // X-axis 0x30 case HID_USAGE_GENERIC_X: v = mapping->axisMap[0]; break; // Y-axis case HID_USAGE_GENERIC_Y: v = mapping->axisMap[1]; break; // Z-axis case HID_USAGE_GENERIC_Z: v = mapping->axisMap[2]; break; // Rotate-X case HID_USAGE_GENERIC_RX: v = mapping->axisMap[3]; break; // Rotate-Y case HID_USAGE_GENERIC_RY: v = mapping->axisMap[4]; break; // Rotate-Z 0x35 case HID_USAGE_GENERIC_RZ: v = mapping->axisMap[5]; break; case HID_USAGE_GENERIC_HATSWITCH: //fprintf(stderr, "Hat: %02X\n", value); v = mapping->axisMap[6]; break; } int type = 0; for(int j=0; j<2; j++) { if(!PLY_IS_MAPPED(j, v)) continue; type = conf.WheelType[j]; switch(PLY_GET_VALUE(j, v)) { case PAD_AXIS_X: // X-axis //fprintf(stderr, "X: %d\n", value); // Need for logical min too? //generic_data.axis_x = ((value - pValueCaps[i].LogicalMin) * 0x3FF) / (pValueCaps[i].LogicalMax - pValueCaps[i].LogicalMin); if(type == WT_DRIVING_FORCE_PRO) mapping->data[j].steering = (value * 0x3FFF) / pValueCaps[i].LogicalMax; else //XXX Limit value range to 0..1023 if using 'generic' wheel descriptor mapping->data[j].steering = (value * 0x3FF) / pValueCaps[i].LogicalMax; break; case PAD_AXIS_Y: // Y-axis if(!(devInfo.hid.dwVendorId == 0x046D && devInfo.hid.dwProductId == 0xCA03)) //XXX Limit value range to 0..255 mapping->data[j].clutch = (value * 0xFF) / pValueCaps[i].LogicalMax; break; case PAD_AXIS_Z: // Z-axis //fprintf(stderr, "Z: %d\n", value); //XXX Limit value range to 0..255 mapping->data[j].throttle = (value * 0xFF) / pValueCaps[i].LogicalMax; break; case PAD_AXIS_RZ: // Rotate-Z //fprintf(stderr, "Rz: %d\n", value); //XXX Limit value range to 0..255 mapping->data[j].brake = (value * 0xFF) / pValueCaps[i].LogicalMax; break; case PAD_AXIS_HAT: // TODO Hat Switch //fprintf(stderr, "Hat: %02X\n", value); //TODO 4 vs 8 direction hat switch if(pValueCaps[i].LogicalMax == 4 && value < 4) mapping->data[j].hatswitch = HATS_8TO4[value]; else mapping->data[j].hatswitch = value; break; } } } } Error: SAFE_FREE(pPreparsedData); SAFE_FREE(pButtonCaps); SAFE_FREE(pValueCaps); }
static void ParseRawInputHID(PRAWINPUT pRawInput, HIDState *hs) { PHIDP_PREPARSED_DATA pPreparsedData = NULL; HIDP_CAPS Caps; PHIDP_BUTTON_CAPS pButtonCaps = NULL; PHIDP_VALUE_CAPS pValueCaps = NULL; UINT bufferSize = 0; ULONG usageLength, value; TCHAR name[1024] = {0}; UINT nameSize = 1024; RID_DEVICE_INFO devInfo = {0}; std::wstring devName; USHORT capsLength = 0; USAGE usage[32] = {0}; int numberOfButtons; GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, name, &nameSize); devName = name; std::transform(devName.begin(), devName.end(), devName.begin(), ::toupper); CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 ); CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)malloc(bufferSize) ); CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 ); CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS ); //Get pressed buttons CHECK( pButtonCaps = (PHIDP_BUTTON_CAPS)malloc(sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps) ); //If fails, maybe wheel only has axes capsLength = Caps.NumberInputButtonCaps; HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData); numberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1; usageLength = countof(usage);//numberOfButtons; NTSTATUS stat; if((stat = HidP_GetUsages( HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData, (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid)) == HIDP_STATUS_SUCCESS ) { for(uint32_t i = 0; i < usageLength; i++) { uint16_t btn = usage[i] - pButtonCaps->Range.UsageMin; } } /// Get axes' values CHECK( pValueCaps = (PHIDP_VALUE_CAPS)malloc(sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) ); capsLength = Caps.NumberInputValueCaps; if(HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS ) { for(USHORT i = 0; i < capsLength; i++) { if(HidP_GetUsageValue( HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData, (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid ) != HIDP_STATUS_SUCCESS ) { continue; // if here then maybe something is up with HIDP_CAPS.NumberInputValueCaps } switch(pValueCaps[i].Range.UsageMin) { case HID_USAGE_GENERIC_X: //0x30 case HID_USAGE_GENERIC_Y: case HID_USAGE_GENERIC_Z: case HID_USAGE_GENERIC_RX: case HID_USAGE_GENERIC_RY: case HID_USAGE_GENERIC_RZ: //0x35 //int axis = (value * 0x3FFF) / pValueCaps[i].LogicalMax; break; case HID_USAGE_GENERIC_HATSWITCH: //fprintf(stderr, "Hat: %02X\n", value); break; } } } Error: SAFE_FREE(pPreparsedData); SAFE_FREE(pButtonCaps); SAFE_FREE(pValueCaps); }
NTSTATUS Hid::GetValueCaps(REPORT_TYPE ReportType, VALUE_CAPS *ValueCaps, USHORT *ValueCapsLength, void *PreparsedData) { return HidP_GetValueCaps(ReportType, ValueCaps, ValueCapsLength, PreparsedData); }
static void ParseRawInput(PRAWINPUT pRawInput) { //IwDebugTraceLinePrintf("%s(%d): Parsing raw input\n", __FUNCTION__, __LINE__); PHIDP_PREPARSED_DATA pPreparsedData; HIDP_CAPS Caps; PHIDP_BUTTON_CAPS pButtonCaps; PHIDP_VALUE_CAPS pValueCaps; USHORT capsLength; UINT bufferSize; HANDLE hHeap; USAGE usage[MAX_BUTTONS]; ULONG i, usageLength, value; pPreparsedData = NULL; pButtonCaps = NULL; pValueCaps = NULL; hHeap = GetProcessHeap(); // // Get the preparsed data block // CHECK( GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, NULL, &bufferSize) == 0 ); CHECK( pPreparsedData = (PHIDP_PREPARSED_DATA)HeapAlloc(hHeap, 0, bufferSize) ); CHECK( (int)GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_PREPARSEDDATA, pPreparsedData, &bufferSize) >= 0 ); // // Get the joystick's capabilities // // Button caps CHECK( HidP_GetCaps(pPreparsedData, &Caps) == HIDP_STATUS_SUCCESS ) CHECK( pButtonCaps = (PHIDP_BUTTON_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_BUTTON_CAPS) * Caps.NumberInputButtonCaps) ); capsLength = Caps.NumberInputButtonCaps; CHECK( HidP_GetButtonCaps(HidP_Input, pButtonCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS ) g_NumberOfButtons = pButtonCaps->Range.UsageMax - pButtonCaps->Range.UsageMin + 1; // Value caps CHECK( pValueCaps = (PHIDP_VALUE_CAPS)HeapAlloc(hHeap, 0, sizeof(HIDP_VALUE_CAPS) * Caps.NumberInputValueCaps) ); capsLength = Caps.NumberInputValueCaps; CHECK( HidP_GetValueCaps(HidP_Input, pValueCaps, &capsLength, pPreparsedData) == HIDP_STATUS_SUCCESS ) // // Get the pressed buttons // usageLength = g_NumberOfButtons; CHECK( HidP_GetUsages( HidP_Input, pButtonCaps->UsagePage, 0, usage, &usageLength, pPreparsedData, (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid ) == HIDP_STATUS_SUCCESS ); ZeroMemory(bButtonStates, sizeof(bButtonStates)); for(i = 0; i < usageLength; i++) bButtonStates[usage[i] - pButtonCaps->Range.UsageMin] = TRUE; // // Get the state of discrete-valued-controls // //#define VALUES_DEBUG #ifdef VALUES_DEBUG char str[512] = ""; #endif for(i = 0; i < Caps.NumberInputValueCaps; i++) { CHECK( HidP_GetUsageValue( HidP_Input, pValueCaps[i].UsagePage, 0, pValueCaps[i].Range.UsageMin, &value, pPreparsedData, (PCHAR)pRawInput->data.hid.bRawData, pRawInput->data.hid.dwSizeHid ) == HIDP_STATUS_SUCCESS ); // NOTE: These values are only correct for the Xbox 360 controller // and for the PS3 Controller (via MotioninJoy '360 Emulation' mode) switch(pValueCaps[i].Range.UsageMin) { case 0x30: // X-axis (L-Stick Horizontal) lAxisX = (LONG)value; break; case 0x31: // Y-axis (L-Stick Vertical) lAxisY = (LONG)value; break; case 0x32: // Z-axis (L-Trigger: 32K-65K, R-Trigger: 0K-32K) lAxisZ = (LONG)value; break; case 0x33: // U-axis (R-Stick Horizontal) lAxisU = (LONG)value; break; case 0x34: // R-axis (R-Stick Vertical) lAxisR = (LONG)value; break; // POV Hat Switch (DPAD: // 1: Up // 2: UP/RIGHT // 3: RIGHT // 4: RIGHT/DOWN // 5: DOWN // 6: DOWN/LEFT // 7: LEFT // 8: LEFT/UP case 0x39: lDPad = (LONG)value; break; } #ifdef VALUES_DEBUG char s[128]; _snprintf(s, 128, "[Usage=0x%2X, Val=%4u] ", pValueCaps[i].Range.UsageMin, value); strcat(str, s); #endif } // // Clean up // Error: SAFE_FREE(pPreparsedData); SAFE_FREE(pButtonCaps); SAFE_FREE(pValueCaps); }