[PATCH 3/3] dinput: Return DIERR_INPUTLOST when device is removed.

Rémi Bernon rbernon at codeweavers.com
Thu Jan 13 04:32:33 CST 2022


This fixes hotplug with DS4 and other DInput-compatible controllers in
Tekken 7.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/device.c          | 33 ++++++++++++++++++++-------------
 dlls/dinput/device_private.h  |  9 ++++++++-
 dlls/dinput/dinput_main.c     |  4 ++--
 dlls/dinput/joystick_hid.c    |  6 +++---
 dlls/dinput/tests/joystick8.c |  5 -----
 5 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 5f8227acd0c..d3e84edb642 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,9 @@ 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 +615,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 +648,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 +697,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 +1015,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 +1554,9 @@ static HRESULT WINAPI dinput_device_GetDeviceState( IDirectInputDevice8W *iface,
     IDirectInputDevice2_Poll( iface );
 
     EnterCriticalSection( &impl->crit );
-    if (!impl->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,7 +1608,8 @@ 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_UNPLUGGED) return DIERR_INPUTLOST;
+        if (This->status != STATUS_ACQUIRED) return DIERR_NOTACQUIRED;
     }
 
     if (!This->queue_len)
@@ -1857,7 +1861,10 @@ 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_UNPLUGGED)
+        hr = DIERR_INPUTLOST;
+    else if (impl->status != STATUS_ACQUIRED)
+        hr = DIERR_NOTACQUIRED;
     LeaveCriticalSection( &impl->crit );
     if (FAILED(hr)) return hr;
 
@@ -2012,7 +2019,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..15a8a6f83b5 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -69,6 +69,13 @@ struct object_properties
     DWORD calibration_mode;
 };
 
+enum device_status
+{
+    STATUS_UNACQUIRED,
+    STATUS_ACQUIRED,
+    STATUS_UNPLUGGED,
+};
+
 /* Device implementation */
 struct dinput_device
 {
@@ -84,7 +91,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..a5bb57c64f3 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -128,12 +128,12 @@ 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;
         list_remove( &impl->entry );
     }
+    impl->status = STATUS_UNPLUGGED;
     LeaveCriticalSection( &impl->crit );
 }
 
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 16fcc06b6e8..29cf3afcdd4 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 )
@@ -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/joystick8.c b/dlls/dinput/tests/joystick8.c
index 7590835fe55..e7ea5345118 100644
--- a/dlls/dinput/tests/joystick8.c
+++ b/dlls/dinput/tests/joystick8.c
@@ -2821,20 +2821,15 @@ static void 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 );
-- 
2.34.1




More information about the wine-devel mailing list