[PATCH 4/4] dinput: Support creating effects using device managed reports.

Rémi Bernon rbernon at codeweavers.com
Fri Nov 19 05:37:20 CST 2021


From: Ivo Ivanov <logos128 at gmail.com>
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/joystick_hid.c | 81 +++++++++++++++++++++++++++++++++-----
 dlls/dinput8/tests/hid.c   |  3 --
 2 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index a43a73fff17..12ff10d7865 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -174,6 +174,7 @@ struct hid_joystick
 
     char *input_report_buf;
     char *output_report_buf;
+    char *feature_report_buf;
     USAGE_AND_PAGE *usages_buf;
     ULONG usages_count;
 
@@ -401,15 +402,54 @@ static const WCHAR *object_usage_to_string( DIDEVICEOBJECTINSTANCEW *instance )
     }
 }
 
-static HRESULT find_next_effect_id( struct hid_joystick *impl, ULONG *index )
+static HRESULT find_next_effect_id( struct hid_joystick *impl, DWORD *index, USAGE type )
 {
-    ULONG i;
+    struct pid_device_pool *device_pool = &impl->pid_device_pool;
+    struct pid_new_effect *new_effect = &impl->pid_new_effect;
+    struct pid_block_load *block_load = &impl->pid_block_load;
+    ULONG i, count, report_len = impl->caps.FeatureReportByteLength;
+    NTSTATUS status;
+    USAGE usage;
 
-    for (i = 0; i < ARRAY_SIZE(impl->effect_inuse); ++i)
-        if (!impl->effect_inuse[i]) break;
-    if (i == ARRAY_SIZE(impl->effect_inuse)) return DIERR_DEVICEFULL;
-    impl->effect_inuse[i] = TRUE;
-    *index = i + 1;
+    if (!device_pool->device_managed_caps)
+    {
+        for (i = 0; i < ARRAY_SIZE(impl->effect_inuse); ++i)
+            if (!impl->effect_inuse[i]) break;
+        if (i == ARRAY_SIZE(impl->effect_inuse)) return DIERR_DEVICEFULL;
+        impl->effect_inuse[i] = TRUE;
+        *index = i + 1;
+    }
+    else
+    {
+        status = HidP_InitializeReportForID( HidP_Feature, new_effect->id, impl->preparsed,
+                                             impl->feature_report_buf, report_len );
+        if (status != HIDP_STATUS_SUCCESS) return status;
+
+        count = 1;
+        status = HidP_SetUsages( HidP_Feature, HID_USAGE_PAGE_PID, new_effect->type_coll,
+                                 &type, &count, impl->preparsed, impl->feature_report_buf, report_len );
+        if (status != HIDP_STATUS_SUCCESS) return status;
+
+        if (!HidD_SetFeature( impl->device, impl->feature_report_buf, report_len )) return DIERR_INPUTLOST;
+
+        status = HidP_InitializeReportForID( HidP_Feature, block_load->id, impl->preparsed,
+                                             impl->feature_report_buf, report_len );
+        if (status != HIDP_STATUS_SUCCESS) return status;
+
+        if (!HidD_GetFeature( impl->device, impl->feature_report_buf, report_len )) return DIERR_INPUTLOST;
+
+        count = 1;
+        status = HidP_GetUsages( HidP_Feature, HID_USAGE_PAGE_PID, block_load->status_coll,
+                                 &usage, &count, impl->preparsed, impl->feature_report_buf, report_len );
+        if (status != HIDP_STATUS_SUCCESS) return status;
+
+        if (count != 1 || usage == PID_USAGE_BLOCK_LOAD_ERROR) return DIERR_INPUTLOST;
+        if (usage == PID_USAGE_BLOCK_LOAD_FULL) return DIERR_DEVICEFULL;
+
+        status = HidP_GetUsageValue( HidP_Feature, HID_USAGE_PAGE_PID, 0, PID_USAGE_EFFECT_BLOCK_INDEX,
+                                     index, impl->preparsed, impl->feature_report_buf, report_len );
+        if (status != HIDP_STATUS_SUCCESS) return status;
+    }
 
     return DI_OK;
 }
