If application sends out-of-range values for FFB effects, they become -1, which is undesireable, when -1 is in the physical range of the field and being sent to the device. This patch fixes it, clamping values to the field range. Clamping was earlier implemented [here](https://gitlab.winehq.org/wine/wine/-/blob/wine-6.19/dlls/dinput/effect_linu...) in 6.19. Windows does this clamping silently, and doesn't fail `SetParameters` call when values is out of range.
Affected application is Assetto Corsa EVO, which with default settings sends out ConstantForce magnitude under/over [documented](https://learn.microsoft.com/en-us/previous-versions/ms835644(v=msdn.10)) [-10000, 10000]. [Link to the discussion with some investigation on Steam](https://steamcommunity.com/app/3058630/discussions/0/756142145462617887/#c75...).
In this submission scaling and clamping were moved to the separate `scale_and_clamp_value` function, which is now called every time from `set_parameter_value`. To avoid regression with sending `-1` for the infinite duration effects, separate function `set_parameter_value_no_scaling` created. Gain values in `hid_joystick_send_device_gain` are also scaled and clamped.
-- v3: dinput: Clamp FFB effect report value to the field range. dinput/tests: Add more tests for force feedback.
From: Makarenko Oleg oleg@makarenk.ooo
Add simple ConstantForce tests. Add Condition effect tests with out-of-bounds saturation values. --- dlls/dinput/joystick_hid.c | 3 + dlls/dinput/tests/force_feedback.c | 492 ++++++++++++++++++++++++++--- 2 files changed, 446 insertions(+), 49 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 367d6356195..63466c2a27c 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -416,6 +416,9 @@ static const WCHAR *object_usage_to_string( DIDEVICEOBJECTINSTANCEW *instance ) case MAKELONG(PID_USAGE_STATE_REPORT, HID_USAGE_PAGE_PID): return L"PID State Report"; case MAKELONG(PID_USAGE_TRIGGER_BUTTON, HID_USAGE_PAGE_PID): return L"Trigger Button";
+ case MAKELONG(PID_USAGE_SET_CONSTANT_FORCE_REPORT, HID_USAGE_PAGE_PID): return L"Set Constant Force Report"; + case MAKELONG(PID_USAGE_SET_RAMP_FORCE_REPORT, HID_USAGE_PAGE_PID): return L"Set Ramp Force Report"; + case MAKELONG(HID_USAGE_SIMULATION_RUDDER, HID_USAGE_PAGE_SIMULATION): return L"Rudder"; case MAKELONG(HID_USAGE_SIMULATION_THROTTLE, HID_USAGE_PAGE_SIMULATION): return L"Throttle"; case MAKELONG(HID_USAGE_SIMULATION_ACCELERATOR, HID_USAGE_PAGE_SIMULATION): return L"Accelerator"; diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 841f627d842..24abdac1e06 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -1610,6 +1610,40 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, }, }; + struct hid_expect expect_create_4[] = + { + /* set condition, saturation 5000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0xa6,0x19,0xd9,0x7f,0x7f,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; + struct hid_expect expect_create_5[] = + { + /* set condition, saturation out-of-bounds (-1) */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 7, + .report_len = 8, + .report_buf = {0x07,0x00,0xa6,0x19,0xd9,0xff,0xff,0x19}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x03,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; struct hid_expect expect_destroy = { .code = IOCTL_HID_WRITE_REPORT, @@ -1636,7 +1670,7 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW .dwFadeLevel = 3000, .dwFadeTime = 4000, }; - static const DICONDITION expect_condition[3] = + static const DICONDITION expect_condition[4] = { { .lOffset = -500, @@ -1656,11 +1690,19 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW }, { .lOffset = -7000, - .lPositiveCoefficient = -8000, - .lNegativeCoefficient = 9000, - .dwPositiveSaturation = 10000, - .dwNegativeSaturation = 11000, - .lDeadBand = -12000, + .lPositiveCoefficient = 2000, + .lNegativeCoefficient = -3000, + .dwPositiveSaturation = 5000, + .dwNegativeSaturation = 5000, + .lDeadBand = 1000, + }, + { + .lOffset = -7000, + .lPositiveCoefficient = 2000, + .lNegativeCoefficient = -3000, + .dwPositiveSaturation = 11000, + .dwNegativeSaturation = -11000, + .lDeadBand = 1000, }, }; const DIEFFECT expect_desc = @@ -1828,8 +1870,292 @@ static void test_condition_effect( IDirectInputDevice8W *device, HANDLE file, DW ok( desc.cbTypeSpecificParams == 0 * sizeof(DICONDITION), "got %lu\n", desc.cbTypeSpecificParams ); ref = IDirectInputEffect_Release( effect ); ok( ref == 0, "Release returned %ld\n", ref ); + + + // Checking saturation coefficients + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[2]; + + set_hid_expect( file, expect_create_4, sizeof(expect_create_4) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = 1 * sizeof(DICONDITION); + desc.lpvTypeSpecificParams = (void *)&expect_condition[3]; + + set_hid_expect( file, expect_create_5, sizeof(expect_create_5) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_Spring, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); }
+static void test_constantforce_effect( IDirectInputDevice8W *device, HANDLE file, DWORD version ) +{ + struct hid_expect expect_create_0[] = + { + /* set constant force, magnitude 5000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 9, + .report_len = 3, + .report_buf = {0x09,0x88,0x13}, + }, + /* set envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x04,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x55,0x00}, + }, + }; + struct hid_expect expect_create_1[] = + { + /* set constantforce, magnitude 10000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 9, + .report_len = 3, + .report_buf = {0x09,0x10,0x27}, + }, + /* update envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x04,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; + + struct hid_expect expect_create_2[] = + { + /* set constantforce, magnitude -10000 */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 9, + .report_len = 3, + .report_buf = {0x09,0xf0,0xd8}, + }, + /* update envelope */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 6, + .report_len = 7, + .report_buf = {0x06,0x19,0x4c,0x02,0x00,0x04,0x00}, + }, + /* update effect */ + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 3, + .report_len = 11, + .report_buf = {0x03,0x01,0x04,0x08,0x01,0x00,version >= 0x700 ? 0x06 : 0x00,0x00,0x01,0x3f,0x00}, + }, + }; + struct hid_expect expect_destroy = + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 2, + .report_len = 4, + .report_buf = {0x02, 0x01, 0x03, 0x00}, + }; + static const DWORD expect_axes[3] = + { + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 2 ) | DIDFT_FFACTUATOR, + DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 1 ) | DIDFT_FFACTUATOR, + }; + static const LONG expect_directions[3] = { + +3000, + 0, + 0, + }; + static const DIENVELOPE expect_envelope = + { + .dwSize = sizeof(DIENVELOPE), + .dwAttackLevel = 1000, + .dwAttackTime = 2000, + .dwFadeLevel = 3000, + .dwFadeTime = 4000, + }; + static const DICONSTANTFORCE input_constant_force[4] = + { + { + .lMagnitude = 5000 + }, + { + .lMagnitude = 10000 + }, + { + .lMagnitude = 16000 + }, + { + .lMagnitude = -16000 + }, + }; + const DIEFFECT expect_desc = + { + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .dwDuration = 1000, + .dwSamplePeriod = 2000, + .dwGain = 3000, + .dwTriggerButton = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( 0 ) | DIDFT_FFEFFECTTRIGGER, + .dwTriggerRepeatInterval = 5000, + .cAxes = 3, + .rgdwAxes = (void *)expect_axes, + .rglDirection = (void *)expect_directions, + .lpEnvelope = (void *)&expect_envelope, + .cbTypeSpecificParams = sizeof(DICONSTANTFORCE), + .lpvTypeSpecificParams = (void *)input_constant_force, + .dwStartDelay = 6000, + }; + struct check_created_effect_params check_params = {0}; + DIENVELOPE envelope = {.dwSize = sizeof(DIENVELOPE)}; + DICONSTANTFORCE constant_force[1] = {{0}}; + IDirectInputEffect *effect; + LONG directions[3] = {0,0,0}; + DWORD axes[3] = {0,0,0}; + DIEFFECT desc = + { + .dwSize = version >= 0x700 ? sizeof(DIEFFECT_DX6) : sizeof(DIEFFECT_DX5), + .dwFlags = DIEFF_SPHERICAL | DIEFF_OBJECTIDS, + .cAxes = 3, + .rgdwAxes = axes, + .rglDirection = directions, + .lpEnvelope = &envelope, + .cbTypeSpecificParams = sizeof(DICONSTANTFORCE), + .lpvTypeSpecificParams = constant_force, + }; + HRESULT hr; + ULONG ref; + GUID guid; + + set_hid_expect( file, expect_create_0, sizeof(expect_create_0) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &expect_desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + check_params.expect_effect = effect; + hr = IDirectInputDevice8_EnumCreatedEffectObjects( device, check_created_effect_objects, &check_params, 0 ); + ok( hr == DI_OK, "EnumCreatedEffectObjects returned %#lx\n", hr ); + ok( check_params.count == 1, "got count %lu, expected 1\n", check_params.count ); + + hr = IDirectInputEffect_GetEffectGuid( effect, &guid ); + ok( hr == DI_OK, "GetEffectGuid returned %#lx\n", hr ); + ok( IsEqualGUID( &guid, &GUID_ConstantForce ), "got guid %s, expected %s\n", debugstr_guid( &guid ), + debugstr_guid( &GUID_ConstantForce ) ); + + hr = IDirectInputEffect_GetParameters( effect, &desc, version >= 0x700 ? DIEP_ALLPARAMS : DIEP_ALLPARAMS_DX5 ); + ok( hr == DI_OK, "GetParameters returned %#lx\n", hr ); + check_member( desc, expect_desc, "%lu", dwDuration ); + check_member( desc, expect_desc, "%lu", dwSamplePeriod ); + check_member( desc, expect_desc, "%lu", dwGain ); + check_member( desc, expect_desc, "%#lx", dwTriggerButton ); + check_member( desc, expect_desc, "%lu", dwTriggerRepeatInterval ); + check_member( desc, expect_desc, "%lu", cAxes ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[0] ); + check_member( desc, expect_desc, "%#lx", rgdwAxes[1] ); + check_member( desc, expect_desc, "%ld", rglDirection[0] ); + check_member( desc, expect_desc, "%ld", rglDirection[1] ); + check_member( desc, expect_desc, "%lu", cbTypeSpecificParams ); + if (version >= 0x700) check_member( desc, expect_desc, "%lu", dwStartDelay ); + else ok( desc.dwStartDelay == 0, "got dwStartDelay %#lx\n", desc.dwStartDelay ); + check_member( envelope, expect_envelope, "%lu", dwAttackLevel ); + check_member( envelope, expect_envelope, "%lu", dwAttackTime ); + check_member( envelope, expect_envelope, "%lu", dwFadeLevel ); + check_member( envelope, expect_envelope, "%lu", dwFadeTime ); + check_member( constant_force[0], input_constant_force[0], "%ld", lMagnitude ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = 2 * sizeof(DICONSTANTFORCE); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DIERR_INVALIDPARAM, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + desc.lpvTypeSpecificParams = (void *)&input_constant_force[1]; + + set_hid_expect( file, expect_create_1, sizeof(expect_create_1) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + desc.lpvTypeSpecificParams = (void *)&input_constant_force[2]; + + set_hid_expect( file, expect_create_1, sizeof(expect_create_1) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); + + + desc = expect_desc; + desc.cAxes = 1; + desc.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + desc.lpvTypeSpecificParams = (void *)&input_constant_force[3]; + + set_hid_expect( file, expect_create_2, sizeof(expect_create_2) ); + hr = IDirectInputDevice8_CreateEffect( device, &GUID_ConstantForce, &desc, &effect, NULL ); + ok( hr == DI_OK, "CreateEffect returned %#lx\n", hr ); + set_hid_expect( file, NULL, 0 ); + + set_hid_expect( file, &expect_destroy, sizeof(expect_destroy) ); + ref = IDirectInputEffect_Release( effect ); + ok( ref == 0, "Release returned %ld\n", ref ); + set_hid_expect( file, NULL, 0 ); +} + + static BOOL test_force_feedback_joystick( DWORD version ) { #include "psh_hid_macros.h" @@ -1976,10 +2302,11 @@ static BOOL test_force_feedback_joystick( DWORD version ) USAGE(1, PID_USAGE_ET_SQUARE), USAGE(1, PID_USAGE_ET_SINE), USAGE(1, PID_USAGE_ET_SPRING), + USAGE(1, PID_USAGE_ET_CONSTANT_FORCE), LOGICAL_MINIMUM(1, 1), - LOGICAL_MAXIMUM(1, 3), + LOGICAL_MAXIMUM(1, 4), PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 3), + PHYSICAL_MAXIMUM(1, 4), REPORT_SIZE(1, 8), REPORT_COUNT(1, 1), OUTPUT(1, Data|Ary|Abs), @@ -2164,6 +2491,21 @@ static BOOL test_force_feedback_joystick( DWORD version ) REPORT_COUNT(1, 1), OUTPUT(1, Data|Var|Abs), END_COLLECTION, + + USAGE(1, PID_USAGE_SET_CONSTANT_FORCE_REPORT), + COLLECTION(1, Logical), + REPORT_ID(1, 9), + + USAGE(1, PID_USAGE_MAGNITUDE), + LOGICAL_MINIMUM(2, 0xd8f0), + LOGICAL_MAXIMUM(2, 0x2710), + PHYSICAL_MINIMUM(2, 0xd8f0), + PHYSICAL_MAXIMUM(2, 0x2710), + REPORT_SIZE(1, 16), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, }; C_ASSERT(sizeof(report_descriptor) < MAX_HID_DESCRIPTOR_LEN); @@ -2378,7 +2720,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x68 : 0x10, + .dwOfs = version >= 0x800 ? 0x6c : 0x10, .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, .dwFlags = DIDOI_FFEFFECTTRIGGER, .tszName = L"Button 0", @@ -2390,7 +2732,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Button, - .dwOfs = version >= 0x800 ? 0x69 : 0x11, + .dwOfs = version >= 0x800 ? 0x6d : 0x11, .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, .dwFlags = DIDOI_FFEFFECTTRIGGER, .tszName = L"Button 1", @@ -2402,7 +2744,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x70 : 0, + .dwOfs = version >= 0x800 ? 0x74 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(12)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"DC Device Reset", @@ -2414,7 +2756,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x71 : 0, + .dwOfs = version >= 0x800 ? 0x75 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(13)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"DC Stop All Effects", @@ -2438,7 +2780,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x72 : 0, + .dwOfs = version >= 0x800 ? 0x76 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start", @@ -2450,7 +2792,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x73 : 0, + .dwOfs = version >= 0x800 ? 0x77 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start Solo", @@ -2462,7 +2804,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x74 : 0, + .dwOfs = version >= 0x800 ? 0x78 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(17)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Stop", @@ -2498,7 +2840,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x75 : 0, + .dwOfs = version >= 0x800 ? 0x79 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Square", @@ -2510,7 +2852,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x76 : 0, + .dwOfs = version >= 0x800 ? 0x7a : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Sine", @@ -2522,7 +2864,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x77 : 0, + .dwOfs = version >= 0x800 ? 0x7b : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Spring", @@ -2534,9 +2876,21 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x78 : 0, + .dwOfs = version >= 0x800 ? 0x7c : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, .dwFlags = 0x80008000, + .tszName = L"ET Constant Force", + .wCollectionNumber = 8, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_ET_CONSTANT_FORCE, + .wReportId = 3, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x7d : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, .tszName = L"Z Axis", .wCollectionNumber = 9, .wUsagePage = HID_USAGE_PAGE_GENERIC, @@ -2546,8 +2900,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x79 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x7e : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Y Axis", .wCollectionNumber = 9, @@ -2558,8 +2912,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x7a : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x7f : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"X Axis", .wCollectionNumber = 9, @@ -2570,8 +2924,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x7b : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x80 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Direction Enable", .wCollectionNumber = 7, @@ -2583,7 +2937,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x1c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Start Delay", .wCollectionNumber = 7, @@ -2597,7 +2951,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x20 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Duration", .wCollectionNumber = 7, @@ -2611,7 +2965,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x24 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Trigger Button", .wCollectionNumber = 7, @@ -2623,9 +2977,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x28 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(31)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 30", + .tszName = L"Unknown 31", .wCollectionNumber = 10, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 2, @@ -2636,9 +2990,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x2c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(31)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 31", + .tszName = L"Unknown 32", .wCollectionNumber = 10, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 1, @@ -2649,7 +3003,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x30 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Magnitude", .wCollectionNumber = 11, @@ -2661,7 +3015,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x34 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Fade Level", .wCollectionNumber = 12, @@ -2673,7 +3027,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x38 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Attack Level", .wCollectionNumber = 12, @@ -2685,7 +3039,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x3c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Fade Time", .wCollectionNumber = 12, @@ -2699,7 +3053,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x40 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Attack Time", .wCollectionNumber = 12, @@ -2713,9 +3067,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x44 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(38)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 37", + .tszName = L"Unknown 38", .wCollectionNumber = 14, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 2, @@ -2725,9 +3079,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x48 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(38)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 38", + .tszName = L"Unknown 39", .wCollectionNumber = 14, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 1, @@ -2737,7 +3091,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x4c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"CP Offset", .wCollectionNumber = 13, @@ -2749,7 +3103,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x50 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Negative Coefficient", .wCollectionNumber = 13, @@ -2761,7 +3115,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x54 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Positive Coefficient", .wCollectionNumber = 13, @@ -2773,7 +3127,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x58 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Negative Saturation", .wCollectionNumber = 13, @@ -2785,7 +3139,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x5c : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(44)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Positive Saturation", .wCollectionNumber = 13, @@ -2797,7 +3151,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x60 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(44)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(45)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Dead Band", .wCollectionNumber = 13, @@ -2809,7 +3163,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x64 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(45)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(46)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Device Gain", .wCollectionNumber = 15, @@ -2817,6 +3171,18 @@ static BOOL test_force_feedback_joystick( DWORD version ) .wUsage = PID_USAGE_DEVICE_GAIN, .wReportId = 8, }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x68 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(47)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Magnitude", + .wCollectionNumber = 16, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_MAGNITUDE, + .wReportId = 9, + }, { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, @@ -2951,9 +3317,27 @@ static BOOL test_force_feedback_joystick( DWORD version ) .wUsagePage = HID_USAGE_PAGE_PID, .wUsage = PID_USAGE_DEVICE_GAIN_REPORT, }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(16), + .tszName = L"Collection 16 - Set Constant Force Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_SET_CONSTANT_FORCE_REPORT, + }, }; const DIEFFECTINFOW expect_effects[] = { + { + .dwSize = sizeof(DIEFFECTINFOW), + .guid = GUID_ConstantForce, + .dwEffType = DIEFT_CONSTANTFORCE | DIEFT_STARTDELAY | DIEFT_FFFADE | DIEFT_FFATTACK, + .dwStaticParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .dwDynamicParams = DIEP_AXES | DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_STARTDELAY | + DIEP_DURATION | DIEP_TRIGGERBUTTON | DIEP_ENVELOPE, + .tszName = L"GUID_ConstantForce", + }, { .dwSize = sizeof(DIEFFECTINFOW), .guid = GUID_Square, @@ -3102,7 +3486,16 @@ static BOOL test_force_feedback_joystick( DWORD version ) check_effects_params.expect_count - check_effects_params.index );
effectinfo.dwSize = sizeof(DIEFFECTINFOW); - hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Sine ); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_ConstantForce ); + ok( hr == DI_OK, "GetEffectInfo returned %#lx\n", hr ); + check_member_guid( effectinfo, expect_effects[0], guid ); + check_member( effectinfo, expect_effects[0], "%#lx", dwEffType ); + check_member( effectinfo, expect_effects[0], "%#lx", dwStaticParams ); + check_member( effectinfo, expect_effects[0], "%#lx", dwDynamicParams ); + check_member_wstr( effectinfo, expect_effects[0], tszName ); + + effectinfo.dwSize = sizeof(DIEFFECTINFOW); + hr = IDirectInputDevice8_GetEffectInfo( device, &effectinfo, &GUID_Square ); ok( hr == DI_OK, "GetEffectInfo returned %#lx\n", hr ); check_member_guid( effectinfo, expect_effects[1], guid ); check_member( effectinfo, expect_effects[1], "%#lx", dwEffType ); @@ -3243,6 +3636,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) if (version < 0x800) ok( hr == DI_OK, "SendDeviceData returned %#lx\n", hr ); else todo_wine ok( hr == DIERR_INVALIDPARAM, "SendDeviceData returned %#lx\n", hr );
+ test_constantforce_effect( device, file, version ); test_periodic_effect( device, file, version ); test_condition_effect( device, file, version );
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 );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=151067
Your paranoid android.
=== debian11 (32 bit report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit ar:MA report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit de report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit fr report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit he:IL report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit hi:IN report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit ja:JP report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11 (32 bit zh:CN report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
=== debian11b (64 bit WoW report) ===
dinput: driver_bus.c:53: Test failed: id 1: force_feedback.c:6828 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:6828 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:6867 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000000 03 01 02 04 00 00 00 00 00 00 00 00 ff ff 1a 00 driver_bus.c:62: Test failed: id 1: force_feedback.c:6867 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7032 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7032 expect[4]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7075 expect[3]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000000 03 01 04 04 00 00 00 00 00 00 00 00 ff 7f 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7075 expect[3]: 00000010 00 00 driver_bus.c:53: Test failed: id 1: force_feedback.c:7118 expect[4]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000000 03 01 05 04 00 00 00 00 00 00 00 00 ff ff 4e 01 driver_bus.c:62: Test failed: id 1: force_feedback.c:7118 expect[4]: 00000010 00 00
user32: input.c:4306: Test succeeded inside todo block: button_down_hwnd_todo 1: got MSG_TEST_WIN hwnd 00000000007900E0, msg WM_LBUTTONDOWN, wparam 0x1, lparam 0x320032