Skip to content
Permalink
Browse files

Moved rumble expiration to the main joystick handling level, and prev…

…ent sending the driver layer duplicate rumble requests.
  • Loading branch information
slouken committed Feb 4, 2020
1 parent 976eee7 commit 6efebf176852a3bfedb57d81c409270cbeb4714f
@@ -758,7 +758,26 @@ SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16
}

SDL_LockJoysticks();
result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
if (low_frequency_rumble == joystick->low_frequency_rumble &&
high_frequency_rumble == joystick->high_frequency_rumble) {
/* Just update the expiration */
result = 0;
} else {
result = joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble);
}

/* Save the rumble value regardless of success, so we don't spam the driver */
joystick->low_frequency_rumble = low_frequency_rumble;
joystick->high_frequency_rumble = high_frequency_rumble;

if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
joystick->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
if (!joystick->rumble_expiration) {
joystick->rumble_expiration = 1;
}
} else {
joystick->rumble_expiration = 0;
}
SDL_UnlockJoysticks();

return result;
@@ -790,6 +809,10 @@ SDL_JoystickClose(SDL_Joystick * joystick)
return;
}

if (joystick->rumble_expiration) {
SDL_JoystickRumble(joystick, 0, 0, 0);
}

joystick->driver->Close(joystick);
joystick->hwdata = NULL;

@@ -1217,6 +1240,16 @@ SDL_JoystickUpdate(void)
}
}

if (joystick->rumble_expiration) {
SDL_LockJoysticks();
/* Double check now that the lock is held */
if (joystick->rumble_expiration &&
SDL_TICKS_PASSED(SDL_GetTicks(), joystick->rumble_expiration)) {
SDL_JoystickRumble(joystick, 0, 0, 0);
}
SDL_UnlockJoysticks();
}

if (joystick->force_recentering) {
/* Tell the app that everything is centered/unpressed... */
for (i = 0; i < joystick->naxes; i++) {
@@ -60,6 +60,10 @@ struct _SDL_Joystick
int nbuttons; /* Number of buttons on the joystick */
Uint8 *buttons; /* Current button states */

Uint16 low_frequency_rumble;
Uint16 high_frequency_rumble;
Uint32 rumble_expiration;

SDL_bool attached;
SDL_bool is_game_controller;
SDL_bool delayed_guide_button; /* SDL_TRUE if this device has the guide button event delayed */
@@ -118,7 +122,7 @@ typedef struct _SDL_JoystickDriver
int (*Open)(SDL_Joystick * joystick, int device_index);

/* Rumble functionality */
int (*Rumble)(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
int (*Rumble)(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);

/* Function to update the state of a joystick - called as a device poll.
* This function shouldn't update the joystick structure directly,
@@ -135,6 +139,9 @@ typedef struct _SDL_JoystickDriver

} SDL_JoystickDriver;

/* Windows and Mac OSX has a limit of MAX_DWORD / 1000, Linux kernel has a limit of 0xFFFF */
#define SDL_MAX_RUMBLE_DURATION_MS 0xFFFF

/* The available joystick drivers */
extern SDL_JoystickDriver SDL_ANDROID_JoystickDriver;
extern SDL_JoystickDriver SDL_BSD_JoystickDriver;
@@ -629,7 +629,7 @@ ANDROID_JoystickOpen(SDL_Joystick * joystick, int device_index)
}

static int
ANDROID_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
ANDROID_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
@@ -757,7 +757,7 @@ report_free(struct report *r)
}

static int
BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
@@ -52,7 +52,7 @@ void FreeRumbleEffectData(FFEFFECT *effect)
SDL_free(effect);
}

FFEFFECT *CreateRumbleEffectData(Sint16 magnitude, Uint32 duration_ms)
FFEFFECT *CreateRumbleEffectData(Sint16 magnitude)
{
FFEFFECT *effect;
FFPERIODIC *periodic;
@@ -65,7 +65,7 @@ FFEFFECT *CreateRumbleEffectData(Sint16 magnitude, Uint32 duration_ms)
effect->dwSize = sizeof(*effect);
effect->dwGain = 10000;
effect->dwFlags = FFEFF_OBJECTOFFSETS;
effect->dwDuration = duration_ms * 1000; /* In microseconds. */
effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; /* In microseconds. */
effect->dwTriggerButton = FFEB_NOTRIGGER;

effect->cAxes = 2;
@@ -832,7 +832,7 @@ FFStrError(unsigned int err)
}

static int
DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude, Uint32 duration_ms)
DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude)
{
HRESULT result;

@@ -855,7 +855,7 @@ DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude, Uint32 duration_m
}

/* Create the effect */
device->ffeffect = CreateRumbleEffectData(magnitude, duration_ms);
device->ffeffect = CreateRumbleEffectData(magnitude);
if (!device->ffeffect) {
return SDL_OutOfMemory();
}
@@ -869,7 +869,7 @@ DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude, Uint32 duration_m
}

static int
DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
HRESULT result;
recDevice *device = joystick->hwdata;
@@ -883,7 +883,6 @@ DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint

if (device->ff_initialized) {
FFPERIODIC *periodic = ((FFPERIODIC *)device->ffeffect->lpvTypeSpecificParams);
device->ffeffect->dwDuration = duration_ms * 1000; /* In microseconds. */
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);

