Rémi Bernon : dinput: Implement hid_joystick_SendForceFeedbackCommand.

Alexandre Julliard julliard at winehq.org
Fri Oct 1 18:02:22 CDT 2021


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

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Fri Oct  1 09:31:02 2021 +0200

dinput: Implement hid_joystick_SendForceFeedbackCommand.

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

---

 dlls/dinput/joystick_hid.c | 51 ++++++++++++++++++++++++++++++++++++++--------
 dlls/dinput8/tests/hid.c   | 18 ++++++++--------
 2 files changed, 51 insertions(+), 18 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index b10ce7fc03b..aee8118191f 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -104,6 +104,7 @@ struct hid_joystick
     struct extra_caps *input_extra_caps;
 
     char *input_report_buf;
+    char *output_report_buf;
     USAGE_AND_PAGE *usages_buf;
     ULONG usages_count;
 
@@ -369,6 +370,7 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface )
     if (!(ref = IDirectInputDevice2WImpl_Release( iface )))
     {
         HeapFree( GetProcessHeap(), 0, tmp.usages_buf );
+        HeapFree( GetProcessHeap(), 0, tmp.output_report_buf );
         HeapFree( GetProcessHeap(), 0, tmp.input_report_buf );
         HeapFree( GetProcessHeap(), 0, tmp.input_extra_caps );
         HidD_FreePreparsedData( tmp.preparsed );
@@ -833,20 +835,48 @@ static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *
 
 static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD command )
 {
-    FIXME( "iface %p, command %x stub!\n", iface, command );
+    struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
+    struct pid_control_report *report = &impl->pid_device_control;
+    ULONG report_len = impl->caps.OutputReportByteLength;
+    char *report_buf = impl->output_report_buf;
+    NTSTATUS status;
+    USAGE usage;
+    ULONG count;
+    HRESULT hr;
+
+    TRACE( "iface %p, flags %x.\n", iface, command );
 
     switch (command)
     {
-    case DISFFC_RESET:
-    case DISFFC_STOPALL:
-    case DISFFC_PAUSE:
-    case DISFFC_CONTINUE:
-    case DISFFC_SETACTUATORSON:
-    case DISFFC_SETACTUATORSOFF:
-        return DIERR_UNSUPPORTED;
+    case DISFFC_RESET: usage = PID_USAGE_DC_DEVICE_RESET; break;
+    case DISFFC_STOPALL: usage = PID_USAGE_DC_STOP_ALL_EFFECTS; break;
+    case DISFFC_PAUSE: usage = PID_USAGE_DC_DEVICE_PAUSE; break;
+    case DISFFC_CONTINUE: usage = PID_USAGE_DC_DEVICE_CONTINUE; break;
+    case DISFFC_SETACTUATORSON: usage = PID_USAGE_DC_ENABLE_ACTUATORS; break;
+    case DISFFC_SETACTUATORSOFF: usage = PID_USAGE_DC_DISABLE_ACTUATORS; break;
+    default: return DIERR_INVALIDPARAM;
     }
 
-    return DIERR_INVALIDPARAM;
+    if (!(impl->dev_caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED;
+
+    EnterCriticalSection( &impl->base.crit );
+    if (!impl->base.acquired || !(impl->base.dwCoopLevel & DISCL_EXCLUSIVE))
+        hr = DIERR_NOTEXCLUSIVEACQUIRED;
+    else
+    {
+        count = 1;
+        status = HidP_InitializeReportForID( HidP_Output, report->id, impl->preparsed, report_buf, report_len );
+        if (status != HIDP_STATUS_SUCCESS) hr = status;
+        else status = HidP_SetUsages( HidP_Output, HID_USAGE_PAGE_PID, report->control_coll, &usage,
+                                      &count, impl->preparsed, report_buf, report_len );
+
+        if (status != HIDP_STATUS_SUCCESS) hr = status;
+        else if (WriteFile( impl->device, report_buf, report_len, NULL, NULL )) hr = DI_OK;
+        else hr = DIERR_GENERIC;
+    }
+    LeaveCriticalSection( &impl->base.crit );
+
+    return hr;
 }
 
 static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface,
@@ -1555,6 +1585,9 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
     size = impl->caps.InputReportByteLength;
     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
     impl->input_report_buf = buffer;
+    size = impl->caps.OutputReportByteLength;
+    if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
+    impl->output_report_buf = buffer;
     impl->usages_count = HidP_MaxUsageListLength( HidP_Input, 0, impl->preparsed );
     size = impl->usages_count * sizeof(USAGE_AND_PAGE);
     if (!(usages = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed;
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index 638d8f0aaeb..618fb4e4c7c 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -5253,6 +5253,13 @@ static void test_force_feedback_joystick( void )
         .dwFFDriverVersion = 1,
     };
     struct hid_expect expect_dc_reset =
+    {
+        .code = IOCTL_HID_WRITE_REPORT,
+        .report_id = 1,
+        .report_len = 2,
+        .report_buf = {1, 0x01},
+    };
+    struct hid_expect expect_dc_reset_todo =
     {
         .code = IOCTL_HID_WRITE_REPORT,
         .todo = TRUE,
@@ -5751,7 +5758,6 @@ static void test_force_feedback_joystick( void )
     todo_wine
     ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "IDirectInputDevice8_GetForceFeedbackState returned %#x\n", hr );
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET );
-    todo_wine
     ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
 
     escape.dwSize = sizeof(DIEFFESCAPE);
@@ -5769,7 +5775,7 @@ static void test_force_feedback_joystick( void )
     hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE );
     ok( hr == DI_OK, "IDirectInputDevice8_SetCooperativeLevel returned: %#x\n", hr );
 
-    set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
+    set_hid_expect( file, &expect_dc_reset_todo, sizeof(expect_dc_reset_todo) );
     hr = IDirectInputDevice8_Acquire( device );
     ok( hr == DI_OK, "IDirectInputDevice8_Acquire returned: %#x\n", hr );
     set_hid_expect( file, NULL, 0 );
@@ -5792,24 +5798,18 @@ static void test_force_feedback_joystick( void )
 
     set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET );
-    todo_wine
     ok( hr == DI_OK, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
     set_hid_expect( file, NULL, 0 );
 
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL );
-    todo_wine
     ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE );
-    todo_wine
     ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE );
-    todo_wine
     ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSON );
-    todo_wine
     ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
     hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_SETACTUATORSOFF );
-    todo_wine
     ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "IDirectInputDevice8_SendForceFeedbackCommand returned %#x\n", hr );
 
     objdata.dwOfs = 0x1e;
@@ -5821,7 +5821,7 @@ static void test_force_feedback_joystick( void )
 
     test_periodic_effect( device, file );
 
-    set_hid_expect( file, &expect_dc_reset, sizeof(expect_dc_reset) );
+    set_hid_expect( file, &expect_dc_reset_todo, sizeof(expect_dc_reset_todo) );
     hr = IDirectInputDevice8_Unacquire( device );
     ok( hr == DI_OK, "IDirectInputDevice8_Unacquire returned: %#x\n", hr );
     set_hid_expect( file, NULL, 0 );




More information about the wine-cvs mailing list