Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Resending the patches. After investigation it looks like the test timeouts are happening randomly, because installing/uninstalling the test driver takes some random amount of time, and fixing them properly will require some unclear amount of work. For now it seems alright, and tests could be split if they start timing out too much, like here.
What is taking the most time are the UpdateDriverForPlugAndPlayDevicesW calls. That can be improved, by installing the test driver only once, and then only creating / destroying the root device, but as far as I could see, this then causes more spurious failures. Probably the device removal is asynchronous, and adding it back quickly is making things worse.
The proper fix, imho, and what I would like to have ultimately anyway for testing multiple devices or hotplug, would be to introduce a bus test device, installed on test startup, and use it to create and remove HID devices, without having to reinstall their drivers. This will require a substantial amount of redesign of the HID test driver, or be done separately and then the other tests switch to it when it's ready.
dlls/dinput/tests/Makefile.in | 1 + dlls/dinput/tests/hotplug.c | 175 ++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 dlls/dinput/tests/hotplug.c
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index b6648008115..44ea9d340bb 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -13,6 +13,7 @@ SOURCES = \ driver_hid.spec \ force_feedback.c \ hid.c \ + hotplug.c \ joystick.c \ joystick8.c \ keyboard.c \ diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c new file mode 100644 index 00000000000..e42af12e810 --- /dev/null +++ b/dlls/dinput/tests/hotplug.c @@ -0,0 +1,175 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define DIRECTINPUT_VERSION 0x0800 + +#include <stdarg.h> +#include <stddef.h> +#include <limits.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" + +#define COBJMACROS +#include "dinput.h" +#include "dinputd.h" +#include "devguid.h" +#include "mmsystem.h" + +#include "wine/hid.h" + +#include "dinput_test.h" + +static BOOL test_input_lost( DWORD version ) +{ +#include "psh_hid_macros.h" + static const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Physical), + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 6), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 8), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 1, + }; + static const DIPROPDWORD buffer_size = + { + .diph = + { + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwSize = sizeof(DIPROPDWORD), + .dwHow = DIPH_DEVICE, + .dwObj = 0, + }, + .dwData = UINT_MAX, + }; + + DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + DIDEVICEOBJECTDATA objdata[32] = {{0}}; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + IDirectInputDevice8W *device = NULL; + ULONG ref, count, size; + DIJOYSTATE2 state; + HRESULT hr; + + winetest_push_context( "%#x", version ); + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 )) goto done; + if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done; + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "SetDataFormat returned %#x\n", hr ); + hr = IDirectInputDevice8_SetCooperativeLevel( device, 0, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND ); + ok( hr == DI_OK, "SetCooperativeLevel returned %#x\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_BUFFERSIZE, &buffer_size.diph ); + ok( hr == DI_OK, "SetProperty returned %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + ok( hr == DI_OK, "GetDeviceState returned %#x\n", hr ); + size = version < 0x0800 ? sizeof(DIDEVICEOBJECTDATA_DX3) : sizeof(DIDEVICEOBJECTDATA); + count = 1; + hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); + ok( hr == DI_OK, "GetDeviceData returned %#x\n", hr ); + ok( count == 0, "got %u expected %u\n", count, 0 ); + + pnp_driver_stop(); + + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + todo_wine + ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + todo_wine + ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); + todo_wine + ok( hr == DIERR_INPUTLOST, "GetDeviceData returned %#x\n", hr ); + hr = IDirectInputDevice8_Poll( device ); + todo_wine + ok( hr == DIERR_INPUTLOST, "Poll returned: %#x\n", hr ); + + hr = IDirectInputDevice8_Acquire( device ); + todo_wine + ok( hr == DIERR_UNPLUGGED, "Acquire returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); + ok( hr == DIERR_NOTACQUIRED, "GetDeviceData returned %#x\n", hr ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_NOEFFECT, "Unacquire returned: %#x\n", hr ); + + dinput_driver_start( report_desc, sizeof(report_desc), &hid_caps, NULL, 0 ); + + hr = IDirectInputDevice8_Acquire( device ); + todo_wine + ok( hr == DIERR_UNPLUGGED, "Acquire returned %#x\n", hr ); + hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + todo_wine + ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#x\n", hr ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "Release returned %d\n", ref ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); + + winetest_pop_context(); + return device != NULL; +} + +START_TEST( hotplug ) +{ + if (!dinput_test_init()) return; + + CoInitialize( NULL ); + if (test_input_lost( 0x500 )) + { + test_input_lost( 0x700 ); + test_input_lost( 0x800 ); + } + CoUninitialize(); + + dinput_test_exit(); +}
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/device.c | 19 +++++++++++-------- dlls/dinput/joystick_hid.c | 17 +++++++++++------ 2 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index a4c85351648..5f8227acd0c 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -82,6 +82,11 @@ static inline const char *debugstr_diobjectdataformat( const DIOBJECTDATAFORMAT debugstr_guid( data->pguid ), data->dwOfs, data->dwType, data->dwFlags ); }
+static inline BOOL is_exclusively_acquired( struct dinput_device *device ) +{ + return device->acquired && (device->dwCoopLevel & DISCL_EXCLUSIVE); +} + /****************************************************************************** * Various debugging tools */ @@ -1073,7 +1078,7 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con
case (DWORD_PTR)DIPROP_FFLOAD: if (!(impl->caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED; - if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) return DIERR_NOTEXCLUSIVEACQUIRED; + if (!is_exclusively_acquired( impl )) return DIERR_NOTEXCLUSIVEACQUIRED; /* fallthrough */ case (DWORD_PTR)DIPROP_PRODUCTNAME: case (DWORD_PTR)DIPROP_INSTANCENAME: @@ -1399,7 +1404,7 @@ static HRESULT WINAPI dinput_device_set_property( IDirectInputDevice8W *iface, c const DIPROPDWORD *value = (const DIPROPDWORD *)header; if (!impl->vtbl->send_device_gain) return DIERR_UNSUPPORTED; impl->device_gain = value->dwData; - if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) return DI_OK; + if (!is_exclusively_acquired( impl )) return DI_OK; return impl->vtbl->send_device_gain( iface, impl->device_gain ); } case (DWORD_PTR)DIPROP_AXISMODE: @@ -1679,7 +1684,7 @@ static HRESULT WINAPI dinput_device_CreateEffect( IDirectInputDevice8W *iface, c if (!params) return DI_OK;
flags = params->dwSize == sizeof(DIEFFECT_DX6) ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5; - if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) flags |= DIEP_NODOWNLOAD; + if (!is_exclusively_acquired( impl )) flags |= DIEP_NODOWNLOAD; hr = IDirectInputEffect_SetParameters( *out, params, flags ); if (FAILED(hr)) goto failed; return DI_OK; @@ -1788,10 +1793,8 @@ static HRESULT WINAPI dinput_device_GetForceFeedbackState( IDirectInputDevice8W if (!(impl->caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED;
EnterCriticalSection( &impl->crit ); - if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) - hr = DIERR_NOTEXCLUSIVEACQUIRED; - else - *out = impl->force_feedback_state; + if (!is_exclusively_acquired( impl )) hr = DIERR_NOTEXCLUSIVEACQUIRED; + else *out = impl->force_feedback_state; LeaveCriticalSection( &impl->crit );
return hr; @@ -1819,7 +1822,7 @@ static HRESULT WINAPI dinput_device_SendForceFeedbackCommand( IDirectInputDevice if (!impl->vtbl->send_force_feedback_command) return DIERR_UNSUPPORTED;
EnterCriticalSection( &impl->crit ); - if (!impl->acquired || !(impl->dwCoopLevel & DISCL_EXCLUSIVE)) hr = DIERR_NOTEXCLUSIVEACQUIRED; + if (!is_exclusively_acquired( impl )) hr = DIERR_NOTEXCLUSIVEACQUIRED; else hr = impl->vtbl->send_force_feedback_command( iface, command, FALSE ); LeaveCriticalSection( &impl->crit );
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index ccf205e275b..7a365137271 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -241,6 +241,11 @@ static inline struct hid_joystick_effect *impl_from_IDirectInputEffect( IDirectI return CONTAINING_RECORD( iface, struct hid_joystick_effect, IDirectInputEffect_iface ); }
+static inline BOOL is_exclusively_acquired( struct hid_joystick *joystick ) +{ + return joystick->base.acquired && (joystick->base.dwCoopLevel & DISCL_EXCLUSIVE); +} + static const GUID *object_usage_to_guid( USAGE usage_page, USAGE usage ) { switch (usage_page) @@ -827,7 +832,7 @@ static HRESULT hid_joystick_get_property( IDirectInputDevice8W *iface, DWORD pro { DIPROPDWORD *value = (DIPROPDWORD *)header; if (!(impl->base.caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED; - if (!impl->base.acquired || !(impl->base.dwCoopLevel & DISCL_EXCLUSIVE)) return DIERR_NOTEXCLUSIVEACQUIRED; + if (!is_exclusively_acquired( impl )) return DIERR_NOTEXCLUSIVEACQUIRED; value->dwData = 0; return DI_OK; } @@ -898,7 +903,7 @@ static HRESULT hid_joystick_unacquire( IDirectInputDevice8W *iface ) else WaitForSingleObject( impl->base.read_event, INFINITE );
if (!(impl->base.caps.dwFlags & DIDC_FORCEFEEDBACK)) return DI_OK; - if (!impl->base.acquired || !(impl->base.dwCoopLevel & DISCL_EXCLUSIVE)) return DI_OK; + if (!is_exclusively_acquired( impl )) return DI_OK; hid_joystick_send_force_feedback_command( iface, DISFFC_RESET, TRUE ); return DI_OK; } @@ -2682,7 +2687,7 @@ static HRESULT WINAPI hid_joystick_effect_Start( IDirectInputEffect *iface, DWOR else control = PID_USAGE_OP_EFFECT_START;
EnterCriticalSection( &impl->joystick->base.crit ); - if (!impl->joystick->base.acquired || !(impl->joystick->base.dwCoopLevel & DISCL_EXCLUSIVE)) + if (!is_exclusively_acquired( impl->joystick )) hr = DIERR_NOTEXCLUSIVEACQUIRED; else if ((flags & DIES_NODOWNLOAD) && !impl->index) hr = DIERR_NOTDOWNLOADED; @@ -2730,7 +2735,7 @@ static HRESULT WINAPI hid_joystick_effect_Stop( IDirectInputEffect *iface ) TRACE( "iface %p.\n", iface );
EnterCriticalSection( &impl->joystick->base.crit ); - if (!impl->joystick->base.acquired || !(impl->joystick->base.dwCoopLevel & DISCL_EXCLUSIVE)) + if (!is_exclusively_acquired( impl->joystick )) hr = DIERR_NOTEXCLUSIVEACQUIRED; else if (!impl->index) hr = DIERR_NOTDOWNLOADED; @@ -2775,7 +2780,7 @@ static HRESULT WINAPI hid_joystick_effect_GetEffectStatus( IDirectInputEffect *i *status = 0;
EnterCriticalSection( &impl->joystick->base.crit ); - if (!impl->joystick->base.acquired || !(impl->joystick->base.dwCoopLevel & DISCL_EXCLUSIVE)) + if (!is_exclusively_acquired( impl->joystick )) hr = DIERR_NOTEXCLUSIVEACQUIRED; else if (!impl->index) hr = DIERR_NOTDOWNLOADED; @@ -2850,7 +2855,7 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) if (impl->modified) hr = DI_OK; else hr = DI_NOEFFECT;
- if (!impl->joystick->base.acquired || !(impl->joystick->base.dwCoopLevel & DISCL_EXCLUSIVE)) + if (!is_exclusively_acquired( impl->joystick )) hr = DIERR_NOTEXCLUSIVEACQUIRED; else if ((impl->flags & complete_mask) != complete_mask) hr = DIERR_INCOMPLETEEFFECT;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/device.c | 26 +++++++++++++------------- dlls/dinput/device_private.h | 8 +++++++- dlls/dinput/dinput_main.c | 4 ++-- dlls/dinput/joystick_hid.c | 2 +- 4 files changed, 23 insertions(+), 17 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 5f8227acd0c..47cf4d72dc3 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -84,7 +84,7 @@ static inline const char *debugstr_diobjectdataformat( const DIOBJECTDATAFORMAT
static inline BOOL is_exclusively_acquired( struct dinput_device *device ) { - return device->acquired && (device->dwCoopLevel & DISCL_EXCLUSIVE); + return device->status == STATUS_ACQUIRED && (device->dwCoopLevel & DISCL_EXCLUSIVE); }
/****************************************************************************** @@ -582,7 +582,7 @@ static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) TRACE( "iface %p.\n", iface );
EnterCriticalSection( &impl->crit ); - if (impl->acquired) + if (impl->status == STATUS_ACQUIRED) hr = DI_NOEFFECT; else if (!impl->user_format) hr = DIERR_INVALIDPARAM; @@ -590,8 +590,8 @@ static HRESULT WINAPI dinput_device_Acquire( IDirectInputDevice8W *iface ) hr = DIERR_OTHERAPPHASPRIO; else { - impl->acquired = TRUE; - if (FAILED(hr = impl->vtbl->acquire( iface ))) impl->acquired = FALSE; + impl->status = STATUS_ACQUIRED; + if (FAILED(hr = impl->vtbl->acquire( iface ))) impl->status = STATUS_UNACQUIRED; } LeaveCriticalSection( &impl->crit ); if (hr != DI_OK) return hr; @@ -614,9 +614,9 @@ static HRESULT WINAPI dinput_device_Unacquire( IDirectInputDevice8W *iface ) TRACE( "iface %p.\n", iface );
EnterCriticalSection( &impl->crit ); - if (!impl->acquired) hr = DI_NOEFFECT; + if (impl->status != STATUS_ACQUIRED) hr = DI_NOEFFECT; else hr = impl->vtbl->unacquire( iface ); - impl->acquired = FALSE; + impl->status = STATUS_UNACQUIRED; LeaveCriticalSection( &impl->crit ); if (hr != DI_OK) return hr;
@@ -647,7 +647,7 @@ static HRESULT WINAPI dinput_device_SetDataFormat( IDirectInputDevice8W *iface,
if (format->dwSize != sizeof(DIDATAFORMAT)) return DIERR_INVALIDPARAM; if (format->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) return DIERR_INVALIDPARAM; - if (This->acquired) return DIERR_ACQUIRED; + if (This->status == STATUS_ACQUIRED) return DIERR_ACQUIRED;
EnterCriticalSection(&This->crit);
@@ -696,7 +696,7 @@ static HRESULT WINAPI dinput_device_SetCooperativeLevel( IDirectInputDevice8W *i
/* Store the window which asks for the mouse */ EnterCriticalSection(&This->crit); - if (This->acquired) hr = DIERR_ACQUIRED; + if (This->status == STATUS_ACQUIRED) hr = DIERR_ACQUIRED; else { This->win = hwnd; @@ -1014,7 +1014,7 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con case (DWORD_PTR)DIPROP_BUFFERSIZE: case (DWORD_PTR)DIPROP_PHYSICALRANGE: case (DWORD_PTR)DIPROP_LOGICALRANGE: - if (impl->acquired) return DIERR_ACQUIRED; + if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED; break; case (DWORD_PTR)DIPROP_FFLOAD: case (DWORD_PTR)DIPROP_GRANULARITY: @@ -1553,7 +1553,7 @@ static HRESULT WINAPI dinput_device_GetDeviceState( IDirectInputDevice8W *iface, IDirectInputDevice2_Poll( iface );
EnterCriticalSection( &impl->crit ); - if (!impl->acquired) + if (impl->status != STATUS_ACQUIRED) hr = DIERR_NOTACQUIRED; else if (!(user_format = impl->user_format)) hr = DIERR_INVALIDPARAM; @@ -1605,7 +1605,7 @@ static HRESULT WINAPI dinput_device_GetDeviceData( IDirectInputDevice8W *iface, if (This->dinput->dwVersion == 0x0800 || size == sizeof(DIDEVICEOBJECTDATA_DX3)) { if (!This->queue_len) return DIERR_NOTBUFFERED; - if (!This->acquired) return DIERR_NOTACQUIRED; + if (This->status != STATUS_ACQUIRED) return DIERR_NOTACQUIRED; }
if (!This->queue_len) @@ -1857,7 +1857,7 @@ static HRESULT WINAPI dinput_device_Poll( IDirectInputDevice8W *iface ) HRESULT hr = DI_NOEFFECT;
EnterCriticalSection( &impl->crit ); - if (!impl->acquired) hr = DIERR_NOTACQUIRED; + if (impl->status != STATUS_ACQUIRED) hr = DIERR_NOTACQUIRED; LeaveCriticalSection( &impl->crit ); if (FAILED(hr)) return hr;
@@ -2012,7 +2012,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D break; }
- if (impl->acquired) return DIERR_ACQUIRED; + if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED;
data_format.dwSize = sizeof(data_format); data_format.dwObjSize = sizeof(DIOBJECTDATAFORMAT); diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index 00a80b16590..7865c3a15a9 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -69,6 +69,12 @@ struct object_properties DWORD calibration_mode; };
+enum device_status +{ + STATUS_UNACQUIRED, + STATUS_ACQUIRED, +}; + /* Device implementation */ struct dinput_device { @@ -84,7 +90,7 @@ struct dinput_device DIDEVCAPS caps; DWORD dwCoopLevel; HWND win; - int acquired; + enum device_status status;
BOOL use_raw_input; /* use raw input instead of low-level messages */ RAWINPUTDEVICE raw_device; /* raw device to (un)register */ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 8347e3aa586..664311b7a31 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -128,10 +128,10 @@ static void dinput_device_internal_unacquire( IDirectInputDevice8W *iface ) TRACE( "iface %p.\n", iface );
EnterCriticalSection( &impl->crit ); - if (impl->acquired) + if (impl->status == STATUS_ACQUIRED) { impl->vtbl->unacquire( iface ); - impl->acquired = FALSE; + impl->status = STATUS_UNACQUIRED; list_remove( &impl->entry ); } LeaveCriticalSection( &impl->crit ); diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 7a365137271..4caaf01affe 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -243,7 +243,7 @@ static inline struct hid_joystick_effect *impl_from_IDirectInputEffect( IDirectI
static inline BOOL is_exclusively_acquired( struct hid_joystick *joystick ) { - return joystick->base.acquired && (joystick->base.dwCoopLevel & DISCL_EXCLUSIVE); + return joystick->base.status == STATUS_ACQUIRED && (joystick->base.dwCoopLevel & DISCL_EXCLUSIVE); }
static const GUID *object_usage_to_guid( USAGE usage_page, USAGE usage )
This fixes hotplug with DS4 and other DInput-compatible controllers in Tekken 7.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/device.c | 8 ++++++-- dlls/dinput/device_private.h | 1 + dlls/dinput/dinput_main.c | 8 +++++--- dlls/dinput/joystick_hid.c | 4 ++-- dlls/dinput/tests/hotplug.c | 5 ----- 5 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 47cf4d72dc3..ff8e2252a40 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -1553,7 +1553,9 @@ static HRESULT WINAPI dinput_device_GetDeviceState( IDirectInputDevice8W *iface, IDirectInputDevice2_Poll( iface );
EnterCriticalSection( &impl->crit ); - if (impl->status != STATUS_ACQUIRED) + if (impl->status == STATUS_UNPLUGGED) + hr = DIERR_INPUTLOST; + else if (impl->status != STATUS_ACQUIRED) hr = DIERR_NOTACQUIRED; else if (!(user_format = impl->user_format)) hr = DIERR_INVALIDPARAM; @@ -1605,6 +1607,7 @@ static HRESULT WINAPI dinput_device_GetDeviceData( IDirectInputDevice8W *iface, if (This->dinput->dwVersion == 0x0800 || size == sizeof(DIDEVICEOBJECTDATA_DX3)) { if (!This->queue_len) return DIERR_NOTBUFFERED; + if (This->status == STATUS_UNPLUGGED) return DIERR_INPUTLOST; if (This->status != STATUS_ACQUIRED) return DIERR_NOTACQUIRED; }
@@ -1857,7 +1860,8 @@ static HRESULT WINAPI dinput_device_Poll( IDirectInputDevice8W *iface ) HRESULT hr = DI_NOEFFECT;
EnterCriticalSection( &impl->crit ); - if (impl->status != STATUS_ACQUIRED) hr = DIERR_NOTACQUIRED; + if (impl->status == STATUS_UNPLUGGED) hr = DIERR_INPUTLOST; + else if (impl->status != STATUS_ACQUIRED) hr = DIERR_NOTACQUIRED; LeaveCriticalSection( &impl->crit ); if (FAILED(hr)) return hr;
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index 7865c3a15a9..15a8a6f83b5 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -73,6 +73,7 @@ enum device_status { STATUS_UNACQUIRED, STATUS_ACQUIRED, + STATUS_UNPLUGGED, };
/* Device implementation */ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 664311b7a31..dbb727c3c43 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -1261,7 +1261,6 @@ static DWORD WINAPI dinput_thread_proc( void *params ) struct dinput_device *impl, *next; SIZE_T events_count = 0; HANDLE finished_event; - HRESULT hr; DWORD ret; MSG msg;
@@ -1282,8 +1281,11 @@ static DWORD WINAPI dinput_thread_proc( void *params ) { if (impl->read_event == events[ret]) { - hr = impl->vtbl->read( &impl->IDirectInputDevice8W_iface ); - if (FAILED( hr )) dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); + if (FAILED( impl->vtbl->read( &impl->IDirectInputDevice8W_iface ) )) + { + dinput_device_internal_unacquire( &impl->IDirectInputDevice8W_iface ); + impl->status = STATUS_UNPLUGGED; + } break; } } diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 4caaf01affe..597a3da4ef8 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -872,7 +872,7 @@ static HRESULT hid_joystick_acquire( IDirectInputDevice8W *iface ) { impl->device = CreateFileW( impl->device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, 0 ); - if (impl->device == INVALID_HANDLE_VALUE) return DIERR_INVALIDPARAM; + if (impl->device == INVALID_HANDLE_VALUE) return DIERR_UNPLUGGED; }
memset( &impl->read_ovl, 0, sizeof(impl->read_ovl) ); @@ -882,7 +882,7 @@ static HRESULT hid_joystick_acquire( IDirectInputDevice8W *iface ) { CloseHandle( impl->device ); impl->device = INVALID_HANDLE_VALUE; - return DIERR_INVALIDPARAM; + return DIERR_UNPLUGGED; }
IDirectInputDevice8_SendForceFeedbackCommand( iface, DISFFC_RESET ); diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index e42af12e810..afe51cf0e97 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -116,20 +116,15 @@ static BOOL test_input_lost( DWORD version ) pnp_driver_stop();
hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); - todo_wine ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#x\n", hr ); hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); - todo_wine ok( hr == DIERR_INPUTLOST, "GetDeviceState returned %#x\n", hr ); hr = IDirectInputDevice8_GetDeviceData( device, size, objdata, &count, DIGDD_PEEK ); - todo_wine ok( hr == DIERR_INPUTLOST, "GetDeviceData returned %#x\n", hr ); hr = IDirectInputDevice8_Poll( device ); - todo_wine ok( hr == DIERR_INPUTLOST, "Poll returned: %#x\n", hr );
hr = IDirectInputDevice8_Acquire( device ); - todo_wine ok( hr == DIERR_UNPLUGGED, "Acquire returned %#x\n", hr ); hr = IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); ok( hr == DIERR_NOTACQUIRED, "GetDeviceState returned %#x\n", hr );