Added SDL_GameControllerGetSensorDataRate() to get the sensor update rate for a controller.

This commit is contained in:
Sam Lantinga 2021-07-29 06:43:39 -07:00
parent ce8261dd6d
commit a186a503e7
12 changed files with 88 additions and 71 deletions

View File

@ -758,6 +758,15 @@ extern DECLSPEC int SDLCALL SDL_GameControllerSetSensorEnabled(SDL_GameControlle
*/ */
extern DECLSPEC SDL_bool SDLCALL SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type); extern DECLSPEC SDL_bool SDLCALL SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type);
/**
* Get the data rate (number of events per second) of a game controller sensor.
*
* \param gamecontroller The controller to query
* \param type The type of sensor to query
* \return the data rate, or 0.0f if the data rate is not available.
*/
extern DECLSPEC float SDLCALL SDL_GameControllerGetSensorDataRate(SDL_GameController *gamecontroller, SDL_SensorType type);
/** /**
* Get the current state of a game controller sensor. * Get the current state of a game controller sensor.
* *

View File

@ -814,3 +814,4 @@
#define SDL_FlashWindow SDL_FlashWindow_REAL #define SDL_FlashWindow SDL_FlashWindow_REAL
#define SDL_GameControllerSendEffect SDL_GameControllerSendEffect_REAL #define SDL_GameControllerSendEffect SDL_GameControllerSendEffect_REAL
#define SDL_JoystickSendEffect SDL_JoystickSendEffect_REAL #define SDL_JoystickSendEffect SDL_JoystickSendEffect_REAL
#define SDL_GameControllerGetSensorDataRate SDL_GameControllerGetSensorDataRate_REAL

View File

@ -879,3 +879,4 @@ SDL_DYNAPI_PROC(void,SDL_SetWindowAlwaysOnTop,(SDL_Window *a, SDL_bool b),(a,b),
SDL_DYNAPI_PROC(int,SDL_FlashWindow,(SDL_Window *a, SDL_FlashOperation b),(a,b),return) SDL_DYNAPI_PROC(int,SDL_FlashWindow,(SDL_Window *a, SDL_FlashOperation b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_GameControllerSendEffect,(SDL_GameController *a, const void *b, int c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_GameControllerSendEffect,(SDL_GameController *a, const void *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_JoystickSendEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_JoystickSendEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(float,SDL_GameControllerGetSensorDataRate,(SDL_GameController *a, SDL_SensorType b),(a,b),return)

View File

@ -2181,6 +2181,29 @@ SDL_bool SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, S
return SDL_FALSE; return SDL_FALSE;
} }
/*
* Get the data rate of a game controller sensor.
*/
float
SDL_GameControllerGetSensorDataRate(SDL_GameController *gamecontroller, SDL_SensorType type)
{
SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller);
int i;
if (!joystick) {
return 0.0f;
}
for (i = 0; i < joystick->nsensors; ++i) {
SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
if (sensor->type == type) {
return sensor->rate;
}
}
return 0.0f;
}
/* /*
* Get the current state of a game controller sensor. * Get the current state of a game controller sensor.
*/ */

View File

@ -1162,7 +1162,7 @@ void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers)
} }
} }
void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type) void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type, float rate)
{ {
int nsensors = joystick->nsensors + 1; int nsensors = joystick->nsensors + 1;
SDL_JoystickSensorInfo *sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo))); SDL_JoystickSensorInfo *sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo)));
@ -1171,6 +1171,7 @@ void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type)
SDL_zerop(sensor); SDL_zerop(sensor);
sensor->type = type; sensor->type = type;
sensor->rate = rate;
joystick->nsensors = nsensors; joystick->nsensors = nsensors;
joystick->sensors = sensors; joystick->sensors = sensors;
@ -2707,25 +2708,23 @@ int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, SDL_SensorType type, const
if (sensor->type == type) { if (sensor->type == type) {
if (sensor->enabled) { if (sensor->enabled) {
num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
if (SDL_memcmp(data, sensor->data, num_values*sizeof(*data)) != 0) {
/* Update internal sensor state */ /* Update internal sensor state */
SDL_memcpy(sensor->data, data, num_values*sizeof(*data)); SDL_memcpy(sensor->data, data, num_values*sizeof(*data));
/* Post the event, if desired */ /* Post the event, if desired */
#if !SDL_EVENTS_DISABLED #if !SDL_EVENTS_DISABLED
if (SDL_GetEventState(SDL_CONTROLLERSENSORUPDATE) == SDL_ENABLE) { if (SDL_GetEventState(SDL_CONTROLLERSENSORUPDATE) == SDL_ENABLE) {
SDL_Event event; SDL_Event event;
event.type = SDL_CONTROLLERSENSORUPDATE; event.type = SDL_CONTROLLERSENSORUPDATE;
event.csensor.which = joystick->instance_id; event.csensor.which = joystick->instance_id;
event.csensor.sensor = type; event.csensor.sensor = type;
num_values = SDL_min(num_values, SDL_arraysize(event.csensor.data)); num_values = SDL_min(num_values, SDL_arraysize(event.csensor.data));
SDL_memset(event.csensor.data, 0, sizeof(event.csensor.data)); SDL_memset(event.csensor.data, 0, sizeof(event.csensor.data));
SDL_memcpy(event.csensor.data, data, num_values*sizeof(*data)); SDL_memcpy(event.csensor.data, data, num_values*sizeof(*data));
posted = SDL_PushEvent(&event) == 1; posted = SDL_PushEvent(&event) == 1;
}
#endif /* !SDL_EVENTS_DISABLED */
} }
#endif /* !SDL_EVENTS_DISABLED */
} }
break; break;
} }

