Navigation Menu

Skip to content

Commit

Permalink
Moved rumble expiration to the main joystick handling level, and prev…
Browse files Browse the repository at this point in the history
…ent sending the driver layer duplicate rumble requests.
  • Loading branch information
slouken committed Feb 4, 2020
1 parent 976eee7 commit 6efebf1
Show file tree
Hide file tree
Showing 25 changed files with 94 additions and 237 deletions.
35 changes: 34 additions & 1 deletion src/joystick/SDL_joystick.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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++) {
Expand Down
9 changes: 8 additions & 1 deletion src/joystick/SDL_sysjoystick.h
Expand Up @@ -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 */
Expand Down Expand Up @@ -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,
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/android/SDL_sysjoystick.c
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/bsd/SDL_sysjoystick.c
Expand Up @@ -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();
}
Expand Down
13 changes: 6 additions & 7 deletions src/joystick/darwin/SDL_sysjoystick.c
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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();
}
Expand All @@ -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;
Expand All @@ -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,
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/dummy/SDL_sysjoystick.c
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/emscripten/SDL_sysjoystick.c
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion src/joystick/haiku/SDL_haikujoystick.cc
Expand Up @@ -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();
}
Expand Down
34 changes: 4 additions & 30 deletions src/joystick/hidapi/SDL_hidapi_gamecube.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
}
Expand All @@ -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;
}
}

Expand Down
31 changes: 3 additions & 28 deletions src/joystick/hidapi/SDL_hidapi_ps4.c
Expand Up @@ -37,8 +37,6 @@

#ifdef SDL_JOYSTICK_HIDAPI_PS4

#define USB_PACKET_LENGTH 64

typedef enum
{
k_EPS4ReportIdUsbState = 1,
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/joystick/hidapi/SDL_hidapi_steam.c
Expand Up @@ -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();
Expand Down

0 comments on commit 6efebf1

Please sign in to comment.