Browse Source

device: added checks, robustness, debug output for Windows raw input

rdb 7 years ago
parent
commit
d106fd6a3a

+ 2 - 1
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
   // 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.
   // 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
     // This is a device we should handle via the XInput API.  Check which of
     // the four players was the lucky one.
     // the four players was the lucky one.
     if (_xinput_device0.check_arrival(info, inst, name, manufacturer)) {
     if (_xinput_device0.check_arrival(info, inst, name, manufacturer)) {

+ 41 - 7
panda/src/device/winRawInputDevice.cxx

@@ -334,6 +334,14 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
     return false;
     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?
   // Do we have a button mapping?
   static const ButtonHandle gamepad_buttons_common[] = {
   static const ButtonHandle gamepad_buttons_common[] = {
     ButtonHandle::none(),
     ButtonHandle::none(),
@@ -374,8 +382,11 @@ on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name) {
   _axes.clear();
   _axes.clear();
 
 
   USHORT num_button_caps = caps.NumberInputButtonCaps;
   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) {
   for (USHORT i = 0; i < num_button_caps; ++i) {
     HIDP_BUTTON_CAPS &cap = 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()) {
       if (device_cat.is_debug()) {
         device_cat.debug()
         device_cat.debug()
           << "Found button: DataIndex=" << dec << cap.NotRange.DataIndex
           << "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
           << ", Usage=0x" << cap.NotRange.Usage
           << dec << "\n";
           << dec << "\n";
       }
       }
     }
     }
 
 
+    nassertd(cap.Range.DataIndexMin + upper < _indices.size()) continue;
+
     // Windows will only tell us which buttons in a report are "on", so we
     // 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
     // need to keep track of which buttons exist in which report so that we
     // can figure out which ones are off.
     // 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);
           handle = MouseButton::button(button);
         }
         }
         break;
         break;
+
+      default:
+        continue;
       }
       }
 
 
       int button_index = _buttons.size();
       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;
   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;
   _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()) {
       if (device_cat.is_debug()) {
         device_cat.debug()
         device_cat.debug()
           << "Found value: DataIndex=" << dec << cap.NotRange.DataIndex
           << "Found value: DataIndex=" << dec << cap.NotRange.DataIndex
-          << ", ReportID=" << dec << (int)cap.ReportID
+          << ", ReportID=" << (int)cap.ReportID
           << ", UsagePage=0x" << hex << cap.UsagePage
           << ", UsagePage=0x" << hex << cap.UsagePage
           << ", Usage=0x" << cap.NotRange.Usage
           << ", Usage=0x" << cap.NotRange.Usage
           << dec << ", LogicalMin=" << cap.LogicalMin
           << 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) {
     for (int j = 0; j <= upper; ++j) {
       USAGE usage = j + cap.Range.UsageMin;
       USAGE usage = j + cap.Range.UsageMin;
       USHORT data_index = j + cap.Range.DataIndexMin;
       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);
   _max_data_count = _HidP_MaxDataListLength(HidP_Input, buffer);
 
 
+  nassertr_always(_max_data_count >= 0, false);
+
   _handle = handle;
   _handle = handle;
   _is_connected = true;
   _is_connected = true;
   return true;
   return true;
@@ -619,6 +642,10 @@ on_input(PRAWINPUT input) {
   nassertv(input != nullptr);
   nassertv(input != nullptr);
   nassertv(_preparsed != nullptr);
   nassertv(_preparsed != nullptr);
 
 
+  if (_max_data_count == 0) {
+    return;
+  }
+
   BYTE *ptr = input->data.hid.bRawData;
   BYTE *ptr = input->data.hid.bRawData;
   if (input->data.hid.dwSizeHid == 0) {
   if (input->data.hid.dwSizeHid == 0) {
     return;
     return;
@@ -626,6 +653,12 @@ on_input(PRAWINPUT input) {
 
 
   LightMutexHolder holder(_lock);
   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) {
   for (DWORD i = 0; i < input->data.hid.dwCount; ++i) {
     process_report((PCHAR)ptr, input->data.hid.dwSizeHid);
     process_report((PCHAR)ptr, input->data.hid.dwSizeHid);
     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) {
   if (status == HIDP_STATUS_SUCCESS) {
     for (ULONG di = 0; di < count; ++di) {
     for (ULONG di = 0; di < count; ++di) {
       if (data[di].DataIndex != _hat_data_index) {
       if (data[di].DataIndex != _hat_data_index) {
+        nassertd(data[di].DataIndex < _indices.size()) continue;
         const Index &idx = _indices[data[di].DataIndex];
         const Index &idx = _indices[data[di].DataIndex];
         if (idx._axis >= 0) {
         if (idx._axis >= 0) {
           if (idx._signed) {
           if (idx._signed) {

+ 4 - 0
panda/src/device/xInputDevice.cxx

@@ -249,6 +249,10 @@ detect(InputDeviceManager *mgr) {
  */
  */
 bool XInputDevice::
 bool XInputDevice::
 init_xinput() {
 init_xinput() {
+  if (_initialized) {
+    return true;
+  }
+
   if (device_cat.is_debug()) {
   if (device_cat.is_debug()) {
     device_cat.debug() << "Initializing XInput library.\n";
     device_cat.debug() << "Initializing XInput library.\n";
   }
   }