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.
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 | 4 +--- dlls/dinput/joystick_hid.c | 3 +++ dlls/winebus.sys/bus_sdl.c | 4 ++++ dlls/winebus.sys/bus_udev.c | 20 ++++++++++++++++++++ 4 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 427d3895700..908cd322439 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; } diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 3320ac92a1c..d53fb7dc3d0 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -882,6 +882,9 @@ static HRESULT hid_joystick_acquire( IDirectInputDevice8W *iface ) }
IDirectInputDevice8_SendForceFeedbackCommand( iface, DISFFC_RESET ); + if (!impl->base.autocenter) + IDirectInputDevice8_SendForceFeedbackCommand( iface, DISFFC_STOPALL ); + 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..5ad0df7da20 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(impl, 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(impl, 100); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: WARN("device pause not supported\n");
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=141785
Your paranoid android.
=== debian11 (32 bit report) ===
dinput: driver_bus.c:295: Test failed: id 1: force_feedback.c:4153 got spurious packet driver_bus.c:1103: Test failed: id 1: force_feedback.c:4153 expect[2]: got 0xb000f, expected 0 driver_bus.c:1104: Test failed: id 1: force_feedback.c:4153 expect[2]: got id 1 driver_bus.c:1105: Test failed: id 1: force_feedback.c:4153 expect[2]: got len 2 driver_bus.c:295: Test failed: id 1: force_feedback.c:4218 got spurious packet driver_bus.c:1103: Test failed: id 1: force_feedback.c:4218 expect[2]: got 0xb000f, expected 0 driver_bus.c:1104: Test failed: id 1: force_feedback.c:4218 expect[2]: got id 1 driver_bus.c:1105: Test failed: id 1: force_feedback.c:4218 expect[2]: got len 2 driver_bus.c:295: Test failed: id 1: force_feedback.c:6110 got spurious packet driver_bus.c:1103: Test failed: id 1: force_feedback.c:6110 expect[5]: got 0xb000f, expected 0 driver_bus.c:1104: Test failed: id 1: force_feedback.c:6110 expect[5]: got id 1 driver_bus.c:1105: Test failed: id 1: force_feedback.c:6110 expect[5]: got len 2
=== debian11b (64 bit WoW report) ===
dinput: driver_bus.c:295: Test failed: id 1: force_feedback.c:4153 got spurious packet driver_bus.c:1103: Test failed: id 1: force_feedback.c:4153 expect[2]: got 0xb000f, expected 0 driver_bus.c:1104: Test failed: id 1: force_feedback.c:4153 expect[2]: got id 1 driver_bus.c:1105: Test failed: id 1: force_feedback.c:4153 expect[2]: got len 2 driver_bus.c:295: Test failed: id 1: force_feedback.c:4218 got spurious packet driver_bus.c:1103: Test failed: id 1: force_feedback.c:4218 expect[2]: got 0xb000f, expected 0 driver_bus.c:1104: Test failed: id 1: force_feedback.c:4218 expect[2]: got id 1 driver_bus.c:1105: Test failed: id 1: force_feedback.c:4218 expect[2]: got len 2 driver_bus.c:295: Test failed: id 1: force_feedback.c:6110 got spurious packet driver_bus.c:1103: Test failed: id 1: force_feedback.c:6110 expect[5]: got 0xb000f, expected 0 driver_bus.c:1104: Test failed: id 1: force_feedback.c:6110 expect[5]: got id 1 driver_bus.c:1105: Test failed: id 1: force_feedback.c:6110 expect[5]: got len 2