result = FFEffectSetParameters(device->ffeffect_ref, device->ffeffect,
@@ -892,7 +891,7 @@ DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint
return SDL_SetError("Unable to update rumble effect: %s", FFStrError(result));
}
} else {
if (DARWIN_JoystickInitRumble(device, magnitude, duration_ms) < 0) {
if (DARWIN_JoystickInitRumble(device, magnitude) < 0) {
return -1;
}
device->ff_initialized = SDL_TRUE;
@@ -84,7 +84,7 @@ DUMMY_JoystickOpen(SDL_Joystick * joystick, int device_index)
}

static int
DUMMY_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
DUMMY_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
@@ -399,7 +399,7 @@ EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
}

static int
EMSCRIPTEN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
EMSCRIPTEN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
@@ -254,7 +254,7 @@ extern "C"
return guid;
}

static int HAIKU_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
static int HAIKU_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
@@ -44,7 +44,6 @@ typedef struct {
Uint8 max_axis[MAX_CONTROLLERS*SDL_CONTROLLER_AXIS_MAX];
Uint8 rumbleAllowed[MAX_CONTROLLERS];
Uint8 rumble[1+MAX_CONTROLLERS];
Uint32 rumbleExpiration[MAX_CONTROLLERS];
/* Without this variable, hid_write starts to lag a TON */
SDL_bool rumbleUpdate;
} SDL_DriverGameCube_Context;
@@ -285,16 +284,6 @@ HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
}

/* Write rumble packet */
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (ctx->rumbleExpiration[i] || (ctx->rumble[1 + i] && !ctx->rumbleAllowed[i])) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumbleExpiration[i]) || !ctx->rumbleAllowed[i]) {
ctx->rumble[1 + i] = 0;
ctx->rumbleExpiration[i] = 0;
ctx->rumbleUpdate = SDL_TRUE;
}
}
}
if (ctx->rumbleUpdate) {
hid_write(device->dev, ctx->rumble, sizeof(ctx->rumble));
ctx->rumbleUpdate = SDL_FALSE;
@@ -321,7 +310,7 @@ HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
}

static int
HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i, val;
@@ -338,14 +327,6 @@ HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo
ctx->rumble[i + 1] = val;
ctx->rumbleUpdate = SDL_TRUE;
}
if (val && duration_ms) {
ctx->rumbleExpiration[i] = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
if (!ctx->rumbleExpiration[i]) {
ctx->rumbleExpiration[i] = 1;
}
} else {
ctx->rumbleExpiration[i] = 0;
}
return 0;
}
}
@@ -359,18 +340,11 @@ static void
HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
Uint8 i;

/* Stop rumble activity */
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
if (!ctx->wireless[i] && ctx->rumbleAllowed[i] && ctx->rumble[1 + i] != 0) {
ctx->rumble[1 + i] = 0;
ctx->rumbleExpiration[i] = 0;
hid_write(device->dev, ctx->rumble, sizeof(ctx->rumble));
}
break;
}
if (ctx->rumbleUpdate) {
hid_write(device->dev, ctx->rumble, sizeof(ctx->rumble));
ctx->rumbleUpdate = SDL_FALSE;
}
}

@@ -37,8 +37,6 @@

#ifdef SDL_JOYSTICK_HIDAPI_PS4

#define USB_PACKET_LENGTH 64

typedef enum
{
k_EPS4ReportIdUsbState = 1,
@@ -103,7 +101,6 @@ typedef struct {
SDL_bool rumble_supported;
Uint8 volume;
Uint32 last_volume_check;
Uint32 rumble_expiration;
PS4StatePacket_t last_state;
} SDL_DriverPS4_Context;

@@ -201,7 +198,7 @@ HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
{
}

static int HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
static int HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);

static SDL_bool
HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
@@ -251,7 +248,7 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
}

/* Initialize LED and effect state */
HIDAPI_DriverPS4_RumbleJoystick(device, joystick, 0, 0, 0);
HIDAPI_DriverPS4_RumbleJoystick(device, joystick, 0, 0);

/* Initialize the joystick capabilities */
joystick->nbuttons = 16;
@@ -262,7 +259,7 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
}

static int
HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
DS4EffectsState_t *effects;
@@ -311,15 +308,6 @@ HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
if (hid_write(device->dev, data, report_size) != report_size) {
return SDL_SetError("Couldn't send rumble packet");
}

if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
ctx->rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
if (!ctx->rumble_expiration) {
ctx->rumble_expiration = 1;
}
} else {
ctx->rumble_expiration = 0;
}
return 0;
}

@@ -465,13 +453,6 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
}
}

if (ctx->rumble_expiration) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
HIDAPI_DriverPS4_RumbleJoystick(device, joystick, 0, 0, 0);
}
}

if (size < 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
@@ -482,12 +463,6 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
static void
HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;

if (ctx->rumble_expiration) {
HIDAPI_DriverPS4_RumbleJoystick(device, joystick, 0, 0, 0);
}

hid_close(device->dev);
device->dev = NULL;

@@ -1029,7 +1029,7 @@ HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
}

static int
HIDAPI_DriverSteam_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
HIDAPI_DriverSteam_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
/* You should use the full Steam Input API for rumble support */
return SDL_Unsupported();

0 comments on commit 6efebf1

Please sign in to comment.