@@ -732,6 +772,7 @@ static void hid_joystick_release( IDirectInputDevice8W *iface )
     if (!ref)
     {
         free( impl->usages_buf );
+        free( impl->feature_report_buf );
         free( impl->output_report_buf );
         free( impl->input_report_buf );
         HidD_FreePreparsedData( impl->preparsed );
@@ -1893,6 +1934,9 @@ HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID *guid,
     size = impl->caps.OutputReportByteLength;
     if (!(buffer = malloc( size ))) goto failed;
     impl->output_report_buf = buffer;
+    size = impl->caps.FeatureReportByteLength;
+    if (!(buffer = malloc( size ))) goto failed;
+    impl->feature_report_buf = buffer;
     impl->usages_count = HidP_MaxUsageListLength( HidP_Input, 0, impl->preparsed );
     size = impl->usages_count * sizeof(USAGE_AND_PAGE);
     if (!(usages = malloc( size ))) goto failed;
@@ -2703,7 +2747,7 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface )
         hr = DIERR_NOTEXCLUSIVEACQUIRED;
     else if ((impl->flags & complete_mask) != complete_mask)
         hr = DIERR_INCOMPLETEEFFECT;
-    else if (!impl->index && SUCCEEDED(hr = find_next_effect_id( impl->joystick, &impl->index )))
+    else if (!impl->index && SUCCEEDED(hr = find_next_effect_id( impl->joystick, &impl->index, impl->type )))
     {
         if (!impl->type_specific_buf[0]) status = HIDP_STATUS_SUCCESS;
         else status = HidP_SetUsageValue( HidP_Output, HID_USAGE_PAGE_PID, 0, PID_USAGE_EFFECT_BLOCK_INDEX,
@@ -2857,7 +2901,11 @@ static HRESULT WINAPI hid_joystick_effect_Unload( IDirectInputEffect *iface )
 {
     struct hid_joystick_effect *impl = impl_from_IDirectInputEffect( iface );
     struct hid_joystick *joystick = impl->joystick;
+    struct pid_device_pool *device_pool = &joystick->pid_device_pool;
+    struct pid_block_free *block_free = &joystick->pid_block_free;
+    ULONG report_len = joystick->caps.OutputReportByteLength;
     HRESULT hr = DI_OK;
+    NTSTATUS status;
 
     TRACE( "iface %p\n", iface );
 
@@ -2866,7 +2914,22 @@ static HRESULT WINAPI hid_joystick_effect_Unload( IDirectInputEffect *iface )
         hr = DI_NOEFFECT;
     else if (SUCCEEDED(hr = IDirectInputEffect_Stop( iface )))
     {
-        impl->joystick->effect_inuse[impl->index - 1] = FALSE;
+        if (!device_pool->device_managed_caps)
+            joystick->effect_inuse[impl->index - 1] = FALSE;
+        else if (block_free->id)
+        {
+            status = HidP_InitializeReportForID( HidP_Output, block_free->id, joystick->preparsed,
+                                                 joystick->output_report_buf, report_len );
+
+            if (status != HIDP_STATUS_SUCCESS) hr = status;
+            else status = HidP_SetUsageValue( HidP_Output, HID_USAGE_PAGE_PID, 0, PID_USAGE_EFFECT_BLOCK_INDEX,
+                                              impl->index, joystick->preparsed, joystick->output_report_buf, report_len );
+
+            if (status != HIDP_STATUS_SUCCESS) hr = status;
+            else if (WriteFile( joystick->device, joystick->output_report_buf, report_len, NULL, NULL )) hr = DI_OK;
+            else hr = DIERR_INPUTLOST;
+        }
+
         impl->index = 0;
     }
     LeaveCriticalSection( &joystick->base.crit );
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index 564ae7335e8..596d318acd9 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -8403,7 +8403,6 @@ static void test_device_managed_effect(void)
             .report_id = 9,
             .report_len = 2,
             .report_buf = {9,0x03},
-            .todo = TRUE,
         },
         /* block load */
         {
@@ -8411,7 +8410,6 @@ static void test_device_managed_effect(void)
             .report_id = 10,
             .report_len = 3,
             .report_buf = {10,0x01,0x01},
-            .todo = TRUE,
         },
         /* set condition */
         {
@@ -8450,7 +8448,6 @@ static void test_device_managed_effect(void)
             .report_id = 11,
             .report_len = 2,
             .report_buf = {11,0x01},
-            .todo = TRUE,
         },
     };
     static const DWORD expect_axes[3] =
-- 
2.33.1




More information about the wine-devel mailing list