Signed-off-by: Rémi Bernon rbernon@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 );