From: Tyson Whitehead twhitehead@gmail.com
The removal of autocenter support from the SDL and udev input backends was based on the belief that the device should not turn auto centering on upon receiving a device reset command from the front end as only some devices do it this way and others have different ways of doing it.
This is a fundamental misunderstanding of what is going on. The messages between the front end and the SDL and udev backends are the front end telling the backends what to do. These are in no way sent to the device, and have nothing to do with how autocenter is turned on or off on the device. Rather the backends interpret them and then makes SDL and udev input API calls to drive the device, including turning on or off autocentering.
The reason the backends call their respective APIs to turn on autocentering on receiving a reset is because that is they way turn on autocenter is communicated to the backend. In the event that the autocenter should not be on, the front end will follow the reset with a stop all effects command which tells the backends to call their underlying API to turn it back off.
If autocenter is different than a users experts it to be, either * the program assumed a given initial state, didn't verify it or or set it, and the initial state was the other, or * the backend API calls are failing to set it (the kernel driver either does not support setting it or is buggy).
I have written a test program that lets people test their devices to ensure things are working correctly and discover what the initial state is under Windows
https://github.com/twhitehead/issue-wine-ff-autocenter
A log file is generated for users to submit so initial states under Windows can be discovered and broken drivers identified. This will allow the unwanted autocenter issue of the author of the commit being reverted to be properly figured out and addressed.
As a final note, the SDL and udev input backends are actually the preferred backends for force feedback as they ultimately dispatch to the kernel driver which can handle any required quirks as well as all the different way autocentering can be implemented.
By comparison, the udev hidraw backend is quite limited. It requires a PID compliant device without any quirks that uses reset and stop all effect autocentering. Such devices are perfectly supported by the kernel ff_pdiff driver, so they to function perfectly with the SDL and udev input backends.
This reverts commit b0db6d50530023a19846f08f1c62f14803448f59. --- dlls/winebus.sys/bus_sdl.c | 2 ++ dlls/winebus.sys/bus_udev.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 6e2c8bef3e4..7c622155fd8 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -518,6 +518,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); @@ -527,6 +528,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); diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c index 9951e3d0ec8..c6b71492f9e 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -827,6 +827,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); @@ -870,6 +888,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) @@ -879,6 +898,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");