Autocenter is a default effect playing on the device following power up or reset. It is disabled by stopping all effects. On at least some devices (all?) it is a spring effect playing in slot 1. Capturing Windows USB packets reveals it dinput acquire does (1) a reset (this enabled autocenter) and, if autocenter is disabled, (2) a stop all effects (this disabled autocenter).
This logic works regardless of whether autocenter is a spring effect playing in slot 1 or not. It does mean autocenter can only be set when the device is not acquired. Testing on Windows reveals setting autocenter properties while acquired returns DIERR_ACQUIRED even if the device is exclusively acquired, so this is consistent.
-- v4: dinput: Update tests for DIPROP_AUTOCENTER dinput: Implement DIPROP_AUTOCENTER
From: Tyson Whitehead twhitehead@gmail.com
Autocenter is a default effect playing on the device following power up or reset. It is disabled by stopping all effects. On at least some devices (all?) it is a spring effect playing in slot 1. Capturing Windows USB packets reveals it dinput acquire does (1) a reset (this enabled autocenter) and, if autocenter is disabled, (2) a stop all effects (this disabled autocenter).
This logic works regardless of whether autocenter is a spring effect playing in slot 1 or not. It does mean autocenter can only be set when the device is not acquired. Testing on Windows reveals setting autocenter properties while acquired returns DIERR_ACQUIRED even if the device is exclusively acquired, so this is consistent. --- dlls/dinput/device.c | 5 ++--- dlls/dinput/joystick_hid.c | 7 ++++++- dlls/winebus.sys/bus_sdl.c | 4 ++++ dlls/winebus.sys/bus_udev.c | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 427d3895700..bb2feb0e8da 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -899,7 +899,7 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con switch (LOWORD( guid )) { case (DWORD_PTR)DIPROP_AUTOCENTER: - if (impl->status == STATUS_ACQUIRED && !is_exclusively_acquired( impl )) return DIERR_ACQUIRED; + if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED; break; case (DWORD_PTR)DIPROP_AXISMODE: case (DWORD_PTR)DIPROP_BUFFERSIZE: @@ -1290,8 +1290,6 @@ static HRESULT dinput_device_set_property( IDirectInputDevice8W *iface, const GU { const DIPROPDWORD *value = (const DIPROPDWORD *)header; if (!(impl->caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED; - - FIXME( "DIPROP_AUTOCENTER stub!\n" ); impl->autocenter = value->dwData; return DI_OK; } @@ -2131,6 +2129,7 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic device->caps.dwSize = sizeof(DIDEVCAPS); device->caps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED; device->device_gain = 10000; + device->autocenter = DIPROPAUTOCENTER_ON; device->force_feedback_state = DIGFFS_STOPPED | DIGFFS_EMPTY; InitializeCriticalSection( &device->crit ); dinput_internal_addref( (device->dinput = dinput) ); diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 3320ac92a1c..367d6356195 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1072,7 +1072,12 @@ static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *i if (status != HIDP_STATUS_SUCCESS) return status;
if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST; - if (!unacquire && command == DISFFC_RESET) hid_joystick_send_device_gain( iface, impl->base.device_gain ); + if (!unacquire && command == DISFFC_RESET) + { + if (impl->base.autocenter == DIPROPAUTOCENTER_OFF) + hid_joystick_send_force_feedback_command( iface, DISFFC_STOPALL, FALSE ); + hid_joystick_send_device_gain( iface, impl->base.device_gain ); + }
return DI_OK; } diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index ed9d3aed4bd..7b43df82f83 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -105,6 +105,7 @@ MAKE_FUNCPTR(SDL_HapticRumbleStop); MAKE_FUNCPTR(SDL_HapticRumbleSupported); MAKE_FUNCPTR(SDL_HapticRunEffect); MAKE_FUNCPTR(SDL_HapticSetGain); +MAKE_FUNCPTR(SDL_HapticSetAutocenter); MAKE_FUNCPTR(SDL_HapticStopAll); MAKE_FUNCPTR(SDL_HapticStopEffect); MAKE_FUNCPTR(SDL_HapticUnpause); @@ -550,6 +551,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US return STATUS_SUCCESS; case PID_USAGE_DC_STOP_ALL_EFFECTS: pSDL_HapticStopAll(impl->sdl_haptic); + pSDL_HapticSetAutocenter(impl->sdl_haptic, 0); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_RESET: pSDL_HapticStopAll(impl->sdl_haptic); @@ -559,6 +561,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US pSDL_HapticDestroyEffect(impl->sdl_haptic, impl->effect_ids[i]); impl->effect_ids[i] = -1; } + pSDL_HapticSetAutocenter(impl->sdl_haptic, 100); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: pSDL_HapticPause(impl->sdl_haptic); @@ -1121,6 +1124,7 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_HapticRumbleSupported); LOAD_FUNCPTR(SDL_HapticRunEffect); LOAD_FUNCPTR(SDL_HapticSetGain); + LOAD_FUNCPTR(SDL_HapticSetAutocenter); LOAD_FUNCPTR(SDL_HapticStopAll); LOAD_FUNCPTR(SDL_HapticStopEffect); LOAD_FUNCPTR(SDL_HapticUnpause); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 34b3305ed88..cc8fe648506 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -952,6 +952,24 @@ static NTSTATUS lnxev_device_physical_effect_run(struct lnxev_device *impl, BYTE return STATUS_SUCCESS; }
+static NTSTATUS lnxev_device_physical_device_set_autocenter(struct unix_device *iface, BYTE percent) +{ + struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); + struct input_event ie = + { + .type = EV_FF, + .code = FF_AUTOCENTER, + .value = 0xffff * percent / 100, + }; + + TRACE("iface %p, percent %#x.\n", iface, percent); + + if (write(impl->base.device_fd, &ie, sizeof(ie)) == -1) + WARN("write failed %d %s\n", errno, strerror(errno)); + + return STATUS_SUCCESS; +} + static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control) { struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); @@ -995,6 +1013,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, if (impl->effect_ids[i] < 0) continue; lnxev_device_physical_effect_run(impl, i, 0); } + lnxev_device_physical_device_set_autocenter(iface, 0); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_RESET: for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) @@ -1004,6 +1023,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, WARN("couldn't free effect, EVIOCRMFF ioctl failed: %d %s\n", errno, strerror(errno)); impl->effect_ids[i] = -1; } + lnxev_device_physical_device_set_autocenter(iface, 100); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: WARN("device pause not supported\n");
From: Tyson Whitehead twhitehead@gmail.com
--- dlls/dinput/tests/force_feedback.c | 159 +++++++++++++++++++---------- 1 file changed, 106 insertions(+), 53 deletions(-)
diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index c20125655f4..8f2a54107ae 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -1912,10 +1912,9 @@ static BOOL test_force_feedback_joystick( DWORD version ) USAGE(1, PID_USAGE_DEVICE_CONTROL), COLLECTION(1, Logical), USAGE(1, PID_USAGE_DC_DEVICE_RESET), + USAGE(1, PID_USAGE_DC_STOP_ALL_EFFECTS), LOGICAL_MINIMUM(1, 1), LOGICAL_MAXIMUM(1, 2), - PHYSICAL_MINIMUM(1, 1), - PHYSICAL_MAXIMUM(1, 2), REPORT_SIZE(1, 8), REPORT_COUNT(1, 1), OUTPUT(1, Data|Ary|Abs), @@ -2194,7 +2193,22 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwHardwareRevision = 1, .dwFFDriverVersion = 1, }; - struct hid_expect expect_acquire[] = + struct hid_expect expect_acquire_autocenter_on[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x01}, + }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 8, + .report_len = 2, + .report_buf = {8, 0x19}, + }, + }; + struct hid_expect expect_acquire_autocenter_off[] = { { .code = IOCTL_HID_WRITE_REPORT, @@ -2202,6 +2216,12 @@ static BOOL test_force_feedback_joystick( DWORD version ) .report_len = 2, .report_buf = {1, 0x01}, }, + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x02}, + }, { .code = IOCTL_HID_WRITE_REPORT, .report_id = 8, @@ -2232,7 +2252,15 @@ static BOOL test_force_feedback_joystick( DWORD version ) .report_len = 2, .report_buf = {8, 0x33}, }; - + struct hid_expect expect_stop_all[] = + { + { + .code = IOCTL_HID_WRITE_REPORT, + .report_id = 1, + .report_len = 2, + .report_buf = {1, 0x02}, + }, + }; const DIDEVICEINSTANCEW expect_devinst = { .dwSize = sizeof(DIDEVICEINSTANCEW), @@ -2384,9 +2412,21 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x10 : 0, + .dwOfs = version >= 0x800 ? 0x71 : 0, .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(13)|DIDFT_OUTPUT, .dwFlags = 0x80008000, + .tszName = L"DC Stop All Effects", + .wCollectionNumber = 4, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DC_STOP_ALL_EFFECTS, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = version >= 0x800 ? 0x10 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(14)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, .tszName = L"Effect Block Index", .wCollectionNumber = 5, .wUsagePage = HID_USAGE_PAGE_PID, @@ -2396,8 +2436,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x71 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(14)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x72 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start", .wCollectionNumber = 6, @@ -2408,8 +2448,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x72 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(15)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x73 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Start Solo", .wCollectionNumber = 6, @@ -2420,8 +2460,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x73 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(16)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x74 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(17)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Op Effect Stop", .wCollectionNumber = 6, @@ -2433,7 +2473,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x14 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(17)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(18)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Loop Count", .wCollectionNumber = 5, @@ -2445,7 +2485,7 @@ static BOOL test_force_feedback_joystick( DWORD version ) .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, .dwOfs = version >= 0x800 ? 0x18 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(18)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(19)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Effect Block Index", .wCollectionNumber = 7, @@ -2456,8 +2496,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x74 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(19)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x75 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Square", .wCollectionNumber = 8, @@ -2468,8 +2508,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x75 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(20)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x76 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Sine", .wCollectionNumber = 8, @@ -2480,8 +2520,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x76 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(21)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x77 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"ET Spring", .wCollectionNumber = 8, @@ -2492,8 +2532,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x77 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(22)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x78 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Z Axis", .wCollectionNumber = 9, @@ -2504,8 +2544,8 @@ static BOOL test_force_feedback_joystick( DWORD version ) { .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), .guidType = GUID_Unknown, - .dwOfs = version >= 0x800 ? 0x78 : 0, - .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(23)|DIDFT_OUTPUT, + .dwOfs = version >= 0x800 ? 0x79 : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(24)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Y Axis", .wCollectionNumber = 9, @@ -2516,8 +2556,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 ? 0x7a : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(25)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"X Axis", .wCollectionNumber = 9, @@ -2528,8 +2568,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 ? 0x7b : 0, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(26)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Direction Enable", .wCollectionNumber = 7, @@ -2541,7 +2581,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(26)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(27)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Start Delay", .wCollectionNumber = 7, @@ -2555,7 +2595,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(27)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(28)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Duration", .wCollectionNumber = 7, @@ -2569,7 +2609,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(28)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(29)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Trigger Button", .wCollectionNumber = 7, @@ -2581,9 +2621,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(29)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(30)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 29", + .tszName = L"Unknown 30", .wCollectionNumber = 10, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 2, @@ -2594,9 +2634,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(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 = 1, @@ -2607,7 +2647,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(31)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(32)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Magnitude", .wCollectionNumber = 11, @@ -2619,7 +2659,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(32)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(33)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Fade Level", .wCollectionNumber = 12, @@ -2631,7 +2671,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(33)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(34)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Attack Level", .wCollectionNumber = 12, @@ -2643,7 +2683,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(34)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(35)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Fade Time", .wCollectionNumber = 12, @@ -2657,7 +2697,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(35)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(36)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Attack Time", .wCollectionNumber = 12, @@ -2671,9 +2711,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(36)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(37)|DIDFT_OUTPUT, .dwFlags = 0x80008000, - .tszName = L"Unknown 36", + .tszName = L"Unknown 37", .wCollectionNumber = 14, .wUsagePage = HID_USAGE_PAGE_ORDINAL, .wUsage = 2, @@ -2683,9 +2723,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(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 = 1, @@ -2695,7 +2735,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(38)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(39)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"CP Offset", .wCollectionNumber = 13, @@ -2707,7 +2747,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(39)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(40)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Negative Coefficient", .wCollectionNumber = 13, @@ -2719,7 +2759,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(40)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(41)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Positive Coefficient", .wCollectionNumber = 13, @@ -2731,7 +2771,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(41)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(42)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Negative Saturation", .wCollectionNumber = 13, @@ -2743,7 +2783,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(42)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(43)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Positive Saturation", .wCollectionNumber = 13, @@ -2755,7 +2795,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(43)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(44)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Dead Band", .wCollectionNumber = 13, @@ -2767,7 +2807,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(44)|DIDFT_OUTPUT, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(45)|DIDFT_OUTPUT, .dwFlags = 0x80008000, .tszName = L"Device Gain", .wCollectionNumber = 15, @@ -3129,11 +3169,23 @@ static BOOL test_force_feedback_joystick( DWORD version ) ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); hr = IDirectInputDevice8_SetCooperativeLevel( device, hwnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE ); ok( hr == DI_OK, "SetCooperativeLevel returned: %#lx\n", hr ); + prop_dword.dwData = DIPROPAUTOCENTER_OFF; + hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); + ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr ); + + set_hid_expect( file, expect_acquire_autocenter_off, sizeof(expect_acquire_autocenter_off) ); + hr = IDirectInputDevice8_Acquire( device ); + ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); + wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ + + set_hid_expect( file, expect_reset, sizeof(expect_reset) ); + hr = IDirectInputDevice8_Unacquire( device ); + ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); prop_dword.dwData = DIPROPAUTOCENTER_ON; hr = IDirectInputDevice8_SetProperty( device, DIPROP_AUTOCENTER, &prop_dword.diph ); ok( hr == DI_OK, "SetProperty DIPROP_AUTOCENTER returned %#lx\n", hr );
- set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + set_hid_expect( file, expect_acquire_autocenter_on, sizeof(expect_acquire_autocenter_on) ); hr = IDirectInputDevice8_Acquire( device ); ok( hr == DI_OK, "Acquire returned: %#lx\n", hr ); wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */ @@ -3166,13 +3218,14 @@ static BOOL test_force_feedback_joystick( DWORD version ) hr = IDirectInputDevice8_SendForceFeedbackCommand( device, 0xdeadbeef ); ok( hr == DIERR_INVALIDPARAM, "SendForceFeedbackCommand returned %#lx\n", hr );
- set_hid_expect( file, expect_acquire, sizeof(expect_acquire) ); + set_hid_expect( file, expect_acquire_autocenter_on, sizeof(expect_acquire_autocenter_on) ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_RESET ); ok( hr == DI_OK, "SendForceFeedbackCommand returned %#lx\n", hr ); wait_hid_expect( file, 100 ); /* device gain reports are written asynchronously */
+ set_hid_expect( file, expect_stop_all, sizeof(expect_stop_all) ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_STOPALL ); - ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); + ok( hr == DI_OK, "SendForceFeedbackCommand returned %#lx\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_PAUSE ); ok( hr == HIDP_STATUS_USAGE_NOT_FOUND, "SendForceFeedbackCommand returned %#lx\n", hr ); hr = IDirectInputDevice8_SendForceFeedbackCommand( device, DISFFC_CONTINUE );
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=141851
Your paranoid android.
=== w8 (32 bit report) ===
dinput: driver_bus.c:1104: Test failed: id 1: force_feedback.c:3176 expect[1]: got id 8 driver_bus.c:53: Test failed: id 1: force_feedback.c:3176 expect[1]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:3176 expect[1]: 00000000 08 19 driver_bus.c:1104: Test failed: id 1: force_feedback.c:3176 expect[2]: got id 1 driver_bus.c:53: Test failed: id 1: force_feedback.c:3176 expect[2]: unexpected data: driver_bus.c:62: Test failed: id 1: force_feedback.c:3176 expect[2]: 00000000 01 02
On Sat Jan 13 18:12:01 2024 +0000, Rémi Bernon wrote:
Only had a quick look so far and it looks okay, so feel free to add these too. Fwiw in general we prefer to add tests first, with todo_wine as needed, and then remove the todo_wine as things are implemented. This better shows the desired behavior which is being implemented.
That makes sense.
I had quite a hard time following the test code. I got it working, but I am still not clear on the `wait_hid_expect` calls. Comments indicate they are required for asynchronous items and they seem to be used in combination with * gain report due to acquire, * gain report due to set property, * gain report due to send reset command, * set parameters * Are these asynchronous due to the code writing writing the request out to the `hid_joystick` device handle (which uses the asynchronous `FILE_FLAG_OVERLAPPED` system)? What is it waiting for, and, even if they are asynchronous, why do you need to wait?
Also, it seems the device handle used for various other routines that there is no `wait_hid_expect` calls after, such as downloading, unacquiring, etc.?
Haven't checked Windows to be sure, but I suspect the `DISFFC_STOPALL` command should probably cycle through any user effects and stop them one-by-one instead of doing the HID `DC Stop All Effects` as that also shuts off any running autocenter and there is no way to get it back besides a `DC Reset`.
On Sun Jan 14 03:17:40 2024 +0000, Tyson Whitehead wrote:
That makes sense. I had quite a hard time following the test code. I got it working, but I am still not clear on the `wait_hid_expect` calls. Comments indicate they are required for asynchronous items and they seem to be used in combination with
- gain report due to acquire,
- gain report due to set property,
- gain report due to send reset command,
- set parameters
Are these asynchronous due to the code writing writing the request out to the `hid_joystick` device handle (which uses the asynchronous `FILE_FLAG_OVERLAPPED` system)? What is it waiting for, and, even if they are asynchronous, why do you need to wait? Also, it seems the device handle used for various other routines that there is no `wait_hid_expect` calls after, such as downloading, unacquiring, etc.?
`wait_hid_expect` is used to synchronize the test with the virtual HID driver, blocking until all the previously set HID reports to expect (with `set_hid_expect`) have been seen or missed, or timeout.
This is most useful in some cases where the HID reports are sent asynchronously, because it's done from another thread, for instance on device acquire or some windows.gaming.input async operations.
Checked Windows XP and 7 and they both kill the autocenter when you do `DISFFC_STOPALL`. That is, they just send do a HID `DC Stop All Effects` command.
So exactly what the current implementation does. Think that is everything for this one then, unless you can think of anything else?
Looks good to me but there's a Win8 specific behavior that I need to figure how to workaround so the tests pass there too. Might take a moment.
I've pushed https://gitlab.winehq.org/rbernon/wine/-/commits/mr/4830 with the needed test changes, would you mind updating your MR with it?
This merge request was closed by Rémi Bernon.
Closing this in favor of !4911