[PATCH 07/11] dinput: Implement support for the PID effect set condition report.

Rémi Bernon rbernon at codeweavers.com
Fri Oct 8 02:50:25 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/joystick_hid.c | 150 +++++++++++++++++++++++++++++++++++++
 dlls/dinput8/tests/hid.c   |   5 --
 2 files changed, 150 insertions(+), 5 deletions(-)

diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 735b3800b31..e2c1a125903 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -124,6 +124,20 @@ struct pid_set_envelope
     struct hid_value_caps *fade_time_caps;
 };
 
+struct pid_set_condition
+{
+    BYTE id;
+    ULONG collection;
+
+    // BYTE offset_bits;
+    struct hid_value_caps *center_point_offset_caps;
+    struct hid_value_caps *positive_coefficient_caps;
+    struct hid_value_caps *negative_coefficient_caps;
+    struct hid_value_caps *positive_saturation_caps;
+    struct hid_value_caps *negative_saturation_caps;
+    struct hid_value_caps *dead_band_caps;
+};
+
 #define DEVICE_STATE_MAX_SIZE 1024
 
 struct hid_joystick
@@ -158,6 +172,7 @@ struct hid_joystick
     struct pid_effect_update pid_effect_update;
     struct pid_set_periodic pid_set_periodic;
     struct pid_set_envelope pid_set_envelope;
+    struct pid_set_condition pid_set_condition;
 };
 
 static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface )
@@ -178,6 +193,7 @@ struct hid_joystick_effect
 
     DWORD axes[6];
     LONG directions[6];
+    DICONDITION condition[2];
     DIENVELOPE envelope;
     DIPERIODIC periodic;
     DIEFFECT params;
@@ -1123,6 +1139,7 @@ static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, D
 {
     struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
     struct pid_effect_update *effect_update = &impl->pid_effect_update;
+    struct pid_set_condition *set_condition = &impl->pid_set_condition;
     struct pid_set_periodic *set_periodic = &impl->pid_set_periodic;
     struct pid_set_envelope *set_envelope = &impl->pid_set_envelope;
     PHIDP_PREPARSED_DATA preparsed = impl->preparsed;
@@ -1219,6 +1236,37 @@ static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, D
         if (set_envelope->fade_time_caps) type |= DIEFT_FFFADE;
     }
 
+    if ((collection = set_condition->collection) && (type == DIEFT_CONDITION))
+    {
+        if (set_condition->center_point_offset_caps)
+            info->dwDynamicParams |= DIEP_TYPESPECIFICPARAMS;
+        if (set_condition->positive_coefficient_caps)
+        {
+            info->dwDynamicParams |= DIEP_TYPESPECIFICPARAMS;
+            type |= DIEFT_POSNEGCOEFFICIENTS;
+        }
+        if (set_condition->negative_coefficient_caps)
+        {
+            info->dwDynamicParams |= DIEP_TYPESPECIFICPARAMS;
+            type |= DIEFT_POSNEGCOEFFICIENTS;
+        }
+        if (set_condition->positive_saturation_caps)
+        {
+            info->dwDynamicParams |= DIEP_TYPESPECIFICPARAMS;
+            type |= DIEFT_SATURATION | DIEFT_POSNEGSATURATION;
+        }
+        if (set_condition->negative_saturation_caps)
+        {
+            info->dwDynamicParams |= DIEP_TYPESPECIFICPARAMS;
+            type |= DIEFT_SATURATION | DIEFT_POSNEGSATURATION;
+        }
+        if (set_condition->dead_band_caps)
+        {
+            info->dwDynamicParams |= DIEP_TYPESPECIFICPARAMS;
+            type |= DIEFT_DEADBAND;
+        }
+    }
+
     info->guid = *guid;
     info->dwEffType = type;
     info->dwStaticParams = info->dwDynamicParams;
