From: Makarenko Oleg oleg@makarenk.ooo
--- dlls/dinput/joystick_hid.c | 81 +++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 15 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 63466c2a27c..4b1e71ae7c9 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -752,22 +752,10 @@ static void set_report_value( struct hid_joystick *impl, char *report_buf, { ULONG report_len = impl->caps.OutputReportByteLength; PHIDP_PREPARSED_DATA preparsed = impl->preparsed; - LONG log_min, log_max, phy_min, phy_max; NTSTATUS status;
if (!caps) return;
- log_min = caps->logical_min; - log_max = caps->logical_max; - phy_min = caps->physical_min; - phy_max = caps->physical_max; - - if (phy_max || phy_min) - { - if (value > phy_max || value < phy_min) value = -1; - else value = log_min + (value - phy_min) * (log_max - log_min) / (phy_max - phy_min); - } - status = HidP_SetUsageValue( HidP_Output, caps->usage_page, caps->link_collection, caps->usage_min, value, preparsed, report_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_SetUsageValue %04x:%04x returned %#lx\n", @@ -840,6 +828,10 @@ static HRESULT hid_joystick_get_property( IDirectInputDevice8W *iface, DWORD pro return DIERR_UNSUPPORTED; }
+static LONG clamp_to_physical_value( LONG value, struct hid_value_caps *caps ); +static LONG scale_to_logical_value( LONG value, struct hid_value_caps *caps ); + + static HRESULT hid_joystick_send_device_gain( IDirectInputDevice8W *iface, LONG device_gain ) { struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); @@ -855,6 +847,8 @@ static HRESULT hid_joystick_send_device_gain( IDirectInputDevice8W *iface, LONG status = HidP_InitializeReportForID( HidP_Output, report->id, impl->preparsed, report_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) return status;
+ device_gain = clamp_to_physical_value( device_gain, report->device_gain_caps ); + device_gain = scale_to_logical_value( device_gain, report->device_gain_caps ); set_report_value( impl, report_buf, report->device_gain_caps, device_gain );
if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST; @@ -1144,6 +1138,40 @@ static LONG scale_value( ULONG value, struct object_properties *properties ) return phy_min + MulDiv( tmp - log_min, phy_max - phy_min, log_max - log_min ); }
+static LONG scale_to_logical_value( LONG value, struct hid_value_caps *caps ) +{ + LONG log_min, log_max, phy_min, phy_max; + + if (!caps) return value; + + log_min = caps->logical_min; + log_max = caps->logical_max; + phy_min = caps->physical_min; + phy_max = caps->physical_max; + + if (phy_max || phy_min) + { + if (value > phy_max || value < phy_min) value = -1; + else value = log_min + (value - phy_min) * (log_max - log_min) / (phy_max - phy_min); + } + + return value; +} + +static LONG clamp_to_physical_value( LONG value, struct hid_value_caps *caps ) +{ + LONG phy_min, phy_max; + + if (!caps) return value; + + phy_min = caps->physical_min; + phy_max = caps->physical_max; + + value = max(min(value, phy_max), phy_min); + + return value; +} + static LONG scale_axis_value( ULONG value, struct object_properties *properties ) { LONG tmp = sign_extend( value, properties ), log_ctr, log_min, log_max, phy_ctr, phy_min, phy_max; @@ -2812,6 +2840,21 @@ static HRESULT WINAPI hid_joystick_effect_GetEffectStatus( IDirectInputEffect *i
static void set_parameter_value( struct hid_joystick_effect *impl, char *report_buf, struct hid_value_caps *caps, LONG value ) +{ + value = clamp_to_physical_value( value, caps ); + value = scale_to_logical_value( value, caps ); + return set_report_value( impl->joystick, report_buf, caps, value ); +} + +static void set_parameter_value_no_clamping( struct hid_joystick_effect *impl, char *report_buf, + struct hid_value_caps *caps, LONG value ) +{ + value = scale_to_logical_value( value, caps ); + return set_report_value( impl->joystick, report_buf, caps, value ); +} + +static void set_parameter_value_no_scaling( struct hid_joystick_effect *impl, char *report_buf, + struct hid_value_caps *caps, LONG value ) { return set_report_value( impl->joystick, report_buf, caps, value ); } @@ -2834,7 +2877,12 @@ static void set_parameter_value_us( struct hid_joystick_effect *impl, char *repo LONG exp; if (!caps) return; exp = caps->units_exp; - if (value == INFINITE) value = caps->physical_min - 1; + if (value == INFINITE) + { + value = caps->physical_min - 1; + set_parameter_value_no_scaling( impl, report_buf, caps, value ); + return; + } else if (caps->units != 0x1003) WARN( "unknown time unit caps %#lx\n", caps->units ); else if (exp < -6) while (exp++ < -6) value *= 10; else if (exp > -6) while (exp-- > -6) value /= 10; @@ -2937,9 +2985,12 @@ static HRESULT WINAPI hid_joystick_effect_Download( IDirectInputEffect *iface ) impl->condition[i].lPositiveCoefficient ); set_parameter_value( impl, impl->type_specific_buf, set_condition->negative_coefficient_caps, impl->condition[i].lNegativeCoefficient ); - set_parameter_value( impl, impl->type_specific_buf, set_condition->positive_saturation_caps, + + // Testing shows that Saturation values are not clamped + // Any out-of-range values becomes -1 + set_parameter_value_no_clamping( impl, impl->type_specific_buf, set_condition->positive_saturation_caps, impl->condition[i].dwPositiveSaturation ); - set_parameter_value( impl, impl->type_specific_buf, set_condition->negative_saturation_caps, + set_parameter_value_no_clamping( impl, impl->type_specific_buf, set_condition->negative_saturation_caps, impl->condition[i].dwNegativeSaturation ); set_parameter_value( impl, impl->type_specific_buf, set_condition->dead_band_caps, impl->condition[i].lDeadBand );