XInput: Fix rumble overload by limiting on state changes and interval
This commit is contained in:
parent
4e30df6392
commit
bd9561d93c
|
@ -31,6 +31,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_inline.h>
|
#include <retro_inline.h>
|
||||||
|
@ -68,6 +69,8 @@ typedef struct
|
||||||
bool connected;
|
bool connected;
|
||||||
} xinput_joypad_state;
|
} xinput_joypad_state;
|
||||||
|
|
||||||
|
#define RUMBLE_INTERVAL 0.005
|
||||||
|
|
||||||
/* TODO/FIXME - static globals */
|
/* TODO/FIXME - static globals */
|
||||||
static int g_xinput_pad_indexes[MAX_USERS];
|
static int g_xinput_pad_indexes[MAX_USERS];
|
||||||
static unsigned g_last_xinput_pad_idx = 0;
|
static unsigned g_last_xinput_pad_idx = 0;
|
||||||
|
@ -90,6 +93,7 @@ static XINPUT_FEEDBACK g_xinput_rumble_states[4];
|
||||||
static XINPUT_VIBRATION g_xinput_rumble_states[4];
|
static XINPUT_VIBRATION g_xinput_rumble_states[4];
|
||||||
#endif
|
#endif
|
||||||
static xinput_joypad_state g_xinput_states[4];
|
static xinput_joypad_state g_xinput_states[4];
|
||||||
|
static clock_t last_rumble_time[4] = {0};
|
||||||
|
|
||||||
/* Buttons are provided by XInput as bits of a uint16.
|
/* Buttons are provided by XInput as bits of a uint16.
|
||||||
* Map from rarch button index (0..10) to a mask to
|
* Map from rarch button index (0..10) to a mask to
|
||||||
|
@ -646,17 +650,31 @@ static bool xinput_joypad_rumble(unsigned pad,
|
||||||
if (xuser == -1)
|
if (xuser == -1)
|
||||||
return dinput_joypad_set_rumble(pad, effect, strength);
|
return dinput_joypad_set_rumble(pad, effect, strength);
|
||||||
|
|
||||||
|
XINPUT_VIBRATION *state = &g_xinput_rumble_states[xuser];
|
||||||
|
XINPUT_VIBRATION new_state = *state;
|
||||||
|
|
||||||
/* Consider the low frequency (left) motor the "strong" one. */
|
/* Consider the low frequency (left) motor the "strong" one. */
|
||||||
if (effect == RETRO_RUMBLE_STRONG)
|
if (effect == RETRO_RUMBLE_STRONG)
|
||||||
g_xinput_rumble_states[xuser].wLeftMotorSpeed = strength;
|
new_state.wLeftMotorSpeed = strength;
|
||||||
else if (effect == RETRO_RUMBLE_WEAK)
|
else if (effect == RETRO_RUMBLE_WEAK)
|
||||||
g_xinput_rumble_states[xuser].wRightMotorSpeed = strength;
|
new_state.wRightMotorSpeed = strength;
|
||||||
|
|
||||||
|
bool rumble_state_unchanged = ((new_state.wLeftMotorSpeed == state->wLeftMotorSpeed) &&
|
||||||
|
(new_state.wRightMotorSpeed == state->wRightMotorSpeed));
|
||||||
|
|
||||||
|
clock_t now = clock();
|
||||||
|
double time_since_last_rumble = (double)(now - last_rumble_time[xuser]) / CLOCKS_PER_SEC;
|
||||||
|
bool rumble_interval_unelapsed = (time_since_last_rumble < RUMBLE_INTERVAL);
|
||||||
|
|
||||||
|
if (rumble_state_unchanged || rumble_interval_unelapsed)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!g_XInputSetState)
|
if (!g_XInputSetState)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (g_XInputSetState(xuser, &g_xinput_rumble_states[xuser])
|
*state = new_state;
|
||||||
== 0);
|
last_rumble_time[xuser] = now;
|
||||||
|
return (g_XInputSetState(xuser, state) == ERROR_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xinput_joypad_destroy(void)
|
static void xinput_joypad_destroy(void)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_inline.h>
|
#include <retro_inline.h>
|
||||||
|
@ -51,6 +52,8 @@ typedef struct
|
||||||
bool connected;
|
bool connected;
|
||||||
} xinput_joypad_state;
|
} xinput_joypad_state;
|
||||||
|
|
||||||
|
#define RUMBLE_INTERVAL 0.005
|
||||||
|
|
||||||
/* Function pointer, to be assigned with dylib_proc */
|
/* Function pointer, to be assigned with dylib_proc */
|
||||||
typedef uint32_t (__stdcall *XInputGetStateEx_t)(uint32_t, XINPUT_STATE*);
|
typedef uint32_t (__stdcall *XInputGetStateEx_t)(uint32_t, XINPUT_STATE*);
|
||||||
typedef uint32_t (__stdcall *XInputSetState_t)(uint32_t, XINPUT_VIBRATION*);
|
typedef uint32_t (__stdcall *XInputSetState_t)(uint32_t, XINPUT_VIBRATION*);
|
||||||
|
@ -71,6 +74,7 @@ static XINPUT_FEEDBACK g_xinput_rumble_states[4];
|
||||||
static XINPUT_VIBRATION g_xinput_rumble_states[4];
|
static XINPUT_VIBRATION g_xinput_rumble_states[4];
|
||||||
#endif
|
#endif
|
||||||
static xinput_joypad_state g_xinput_states[4];
|
static xinput_joypad_state g_xinput_states[4];
|
||||||
|
static clock_t last_rumble_time[4] = {0};
|
||||||
|
|
||||||
/* Buttons are provided by XInput as bits of a uint16.
|
/* Buttons are provided by XInput as bits of a uint16.
|
||||||
* Map from rarch button index (0..10) to a mask to
|
* Map from rarch button index (0..10) to a mask to
|
||||||
|
@ -371,17 +375,31 @@ static bool xinput_joypad_rumble(unsigned pad,
|
||||||
if (xuser == -1)
|
if (xuser == -1)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
XINPUT_VIBRATION *state = &g_xinput_rumble_states[xuser];
|
||||||
|
XINPUT_VIBRATION new_state = *state;
|
||||||
|
|
||||||
/* Consider the low frequency (left) motor the "strong" one. */
|
/* Consider the low frequency (left) motor the "strong" one. */
|
||||||
if (effect == RETRO_RUMBLE_STRONG)
|
if (effect == RETRO_RUMBLE_STRONG)
|
||||||
g_xinput_rumble_states[xuser].wLeftMotorSpeed = strength;
|
new_state.wLeftMotorSpeed = strength;
|
||||||
else if (effect == RETRO_RUMBLE_WEAK)
|
else if (effect == RETRO_RUMBLE_WEAK)
|
||||||
g_xinput_rumble_states[xuser].wRightMotorSpeed = strength;
|
new_state.wRightMotorSpeed = strength;
|
||||||
|
|
||||||
|
bool rumble_state_unchanged = ((new_state.wLeftMotorSpeed == state->wLeftMotorSpeed) &&
|
||||||
|
(new_state.wRightMotorSpeed == state->wRightMotorSpeed));
|
||||||
|
|
||||||
|
clock_t now = clock();
|
||||||
|
double time_since_last_rumble = (double)(now - last_rumble_time[xuser]) / CLOCKS_PER_SEC;
|
||||||
|
bool rumble_interval_unelapsed = (time_since_last_rumble < RUMBLE_INTERVAL);
|
||||||
|
|
||||||
|
if (rumble_state_unchanged || rumble_interval_unelapsed)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!g_XInputSetState)
|
if (!g_XInputSetState)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (g_XInputSetState(xuser, &g_xinput_rumble_states[xuser])
|
*state = new_state;
|
||||||
== 0);
|
last_rumble_time[xuser] = now;
|
||||||
|
return (g_XInputSetState(xuser, state) == ERROR_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_device_driver_t xinput_joypad = {
|
input_device_driver_t xinput_joypad = {
|
||||||
|
|
Loading…
Reference in New Issue