@@ -1867,6 +1915,7 @@ static BOOL init_pid_reports( struct hid_joystick *impl, struct hid_value_caps *
     struct pid_control_report *device_control = &impl->pid_device_control;
     struct pid_control_report *effect_control = &impl->pid_effect_control;
     struct pid_effect_update *effect_update = &impl->pid_effect_update;
+    struct pid_set_condition *set_condition = &impl->pid_set_condition;
     struct pid_set_periodic *set_periodic = &impl->pid_set_periodic;
     struct pid_set_envelope *set_envelope = &impl->pid_set_envelope;
 
@@ -1896,6 +1945,7 @@ static BOOL init_pid_reports( struct hid_joystick *impl, struct hid_value_caps *
         case PID_USAGE_SET_EFFECT_REPORT: SET_COLLECTION( effect_update ); break;
         case PID_USAGE_SET_PERIODIC_REPORT: SET_COLLECTION( set_periodic ); break;
         case PID_USAGE_SET_ENVELOPE_REPORT: SET_COLLECTION( set_envelope ); break;
+        case PID_USAGE_SET_CONDITION_REPORT: SET_COLLECTION( set_condition ); break;
 
         case PID_USAGE_DEVICE_CONTROL: SET_SUB_COLLECTION( device_control, control_coll ); break;
         case PID_USAGE_EFFECT_OPERATION: SET_SUB_COLLECTION( effect_control, control_coll ); break;
@@ -1920,6 +1970,7 @@ static BOOL init_pid_caps( struct hid_joystick *impl, struct hid_value_caps *cap
     struct pid_control_report *device_control = &impl->pid_device_control;
     struct pid_control_report *effect_control = &impl->pid_effect_control;
     struct pid_effect_update *effect_update = &impl->pid_effect_update;
+    struct pid_set_condition *set_condition = &impl->pid_set_condition;
     struct pid_set_periodic *set_periodic = &impl->pid_set_periodic;
     struct pid_set_envelope *set_envelope = &impl->pid_set_envelope;
 
@@ -1963,6 +2014,8 @@ static BOOL init_pid_caps( struct hid_joystick *impl, struct hid_value_caps *cap
     if (instance->wCollectionNumber == effect_update->axes_coll)
     {
         SET_REPORT_ID( effect_update );
+        caps->physical_min = 0;
+        caps->physical_max = 36000;
         if (effect_update->axis_count >= 6) FIXME( "more than 6 PID axes detected\n" );
         else effect_update->axis_caps[effect_update->axis_count] = caps;
         effect_update->axis_count++;
@@ -2020,6 +2073,46 @@ static BOOL init_pid_caps( struct hid_joystick *impl, struct hid_value_caps *cap
         if (instance->wUsage == PID_USAGE_FADE_TIME)
             set_envelope->fade_time_caps = caps;
     }
+    if (instance->wCollectionNumber == set_condition->collection)
+    {
+        SET_REPORT_ID( set_condition );
+        if (instance->wUsage == PID_USAGE_CP_OFFSET)
+        {
+            caps->physical_min = -10000;
+            caps->physical_max = 10000;
+            set_condition->center_point_offset_caps = caps;
+        }
+        if (instance->wUsage == PID_USAGE_POSITIVE_COEFFICIENT)
+        {
+            caps->physical_min = -10000;
+            caps->physical_max = 10000;
+            set_condition->positive_coefficient_caps = caps;
+        }
+        if (instance->wUsage == PID_USAGE_NEGATIVE_COEFFICIENT)
+        {
+            caps->physical_min = -10000;
+            caps->physical_max = 10000;
+            set_condition->negative_coefficient_caps = caps;
+        }
+        if (instance->wUsage == PID_USAGE_POSITIVE_SATURATION)
+        {
+            caps->physical_min = 0;
+            caps->physical_max = 10000;
+            set_condition->positive_saturation_caps = caps;
+        }
+        if (instance->wUsage == PID_USAGE_NEGATIVE_SATURATION)
+        {
+            caps->physical_min = 0;
+            caps->physical_max = 10000;
+            set_condition->negative_saturation_caps = caps;
+        }
+        if (instance->wUsage == PID_USAGE_DEAD_BAND)
+        {
+            caps->physical_min = 0;
+            caps->physical_max = 10000;
+            set_condition->dead_band_caps = caps;
+        }
+    }
 
 #undef SET_REPORT_ID
 
@@ -2128,6 +2221,7 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
            impl->pid_effect_update.collection, impl->pid_effect_update.type_coll );
     TRACE( "set periodic id %u, coll %u\n", impl->pid_set_periodic.id, impl->pid_set_periodic.collection );
     TRACE( "set envelope id %u, coll %u\n", impl->pid_set_envelope.id, impl->pid_set_envelope.collection );
+    TRACE( "set condition id %u, coll %u\n", impl->pid_set_condition.id, impl->pid_set_condition.collection );
 
     if (impl->pid_device_control.id)
     {
@@ -2140,6 +2234,14 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID
         if (impl->pid_set_envelope.fade_level_caps ||
             impl->pid_set_envelope.fade_time_caps)
             impl->dev_caps.dwFlags |= DIDC_FFFADE;
+        if (impl->pid_set_condition.positive_coefficient_caps ||
+            impl->pid_set_condition.negative_coefficient_caps)
+            impl->dev_caps.dwFlags |= DIDC_POSNEGCOEFFICIENTS;
+        if (impl->pid_set_condition.positive_saturation_caps ||
+            impl->pid_set_condition.negative_saturation_caps)
+            impl->dev_caps.dwFlags |= DIDC_SATURATION|DIDC_POSNEGSATURATION;
+        if (impl->pid_set_condition.dead_band_caps)
+            impl->dev_caps.dwFlags |= DIDC_DEADBAND;
         impl->dev_caps.dwFFSamplePeriod = 1000000;
         impl->dev_caps.dwFFMinTimeResolution = 1000000;
         impl->dev_caps.dwHardwareRevision = 1;
@@ -2269,6 +2371,13 @@ static HRESULT WINAPI hid_joystick_effect_Initialize( IDirectInputEffect *iface,
     case PID_USAGE_ET_DAMPER:
     case PID_USAGE_ET_INERTIA:
     case PID_USAGE_ET_FRICTION:
+        status = HidP_InitializeReportForID( HidP_Output, joystick->pid_set_condition.id, joystick->preparsed,
+                                             impl->type_specific_buf[0], report_len );
+        if (status != HIDP_STATUS_SUCCESS) return DIERR_DEVICENOTREG;
+        status = HidP_InitializeReportForID( HidP_Output, joystick->pid_set_condition.id, joystick->preparsed,
+                                             impl->type_specific_buf[1], report_len );
+        if (status != HIDP_STATUS_SUCCESS) return DIERR_DEVICENOTREG;
+        break;
     case PID_USAGE_ET_CONSTANT_FORCE:
     case PID_USAGE_ET_RAMP:
     case PID_USAGE_ET_CUSTOM_FORCE_DATA:
@@ -2412,6 +2521,12 @@ static HRESULT WINAPI hid_joystick_effect_GetParameters( IDirectInputEffect *ifa
         case PID_USAGE_ET_DAMPER:
         case PID_USAGE_ET_INERTIA:
         case PID_USAGE_ET_FRICTION:
+            count = impl->params.cbTypeSpecificParams;
+            capacity = params->cbTypeSpecificParams;
+            params->cbTypeSpecificParams = count;
+            if (capacity < count) return DIERR_MOREDATA;
+            memcpy( params->lpvTypeSpecificParams, impl->condition, params->cbTypeSpecificParams );
+            break;
         case PID_USAGE_ET_CONSTANT_FORCE:
         case PID_USAGE_ET_RAMP:
         case PID_USAGE_ET_CUSTOM_FORCE_DATA:
@@ -2554,11 +2669,22 @@ static HRESULT WINAPI hid_joystick_effect_SetParameters( IDirectInputEffect *ifa
             if (memcmp( &impl->periodic, params->lpvTypeSpecificParams, sizeof(DIPERIODIC) ))
                 impl->modified = TRUE;
             memcpy( &impl->periodic, params->lpvTypeSpecificParams, sizeof(DIPERIODIC) );
+            impl->params.cbTypeSpecificParams = sizeof(DIPERIODIC);
             break;
         case PID_USAGE_ET_SPRING:
         case PID_USAGE_ET_DAMPER:
         case PID_USAGE_ET_INERTIA:
         case PID_USAGE_ET_FRICTION:
+            if ((count = impl->params.cAxes))
+            {
+                if (!params->lpvTypeSpecificParams) return E_POINTER;
+                if (params->cbTypeSpecificParams != count * sizeof(DICONDITION) &&
+                    params->cbTypeSpecificParams != sizeof(DICONDITION))
+                    return DIERR_INVALIDPARAM;
+                memcpy( impl->condition, params->lpvTypeSpecificParams, params->cbTypeSpecificParams );
+                impl->params.cbTypeSpecificParams = params->cbTypeSpecificParams;
+            }
+            break;
         case PID_USAGE_ET_CONSTANT_FORCE:
         case PID_USAGE_ET_RAMP:
         case PID_USAGE_ET_CUSTOM_FORCE_DATA:
@@ -2767,6 +2893,7 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface )
     static const DWORD complete_mask = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS;
     struct hid_joystick_effect *impl = impl_from_IDirectInputEffect( iface );
     struct pid_effect_update *effect_update = &impl->joystick->pid_effect_update;
+    struct pid_set_condition *set_condition = &impl->joystick->pid_set_condition;
     struct pid_set_periodic *set_periodic = &impl->joystick->pid_set_periodic;
     struct pid_set_envelope *set_envelope = &impl->joystick->pid_set_envelope;
     ULONG report_len = impl->joystick->caps.OutputReportByteLength;
@@ -2833,6 +2960,29 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface )
             if (WriteFile( device, impl->type_specific_buf[1], report_len, NULL, NULL )) hr = DI_OK;
             else hr = DIERR_INPUTLOST;
             break;
+        case PID_USAGE_ET_SPRING:
+        case PID_USAGE_ET_DAMPER:
+        case PID_USAGE_ET_INERTIA:
+        case PID_USAGE_ET_FRICTION:
+            for (i = 0; i < min( 2, impl->params.cbTypeSpecificParams / sizeof(DICONDITION) ); ++i)
+            {
+                set_parameter_value( impl, impl->type_specific_buf[i], set_condition->center_point_offset_caps,
+                                     impl->condition[i].lOffset );
+                set_parameter_value( impl, impl->type_specific_buf[i], set_condition->positive_coefficient_caps,
+                                     impl->condition[i].lPositiveCoefficient );
+                set_parameter_value( impl, impl->type_specific_buf[i], set_condition->negative_coefficient_caps,
+                                     impl->condition[i].lNegativeCoefficient );
+                set_parameter_value( impl, impl->type_specific_buf[i], set_condition->positive_saturation_caps,
+                                     impl->condition[i].dwPositiveSaturation );
+                set_parameter_value( impl, impl->type_specific_buf[i], set_condition->negative_saturation_caps,
+                                     impl->condition[i].dwNegativeSaturation );
+                set_parameter_value( impl, impl->type_specific_buf[i], set_condition->dead_band_caps,
+                                     impl->condition[i].lDeadBand );
+
+                if (WriteFile( device, impl->type_specific_buf[i], report_len, NULL, NULL )) hr = DI_OK;
+                else hr = DIERR_INPUTLOST;
+            }
+            break;
         }
 
         set_parameter_value_us( impl, impl->effect_update_buf, effect_update->duration_caps,
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index 35f7ccab4e6..cdb19808fcd 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -5778,7 +5778,6 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file )
         /* set condition */
         {
             .code = IOCTL_HID_WRITE_REPORT,
-            .todo = TRUE,
             .report_id = 7,
             .report_len = 8,
             .report_buf = {0x07,0x00,0xf9,0x19,0xd9,0xff,0xff,0x99},
@@ -5786,7 +5785,6 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file )
         /* set condition */
         {
             .code = IOCTL_HID_WRITE_REPORT,
-            .todo = TRUE,
             .report_id = 7,
             .report_len = 8,
             .report_buf = {0x07,0x00,0x4c,0x3f,0xcc,0x4c,0x33,0x19},
@@ -5794,7 +5792,6 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file )
         /* update effect */
         {
             .code = IOCTL_HID_WRITE_REPORT,
-            .todo = TRUE,
             .report_id = 3,
             .report_len = 11,
             .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,0x06,0x00,0x01,0x55,0x00},
@@ -5927,10 +5924,8 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file )
 
     set_hid_expect( file, expect_create, sizeof(expect_create) );
     hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &expect_desc, &effect, NULL );
-    todo_wine
     ok( hr == DI_OK, "CreateEffect returned %#x\n", hr );
     set_hid_expect( file, NULL, 0 );
-    if (hr != DI_OK) return;
 
     check_params.expect_effect = effect;
     hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 );
-- 
2.33.0




More information about the wine-devel mailing list