Module: wine Branch: master Commit: 3ed121bffa3d1a4394277a532edb150c6b4bebfd URL: https://source.winehq.org/git/wine.git/?a=commit;h=3ed121bffa3d1a4394277a532...
Author: Rémi Bernon rbernon@codeweavers.com Date: Thu Dec 2 10:47:48 2021 +0100
winebus.sys: Send PID effect state reports for SDL devices.
Checking for effect state updates periodically, as well as whenever the device state changes but not more than once every 10ms.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52062 Signed-off-by: Rémi Bernon rbernon@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/winebus.sys/bus_sdl.c | 62 +++++++++++++++++++++++++++++++++++++---- dlls/winebus.sys/hid.c | 8 ++++++ dlls/winebus.sys/unix_private.h | 2 ++ 3 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c index 254971e1185..76d90ab7912 100644 --- a/dlls/winebus.sys/bus_sdl.c +++ b/dlls/winebus.sys/bus_sdl.c @@ -78,7 +78,7 @@ MAKE_FUNCPTR(SDL_JoystickInstanceID); MAKE_FUNCPTR(SDL_JoystickName); MAKE_FUNCPTR(SDL_JoystickNumAxes); MAKE_FUNCPTR(SDL_JoystickOpen); -MAKE_FUNCPTR(SDL_WaitEvent); +MAKE_FUNCPTR(SDL_WaitEventTimeout); MAKE_FUNCPTR(SDL_JoystickNumButtons); MAKE_FUNCPTR(SDL_JoystickNumBalls); MAKE_FUNCPTR(SDL_JoystickNumHats); @@ -93,6 +93,7 @@ MAKE_FUNCPTR(SDL_GameControllerOpen); MAKE_FUNCPTR(SDL_GameControllerEventState); MAKE_FUNCPTR(SDL_HapticClose); MAKE_FUNCPTR(SDL_HapticDestroyEffect); +MAKE_FUNCPTR(SDL_HapticGetEffectStatus); MAKE_FUNCPTR(SDL_HapticNewEffect); MAKE_FUNCPTR(SDL_HapticOpenFromJoystick); MAKE_FUNCPTR(SDL_HapticPause); @@ -110,6 +111,7 @@ MAKE_FUNCPTR(SDL_JoystickIsHaptic); MAKE_FUNCPTR(SDL_GameControllerAddMapping); MAKE_FUNCPTR(SDL_RegisterEvents); MAKE_FUNCPTR(SDL_PushEvent); +MAKE_FUNCPTR(SDL_GetTicks); static int (*pSDL_JoystickRumble)(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick); static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick); @@ -136,6 +138,8 @@ struct sdl_device SDL_Haptic *sdl_haptic; int haptic_effect_id; int effect_ids[256]; + int effect_state[256]; + LONG effect_flags; };
static inline struct sdl_device *impl_from_unix_device(struct unix_device *iface) @@ -453,9 +457,11 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US { case PID_USAGE_DC_ENABLE_ACTUATORS: pSDL_HapticSetGain(impl->sdl_haptic, 100); + InterlockedOr(&impl->effect_flags, EFFECT_STATE_ACTUATORS_ENABLED); return STATUS_SUCCESS; case PID_USAGE_DC_DISABLE_ACTUATORS: pSDL_HapticSetGain(impl->sdl_haptic, 0); + InterlockedAnd(&impl->effect_flags, ~EFFECT_STATE_ACTUATORS_ENABLED); return STATUS_SUCCESS; case PID_USAGE_DC_STOP_ALL_EFFECTS: pSDL_HapticStopAll(impl->sdl_haptic); @@ -471,9 +477,11 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_PAUSE: pSDL_HapticPause(impl->sdl_haptic); + InterlockedOr(&impl->effect_flags, EFFECT_STATE_DEVICE_PAUSED); return STATUS_SUCCESS; case PID_USAGE_DC_DEVICE_CONTINUE: pSDL_HapticUnpause(impl->sdl_haptic); + InterlockedAnd(&impl->effect_flags, ~EFFECT_STATE_DEVICE_PAUSED); return STATUS_SUCCESS; }
@@ -686,6 +694,42 @@ static const struct hid_device_vtbl sdl_device_vtbl = sdl_device_physical_effect_update, };
+static void check_device_effects_state(struct sdl_device *impl) +{ + struct unix_device *iface = &impl->unix_device; + struct hid_effect_state *effect_state = &iface->hid_physical.effect_state; + ULONG effect_flags = InterlockedOr(&impl->effect_flags, 0); + unsigned int i, ret; + + if (!impl->sdl_haptic) return; + if (!(impl->effect_support & SDL_HAPTIC_STATUS)) return; + + for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) + { + if (impl->effect_ids[i] == -1) continue; + ret = pSDL_HapticGetEffectStatus(impl->sdl_haptic, impl->effect_ids[i]); + if (impl->effect_state[i] == ret) continue; + impl->effect_state[i] = ret; + hid_device_set_effect_state(iface, i, effect_flags | (ret == 1 ? EFFECT_STATE_EFFECT_PLAYING : 0)); + bus_event_queue_input_report(&event_queue, iface, effect_state->report_buf, effect_state->report_len); + } +} + +static void check_all_devices_effects_state(void) +{ + static UINT last_ticks = 0; + UINT ticks = pSDL_GetTicks(); + struct sdl_device *impl; + + if (ticks - last_ticks < 10) return; + last_ticks = ticks; + + pthread_mutex_lock(&sdl_cs); + LIST_FOR_EACH_ENTRY(impl, &device_list, struct sdl_device, unix_device.entry) + check_device_effects_state(impl); + pthread_mutex_unlock(&sdl_cs); +} + static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *event) { struct unix_device *iface = &impl->unix_device; @@ -693,7 +737,7 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e
if (impl->sdl_controller) return TRUE; /* use controller events instead */
- switch(event->type) + switch (event->type) { case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: @@ -732,6 +776,8 @@ static BOOL set_report_from_joystick_event(struct sdl_device *impl, SDL_Event *e default: ERR("TODO: Process Report (0x%x)\n",event->type); } + + check_device_effects_state(impl); return FALSE; }
@@ -740,7 +786,7 @@ static BOOL set_report_from_controller_event(struct sdl_device *impl, SDL_Event struct unix_device *iface = &impl->unix_device; struct hid_device_state *state = &iface->hid_device_state;
- switch(event->type) + switch (event->type) { case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: @@ -786,6 +832,8 @@ static BOOL set_report_from_controller_event(struct sdl_device *impl, SDL_Event default: ERR("TODO: Process Report (%x)\n",event->type); } + + check_device_effects_state(impl); return FALSE; }
@@ -924,7 +972,7 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_JoystickName); LOAD_FUNCPTR(SDL_JoystickNumAxes); LOAD_FUNCPTR(SDL_JoystickOpen); - LOAD_FUNCPTR(SDL_WaitEvent); + LOAD_FUNCPTR(SDL_WaitEventTimeout); LOAD_FUNCPTR(SDL_JoystickNumButtons); LOAD_FUNCPTR(SDL_JoystickNumBalls); LOAD_FUNCPTR(SDL_JoystickNumHats); @@ -939,6 +987,7 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_GameControllerEventState); LOAD_FUNCPTR(SDL_HapticClose); LOAD_FUNCPTR(SDL_HapticDestroyEffect); + LOAD_FUNCPTR(SDL_HapticGetEffectStatus); LOAD_FUNCPTR(SDL_HapticNewEffect); LOAD_FUNCPTR(SDL_HapticOpenFromJoystick); LOAD_FUNCPTR(SDL_HapticPause); @@ -956,6 +1005,7 @@ NTSTATUS sdl_bus_init(void *args) LOAD_FUNCPTR(SDL_GameControllerAddMapping); LOAD_FUNCPTR(SDL_RegisterEvents); LOAD_FUNCPTR(SDL_PushEvent); + LOAD_FUNCPTR(SDL_GetTicks); #undef LOAD_FUNCPTR pSDL_JoystickRumble = dlsym(sdl_handle, "SDL_JoystickRumble"); pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct"); @@ -1013,8 +1063,8 @@ NTSTATUS sdl_bus_wait(void *args) do { if (bus_event_queue_pop(&event_queue, result)) return STATUS_PENDING; - if (pSDL_WaitEvent(&event) != 0) process_device_event(&event); - else WARN("SDL_WaitEvent failed: %s\n", pSDL_GetError()); + if (pSDL_WaitEventTimeout(&event, 10) != 0) process_device_event(&event); + else check_all_devices_effects_state(); } while (event.type != quit_event);
TRACE("SDL main loop exiting\n"); diff --git a/dlls/winebus.sys/hid.c b/dlls/winebus.sys/hid.c index 29d5debcfe2..8680f8a088c 100644 --- a/dlls/winebus.sys/hid.c +++ b/dlls/winebus.sys/hid.c @@ -1405,3 +1405,11 @@ void hid_device_drop_report(struct unix_device *iface) { iface->hid_device_state.dropped = TRUE; } + +void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) +{ + struct hid_effect_state *state = &iface->hid_physical.effect_state; + struct pid_effect_state *report = (struct pid_effect_state *)(state->report_buf + 1); + report->index = index; + report->flags = flags; +} diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h index 564fec9fc3a..efecf6cdbe3 100644 --- a/dlls/winebus.sys/unix_private.h +++ b/dlls/winebus.sys/unix_private.h @@ -262,6 +262,8 @@ extern BOOL hid_device_set_hatswitch_y(struct unix_device *iface, ULONG index, L extern BOOL hid_device_sync_report(struct unix_device *iface) DECLSPEC_HIDDEN; extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN;
+extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; + BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN;