Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 107 additions & 5 deletions input/drivers/sdl3_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ typedef struct sdl3_input
float x;
float y;
} touches[SDL3_MAX_TOUCH];

/* Sensors. Used if the SDL3 joypad driver isn't active. */
SDL_Sensor *accel;
SDL_Sensor *gyro;
bool sensors_init;
} sdl3_input_t;

/* Rebuilt on SDL_EVENT_KEYMAP_CHANGED (e.g. system layout switch). */
Expand Down Expand Up @@ -445,20 +450,86 @@ static void sdl3_input_free(void *data)
SDL_FlushEvents(SDL_EVENT_FINGER_DOWN, SDL_EVENT_FINGER_CANCELED);
SDL_FlushEvents(SDL_EVENT_PEN_PROXIMITY_IN, SDL_EVENT_PEN_AXIS);

if (sdl->accel)
SDL_CloseSensor(sdl->accel);
if (sdl->gyro)
SDL_CloseSensor(sdl->gyro);
if (sdl->sensors_init)
SDL_QuitSubSystem(SDL_INIT_SENSOR);

SDL_QuitSubSystem(SDL_INIT_EVENTS);
free(sdl);
}

/* Opens the first sensor of the given type. */
static SDL_Sensor *sdl3_open_sensor(SDL_SensorType type)
{
int i;
int num_sensors = 0;
SDL_Sensor *sensor = NULL;
SDL_SensorID *sensors = SDL_GetSensors(&num_sensors);

if (!sensors)
return NULL;

for (i = 0; i < num_sensors; i++)
{
if (SDL_GetSensorTypeForID(sensors[i]) == type)
{
sensor = SDL_OpenSensor(sensors[i]);
break;
}
}

SDL_free(sensors);
return sensor;
}

/* Enables the accelerometer/gyroscope. */
static bool sdl3_set_sensor_state(void *data, unsigned port,
enum retro_sensor_action action, unsigned rate)
{
/* Sensors are not exposed through the SDL3 keyboard/mouse driver.
* Gamepad gyro/accel are handled by the SDL3 joypad driver. */
sdl3_input_t *sdl = (sdl3_input_t*)data;

/* The host device's sensors only ever map to port 0. */
if (port != 0)
return false;

switch (action)
{
case RETRO_SENSOR_ILLUMINANCE_DISABLE:
case RETRO_SENSOR_GYROSCOPE_DISABLE:
case RETRO_SENSOR_ACCELEROMETER_ENABLE:
case RETRO_SENSOR_GYROSCOPE_ENABLE:
{
bool accelerometer = action == RETRO_SENSOR_ACCELEROMETER_ENABLE;
SDL_Sensor **sensor = accelerometer ? &sdl->accel : &sdl->gyro;

if (*sensor)
return true;

/* Make sure the Sensor subsystem is available. */
if (!sdl->sensors_init)
{
if (!SDL_InitSubSystem(SDL_INIT_SENSOR))
return false;
sdl->sensors_init = true;
}

return (*sensor = sdl3_open_sensor(accelerometer ? SDL_SENSOR_ACCEL : SDL_SENSOR_GYRO)) != NULL;
}
case RETRO_SENSOR_ACCELEROMETER_DISABLE:
case RETRO_SENSOR_GYROSCOPE_DISABLE:
{
SDL_Sensor **sensor = action == RETRO_SENSOR_ACCELEROMETER_DISABLE
? &sdl->accel : &sdl->gyro;

if (*sensor)
{
SDL_CloseSensor(*sensor);
*sensor = NULL;
}
return true;
}
case RETRO_SENSOR_ILLUMINANCE_DISABLE:
/* Disabling an unsupported sensor shouldn't fail. */
return true;
default:
Expand All @@ -468,6 +539,31 @@ static bool sdl3_set_sensor_state(void *data, unsigned port,
return false;
}

static float sdl3_get_sensor_input(void *data, unsigned port, unsigned id)
{
sdl3_input_t *sdl = (sdl3_input_t*)data;
float v[3];

/* The host device's sensors only ever map to port 0. */
if (port != 0)
return 0.0f;

/* Acceleration is m/s^2, though libretro expects gravity. The
* gyroscope uses radians per second. */
if (id <= RETRO_SENSOR_ACCELEROMETER_Z)
{
if (sdl->accel && SDL_GetSensorData(sdl->accel, v, 3))
return v[id - RETRO_SENSOR_ACCELEROMETER_X] / SDL_STANDARD_GRAVITY;
}
else if (id >= RETRO_SENSOR_GYROSCOPE_X && id <= RETRO_SENSOR_GYROSCOPE_Z)
{
if (sdl->gyro && SDL_GetSensorData(sdl->gyro, v, 3))
return v[id - RETRO_SENSOR_GYROSCOPE_X];
}

return 0.0f;
}

/* Gets the SDL_Window, if it exists. */
static SDL_Window *sdl3_input_window(void)
{
Expand Down Expand Up @@ -676,6 +772,10 @@ static void sdl3_input_poll(void *data)
sdl3_poll_mouse(sdl);
sdl3_poll_touch(sdl);

/* SDL_UpdateSensors works without a focused window. */
if (sdl->accel || sdl->gyro)
SDL_UpdateSensors();

sdl->mouse_wu = false;
sdl->mouse_wd = false;
sdl->mouse_wl = false;
Expand Down Expand Up @@ -742,6 +842,8 @@ static void sdl3_input_poll(void *data)
* keys) get dropped along with them. */
SDL_FlushEvents(SDL_EVENT_FINGER_DOWN, SDL_EVENT_FINGER_CANCELED);
SDL_FlushEvents(SDL_EVENT_PEN_PROXIMITY_IN, SDL_EVENT_PEN_AXIS);
if (sdl->sensors_init)
SDL_FlushEvent(SDL_EVENT_SENSOR_UPDATE);
}

static void sdl3_grab_mouse(void *data, bool state)
Expand Down Expand Up @@ -773,7 +875,7 @@ input_driver_t input_sdl3 = {
sdl3_input_state,
sdl3_input_free,
sdl3_set_sensor_state,
NULL, /* get_sensor_input */
sdl3_get_sensor_input,
sdl3_get_capabilities,
"sdl3",
sdl3_grab_mouse,
Expand Down
65 changes: 54 additions & 11 deletions input/drivers_joypad/sdl3_joypad.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ typedef struct _sdl3_joypad
unsigned num_hats;
uint16_t rumble_gain; /* 0-100 */
uint16_t rumble[2]; /* raw magnitude per retro_rumble_effect (strong/weak) */
bool sensor_accel; /* Whether or not the sensor has been connected. */
bool sensor_gyro;
} sdl3_joypad_t;

/**
Expand Down Expand Up @@ -252,6 +254,24 @@ static void sdl3_joypad_connect(SDL_JoystickID jid)
pad->num_buttons = (num_buttons > 0) ? (unsigned)num_buttons : 0;
pad->num_hats = (num_hats > 0) ? (unsigned)num_hats : 0;
}

if (gamepad)
{
bool has_accel = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_ACCEL);
bool has_gyro = SDL_GamepadHasSensor(gamepad, SDL_SENSOR_GYRO);
if (has_accel || has_gyro)
RARCH_LOG("[SDL3] Pad #%d: found sensors (accel=%s, gyro=%s).\n",
slot,
has_accel ? "yes" : "no",
has_gyro ? "yes" : "no");

/* Restore any sensor state that was requested before connecting,
* e.g. when the pad is unplugged and plugged back in. */
if (has_accel && pad->sensor_accel)
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_ACCEL, true);
if (has_gyro && pad->sensor_gyro)
SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_GYRO, true);
}
}

