xinput1_3: Register for device notifications to update controller list.

Based on a patch from Andrew Eikum <aeikum@codeweavers.com>.

Dark Souls Remasters checks for xinput devices when it receives a
WM_DEVICECHANGE message. We would only poll for new devices if it had
been at least 2 seconds since the last check. So often, DS would receive
the message, but we would refuse to poll for devices, so the game would
think no controller was present.

This commit fixes that by also subscribing to event notifications and
triggering a poll.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-10-08 13:02:26 +02:00 committed by Alexandre Julliard
parent 65ba91d443
commit ebc70f78fb
6 changed files with 42 additions and 6 deletions

View File

@ -1,5 +1,5 @@
MODULE = xinput1_1.dll
IMPORTS = hid setupapi advapi32
IMPORTS = hid setupapi advapi32 user32
PARENTSRC = ../xinput1_3
C_SRCS = \

View File

@ -1,5 +1,5 @@
MODULE = xinput1_2.dll
IMPORTS = hid setupapi advapi32
IMPORTS = hid setupapi advapi32 user32
PARENTSRC = ../xinput1_3
C_SRCS = \

View File

@ -1,6 +1,6 @@
MODULE = xinput1_3.dll
IMPORTLIB = xinput
IMPORTS = hid setupapi advapi32
IMPORTS = hid setupapi advapi32 user32
C_SRCS = \
main.c

View File

@ -33,6 +33,7 @@
#include "winnls.h"
#include "winternl.h"
#include "dbt.h"
#include "setupapi.h"
#include "devpkey.h"
#include "hidusage.h"
@ -118,6 +119,7 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] =
{{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }},
};
static HMODULE xinput_instance;
static HANDLE start_event;
static HANDLE stop_event;
static HANDLE done_event;
@ -641,17 +643,45 @@ static void read_controller_state(struct xinput_controller *controller)
LeaveCriticalSection(&controller->crit);
}
static LRESULT CALLBACK xinput_devnotify_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
if (msg == WM_DEVICECHANGE && wparam == DBT_DEVICEARRIVAL) update_controller_list();
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
static DWORD WINAPI hid_update_thread_proc(void *param)
{
struct xinput_controller *devices[XUSER_MAX_COUNT + 2];
HANDLE events[XUSER_MAX_COUNT + 2];
DWORD i, count = 2, ret = WAIT_TIMEOUT;
DEV_BROADCAST_DEVICEINTERFACE_W filter =
{
.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W),
.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
.dbcc_classguid = GUID_DEVINTERFACE_WINEXINPUT,
};
WNDCLASSEXW cls =
{
.cbSize = sizeof(WNDCLASSEXW),
.hInstance = xinput_instance,
.lpszClassName = L"__wine_xinput_devnotify",
.lpfnWndProc = xinput_devnotify_wndproc,
};
HDEVNOTIFY notif;
HWND hwnd;
MSG msg;
RegisterClassExW(&cls);
hwnd = CreateWindowExW(0, cls.lpszClassName, NULL, 0, 0, 0, 0, 0,
HWND_MESSAGE, NULL, NULL, NULL);
notif = RegisterDeviceNotificationW(hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
update_controller_list();
SetEvent(start_event);
do
{
if (ret == count) while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
if (ret == WAIT_TIMEOUT) update_controller_list();
if (ret < count - 2) read_controller_state(devices[ret]);
@ -671,7 +701,12 @@ static DWORD WINAPI hid_update_thread_proc(void *param)
events[count++] = update_event;
events[count++] = stop_event;
}
while ((ret = WaitForMultipleObjectsEx( count, events, FALSE, 2000, TRUE )) < count - 1 || ret == WAIT_TIMEOUT);
while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) < count - 1 ||
ret == count || ret == WAIT_TIMEOUT);
UnregisterDeviceNotification(notif);
DestroyWindow(hwnd);
UnregisterClassW(cls.lpszClassName, xinput_instance);
if (ret != count - 1) ERR("update thread exited unexpectedly, ret %u\n", ret);
SetEvent(done_event);
@ -733,6 +768,7 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
switch (reason)
{
case DLL_PROCESS_ATTACH:
xinput_instance = inst;
DisableThreadLibraryCalls(inst);
break;
case DLL_PROCESS_DETACH:

View File

@ -1,5 +1,5 @@
MODULE = xinput1_4.dll
IMPORTS = hid setupapi advapi32
IMPORTS = hid setupapi advapi32 user32
PARENTSRC = ../xinput1_3
C_SRCS = \

View File

@ -1,5 +1,5 @@
MODULE = xinput9_1_0.dll
IMPORTS = hid setupapi advapi32
IMPORTS = hid setupapi advapi32 user32
PARENTSRC = ../xinput1_3
C_SRCS = \