For gamepads that don't have their own sensors, try to use the system sensors.
This allows using the gyro and accelerometer in handheld devices in conjunction with built-in or wraparound controllers.
This commit is contained in:
parent
d584592822
commit
42e4639a5e
8 changed files with 272 additions and 11 deletions
|
@ -616,6 +616,18 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS "SDL_GAMECONTROLLER_USE_BUTTON_LABELS"
|
#define SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS "SDL_GAMECONTROLLER_USE_BUTTON_LABELS"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Controls whether the device's built-in accelerometer and gyro should be used as sensors for gamepads.
|
||||||
|
*
|
||||||
|
* The variable can be set to the following values:
|
||||||
|
* "auto" - Sensor fusion is enabled for known wraparound controllers like the Razer Kishi and Backbone One
|
||||||
|
* "0" - Sensor fusion is disabled
|
||||||
|
* "1" - Sensor fusion is enabled for all controllers that lack sensors
|
||||||
|
*
|
||||||
|
* The default value is "auto". This hint is checked when a gamepad is opened.
|
||||||
|
*/
|
||||||
|
#define SDL_HINT_GAMECONTROLLER_SENSOR_FUSION "SDL_GAMECONTROLLER_SENSOR_FUSION"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief A variable controlling whether grabbing input grabs the keyboard
|
* \brief A variable controlling whether grabbing input grabs the keyboard
|
||||||
*
|
*
|
||||||
|
|
|
@ -171,6 +171,23 @@ const char *SDL_GetHint(const char *name)
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SDL_GetStringInteger(const char *value, int default_value)
|
||||||
|
{
|
||||||
|
if (value == NULL || !*value) {
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
if (*value == '0' || SDL_strcasecmp(value, "false") == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (*value == '1' || SDL_strcasecmp(value, "true") == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (*value == '-' || SDL_isdigit(*value)) {
|
||||||
|
return SDL_atoi(value);
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value)
|
SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value)
|
||||||
{
|
{
|
||||||
if (value == NULL || !*value) {
|
if (value == NULL || !*value) {
|
||||||
|
|
|
@ -26,5 +26,6 @@
|
||||||
#define SDL_hints_c_h_
|
#define SDL_hints_c_h_
|
||||||
|
|
||||||
extern SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value);
|
extern SDL_bool SDL_GetStringBoolean(const char *value, SDL_bool default_value);
|
||||||
|
extern int SDL_GetStringInteger(const char *value, int default_value);
|
||||||
|
|
||||||
#endif /* SDL_hints_c_h_ */
|
#endif /* SDL_hints_c_h_ */
|
||||||
|
|
|
@ -444,6 +444,19 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
|
||||||
SDL_PushEvent(&deviceevent);
|
SDL_PushEvent(&deviceevent);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case SDL_EVENT_SENSOR_UPDATE:
|
||||||
|
{
|
||||||
|
SDL_LockJoysticks();
|
||||||
|
for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) {
|
||||||
|
if (gamepad->joystick->accel && gamepad->joystick->accel_sensor == event->sensor.which) {
|
||||||
|
SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_ACCEL, event->sensor.sensor_timestamp, event->sensor.data, SDL_arraysize(event->sensor.data));
|
||||||
|
}
|
||||||
|
if (gamepad->joystick->gyro && gamepad->joystick->gyro_sensor == event->sensor.which) {
|
||||||
|
SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_GYRO, event->sensor.sensor_timestamp, event->sensor.data, SDL_arraysize(event->sensor.data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_UnlockJoysticks();
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2523,6 +2536,33 @@ int SDL_SetGamepadSensorEnabled(SDL_Gamepad *gamepad, SDL_SensorType type, SDL_b
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == SDL_SENSOR_ACCEL && joystick->accel_sensor) {
|
||||||
|
if (enabled) {
|
||||||
|
joystick->accel = SDL_OpenSensor(joystick->accel_sensor);
|
||||||
|
if (!joystick->accel) {
|
||||||
|
SDL_UnlockJoysticks();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (joystick->accel) {
|
||||||
|
SDL_CloseSensor(joystick->accel);
|
||||||
|
joystick->accel = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == SDL_SENSOR_GYRO && joystick->gyro_sensor) {
|
||||||
|
if (enabled) {
|
||||||
|
joystick->gyro = SDL_OpenSensor(joystick->gyro_sensor);
|
||||||
|
if (!joystick->gyro) {
|
||||||
|
SDL_UnlockJoysticks();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (joystick->gyro) {
|
||||||
|
SDL_CloseSensor(joystick->gyro);
|
||||||
|
joystick->gyro = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (joystick->nsensors_enabled == 0) {
|
if (joystick->nsensors_enabled == 0) {
|
||||||
if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) {
|
if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) {
|
||||||
|
@ -2540,6 +2580,7 @@ int SDL_SetGamepadSensorEnabled(SDL_Gamepad *gamepad, SDL_SensorType type, SDL_b
|
||||||
}
|
}
|
||||||
--joystick->nsensors_enabled;
|
--joystick->nsensors_enabled;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sensor->enabled = enabled;
|
sensor->enabled = enabled;
|
||||||
SDL_UnlockJoysticks();
|
SDL_UnlockJoysticks();
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "../events/SDL_events_c.h"
|
#include "../events/SDL_events_c.h"
|
||||||
#endif
|
#endif
|
||||||
#include "../video/SDL_sysvideo.h"
|
#include "../video/SDL_sysvideo.h"
|
||||||
|
#include "../sensor/SDL_sensor_c.h"
|
||||||
#include "hidapi/SDL_hidapijoystick_c.h"
|
#include "hidapi/SDL_hidapijoystick_c.h"
|
||||||
|
|
||||||
/* This is included in only one place because it has a large static list of controllers */
|
/* This is included in only one place because it has a large static list of controllers */
|
||||||
|
@ -510,6 +511,166 @@ static SDL_bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
|
||||||
#endif /* __WINRT__ */
|
#endif /* __WINRT__ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_bool IsBackboneOne(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
if (joystick->name && SDL_strstr(joystick->name, "Backbone One")) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_bool IsROGAlly(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
Uint16 vendor, product;
|
||||||
|
SDL_JoystickGUID guid = SDL_GetJoystickGUID(joystick);
|
||||||
|
|
||||||
|
/* The ROG Ally controller spoofs an Xbox 360 controller */
|
||||||
|
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
|
||||||
|
if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX360_WIRED_CONTROLLER) {
|
||||||
|
/* Check to see if this system has the expected sensors */
|
||||||
|
SDL_bool has_ally_accel = SDL_FALSE;
|
||||||
|
SDL_bool has_ally_gyro = SDL_FALSE;
|
||||||
|
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_SENSOR) == 0) {
|
||||||
|
SDL_SensorID *sensors = SDL_GetSensors(NULL);
|
||||||
|
if (sensors) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; sensors[i]; ++i) {
|
||||||
|
SDL_SensorID sensor = sensors[i];
|
||||||
|
|
||||||
|
if (!has_ally_accel && SDL_GetSensorInstanceType(sensor) == SDL_SENSOR_ACCEL) {
|
||||||
|
const char *sensor_name = SDL_GetSensorInstanceName(sensor);
|
||||||
|
if (sensor_name && SDL_strcmp(sensor_name, "Sensor BMI320 Acc") == 0) {
|
||||||
|
has_ally_accel = SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!has_ally_gyro && SDL_GetSensorInstanceType(sensor) == SDL_SENSOR_GYRO) {
|
||||||
|
const char *sensor_name = SDL_GetSensorInstanceName(sensor);
|
||||||
|
if (sensor_name && SDL_strcmp(sensor_name, "Sensor BMI320 Gyr") == 0) {
|
||||||
|
has_ally_gyro = SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_free(sensors);
|
||||||
|
}
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_SENSOR);
|
||||||
|
}
|
||||||
|
if (has_ally_accel && has_ally_gyro) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
static Uint32 wraparound_gamepads[] = {
|
||||||
|
MAKE_VIDPID(0x1949, 0x0402), /* Ipega PG-9083S */
|
||||||
|
MAKE_VIDPID(0x27f8, 0x0bbc), /* Gamevice */
|
||||||
|
MAKE_VIDPID(0x27f8, 0x0bbf), /* Razer Kishi */
|
||||||
|
};
|
||||||
|
SDL_JoystickGUID guid;
|
||||||
|
Uint16 vendor, product;
|
||||||
|
Uint32 vidpid;
|
||||||
|
int i;
|
||||||
|
int hint;
|
||||||
|
|
||||||
|
/* The SDL controller sensor API is only available for gamepads (at the moment) */
|
||||||
|
if (!joystick->is_gamepad) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the controller already has sensors, use those */
|
||||||
|
if (joystick->nsensors > 0) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hint = SDL_GetStringInteger(SDL_GetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION), -1);
|
||||||
|
if (hint > 0) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
if (hint == 0) {
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the controller is in our list of wraparound gamepads */
|
||||||
|
guid = SDL_GetJoystickGUID(joystick);
|
||||||
|
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
|
||||||
|
vidpid = MAKE_VIDPID(vendor, product);
|
||||||
|
for (i = 0; i < SDL_arraysize(wraparound_gamepads); ++i) {
|
||||||
|
if (vidpid == wraparound_gamepads[i]) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if this is another known wraparound gamepad */
|
||||||
|
if (IsBackboneOne(joystick) || IsROGAlly(joystick)) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AttemptSensorFusion(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
SDL_SensorID *sensors;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_SENSOR) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sensors = SDL_GetSensors(NULL);
|
||||||
|
if (sensors) {
|
||||||
|
for (i = 0; sensors[i]; ++i) {
|
||||||
|
SDL_SensorID sensor = sensors[i];
|
||||||
|
|
||||||
|
if (!joystick->accel_sensor && SDL_GetSensorInstanceType(sensor) == SDL_SENSOR_ACCEL) {
|
||||||
|
/* Increment the sensor subsystem reference count */
|
||||||
|
SDL_InitSubSystem(SDL_INIT_SENSOR);
|
||||||
|
|
||||||
|
joystick->accel_sensor = sensor;
|
||||||
|
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f);
|
||||||
|
}
|
||||||
|
if (!joystick->gyro_sensor && SDL_GetSensorInstanceType(sensor) == SDL_SENSOR_GYRO) {
|
||||||
|
/* Increment the sensor subsystem reference count */
|
||||||
|
SDL_InitSubSystem(SDL_INIT_SENSOR);
|
||||||
|
|
||||||
|
joystick->gyro_sensor = sensor;
|
||||||
|
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_free(sensors);
|
||||||
|
}
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_SENSOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CleanupSensorFusion(SDL_Joystick *joystick)
|
||||||
|
{
|
||||||
|
if (joystick->accel_sensor || joystick->gyro_sensor) {
|
||||||
|
if (joystick->accel_sensor) {
|
||||||
|
if (joystick->accel) {
|
||||||
|
SDL_CloseSensor(joystick->accel);
|
||||||
|
joystick->accel = NULL;
|
||||||
|
}
|
||||||
|
joystick->accel_sensor = 0;
|
||||||
|
|
||||||
|
/* Decrement the sensor subsystem reference count */
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_SENSOR);
|
||||||
|
}
|
||||||
|
if (joystick->gyro_sensor) {
|
||||||
|
if (joystick->gyro) {
|
||||||
|
SDL_CloseSensor(joystick->gyro);
|
||||||
|
joystick->gyro = NULL;
|
||||||
|
}
|
||||||
|
joystick->gyro_sensor = 0;
|
||||||
|
|
||||||
|
/* Decrement the sensor subsystem reference count */
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_SENSOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open a joystick for use - the index passed as an argument refers to
|
* Open a joystick for use - the index passed as an argument refers to
|
||||||
* the N'th joystick on the system. This index is the value which will
|
* the N'th joystick on the system. This index is the value which will
|
||||||
|
@ -611,6 +772,11 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
||||||
|
|
||||||
joystick->is_gamepad = SDL_IsGamepad(instance_id);
|
joystick->is_gamepad = SDL_IsGamepad(instance_id);
|
||||||
|
|
||||||
|
/* Use system gyro and accelerometer if the gamepad doesn't have built-in sensors */
|
||||||
|
if (ShouldAttemptSensorFusion(joystick)) {
|
||||||
|
AttemptSensorFusion(joystick);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add joystick to list */
|
/* Add joystick to list */
|
||||||
++joystick->ref_count;
|
++joystick->ref_count;
|
||||||
/* Link the joystick in the list */
|
/* Link the joystick in the list */
|
||||||
|
@ -1253,6 +1419,8 @@ void SDL_CloseJoystick(SDL_Joystick *joystick)
|
||||||
SDL_RumbleJoystickTriggers(joystick, 0, 0, 0);
|
SDL_RumbleJoystickTriggers(joystick, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CleanupSensorFusion(joystick);
|
||||||
|
|
||||||
joystick->driver->Close(joystick);
|
joystick->driver->Close(joystick);
|
||||||
joystick->hwdata = NULL;
|
joystick->hwdata = NULL;
|
||||||
joystick->magic = NULL;
|
joystick->magic = NULL;
|
||||||
|
@ -1273,11 +1441,10 @@ void SDL_CloseJoystick(SDL_Joystick *joystick)
|
||||||
joysticklist = joysticklist->next;
|
joysticklist = joysticklist->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free the data associated with this joystick */
|
||||||
SDL_free(joystick->name);
|
SDL_free(joystick->name);
|
||||||
SDL_free(joystick->path);
|
SDL_free(joystick->path);
|
||||||
SDL_free(joystick->serial);
|
SDL_free(joystick->serial);
|
||||||
|
|
||||||
/* Free the data associated with this joystick */
|
|
||||||
SDL_free(joystick->axes);
|
SDL_free(joystick->axes);
|
||||||
SDL_free(joystick->hats);
|
SDL_free(joystick->hats);
|
||||||
SDL_free(joystick->buttons);
|
SDL_free(joystick->buttons);
|
||||||
|
@ -1682,6 +1849,16 @@ void SDL_UpdateJoysticks(void)
|
||||||
|
|
||||||
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
|
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
|
||||||
if (joystick->attached) {
|
if (joystick->attached) {
|
||||||
|
if (joystick->accel || joystick->gyro) {
|
||||||
|
SDL_LockSensors();
|
||||||
|
if (joystick->gyro) {
|
||||||
|
SDL_UpdateSensor(joystick->gyro);
|
||||||
|
}
|
||||||
|
if (joystick->accel) {
|
||||||
|
SDL_UpdateSensor(joystick->accel);
|
||||||
|
}
|
||||||
|
SDL_UnlockSensors();
|
||||||
|
}
|
||||||
joystick->driver->Update(joystick);
|
joystick->driver->Update(joystick);
|
||||||
|
|
||||||
if (joystick->delayed_guide_button) {
|
if (joystick->delayed_guide_button) {
|
||||||
|
|
|
@ -113,6 +113,11 @@ struct SDL_Joystick
|
||||||
SDL_bool delayed_guide_button _guarded; /* SDL_TRUE if this device has the guide button event delayed */
|
SDL_bool delayed_guide_button _guarded; /* SDL_TRUE if this device has the guide button event delayed */
|
||||||
SDL_JoystickPowerLevel epowerlevel _guarded; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
|
SDL_JoystickPowerLevel epowerlevel _guarded; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
|
||||||
|
|
||||||
|
SDL_SensorID accel_sensor _guarded;
|
||||||
|
SDL_Sensor *accel _guarded;
|
||||||
|
SDL_SensorID gyro_sensor _guarded;
|
||||||
|
SDL_Sensor *gyro _guarded;
|
||||||
|
|
||||||
struct SDL_JoystickDriver *driver _guarded;
|
struct SDL_JoystickDriver *driver _guarded;
|
||||||
|
|
||||||
struct joystick_hwdata *hwdata _guarded; /* Driver dependent information */
|
struct joystick_hwdata *hwdata _guarded; /* Driver dependent information */
|
||||||
|
|
|
@ -504,6 +504,11 @@ int SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_tim
|
||||||
return posted;
|
return posted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SDL_UpdateSensor(SDL_Sensor *sensor)
|
||||||
|
{
|
||||||
|
sensor->driver->Update(sensor);
|
||||||
|
}
|
||||||
|
|
||||||
void SDL_UpdateSensors(void)
|
void SDL_UpdateSensors(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
|
@ -40,6 +40,9 @@ extern void SDL_UnlockSensors(void);
|
||||||
/* Function to return whether there are any sensors opened by the application */
|
/* Function to return whether there are any sensors opened by the application */
|
||||||
extern SDL_bool SDL_SensorsOpened(void);
|
extern SDL_bool SDL_SensorsOpened(void);
|
||||||
|
|
||||||
|
/* Update an individual sensor, used by gamepad sensor fusion */
|
||||||
|
extern void SDL_UpdateSensor(SDL_Sensor *sensor);
|
||||||
|
|
||||||
/* Internal event queueing functions */
|
/* Internal event queueing functions */
|
||||||
extern int SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values);
|
extern int SDL_SendSensorUpdate(Uint64 timestamp, SDL_Sensor *sensor, Uint64 sensor_timestamp, float *data, int num_values);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue