Module: wine Branch: master Commit: 9dc1ddf801d9db287eb6e7dc13036efde38bd88e URL: https://gitlab.winehq.org/wine/wine/-/commit/9dc1ddf801d9db287eb6e7dc13036ef...
Author: Tyson Whitehead twhitehead@gmail.com Date: Fri Jan 12 23:20:42 2024 -0500
dinput: Implement DIPROP_AUTOCENTER.
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/dinput/tests/force_feedback.c | 1 - dlls/winebus.sys/bus_sdl.c | 4 ++++ dlls/winebus.sys/bus_udev.c | 20 ++++++++++++++++++++ 5 files changed, 32 insertions(+), 5 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/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c index 69060c0706c..841f627d842 100644 --- a/dlls/dinput/tests/force_feedback.c +++ b/dlls/dinput/tests/force_feedback.c @@ -2222,7 +2222,6 @@ static BOOL test_force_feedback_joystick( DWORD version ) .report_len = 2, .report_buf = {1, 0x02}, .broken_id = 8, /* Win8 sends them in the reverse order */ - .todo = TRUE, }, { .code = IOCTL_HID_WRITE_REPORT, 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 c8620352766..f8c6ccb9060 100644 --- a/dlls/winebus.sys/bus_udev.c +++ b/dlls/winebus.sys/bus_udev.c @@ -929,6 +929,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); @@ -972,6 +990,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) @@ -981,6 +1000,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");