소스 검색

device: a couple of fixes with Windows device input

rdb 7 년 전
부모
커밋
2bde2baed2
4개의 변경된 파일71개의 추가작업 그리고 47개의 파일을 삭제
  1. 0 1
      panda/src/device/winInputDeviceManager.cxx
  2. 58 46
      panda/src/device/winRawInputDevice.cxx
  3. 1 0
      panda/src/device/winRawInputDevice.h
  4. 12 0
      panda/src/device/xInputDevice.cxx

+ 0 - 1
panda/src/device/winInputDeviceManager.cxx

@@ -277,7 +277,6 @@ on_input_device_arrival(HANDLE handle) {
   if (info.dwType == RIM_TYPEHID && strstr(path, "&IG_") != nullptr) {
     // This is a device we should handle via the XInput API.  Check which of
     // the four players was the lucky one.
-    WinRawInputDevice idev(this, path);
     if (_xinput_device0.check_arrival(info, inst, name, manufacturer)) {
       add_device(&_xinput_device0);
     }

+ 58 - 46
panda/src/device/winRawInputDevice.cxx

@@ -604,13 +604,16 @@ on_removal() {
   _is_connected = false;
   _handle = nullptr;
   if (_preparsed != nullptr) {
-    delete _preparsed;
+    free(_preparsed);
     _preparsed = nullptr;
   }
   _indices.clear();
   _report_buttons.clear();
 }
 
+/**
+ * Called by InputDeviceManager when raw input is received for this device.
+ */
 void WinRawInputDevice::
 on_input(PRAWINPUT input) {
   nassertv(input != nullptr);
@@ -621,59 +624,68 @@ on_input(PRAWINPUT input) {
     return;
   }
 
-  PHIDP_DATA data = (PHIDP_DATA)alloca(sizeof(HIDP_DATA) * _max_data_count);
-  nassertv(data != nullptr);
-  ULONG count;
-
   LightMutexHolder holder(_lock);
 
   for (DWORD i = 0; i < input->data.hid.dwCount; ++i) {
-    // The first byte is the report identifier.  We need it to figure out
-    // which buttons are off, since each report only contains the buttons that
-    // are "on".
-    UCHAR report_id = ptr[0];
-    BitArray unset_buttons = _report_buttons[report_id];
-
-    count = _max_data_count;
-    NTSTATUS status = _HidP_GetData(HidP_Input, data, &count, (PHIDP_PREPARSED_DATA)_preparsed, (PCHAR)ptr, input->data.hid.dwSizeHid);
-    if (status == HIDP_STATUS_SUCCESS) {
-      for (ULONG di = 0; di < count; ++di) {
-        if (data[di].DataIndex != _hat_data_index) {
-          const Index &idx = _indices[data[di].DataIndex];
-          if (idx._axis >= 0) {
-            if (idx._signed) {
-              axis_changed(idx._axis, (SHORT)data[di].RawValue);
-            } else {
-              axis_changed(idx._axis, data[di].RawValue);
-            }
-          }
-          if (idx._button >= 0) {
-            unset_buttons.clear_bit(idx._button);
-            button_changed(idx._button, (data[di].On != FALSE));
+    process_report((PCHAR)ptr, input->data.hid.dwSizeHid);
+    ptr += input->data.hid.dwSizeHid;
+  }
+}
+
+/**
+ * Processes a single HID report.  Assumes the lock is held.
+ */
+void WinRawInputDevice::
+process_report(PCHAR ptr, size_t size) {
+  // The first byte is the report identifier.  We need it to figure out which
+  // buttons are off, since each report only contains the "on" buttons.
+  UCHAR report_id = ptr[0];
+  BitArray unset_buttons;
+
+  if (report_id < _report_buttons.size()) {
+    unset_buttons = _report_buttons[report_id];
+  }
+
+  PHIDP_DATA data = (PHIDP_DATA)alloca(sizeof(HIDP_DATA) * _max_data_count);
+  nassertv(data != nullptr);
+
+  ULONG count = _max_data_count;
+  NTSTATUS status = _HidP_GetData(HidP_Input, data, &count, (PHIDP_PREPARSED_DATA)_preparsed, ptr, size);
+  if (status == HIDP_STATUS_SUCCESS) {
+    for (ULONG di = 0; di < count; ++di) {
+      if (data[di].DataIndex != _hat_data_index) {
+        const Index &idx = _indices[data[di].DataIndex];
+        if (idx._axis >= 0) {
+          if (idx._signed) {
+            axis_changed(idx._axis, (SHORT)data[di].RawValue);
+          } else {
+            axis_changed(idx._axis, data[di].RawValue);
           }
-        } else {
-          int value = (int)data[di].RawValue - _hat_data_minimum;
-          button_changed(_hat_left_button + 0, value >= 5 && value <= 7); // left
-          button_changed(_hat_left_button + 1, value >= 1 && value <= 3); // right
-          button_changed(_hat_left_button + 2, value >= 3 && value <= 5); // down
-          button_changed(_hat_left_button + 3, value == 7 || value == 0 || value == 1); // up
         }
+        if (idx._button >= 0) {
+          unset_buttons.clear_bit(idx._button);
+          button_changed(idx._button, (data[di].On != FALSE));
+        }
+      } else {
+        int value = (int)data[di].RawValue - _hat_data_minimum;
+        button_changed(_hat_left_button + 0, value >= 5 && value <= 7); // left
+        button_changed(_hat_left_button + 1, value >= 1 && value <= 3); // right
+        button_changed(_hat_left_button + 2, value >= 3 && value <= 5); // down
+        button_changed(_hat_left_button + 3, value == 7 || value == 0 || value == 1); // up
       }
-
-      // Now unset the buttons in this report that aren't pressed.
-      int button_index = unset_buttons.get_lowest_on_bit();
-      while (button_index >= 0) {
-        button_changed(button_index, false);
-        unset_buttons.clear_bit(button_index);
-        button_index = unset_buttons.get_lowest_on_bit();
-      }
-    } else if (device_cat.is_spam()) {
-      device_cat.spam()
-        << "Failed to get data from raw device " << _path
-        << " (error 0x" << std::hex << (status & 0xffffffffu) << std::dec << ")\n";
     }
 
-    ptr += input->data.hid.dwSizeHid;
+    // Now unset the buttons in this report that aren't pressed.
+    int button_index = unset_buttons.get_lowest_on_bit();
+    while (button_index >= 0) {
+      button_changed(button_index, false);
+      unset_buttons.clear_bit(button_index);
+      button_index = unset_buttons.get_lowest_on_bit();
+    }
+  } else if (device_cat.is_spam()) {
+    device_cat.spam()
+      << "Failed to get data from raw device " << _path
+      << " (error 0x" << std::hex << (status & 0xffffffffu) << std::dec << ")\n";
   }
 }
 

+ 1 - 0
panda/src/device/winRawInputDevice.h

@@ -34,6 +34,7 @@ public:
   bool on_arrival(HANDLE handle, const RID_DEVICE_INFO &info, std::string name);
   void on_removal();
   void on_input(PRAWINPUT input);
+  void process_report(PCHAR ptr, size_t size);
 
 private:
   virtual void do_poll();

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

@@ -161,6 +161,10 @@ check_arrival(const RID_DEVICE_INFO &info, DEVINST inst,
     return false;
   }
 
+  if (get_state(_index, &state) != ERROR_SUCCESS) {
+    return false;
+  }
+
   // Extra check for VID/PID if we have it, just to be sure.
   if ((caps.VendorID != 0 && caps.VendorID != info.hid.dwVendorId) ||
       (caps.ProductID != 0 && caps.ProductID != info.hid.dwProductId)) {
@@ -205,6 +209,10 @@ check_arrival(const RID_DEVICE_INFO &info, DEVINST inst,
  */
 void XInputDevice::
 detect(InputDeviceManager *mgr) {
+  if (!_initialized) {
+    nassertv_always(init_xinput());
+  }
+
   bool connected = false;
 
   XINPUT_CAPABILITIES_EX caps = {0};
@@ -225,6 +233,10 @@ detect(InputDeviceManager *mgr) {
   _is_connected = connected;
 
   if (connected) {
+    _name = "XInput Device #";
+    _name += format_string(_index + 1);
+    _vendor_id = caps.VendorID;
+    _product_id = caps.ProductID;
     init_device(caps, state);
     mgr->add_device(this);
   } else {