From 8de6ce7e92907c5f509c6b33c5ee2a5f7b3c1c0c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 16 Jun 2023 17:48:34 -0700
Subject: [PATCH] Rotate the sensor axes to match gamepad orientation when
using the device sensors for game controllers
---
include/SDL3/SDL_sensor.h | 10 ++++------
src/joystick/SDL_gamepad.c | 26 ++++++++++++++++++++++++--
2 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/include/SDL3/SDL_sensor.h b/include/SDL3/SDL_sensor.h
index 9b4a48290b21..dda75f036505 100644
--- a/include/SDL3/SDL_sensor.h
+++ b/include/SDL3/SDL_sensor.h
@@ -89,13 +89,12 @@ typedef enum
* values[1]: Acceleration on the y axis
* values[2]: Acceleration on the z axis
*
- * For phones held in portrait mode and game controllers held in front of you,
- * the axes are defined as follows:
+ * For phones and tablets held in natural orientation and game controllers held in front of you, the axes are defined as follows:
* -X ... +X : left ... right
* -Y ... +Y : bottom ... top
* -Z ... +Z : farther ... closer
*
- * The axis data is not changed when the phone is rotated.
+ * The axis data is not changed when the device is rotated.
*
* \sa SDL_GetDisplayOrientation()
*/
@@ -114,13 +113,12 @@ typedef enum
* values[1]: Angular speed around the y axis (yaw)
* values[2]: Angular speed around the z axis (roll)
*
- * For phones held in portrait mode and game controllers held in front of you,
- * the axes are defined as follows:
+ * For phones and tablets held in natural orientation and game controllers held in front of you, the axes are defined as follows:
* -X ... +X : left ... right
* -Y ... +Y : bottom ... top
* -Z ... +Z : farther ... closer
*
- * The axis data is not changed when the phone or controller is rotated.
+ * The axis data is not changed when the device is rotated.
*
* \sa SDL_GetDisplayOrientation()
*/
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index 01b133561885..88e6efee1ef4 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -370,6 +370,24 @@ static void RecenterGamepad(SDL_Gamepad *gamepad)
}
}
+/* SDL defines sensor orientation for phones relative to the natural
+ orientation, and for gamepads relative to being held in front of you.
+ When a phone is being used as a gamepad, its orientation changes,
+ so adjust sensor axes to match.
+ */
+static void AdjustSensorOrientation(float *src, float *dst)
+{
+ /* When a phone is rotated left and laid flat, the axes change
+ orientation as follows:
+ -X to +X becomes +Z to -Z
+ -Y to +Y becomes +X to -X
+ -Z to +Z becomes -Y to +Y
+ */
+ dst[0] = -src[1];
+ dst[1] = src[2];
+ dst[2] = -src[0];
+}
+
/*
* Event filter to fire gamepad events from joystick ones
*/
@@ -449,10 +467,14 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
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));
+ float data[3];
+ AdjustSensorOrientation(event->sensor.data, data);
+ SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_ACCEL, event->sensor.sensor_timestamp, data, SDL_arraysize(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));
+ float data[3];
+ AdjustSensorOrientation(event->sensor.data, data);
+ SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_GYRO, event->sensor.sensor_timestamp, data, SDL_arraysize(data));
}
}
SDL_UnlockJoysticks();