View File

@ -116,7 +116,7 @@ extern void SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick);
/* Internal event queueing functions */ /* Internal event queueing functions */
extern void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers); extern void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers);
extern void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type); extern void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type, float rate);
extern void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance); extern void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance);
extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance); extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance);
extern int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, extern int SDL_PrivateJoystickAxis(SDL_Joystick *joystick,

View File

@ -56,6 +56,7 @@ typedef struct _SDL_JoystickSensorInfo
{ {
SDL_SensorType type; SDL_SensorType type;
SDL_bool enabled; SDL_bool enabled;
float rate;
float data[3]; /* If this needs to expand, update SDL_ControllerSensorEvent */ float data[3]; /* If this needs to expand, update SDL_ControllerSensorEvent */
} SDL_JoystickSensorInfo; } SDL_JoystickSensorInfo;

View File

@ -432,8 +432,8 @@ HIDAPI_DriverPS4_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
ctx->enhanced_mode = SDL_TRUE; ctx->enhanced_mode = SDL_TRUE;
SDL_PrivateJoystickAddTouchpad(joystick, 2); SDL_PrivateJoystickAddTouchpad(joystick, 2);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
HIDAPI_DriverPS4_UpdateEffects(device); HIDAPI_DriverPS4_UpdateEffects(device);
} }

View File

@ -488,8 +488,8 @@ HIDAPI_DriverPS5_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
ctx->enhanced_mode = SDL_TRUE; ctx->enhanced_mode = SDL_TRUE;
SDL_PrivateJoystickAddTouchpad(joystick, 2); SDL_PrivateJoystickAddTouchpad(joystick, 2);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
/* Switch into enhanced report mode */ /* Switch into enhanced report mode */
HIDAPI_DriverPS5_UpdateEffects(device, 0); HIDAPI_DriverPS5_UpdateEffects(device, 0);

View File

