diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 7091c11a2d..3282c7284e 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -370,33 +370,19 @@ 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. +/* SDL defines sensor orientation relative to the device natural + orientation, so when it's changed orientation to be used as a + gamepad, change the sensor orientation to match. */ -static void AdjustSensorOrientation(float *src, float *dst) +static void AdjustSensorOrientation(SDL_Joystick *joystick, float *src, float *dst) { - if (SDL_GetDisplayNaturalOrientation(SDL_GetPrimaryDisplay()) == SDL_ORIENTATION_LANDSCAPE) { - /* When a device in landscape orientation is laid flat, the axes change - orientation as follows: - -X to +X becomes -X to +X - -Y to +Y becomes +Z to -Z - -Z to +Z becomes -Y to +Y - */ - dst[0] = src[0]; - dst[1] = src[2]; - dst[2] = -src[1]; - } else { - /* When a device in portrait orientation 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]; + unsigned int i, j; + + for (i = 0; i < 3; ++i) { + dst[i] = 0.0f; + for (j = 0; j < 3; ++j) { + dst[i] += joystick->sensor_transform[i][j] * src[j]; + } } } @@ -480,12 +466,12 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event) for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) { if (gamepad->joystick->accel && gamepad->joystick->accel_sensor == event->sensor.which) { float data[3]; - AdjustSensorOrientation(event->sensor.data, data); + AdjustSensorOrientation(gamepad->joystick, 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) { float data[3]; - AdjustSensorOrientation(event->sensor.data, data); + AdjustSensorOrientation(gamepad->joystick, event->sensor.data, data); SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_GYRO, event->sensor.sensor_timestamp, data, SDL_arraysize(data)); } } diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 498d31c039..993871b11a 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -562,7 +562,7 @@ static SDL_bool IsROGAlly(SDL_Joystick *joystick) return SDL_FALSE; } -static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick) +static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick, SDL_bool *invert_sensors) { static Uint32 wraparound_gamepads[] = { MAKE_VIDPID(0x1532, 0x0709), /* Razer Junglecat (L) */ @@ -578,6 +578,8 @@ static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick) int i; int hint; + *invert_sensors = SDL_FALSE; + /* The SDL controller sensor API is only available for gamepads (at the moment) */ if (!joystick->is_gamepad) { return SDL_FALSE; @@ -607,17 +609,23 @@ static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick) } /* See if this is another known wraparound gamepad */ - if (IsBackboneOne(joystick) || IsROGAlly(joystick)) { + if (IsBackboneOne(joystick)) { + return SDL_TRUE; + } + if (IsROGAlly(joystick)) { + /* I'm not sure if this is a Windows thing, or a quirk for ROG Ally, + * but we need to invert the sensor data on all axes. + */ + *invert_sensors = SDL_TRUE; return SDL_TRUE; } - return SDL_FALSE; } -static void AttemptSensorFusion(SDL_Joystick *joystick) +static void AttemptSensorFusion(SDL_Joystick *joystick, SDL_bool invert_sensors) { SDL_SensorID *sensors; - int i; + unsigned int i, j; if (SDL_InitSubSystem(SDL_INIT_SENSOR) < 0) { return; @@ -646,6 +654,41 @@ static void AttemptSensorFusion(SDL_Joystick *joystick) SDL_free(sensors); } SDL_QuitSubSystem(SDL_INIT_SENSOR); + + /* 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. + */ + if (SDL_GetDisplayNaturalOrientation(SDL_GetPrimaryDisplay()) == SDL_ORIENTATION_LANDSCAPE) { + /* When a device in landscape orientation is laid flat, the axes change + orientation as follows: + -X to +X becomes -X to +X + -Y to +Y becomes +Z to -Z + -Z to +Z becomes -Y to +Y + */ + joystick->sensor_transform[0][0] = 1.0f; + joystick->sensor_transform[1][2] = 1.0f; + joystick->sensor_transform[2][1] = -1.0f; + } else { + /* When a device in portrait orientation 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 + */ + joystick->sensor_transform[0][1] = -1.0f; + joystick->sensor_transform[1][2] = 1.0f; + joystick->sensor_transform[2][0] = -1.0f; + } + + if (invert_sensors) { + for (i = 0; i < SDL_arraysize(joystick->sensor_transform); ++i) { + for (j = 0; j < SDL_arraysize(joystick->sensor_transform[i]); ++j) { + joystick->sensor_transform[i][j] *= -1.0f; + } + } + } } static void CleanupSensorFusion(SDL_Joystick *joystick) @@ -690,6 +733,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id) const char *joystickname = NULL; const char *joystickpath = NULL; SDL_JoystickPowerLevel initial_power_level; + SDL_bool invert_sensors = SDL_FALSE; SDL_LockJoysticks(); @@ -776,8 +820,8 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID 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); + if (ShouldAttemptSensorFusion(joystick, &invert_sensors)) { + AttemptSensorFusion(joystick, invert_sensors); } /* Add joystick to list */ diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 4b2225ccdd..99784dcf21 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -117,6 +117,7 @@ struct SDL_Joystick SDL_Sensor *accel _guarded; SDL_SensorID gyro_sensor _guarded; SDL_Sensor *gyro _guarded; + float sensor_transform[3][3] _guarded; struct SDL_JoystickDriver *driver _guarded;