FFB Autocenter introduced in https://gitlab.winehq.org/wine/wine/-/merge_requests/4911 had one major misunderstanding.
The USB PID standard doesn't actually define any explicit way to autocenter a device. One could of course use the spring effect with a deadzone of 0 and dead band of 0. This is what I'm actually working on for the Linux PID driver (spring + friction/damper).
Some devices implement autocenter in firmware when they receive the DC Disable Actuators command. Very few, if not just one, implement this weird autocenter effect on slot 1. This is, from what I can gather, only implemented on the MS SideWinder joystick(s) and the Windows' USB PID driver is created around these devices.
Windows PID driver is a bit out of spec, is quite permissive when it comes to fields missing in the descriptor (basically, only effect types and their effect type blocks are optional). Another thing it does is handling of this out-of-spec autocentering for their joysticks. Funnliy enough, the creator of the Linux PID driver based the initial code on testing with MS Sidewinder so it's autocentering is supported.
This is where the autocentering mentioned in the MR comes from. It's not the directinput api that does it but the Windows PID driver. As such, autocentering on reset should be left to the drivers, not handeled by Wine.
SDL lacks full reset support and Linux is even more barebones, whre it's not even possible to query the device state, effects etc (something I'm working on slowly). As such, when games send out RESET to prepare the device, the device starts autocentering for no good reason and the effect is not removed once other effect are uploaded and played which would be the case for MS sidewinder.
In any case, even Windows in inconsistent and I think the directinput documentation has some errors. directinput ffb api is largely based on USB PID but:


Testing with my Moza Racing R9 wheelbase, the DC Reset PID command is sent, but there's no DC Disable Actuators in sight. The games still call reset then enable actuators though.
tl;dr Set autocentering to 0 instead of max value when DISFFC_RESET is received to remove the unwanted autocenter behavior.
Signed-off-by: Tomasz Pakuła tomasz.pakula.oficjalny@gmail.com
-- v6: winebus: Do not touch autocenter on device init and device reset
From: Tomasz Pakuła tomasz.pakula.oficjalny@gmail.com
FFB Autocenter introduced in https://gitlab.winehq.org/wine/wine/-/merge_requests/4911 had one major misunderstanding.
The USB PID standard doesn't actually define any explicit way to autocenter a device. One could of course use the spring effect with a deadzone of 0 and dead band of 0. This is what I'm actually working on for the Linux PID driver (spring + friction/damper).
Some devices implement autocenter in firmware when they receive the DC Disable Actuators command. Very few, if not just one, implement this weird autocenter effect on slot 1. This is, from what I can gather, only implemented on the MS SideWinder joystick(s) and the Windows' USB PID driver is created around these devices.
Windows PID driver is a bit out of spec, is quite permissive when it comes to fields missing in the descriptor (basically, only effect types and their effect type blocks are optional). Another thing it does is handling of this out-of-spec autocentering for their joysticks. Funnliy enough, the creator of the Linux PID driver based the initial code on testing with MS Sidewinder so it's autocentering is supported.
This is where the autocentering mentioned in the MR comes from. It's not the directinput api that does it but the Windows PID driver. As such, autocentering on reset should be left to the drivers, not handeled by Wine.
SDL lacks full reset support and Linux is even more barebones, whre it's not even possible to query the device state, effects etc (something I'm working on slowly). As such, when games send out RESET to prepare the device, the device starts autocentering for no good reason and the effect is not removed once other effect are uploaded and played which would be the case for MS sidewinder.
tl;dr Set autocentering to 0 instead of max value when DISFFC_RESET is reveived to remove the unwanted autocenter behavior.
Signed-off-by: Tomasz Pakuła tomasz.pakula.oficjalny@gmail.com --- dlls/winebus.sys/bus_sdl.c | 2 -- dlls/winebus.sys/bus_udev.c | 20 -------------------- 2 files changed, 22 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 2c49f0f408b..dd8a1eb24b9 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -550,7 +550,6 @@ 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); @@ -560,7 +559,6 @@ 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); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 3f9a4fe43b9..587073ce8f1 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -850,24 +850,6 @@ 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); @@ -911,7 +893,6 @@ 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) @@ -921,7 +902,6 @@ 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");
This merge request was approved by Rémi Bernon.