@ -898,8 +898,8 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
} }
if (input_mode == k_eSwitchInputReportIDs_FullControllerState) { if (input_mode == k_eSwitchInputReportIDs_FullControllerState) {
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 200.0f);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 200.0f);
ctx->m_bHasSensors = SDL_TRUE; ctx->m_bHasSensors = SDL_TRUE;
} }
@ -1333,6 +1333,27 @@ static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch
ctx->m_lastSimpleState = *packet; ctx->m_lastSimpleState = *packet;
} }
static void SendSensorUpdate(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SDL_SensorType type, Sint16 *values)
{
float data[3];
/* Note the order of components has been shuffled to match PlayStation controllers,
* since that's our de facto standard from already supporting those controllers, and
* users will want consistent axis mappings across devices.
*/
data[0] = -HIDAPI_DriverSwitch_ScaleGyro(values[1]);
data[1] = HIDAPI_DriverSwitch_ScaleGyro(values[2]);
data[2] = -HIDAPI_DriverSwitch_ScaleGyro(values[0]);
/* Right Joy-Con flips some axes, so let's flip them back for consistency */
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
data[0] = -data[0];
data[1] = -data[1];
}
SDL_PrivateJoystickSensor(joystick, type, data, 3);
}
static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet) static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
{ {
Sint16 axis; Sint16 axis;
@ -1416,51 +1437,13 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
} }
if (ctx->m_bReportSensors) { if (ctx->m_bReportSensors) {
float data[3]; SendSensorUpdate(joystick, ctx, SDL_SENSOR_GYRO, &packet->imuState[2].sGyroX);
SendSensorUpdate(joystick, ctx, SDL_SENSOR_GYRO, &packet->imuState[1].sGyroX);
SendSensorUpdate(joystick, ctx, SDL_SENSOR_GYRO, &packet->imuState[0].sGyroX);
/* Note the order of components has been shuffled to match PlayStation controllers, SendSensorUpdate(joystick, ctx, SDL_SENSOR_ACCEL, &packet->imuState[2].sAccelX);
* since that's our de facto standard from already supporting those controllers, and SendSensorUpdate(joystick, ctx, SDL_SENSOR_ACCEL, &packet->imuState[1].sAccelX);
* users will want consistent axis mappings across devices. SendSensorUpdate(joystick, ctx, SDL_SENSOR_ACCEL, &packet->imuState[0].sAccelX);
*/
data[0] = HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[0].sGyroY);
data[1] = HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[0].sGyroZ);
data[2] = HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[0].sGyroX);
data[0] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[1].sGyroY);
data[1] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[1].sGyroZ);
data[2] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[1].sGyroX);
data[0] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[2].sGyroY);
data[1] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[2].sGyroZ);
data[2] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[2].sGyroX);
data[0] /= -3.f;
data[1] /= 3.f;
data[2] /= -3.f;
/* Right Joy-Con flips some axes, so let's flip them back for consistency */
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
data[0] = -data[0];
data[1] = -data[1];
}
SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3);
data[0] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelY);
data[1] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelZ);
data[2] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelX);
data[0] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[1].sAccelY);
data[1] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[1].sAccelZ);
data[2] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[1].sAccelX);
data[0] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[2].sAccelY);
data[1] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[2].sAccelZ);
data[2] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[2].sAccelX);
data[0] /= -3.f;
data[1] /= 3.f;
data[2] /= -3.f;
/* Right Joy-Con flips some axes, so let's flip them back for consistency */
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
data[0] = -data[0];
data[1] = -data[1];
}
SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3);
} }
ctx->m_lastFullState = *packet; ctx->m_lastFullState = *packet;

View File

@ -720,10 +720,10 @@ IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
GCController *controller = joystick->hwdata->controller; GCController *controller = joystick->hwdata->controller;
GCMotion *motion = controller.motion; GCMotion *motion = controller.motion;
if (motion && motion.hasRotationRate) { if (motion && motion.hasRotationRate) {
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 0.0f);
} }
if (motion && motion.hasGravityAndUserAcceleration) { if (motion && motion.hasGravityAndUserAcceleration) {
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 0.0f);
} }
} }
#endif /* ENABLE_MFI_SENSORS */ #endif /* ENABLE_MFI_SENSORS */

View File

@ -156,14 +156,14 @@ static void AddController(int device_index, SDL_bool verbose)
if (SDL_GameControllerHasSensor(gamecontroller, SDL_SENSOR_ACCEL)) { if (SDL_GameControllerHasSensor(gamecontroller, SDL_SENSOR_ACCEL)) {
if (verbose) { if (verbose) {
SDL_Log("Enabling accelerometer\n"); SDL_Log("Enabling accelerometer at %.2f Hz\n", SDL_GameControllerGetSensorDataRate(gamecontroller, SDL_SENSOR_ACCEL));
} }
SDL_GameControllerSetSensorEnabled(gamecontroller, SDL_SENSOR_ACCEL, SDL_TRUE); SDL_GameControllerSetSensorEnabled(gamecontroller, SDL_SENSOR_ACCEL, SDL_TRUE);
} }
if (SDL_GameControllerHasSensor(gamecontroller, SDL_SENSOR_GYRO)) { if (SDL_GameControllerHasSensor(gamecontroller, SDL_SENSOR_GYRO)) {
if (verbose) { if (verbose) {
SDL_Log("Enabling gyro\n"); SDL_Log("Enabling gyro at %.2f Hz\n", SDL_GameControllerGetSensorDataRate(gamecontroller, SDL_SENSOR_ACCEL));
} }
SDL_GameControllerSetSensorEnabled(gamecontroller, SDL_SENSOR_GYRO, SDL_TRUE); SDL_GameControllerSetSensorEnabled(gamecontroller, SDL_SENSOR_GYRO, SDL_TRUE);
} }