static void sdl3_joypad_disconnect(SDL_JoystickID jid)
Expand All @@ -270,7 +290,14 @@ static void sdl3_joypad_disconnect(SDL_JoystickID jid)

input_autoconfigure_disconnect(i, sdl3_joypad.ident);

memset(&sdl3_joypads[i], 0, sizeof(sdl3_joypads[i]));
/* Keep the requested sensor state so it can be restored on reconnect. */
{
bool sensor_accel = sdl3_joypads[i].sensor_accel;
bool sensor_gyro = sdl3_joypads[i].sensor_gyro;
memset(&sdl3_joypads[i], 0, sizeof(sdl3_joypads[i]));
sdl3_joypads[i].sensor_accel = sensor_accel;
sdl3_joypads[i].sensor_gyro = sensor_gyro;
}
return;
}
}
Expand Down Expand Up @@ -547,6 +574,9 @@ static bool sdl3_joypad_set_rumble(unsigned pad,
/**
* Enables or disables a sensor on the specified gamepad.
*
* The requested state is remembered so it can be re-applied if the
* pad disconnects and reconnects.
*
* @param pad Index of the gamepad.
* @param action Sensor action to perform (enable/disable gyroscope or accelerometer).
* @param rate Requested sensor update rate (unused).
Expand All @@ -555,27 +585,40 @@ static bool sdl3_joypad_set_rumble(unsigned pad,
static bool sdl3_joypad_set_sensor_state(unsigned pad,
enum retro_sensor_action action, unsigned rate)
{
SDL_Gamepad *gamepad;

if (pad >= MAX_USERS)
return false;

if (!sdl3_joypads[pad].gamepad)
return false;
gamepad = sdl3_joypads[pad].gamepad;

switch (action)
{
case RETRO_SENSOR_GYROSCOPE_ENABLE:
case RETRO_SENSOR_GYROSCOPE_DISABLE:
if (SDL_GamepadHasSensor(sdl3_joypads[pad].gamepad, SDL_SENSOR_GYRO))
return SDL_SetGamepadSensorEnabled(sdl3_joypads[pad].gamepad, SDL_SENSOR_GYRO,
action == RETRO_SENSOR_GYROSCOPE_ENABLE);
return false;
{
bool enable = action == RETRO_SENSOR_GYROSCOPE_ENABLE;
sdl3_joypads[pad].sensor_gyro = enable;
if (gamepad && SDL_GamepadHasSensor(gamepad, SDL_SENSOR_GYRO))
return SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_GYRO, enable);
/* Disabling a missing sensor shouldn't fail. */
return !enable;
}

case RETRO_SENSOR_ACCELEROMETER_ENABLE:
case RETRO_SENSOR_ACCELEROMETER_DISABLE:
if (SDL_GamepadHasSensor(sdl3_joypads[pad].gamepad, SDL_SENSOR_ACCEL))
return SDL_SetGamepadSensorEnabled(sdl3_joypads[pad].gamepad, SDL_SENSOR_ACCEL,
action == RETRO_SENSOR_ACCELEROMETER_ENABLE);
return false;
{
bool enable = action == RETRO_SENSOR_ACCELEROMETER_ENABLE;
sdl3_joypads[pad].sensor_accel = enable;
if (gamepad && SDL_GamepadHasSensor(gamepad, SDL_SENSOR_ACCEL))
return SDL_SetGamepadSensorEnabled(gamepad, SDL_SENSOR_ACCEL, enable);
/* Disabling a missing sensor shouldn't fail. */
return !enable;
}

case RETRO_SENSOR_ILLUMINANCE_DISABLE:
/* Disabling an unsupported sensor shouldn't fail. */
return true;

default:
return false;
Expand Down
Loading