Rémi Bernon : xinput1_3: Use WM_DEVICECHANGE device path to add or remove devices.

Alexandre Julliard julliard at winehq.org
Tue Feb 15 16:07:20 CST 2022


Module: wine
Branch: master
Commit: baf66e12efefa7b0993db5fe8aaefafc31476141
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=baf66e12efefa7b0993db5fe8aaefafc31476141

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Tue Feb 15 09:07:25 2022 +0100

xinput1_3: Use WM_DEVICECHANGE device path to add or remove devices.

Instead of iterating the entire device list every time.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/xinput1_3/main.c | 95 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 58 insertions(+), 37 deletions(-)

diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c
index 2966028491e..0e5bd7283c4 100644
--- a/dlls/xinput1_3/main.c
+++ b/dlls/xinput1_3/main.c
@@ -127,7 +127,7 @@ static HANDLE stop_event;
 static HANDLE done_event;
 static HANDLE update_event;
 
-static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot)
+static BOOL find_opened_device(const WCHAR *device_path, int *free_slot)
 {
     int i;
 
@@ -135,7 +135,7 @@ static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *f
     for (i = XUSER_MAX_COUNT; i > 0; i--)
     {
         if (!controllers[i - 1].device) *free_slot = i - 1;
-        else if (!wcscmp(detail->DevicePath, controllers[i - 1].device_path)) return TRUE;
+        else if (!wcsicmp(device_path, controllers[i - 1].device_path)) return TRUE;
     }
     return FALSE;
 }
@@ -399,7 +399,7 @@ static void controller_disable(struct xinput_controller *controller)
 }
 
 static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSED_DATA preparsed,
-                            HIDP_CAPS *caps, HANDLE device, WCHAR *device_path)
+                            HIDP_CAPS *caps, HANDLE device, const WCHAR *device_path)
 {
     HANDLE event = NULL;
 
@@ -481,19 +481,60 @@ static BOOL device_is_overriden(HANDLE device)
     return disable;
 }
 
-static void update_controller_list(void)
+static BOOL try_add_device(const WCHAR *device_path)
 {
-    char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
-    SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer;
     SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
     PHIDP_PREPARSED_DATA preparsed;
     HIDP_CAPS caps;
     NTSTATUS status;
-    HDEVINFO set;
     HANDLE device;
+    int i;
+
+    if (find_opened_device(device_path, &i)) return TRUE; /* already opened */
+    if (i == XUSER_MAX_COUNT) return FALSE; /* no more slots */
+
+    device = CreateFileW(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                         NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
+    if (device == INVALID_HANDLE_VALUE) return TRUE;
+
+    preparsed = NULL;
+    if (!HidD_GetPreparsedData(device, &preparsed))
+        WARN("ignoring HID device, HidD_GetPreparsedData failed with error %lu\n", GetLastError());
+    else if ((status = HidP_GetCaps(preparsed, &caps)) != HIDP_STATUS_SUCCESS)
+        WARN("ignoring HID device, HidP_GetCaps returned %#lx\n", status);
+    else if (caps.UsagePage != HID_USAGE_PAGE_GENERIC)
+        WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage);
+    else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK &&
+             caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER)
+        WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage);
+    else if (device_is_overriden(device))
+        WARN("ignoring HID device, overriden for dinput\n");
+    else if (!controller_init(&controllers[i], preparsed, &caps, device, device_path))
+        WARN("ignoring HID device, failed to initialize\n");
+    else
+        return TRUE;
+
+    CloseHandle(device);
+    HidD_FreePreparsedData(preparsed);
+    return TRUE;
+}
+
+static void try_remove_device(const WCHAR *device_path)
+{
+    int i;
+
+    if (find_opened_device(device_path, &i))
+        controller_destroy(&controllers[i], TRUE);
+}
+
+static void update_controller_list(void)
+{
+    char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
+    SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer;
+    SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
+    HDEVINFO set;
     DWORD idx;
     GUID guid;
-    int i;
 
     guid = GUID_DEVINTERFACE_WINEXINPUT;
 
@@ -505,34 +546,8 @@ static void update_controller_list(void)
     {
         if (!SetupDiGetDeviceInterfaceDetailW(set, &iface, detail, sizeof(buffer), NULL, NULL))
             continue;
-
-        if (find_opened_device(detail, &i)) continue; /* already opened */
-        if (i == XUSER_MAX_COUNT) break; /* no more slots */
-
-        device = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE,
-                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-                             FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
-        if (device == INVALID_HANDLE_VALUE) continue;
-
-        preparsed = NULL;
-        if (!HidD_GetPreparsedData(device, &preparsed))
-            WARN("ignoring HID device, HidD_GetPreparsedData failed with error %lu\n", GetLastError());
-        else if ((status = HidP_GetCaps(preparsed, &caps)) != HIDP_STATUS_SUCCESS)
-            WARN("ignoring HID device, HidP_GetCaps returned %#lx\n", status);
-        else if (caps.UsagePage != HID_USAGE_PAGE_GENERIC)
-            WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage);
-        else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK &&
-                 caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER)
-            WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage);
-        else if (device_is_overriden(device))
-            WARN("ignoring HID device, overriden for dinput\n");
-        else if (!controller_init(&controllers[i], preparsed, &caps, device, detail->DevicePath))
-            WARN("ignoring HID device, failed to initialize\n");
-        else
-            continue;
-
-        CloseHandle(device);
-        HidD_FreePreparsedData(preparsed);
+        if (!try_add_device(detail->DevicePath))
+            break;
     }
 
     SetupDiDestroyDeviceInfoList(set);
@@ -686,7 +701,13 @@ static void read_controller_state(struct xinput_controller *controller)
 
 static LRESULT CALLBACK xinput_devnotify_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 {
-    if (msg == WM_DEVICECHANGE && wparam == DBT_DEVICEARRIVAL) update_controller_list();
+    if (msg == WM_DEVICECHANGE)
+    {
+        DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)lparam;
+        if (wparam == DBT_DEVICEARRIVAL) try_add_device(iface->dbcc_name);
+        if (wparam == DBT_DEVICEREMOVECOMPLETE) try_remove_device(iface->dbcc_name);
+    }
+
     return DefWindowProcW(hwnd, msg, wparam, lparam);
 }
 




More information about the wine-cvs mailing list