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 reveived to remove the unwanted autocenter behavior.
Signed-off-by: Tomasz Pakuła tomasz.pakula.oficjalny@gmail.com
-- v2: winebus: Set FFB autcenter to 0 instead of 100 on 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 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 5cec049a845..318a0b8c6e5 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -560,7 +560,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); + pSDL_HapticSetAutocenter(impl->sdl_haptic, 0); 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 39b810b7588..d660da71644 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -921,7 +921,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); + lnxev_device_physical_device_set_autocenter(iface, 0); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: WARN("device pause not supported\n");
@twhitehead what was the device you were testing this with?
The USB info for my device is
ID 045e:001b Microsoft Corp. SideWinder Force Feedback 2 Joystick
Yeah, that's what I thought. Together with @jacketus, we are maintainers of `hid-universal-pidff` and defacto maintainers of `hid-pidff` drivers. You can contact us and we could figure out the autocenter situation on the sidewinder.
I'm now doing another batch of driver improvememnts and features and I could prod around this while working on effect-based autocenter for all PID devices.
The issue I was working on when I did the initial implementation was making the Sidewinder work for a flight simulator I use (I still have to implement [loading effect for a file API](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee417886...)) to complete this). As there was originally no support for `DIPROP_AUTOCENTER` (it was ignored), the default autocentering never got turned off, and so autocentering was overlaid on top of everything.
I based the patch on reading the USB PID spec and testing my device under Windows and Linux. Under Windows I snooped the USB packets (thanks wireshark) and under Linux I read through the actual driver code. One item that concerned me is I didn't want autocentering to waste an effect slot, as there aren't a lot of them on the Sidewinder, hence why hooked into the Linux FF autocentering API instead of emulating anything with a spring effect.
From your commit, I believe you are turning autocentering off on device reset? This would be different behaviour than I saw with my Sidewinder under Windows? Am I correct then in understanding that you are saying the reason you are doing this is that
1. my implementation has all devices turning on autocentering on reset, while 2. under Windows all devices, but the Sidewinder, turn off autocentering on reset?
In other words, the Windows dinput FF world is a mess whereby code that was written where the developers were testing with the Sidewinder (e.g., flying simulators) are written expecting auto centering to be enabled on reset, while codes that were written were the developers were using wheels (e.g., driving simulators) are written to not expect auto centering to be enabled on reset?
1. MS Sidewinder uses USB PID 2. MS Wanted an easy way to enable autocentering, not by using a combination of two effects (a lone spring will be too violent and unstable). 3. The Windows PID driver is just setting the autocenter on sidewinder after every DC Reset command. This is something we could easily replicate in the Linux driver. After doing all the reset routines (we decided it's best to do reset + stop all effects + enable actuators) I could add the autocenter for sidewinder if the weird autocenter stuff is detected (Linux driver can already detect it).
Now, this is getting tricky on Linux because Linux does not expose the device control (yet). If we want the true functionality of the reset command, we should disable the autocenter but in your case, that would again disable the autocenter activated by reset.
I think it's a though call now. We could eiter revert to pre-wine 10 behavior of just leaving autocenter alone or do as I did in this change.
Again, this autocenter behavior on SideWinder is custom just for that joystick line. For all other devices, they just receive the DC Reset command. Other devices could still autocenter after reset/disable actuators but that's up to the firmware and not controlled by the API/Driver.
tl;dr The Reset command in directinput api doesn't explicitly touch the autocenter setting. Wheter wine should disable it, without access to proper device control is a decision that isn't straightforward
I just confirmed with Wireshark and few games like American Truck simulator. The directinput docs are wrong and reset does not disable actuators. Some games/applications send a combination of:
DC Reset
DC Stop All Effects
DC Enable Actuators
Set gain to max
But with ATS, the only init the game does is DC reset + max gain.