diff --git a/panda/src/device/winInputDeviceManager.cxx b/panda/src/device/winInputDeviceManager.cxx index 033a174f6b..95f73549dd 100644 --- a/panda/src/device/winInputDeviceManager.cxx +++ b/panda/src/device/winInputDeviceManager.cxx @@ -315,7 +315,8 @@ on_input_device_arrival(HANDLE handle) { // Is this an XInput device? If so, handle it via XInput, which allows us // to handle independent left/right triggers as well as vibration output. - if (info.dwType == RIM_TYPEHID && strstr(path, "&IG_") != nullptr) { + if (info.dwType == RIM_TYPEHID && strstr(path, "&IG_") != nullptr && + XInputDevice::init_xinput()) { // This is a device we should handle via the XInput API. Check which of // the four players was the lucky one. if (_xinput_device0.check_arrival(info, inst, name, manufacturer)) { diff --git a/panda/src/device/winRawInputDevice.cxx b/panda/src/device/winRawInputDevice.cxx index eeb98f112d..9c49d83122 100644 --- a/panda/src/device/winRawInputDevice.cxx +++ b/panda/src/device/winRawInputDevice.cxx @@ -334,6 +334,14 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { return false; } + if (device_cat.is_debug()) { + device_cat.debug() + << "Found " << _device_class << " device \"" << _name << "\" with " + << caps.NumberInputDataIndices << " data indices, " + << caps.NumberInputButtonCaps << " button caps, " + << caps.NumberInputValueCaps << " value caps\n"; + } + // Do we have a button mapping? static const ButtonHandle gamepad_buttons_common[] = { ButtonHandle::none(), @@ -374,8 +382,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { _axes.clear(); USHORT num_button_caps = caps.NumberInputButtonCaps; - PHIDP_BUTTON_CAPS button_caps = (PHIDP_BUTTON_CAPS)alloca(num_button_caps * sizeof(HIDP_BUTTON_CAPS)); - _HidP_GetButtonCaps(HidP_Input, button_caps, &num_button_caps, buffer); + PHIDP_BUTTON_CAPS button_caps; + if (num_button_caps > 0u) { + button_caps = (PHIDP_BUTTON_CAPS)alloca(num_button_caps * sizeof(HIDP_BUTTON_CAPS)); + _HidP_GetButtonCaps(HidP_Input, button_caps, &num_button_caps, buffer); + } for (USHORT i = 0; i < num_button_caps; ++i) { HIDP_BUTTON_CAPS &cap = button_caps[i]; @@ -396,13 +407,15 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { if (device_cat.is_debug()) { device_cat.debug() << "Found button: DataIndex=" << dec << cap.NotRange.DataIndex - << ", ReportID=" << dec << (int)cap.ReportID - << ", UsagePage=0x" << cap.UsagePage + << ", ReportID=" << (int)cap.ReportID + << ", UsagePage=0x" << hex << cap.UsagePage << ", Usage=0x" << cap.NotRange.Usage << dec << "\n"; } } + nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue; + // Windows will only tell us which buttons in a report are "on", so we // need to keep track of which buttons exist in which report so that we // can figure out which ones are off. @@ -429,6 +442,9 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { handle = MouseButton::button(button); } break; + + default: + continue; } int button_index = _buttons.size(); @@ -439,8 +455,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { } USHORT num_value_caps = caps.NumberInputValueCaps; - PHIDP_VALUE_CAPS value_caps = (PHIDP_VALUE_CAPS)alloca(num_value_caps * sizeof(HIDP_VALUE_CAPS)); - _HidP_GetValueCaps(HidP_Input, value_caps, &num_value_caps, buffer); + PHIDP_VALUE_CAPS value_caps; + if (num_value_caps > 0u) { + value_caps = (PHIDP_VALUE_CAPS)alloca(num_value_caps * sizeof(HIDP_VALUE_CAPS)); + _HidP_GetValueCaps(HidP_Input, value_caps, &num_value_caps, buffer); + } _hat_data_index = -1; @@ -464,7 +483,7 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { if (device_cat.is_debug()) { device_cat.debug() << "Found value: DataIndex=" << dec << cap.NotRange.DataIndex - << ", ReportID=" << dec << (int)cap.ReportID + << ", ReportID=" << (int)cap.ReportID << ", UsagePage=0x" << hex << cap.UsagePage << ", Usage=0x" << cap.NotRange.Usage << dec << ", LogicalMin=" << cap.LogicalMin @@ -472,6 +491,8 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { } } + nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue; + for (int j = 0; j <= upper; ++j) { USAGE usage = j + cap.Range.UsageMin; USHORT data_index = j + cap.Range.DataIndexMin; @@ -590,6 +611,8 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) { _max_data_count = _HidP_MaxDataListLength(HidP_Input, buffer); + nassertr_always(_max_data_count >= 0, false); + _handle = handle; _is_connected = true; return true; @@ -619,6 +642,10 @@ on_input(PRAWINPUT input) { nassertv(input != nullptr); nassertv(_preparsed != nullptr); + if (_max_data_count == 0) { + return; + } + BYTE *ptr = input->data.hid.bRawData; if (input->data.hid.dwSizeHid == 0) { return; @@ -626,6 +653,12 @@ on_input(PRAWINPUT input) { LightMutexHolder holder(_lock); + if (device_cat.is_spam()) { + device_cat.spam() + << _name << " received " << input->data.hid.dwCount << " reports of size " + << input->data.hid.dwSizeHid << "\n"; + } + for (DWORD i = 0; i < input->data.hid.dwCount; ++i) { process_report((PCHAR)ptr, input->data.hid.dwSizeHid); ptr += input->data.hid.dwSizeHid; @@ -654,6 +687,7 @@ process_report(PCHAR ptr, size_t size) { if (status == HIDP_STATUS_SUCCESS) { for (ULONG di = 0; di < count; ++di) { if (data[di].DataIndex != _hat_data_index) { + nassertd(data[di].DataIndex < _indices.size()) continue; const Index &idx = _indices[data[di].DataIndex]; if (idx._axis >= 0) { if (idx._signed) { diff --git a/panda/src/device/xInputDevice.cxx b/panda/src/device/xInputDevice.cxx index 4621d467b9..9e8035fb0e 100644 --- a/panda/src/device/xInputDevice.cxx +++ b/panda/src/device/xInputDevice.cxx @@ -249,6 +249,10 @@ detect(InputDeviceManager *mgr) { */ bool XInputDevice:: init_xinput() { + if (_initialized) { + return true; + } + if (device_cat.is_debug()) { device_cat.debug() << "Initializing XInput library.\n"; }