From 6dc172d093d46f528be802bbf06a54d3f9921d37 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 23 Jan 2020 12:53:39 -0800 Subject: [PATCH] Turn off rumble on drivers which don't respect the replay.length value --- src/joystick/linux/SDL_sysjoystick.c | 28 ++++++++++++++++++++++++-- src/joystick/linux/SDL_sysjoystick_c.h | 1 + 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index cb7ffad5f399c..eecb4606aba8b 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -803,16 +803,30 @@ LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index) return (0); } +#define MAX_KERNEL_RUMBLE_DURATION_MS 0xFFFF + static int LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) { struct input_event event; + if (duration_ms > MAX_KERNEL_RUMBLE_DURATION_MS) { + duration_ms = MAX_KERNEL_RUMBLE_DURATION_MS; + } + if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) { + joystick->hwdata->effect_expiration = SDL_GetTicks() + duration_ms; + if (!joystick->hwdata->effect_expiration) { + joystick->hwdata->effect_expiration = 1; + } + } else { + joystick->hwdata->effect_expiration = 0; + } + if (joystick->hwdata->ff_rumble) { struct ff_effect *effect = &joystick->hwdata->effect; effect->type = FF_RUMBLE; - effect->replay.length = SDL_min(duration_ms, 32767); + effect->replay.length = duration_ms; effect->u.rumble.strong_magnitude = low_frequency_rumble; effect->u.rumble.weak_magnitude = high_frequency_rumble; } else if (joystick->hwdata->ff_sine) { @@ -821,7 +835,7 @@ LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint1 struct ff_effect *effect = &joystick->hwdata->effect; effect->type = FF_PERIODIC; - effect->replay.length = SDL_min(duration_ms, 32767); + effect->replay.length = duration_ms; effect->u.periodic.waveform = FF_SINE; effect->u.periodic.magnitude = magnitude; } else { @@ -1038,6 +1052,13 @@ LINUX_JoystickUpdate(SDL_Joystick * joystick) SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel); } } + + if (joystick->hwdata->effect_expiration) { + Uint32 now = SDL_GetTicks(); + if (SDL_TICKS_PASSED(now, joystick->hwdata->effect_expiration)) { + LINUX_JoystickRumble(joystick, 0, 0, 0); + } + } } /* Function to close a joystick after use */ @@ -1045,6 +1066,9 @@ static void LINUX_JoystickClose(SDL_Joystick * joystick) { if (joystick->hwdata) { + if (joystick->hwdata->effect_expiration) { + LINUX_JoystickRumble(joystick, 0, 0, 0); + } if (joystick->hwdata->effect.id >= 0) { ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id); joystick->hwdata->effect.id = -1; diff --git a/src/joystick/linux/SDL_sysjoystick_c.h b/src/joystick/linux/SDL_sysjoystick_c.h index 1238ad5f899e5..a92429bccf7ca 100644 --- a/src/joystick/linux/SDL_sysjoystick_c.h +++ b/src/joystick/linux/SDL_sysjoystick_c.h @@ -37,6 +37,7 @@ struct joystick_hwdata SDL_bool ff_rumble; SDL_bool ff_sine; struct ff_effect effect; + Uint32 effect_expiration; /* The current Linux joystick driver maps hats to two axes */ struct hwdata_hat