diff --git a/include/SDL_events.h b/include/SDL_events.h index a9da3fa2e..ae560c085 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -128,6 +128,7 @@ typedef enum SDL_CONTROLLERTOUCHPADDOWN, /**< Game controller touchpad was touched */ SDL_CONTROLLERTOUCHPADMOTION, /**< Game controller touchpad finger was moved */ SDL_CONTROLLERTOUCHPADUP, /**< Game controller touchpad finger was lifted */ + SDL_CONTROLLERSENSORUPDATE, /**< Game controller sensor was updated */ /* Touch events */ SDL_FINGERDOWN = 0x700, @@ -426,13 +427,24 @@ typedef struct SDL_ControllerTouchpadEvent Uint32 type; /**< ::SDL_CONTROLLERTOUCHPADDOWN or ::SDL_CONTROLLERTOUCHPADMOTION or ::SDL_CONTROLLERTOUCHPADUP */ Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */ SDL_JoystickID which; /**< The joystick instance id */ - int touchpad; /**< The index of the touchpad */ - int finger; /**< The index of the finger on the touchpad */ + Sint32 touchpad; /**< The index of the touchpad */ + Sint32 finger; /**< The index of the finger on the touchpad */ float x; /**< Normalized in the range 0...1 with 0 being on the left */ float y; /**< Normalized in the range 0...1 with 0 being at the top */ float pressure; /**< Normalized in the range 0...1 */ } SDL_ControllerTouchpadEvent; +/** + * \brief Game controller sensor event structure (event.csensor.*) + */ +typedef struct SDL_ControllerSensorEvent +{ + Uint32 type; /**< ::SDL_CONTROLLERSENSORUPDATE */ + Uint32 timestamp; /**< In milliseconds, populated using SDL_GetTicks() */ + SDL_JoystickID which; /**< The joystick instance id */ + Sint32 sensor; /**< The type of the sensor, one of the values of ::SDL_SensorType */ + float data[3]; /**< Up to 3 values from the sensor, as defined in SDL_sensor.h */ +} SDL_ControllerSensorEvent; /** * \brief Audio device event structure (event.adevice.*) @@ -597,6 +609,7 @@ typedef union SDL_Event SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */ SDL_ControllerDeviceEvent cdevice; /**< Game Controller device event data */ SDL_ControllerTouchpadEvent ctouchpad; /**< Game Controller touchpad event data */ + SDL_ControllerSensorEvent csensor; /**< Game Controller sensor event data */ SDL_AudioDeviceEvent adevice; /**< Audio device event data */ SDL_SensorEvent sensor; /**< Sensor event data */ SDL_QuitEvent quit; /**< Quit request event data */ diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h index ee7ef6475..e42433c95 100644 --- a/include/SDL_gamecontroller.h +++ b/include/SDL_gamecontroller.h @@ -31,6 +31,7 @@ #include "SDL_stdinc.h" #include "SDL_error.h" #include "SDL_rwops.h" +#include "SDL_sensor.h" #include "SDL_joystick.h" #include "begin_code.h" @@ -430,6 +431,52 @@ extern DECLSPEC int SDLCALL SDL_GameControllerGetNumTouchpadFingers(SDL_GameCont */ extern DECLSPEC int SDLCALL SDL_GameControllerGetTouchpadFinger(SDL_GameController *gamecontroller, int touchpad, int finger, Uint8 *state, float *x, float *y, float *pressure); +/** + * Return whether a game controller has a particular sensor. + * + * \param gamecontroller The controller to query + * \param type The type of sensor to query + * + * \return SDL_TRUE if the sensor exists, SDL_FALSE otherwise. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType type); + +/** + * Set whether data reporting for a game controller sensor is enabled + * + * \param gamecontroller The controller to update + * \param type The type of sensor to enable/disable + * \param enabled Whether data reporting should be enabled + * + * \return 0 or -1 if an error occurred. + */ +extern DECLSPEC int SDLCALL SDL_GameControllerSetSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type, SDL_bool enabled); + +/** + * Query whether sensor data reporting is enabled for a game controller + * + * \param gamecontroller The controller to query + * \param type The type of sensor to query + * + * \return SDL_TRUE if the sensor is enabled, SDL_FALSE otherwise. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type); + +/** + * Get the current state of a game controller sensor. + * + * The number of values and interpretation of the data is sensor dependent. + * See SDL_sensor.h for the details for each type of sensor. + * + * \param gamecontroller The controller to query + * \param type The type of sensor to query + * \param data A pointer filled with the current sensor state + * \param num_values The number of values to write to data + * + * \return 0 or -1 if an error occurred. + */ +extern DECLSPEC int SDLCALL SDL_GameControllerGetSensorData(SDL_GameController *gamecontroller, SDL_SensorType type, float *data, int num_values); + /** * Start a rumble effect * Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling. diff --git a/include/SDL_sensor.h b/include/SDL_sensor.h index 83abf1ee4..e6236341e 100644 --- a/include/SDL_sensor.h +++ b/include/SDL_sensor.h @@ -78,14 +78,16 @@ typedef enum * Accelerometer sensor * * The accelerometer returns the current acceleration in SI meters per - * second squared. This includes gravity, so a device at rest will have - * an acceleration of SDL_STANDARD_GRAVITY straight down. + * second squared. This measurement includes the force of gravity, so + * a device at rest will have an value of SDL_STANDARD_GRAVITY away + * from the center of the earth. * * values[0]: Acceleration on the x axis * values[1]: Acceleration on the y axis * values[2]: Acceleration on the z axis * - * For phones held in portrait mode, the axes are defined as follows: + * For phones held in portrait mode 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 @@ -105,16 +107,17 @@ typedef enum * see positive rotation on that axis when it appeared to be rotating * counter-clockwise. * - * values[0]: Angular speed around the x axis - * values[1]: Angular speed around the y axis - * values[2]: Angular speed around the z axis + * values[0]: Angular speed around the x axis (pitch) + * values[1]: Angular speed around the y axis (yaw) + * values[2]: Angular speed around the z axis (roll) * - * For phones held in portrait mode, the axes are defined as follows: + * For phones held in portrait mode 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 phone or controller is rotated. * * \sa SDL_GetDisplayOrientation() */ diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 278bbdff9..1a583cf53 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -782,3 +782,7 @@ #define SDL_crc32 SDL_crc32_REAL #define SDL_GameControllerGetSerial SDL_GameControllerGetSerial_REAL #define SDL_JoystickGetSerial SDL_JoystickGetSerial_REAL +#define SDL_GameControllerHasSensor SDL_GameControllerHasSensor_REAL +#define SDL_GameControllerSetSensorEnabled SDL_GameControllerSetSensorEnabled_REAL +#define SDL_GameControllerIsSensorEnabled SDL_GameControllerIsSensorEnabled_REAL +#define SDL_GameControllerGetSensorData SDL_GameControllerGetSensorData_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 8847a9ff4..0fd1939ad 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -843,3 +843,7 @@ SDL_DYNAPI_PROC(int,SDL_GameControllerGetTouchpadFinger,(SDL_GameController *a, SDL_DYNAPI_PROC(Uint32,SDL_crc32,(Uint32 a, const void *b, size_t c),(a,b,c),return) SDL_DYNAPI_PROC(const char*,SDL_GameControllerGetSerial,(SDL_GameController *a),(a),return) SDL_DYNAPI_PROC(const char*,SDL_JoystickGetSerial,(SDL_Joystick *a),(a),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerHasSensor,(SDL_GameController *a, SDL_SensorType b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_GameControllerSetSensorEnabled,(SDL_GameController *a, SDL_SensorType b, SDL_bool c),(a,b,c),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerIsSensorEnabled,(SDL_GameController *a, SDL_SensorType b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_GameControllerGetSensorData,(SDL_GameController *a, SDL_SensorType b, float *c, int d),(a,b,c,d),return) diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 89a216467..a90d2b295 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -2059,6 +2059,111 @@ SDL_GameControllerGetTouchpadFinger(SDL_GameController *gamecontroller, int touc } } +/** + * Return whether a game controller has a particular sensor. + */ +SDL_bool +SDL_GameControllerHasSensor(SDL_GameController *gamecontroller, SDL_SensorType type) +{ + SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); + int i; + + if (joystick) { + for (i = 0; i < joystick->nsensors; ++i) { + if (joystick->sensors[i].type == type) { + return SDL_TRUE; + } + } + } + return SDL_FALSE; +} + +/* + * Set whether data reporting for a game controller sensor is enabled + */ +int SDL_GameControllerSetSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type, SDL_bool enabled) +{ + SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); + int i; + + if (!joystick) { + return SDL_InvalidParamError("gamecontroller"); + } + + for (i = 0; i < joystick->nsensors; ++i) { + SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; + + if (sensor->type == type) { + if (sensor->enabled == enabled) { + return 0; + } + + if (enabled) { + if (joystick->nsensors_enabled == 0) { + if (joystick->driver->SetSensorsEnabled(joystick, SDL_TRUE) < 0) { + return -1; + } + } + ++joystick->nsensors_enabled; + } else { + if (joystick->nsensors_enabled == 1) { + if (joystick->driver->SetSensorsEnabled(joystick, SDL_FALSE) < 0) { + return -1; + } + } + --joystick->nsensors_enabled; + } + + sensor->enabled = enabled; + return 0; + } + } + return SDL_Unsupported(); +} + +/* + * Query whether sensor data reporting is enabled for a game controller + */ +SDL_bool SDL_GameControllerIsSensorEnabled(SDL_GameController *gamecontroller, SDL_SensorType type) +{ + SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); + int i; + + if (joystick) { + for (i = 0; i < joystick->nsensors; ++i) { + if (joystick->sensors[i].type == type) { + return joystick->sensors[i].enabled; + } + } + } + return SDL_FALSE; +} + +/* + * Get the current state of a game controller sensor. + */ +int +SDL_GameControllerGetSensorData(SDL_GameController *gamecontroller, SDL_SensorType type, float *data, int num_values) +{ + SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gamecontroller); + int i; + + if (!joystick) { + return SDL_InvalidParamError("gamecontroller"); + } + + for (i = 0; i < joystick->nsensors; ++i) { + SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; + + if (sensor->type == type) { + num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); + SDL_memcpy(data, sensor->data, num_values*sizeof(*data)); + return 0; + } + } + return SDL_Unsupported(); +} + const char * SDL_GameControllerName(SDL_GameController *gamecontroller) { diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 8ee009aac..4c5623e19 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1109,7 +1109,7 @@ SDL_PrivateJoystickShouldIgnoreEvent() void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers) { int ntouchpads = joystick->ntouchpads + 1; - SDL_JoystickTouchpadInfo *touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, sizeof(SDL_JoystickTouchpadInfo)); + SDL_JoystickTouchpadInfo *touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo))); if (touchpads) { SDL_JoystickTouchpadInfo *touchpad = &touchpads[ntouchpads - 1]; SDL_JoystickTouchpadFingerInfo *fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(nfingers, sizeof(SDL_JoystickTouchpadFingerInfo)); @@ -1128,6 +1128,21 @@ void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers) } } +void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type) +{ + int nsensors = joystick->nsensors + 1; + SDL_JoystickSensorInfo *sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo))); + if (sensors) { + SDL_JoystickSensorInfo *sensor = &sensors[nsensors - 1]; + + SDL_zerop(sensor); + sensor->type = type; + + joystick->nsensors = nsensors; + joystick->sensors = sensors; + } +} + void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance) { SDL_JoystickDriver *driver; @@ -2463,8 +2478,8 @@ int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger { SDL_JoystickTouchpadInfo *touchpad_info; SDL_JoystickTouchpadFingerInfo *finger_info; -#if !SDL_EVENTS_DISABLED int posted; +#if !SDL_EVENTS_DISABLED Uint32 event_type; #endif @@ -2544,4 +2559,41 @@ int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger return posted; } +int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, SDL_SensorType type, const float *data, int num_values) +{ + int i; + int posted = 0; + + for (i = 0; i < joystick->nsensors; ++i) { + SDL_JoystickSensorInfo *sensor = &joystick->sensors[i]; + + if (sensor->type == type) { + if (sensor->enabled) { + /* Allow duplicate events, for things like gyro updates */ + + /* Update internal sensor state */ + num_values = SDL_min(num_values, SDL_arraysize(sensor->data)); + SDL_memcpy(sensor->data, data, num_values*sizeof(*data)); + + /* Post the event, if desired */ + posted = 0; +#if !SDL_EVENTS_DISABLED + if (SDL_GetEventState(SDL_CONTROLLERSENSORUPDATE) == SDL_ENABLE) { + SDL_Event event; + event.type = SDL_CONTROLLERSENSORUPDATE; + event.csensor.which = joystick->instance_id; + event.csensor.sensor = type; + num_values = SDL_min(num_values, SDL_arraysize(event.csensor.data)); + SDL_memset(event.csensor.data, 0, sizeof(event.csensor.data)); + SDL_memcpy(event.csensor.data, data, num_values*sizeof(*data)); + posted = SDL_PushEvent(&event) == 1; + } +#endif /* !SDL_EVENTS_DISABLED */ + } + break; + } + } + return posted; +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 2839930d2..2cceb3410 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -109,6 +109,7 @@ extern void SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick); /* Internal event queueing functions */ extern void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers); +extern void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type); extern void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance); extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance); extern int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, @@ -121,6 +122,8 @@ extern int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state); extern int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure); +extern int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, + SDL_SensorType type, const float *data, int num_values); extern void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel); diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 158bb86cd..3ea7d39c1 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -53,6 +53,13 @@ typedef struct _SDL_JoystickTouchpadInfo SDL_JoystickTouchpadFingerInfo *fingers; } SDL_JoystickTouchpadInfo; +typedef struct _SDL_JoystickSensorInfo +{ + SDL_SensorType type; + SDL_bool enabled; + float data[3]; /* If this needs to expand, update SDL_ControllerSensorEvent */ +} SDL_JoystickSensorInfo; + struct _SDL_Joystick { SDL_JoystickID instance_id; /* Device instance, monotonically increasing from 0 */ @@ -78,6 +85,10 @@ struct _SDL_Joystick int ntouchpads; /* Number of touchpads on the joystick */ SDL_JoystickTouchpadInfo *touchpads; /* Current touchpad states */ + int nsensors; /* Number of sensors on the joystick */ + int nsensors_enabled; + SDL_JoystickSensorInfo *sensors; + Uint16 low_frequency_rumble; Uint16 high_frequency_rumble; Uint32 rumble_expiration; @@ -94,6 +105,7 @@ struct _SDL_Joystick SDL_bool is_game_controller; SDL_bool delayed_guide_button; /* SDL_TRUE if this device has the guide button event delayed */ SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */ + struct _SDL_JoystickDriver *driver; struct joystick_hwdata *hwdata; /* Driver dependent information */ @@ -154,6 +166,9 @@ typedef struct _SDL_JoystickDriver SDL_bool (*HasLED)(SDL_Joystick *joystick); int (*SetLED)(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue); + /* Sensor functionality */ + int (*SetSensorsEnabled)(SDL_Joystick *joystick, SDL_bool enabled); + /* Function to update the state of a joystick - called as a device poll. * This function shouldn't update the joystick structure directly, * but instead should call SDL_PrivateJoystick*() to deliver events diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index a00343e7a..a226d3909 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -630,6 +630,12 @@ ANDROID_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 bl return SDL_Unsupported(); } +static int +ANDROID_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void ANDROID_JoystickUpdate(SDL_Joystick * joystick) { @@ -711,6 +717,7 @@ SDL_JoystickDriver SDL_ANDROID_JoystickDriver = ANDROID_JoystickRumbleTriggers, ANDROID_JoystickHasLED, ANDROID_JoystickSetLED, + ANDROID_JoystickSetSensorsEnabled, ANDROID_JoystickUpdate, ANDROID_JoystickClose, ANDROID_JoystickQuit, diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c index c68629ae7..1595acf3c 100644 --- a/src/joystick/bsd/SDL_sysjoystick.c +++ b/src/joystick/bsd/SDL_sysjoystick.c @@ -206,8 +206,8 @@ static void report_free(struct report *); static int numjoysticks = 0; -static int BSD_JoystickOpen(SDL_Joystick * joy, int device_index); -static void BSD_JoystickClose(SDL_Joystick * joy); +static int BSD_JoystickOpen(SDL_Joystick *joy, int device_index); +static void BSD_JoystickClose(SDL_Joystick *joy); static int BSD_JoystickInit(void) @@ -340,7 +340,7 @@ hatval_to_sdl(Sint32 hatval) static int -BSD_JoystickOpen(SDL_Joystick * joy, int device_index) +BSD_JoystickOpen(SDL_Joystick *joy, int device_index) { char *path = joynames[device_index]; struct joystick_hwdata *hw; @@ -532,7 +532,7 @@ desc_failed: } static void -BSD_JoystickUpdate(SDL_Joystick * joy) +BSD_JoystickUpdate(SDL_Joystick *joy) { struct hid_item hitem; struct hid_data *hdata; @@ -666,7 +666,7 @@ BSD_JoystickUpdate(SDL_Joystick * joy) /* Function to close a joystick after use */ static void -BSD_JoystickClose(SDL_Joystick * joy) +BSD_JoystickClose(SDL_Joystick *joy) { if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) { report_free(&joy->hwdata->inreport); @@ -757,13 +757,13 @@ report_free(struct report *r) } static int -BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +BSD_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { return SDL_Unsupported(); } static int -BSD_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +BSD_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } @@ -775,13 +775,19 @@ BSD_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) } static SDL_bool -BSD_JoystickHasLED(SDL_Joystick * joystick) +BSD_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -BSD_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +BSD_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +BSD_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); } @@ -801,6 +807,7 @@ SDL_JoystickDriver SDL_BSD_JoystickDriver = BSD_JoystickRumbleTriggers, BSD_JoystickHasLED, BSD_JoystickSetLED, + BSD_JoystickSetSensorsEnabled, BSD_JoystickUpdate, BSD_JoystickClose, BSD_JoystickQuit, diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c index 408bdab67..8bea24410 100644 --- a/src/joystick/darwin/SDL_sysjoystick.c +++ b/src/joystick/darwin/SDL_sysjoystick.c @@ -940,6 +940,12 @@ DARWIN_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blu return SDL_Unsupported(); } +static int +DARWIN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void DARWIN_JoystickUpdate(SDL_Joystick * joystick) { @@ -1090,6 +1096,7 @@ SDL_JoystickDriver SDL_DARWIN_JoystickDriver = DARWIN_JoystickRumbleTriggers, DARWIN_JoystickHasLED, DARWIN_JoystickSetLED, + DARWIN_JoystickSetSensorsEnabled, DARWIN_JoystickUpdate, DARWIN_JoystickClose, DARWIN_JoystickQuit, diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c index 04d744d2d..a51fb206a 100644 --- a/src/joystick/dummy/SDL_sysjoystick.c +++ b/src/joystick/dummy/SDL_sysjoystick.c @@ -78,42 +78,48 @@ DUMMY_JoystickGetDeviceInstanceID(int device_index) } static int -DUMMY_JoystickOpen(SDL_Joystick * joystick, int device_index) +DUMMY_JoystickOpen(SDL_Joystick *joystick, int device_index) { return SDL_SetError("Logic error: No joysticks available"); } static int -DUMMY_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +DUMMY_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { return SDL_Unsupported(); } static int -DUMMY_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +DUMMY_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } static SDL_bool -DUMMY_JoystickHasLED(SDL_Joystick * joystick) +DUMMY_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -DUMMY_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +DUMMY_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +DUMMY_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); } static void -DUMMY_JoystickUpdate(SDL_Joystick * joystick) +DUMMY_JoystickUpdate(SDL_Joystick *joystick) { } static void -DUMMY_JoystickClose(SDL_Joystick * joystick) +DUMMY_JoystickClose(SDL_Joystick *joystick) { } @@ -143,6 +149,7 @@ SDL_JoystickDriver SDL_DUMMY_JoystickDriver = DUMMY_JoystickRumbleTriggers, DUMMY_JoystickHasLED, DUMMY_JoystickSetLED, + DUMMY_JoystickSetSensorsEnabled, DUMMY_JoystickUpdate, DUMMY_JoystickClose, DUMMY_JoystickQuit, diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c index 74327ab3e..cafea91f7 100644 --- a/src/joystick/emscripten/SDL_sysjoystick.c +++ b/src/joystick/emscripten/SDL_sysjoystick.c @@ -304,7 +304,7 @@ EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index) It returns 0, or -1 if there is an error. */ static int -EMSCRIPTEN_JoystickOpen(SDL_Joystick * joystick, int device_index) +EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index) { SDL_joylist_item *item = JoystickByDeviceIndex(device_index); @@ -336,7 +336,7 @@ EMSCRIPTEN_JoystickOpen(SDL_Joystick * joystick, int device_index) * and update joystick device state. */ static void -EMSCRIPTEN_JoystickUpdate(SDL_Joystick * joystick) +EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick) { EmscriptenGamepadEvent gamepadState; SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata; @@ -378,7 +378,7 @@ EMSCRIPTEN_JoystickUpdate(SDL_Joystick * joystick) /* Function to close a joystick after use */ static void -EMSCRIPTEN_JoystickClose(SDL_Joystick * joystick) +EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick) { SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata; if (item) { @@ -398,13 +398,13 @@ EMSCRIPTEN_JoystickGetDeviceGUID(int device_index) } static int -EMSCRIPTEN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { return SDL_Unsupported(); } static int -EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } @@ -416,13 +416,19 @@ EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) } static SDL_bool -EMSCRIPTEN_JoystickHasLED(SDL_Joystick * joystick) +EMSCRIPTEN_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -EMSCRIPTEN_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); } @@ -442,6 +448,7 @@ SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver = EMSCRIPTEN_JoystickRumbleTriggers, EMSCRIPTEN_JoystickHasLED, EMSCRIPTEN_JoystickSetLED, + EMSCRIPTEN_JoystickSetSensorsEnabled, EMSCRIPTEN_JoystickUpdate, EMSCRIPTEN_JoystickClose, EMSCRIPTEN_JoystickQuit, diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc index 6adb4da3e..31f52ae0e 100644 --- a/src/joystick/haiku/SDL_haikujoystick.cc +++ b/src/joystick/haiku/SDL_haikujoystick.cc @@ -114,14 +114,14 @@ extern "C" return device_index; } - static void HAIKU_JoystickClose(SDL_Joystick * joystick); + static void HAIKU_JoystickClose(SDL_Joystick *joystick); /* Function to open a joystick for use. The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ - static int HAIKU_JoystickOpen(SDL_Joystick * joystick, int device_index) + static int HAIKU_JoystickOpen(SDL_Joystick *joystick, int device_index) { BJoystick *stick; @@ -168,7 +168,7 @@ extern "C" * but instead should call SDL_PrivateJoystick*() to deliver events * and update joystick device state. */ - static void HAIKU_JoystickUpdate(SDL_Joystick * joystick) + static void HAIKU_JoystickUpdate(SDL_Joystick *joystick) { static const Uint8 hat_map[9] = { SDL_HAT_CENTERED, @@ -217,7 +217,7 @@ extern "C" } /* Function to close a joystick after use */ - static void HAIKU_JoystickClose(SDL_Joystick * joystick) + static void HAIKU_JoystickClose(SDL_Joystick *joystick) { if (joystick->hwdata) { joystick->hwdata->stick->Close(); @@ -254,13 +254,13 @@ extern "C" return guid; } - static int HAIKU_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) + static int HAIKU_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { return SDL_Unsupported(); } - static int HAIKU_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) + static int HAIKU_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } @@ -271,12 +271,17 @@ extern "C" return SDL_FALSE; } - static SDL_bool HAIKU_JoystickHasLED(SDL_Joystick * joystick) + static SDL_bool HAIKU_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } - static int HAIKU_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) + static int HAIKU_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) + { + return SDL_Unsupported(); + } + + static int HAIKU_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); } @@ -296,6 +301,7 @@ extern "C" HAIKU_JoystickRumbleTriggers, HAIKU_JoystickHasLED, HAIKU_JoystickSetLED, + HAIKU_JoystickSetSensorsEnabled, HAIKU_JoystickUpdate, HAIKU_JoystickClose, HAIKU_JoystickQuit, diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c index 61688c8b5..d85516ba3 100644 --- a/src/joystick/hidapi/SDL_hidapi_gamecube.c +++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c @@ -381,6 +381,12 @@ HIDAPI_DriverGameCube_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *jo return SDL_Unsupported(); } +static int +HIDAPI_DriverGameCube_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { @@ -423,6 +429,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube = HIDAPI_DriverGameCube_RumbleJoystickTriggers, HIDAPI_DriverGameCube_HasJoystickLED, HIDAPI_DriverGameCube_SetJoystickLED, + HIDAPI_DriverGameCube_SetJoystickSensorsEnabled, HIDAPI_DriverGameCube_CloseJoystick, HIDAPI_DriverGameCube_FreeDevice, NULL, diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index c7d6e25b0..e4056fd28 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -37,6 +37,17 @@ #ifdef SDL_JOYSTICK_HIDAPI_PS4 +/* Define this if you want to log all packets from the controller */ +/*#define DEBUG_PS4_PROTOCOL*/ + +/* Define this if you want to log calibration data */ +/*#define DEBUG_PS4_CALIBRATION*/ + +#define GYRO_RES_PER_DEGREE 1024.0f +#define ACCEL_RES_PER_G 8192.0f + +#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) + typedef enum { k_EPS4ReportIdUsbState = 1, @@ -71,12 +82,12 @@ typedef struct Uint8 ucTriggerLeft; Uint8 ucTriggerRight; Uint8 _rgucPad0[ 3 ]; - Sint16 sGyroX; - Sint16 sGyroY; - Sint16 sGyroZ; - Sint16 sAccelX; - Sint16 sAccelY; - Sint16 sAccelZ; + Uint8 rgucGyroX[2]; + Uint8 rgucGyroY[2]; + Uint8 rgucGyroZ[2]; + Uint8 rgucAccelX[2]; + Uint8 rgucAccelY[2]; + Uint8 rgucAccelZ[2]; Uint8 _rgucPad1[ 5 ]; Uint8 ucBatteryLevel; Uint8 _rgucPad2[ 4 ]; @@ -102,11 +113,20 @@ typedef struct Uint8 ucVolumeSpeaker; } DS4EffectsState_t; +typedef struct { + Sint16 bias; + float sensitivity; +} IMUCalibrationData; + typedef struct { SDL_bool is_dongle; SDL_bool is_bluetooth; + SDL_bool official_controller; SDL_bool audio_supported; SDL_bool effects_supported; + SDL_bool report_sensors; + SDL_bool hardware_calibration; + IMUCalibrationData calibration[6]; int player_index; Uint8 rumble_left; Uint8 rumble_right; @@ -191,6 +211,168 @@ HIDAPI_DriverPS4_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID return -1; } +static void +HIDAPI_DriverPS4_LoadCalibrationData(SDL_HIDAPI_Device *device) +{ + SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context; + int i, tries, size; + SDL_bool have_data = SDL_FALSE; + Uint8 data[USB_PACKET_LENGTH]; + + if (!ctx->official_controller) { +#ifdef DEBUG_PS4_CALIBRATION + SDL_Log("Not an official controller, ignoring calibration\n"); +#endif + return; + } + + for( tries = 0; tries < 5; ++tries ) { + /* For Bluetooth controllers, this report switches them into advanced report mode */ + size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdGyroCalibration_USB, data, sizeof(data)); + if (size < 35) { +#ifdef DEBUG_PS4_CALIBRATION + SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size); +#endif + return; + } + + if (ctx->is_bluetooth) { + size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdGyroCalibration_BT, data, sizeof(data)); + if (size < 35) { +#ifdef DEBUG_PS4_CALIBRATION + SDL_Log("Short read of calibration data: %d, ignoring calibration\n", size); +#endif + return; + } + } + + /* In some cases this report returns all zeros. Usually immediately after connection with the PS4 Dongle */ + for (i = 0; i < size; ++i) { + if (data[i]) { + have_data = SDL_TRUE; + break; + } + } + if (have_data) { + break; + } + + SDL_Delay(2); + } + + if (have_data) { + Sint16 sGyroPitchBias, sGyroYawBias, sGyroRollBias; + Sint16 sGyroPitchPlus, sGyroPitchMinus; + Sint16 sGyroYawPlus, sGyroYawMinus; + Sint16 sGyroRollPlus, sGyroRollMinus; + Sint16 sGyroSpeedPlus, sGyroSpeedMinus; + + Sint16 sAccXPlus, sAccXMinus; + Sint16 sAccYPlus, sAccYMinus; + Sint16 sAccZPlus, sAccZMinus; + + float flNumerator; + Sint16 sRange2g; + +#ifdef DEBUG_PS4_CALIBRATION + HIDAPI_DumpPacket("PS4 calibration packet: size = %d", data, size); +#endif + + sGyroPitchBias = LOAD16(data[1], data[2]); + sGyroYawBias = LOAD16(data[3], data[4]); + sGyroRollBias = LOAD16(data[5], data[6]); + + if (ctx->is_bluetooth || ctx->is_dongle) { + sGyroPitchPlus = LOAD16(data[7], data[8]); + sGyroYawPlus = LOAD16(data[9], data[10]); + sGyroRollPlus = LOAD16(data[11], data[12]); + sGyroPitchMinus = LOAD16(data[13], data[14]); + sGyroYawMinus = LOAD16(data[15], data[16]); + sGyroRollMinus = LOAD16(data[17], data[18]); + } else { + sGyroPitchPlus = LOAD16(data[7], data[8]); + sGyroPitchMinus = LOAD16(data[9], data[10]); + sGyroYawPlus = LOAD16(data[11], data[12]); + sGyroYawMinus = LOAD16(data[13], data[14]); + sGyroRollPlus = LOAD16(data[15], data[16]); + sGyroRollMinus = LOAD16(data[17], data[18]); + } + + sGyroSpeedPlus = LOAD16(data[19], data[20]); + sGyroSpeedMinus = LOAD16(data[21], data[22]); + + sAccXPlus = LOAD16(data[23], data[24]); + sAccXMinus = LOAD16(data[25], data[26]); + sAccYPlus = LOAD16(data[27], data[28]); + sAccYMinus = LOAD16(data[29], data[30]); + sAccZPlus = LOAD16(data[31], data[32]); + sAccZMinus = LOAD16(data[33], data[34]); + + flNumerator = (sGyroSpeedPlus + sGyroSpeedMinus) * GYRO_RES_PER_DEGREE; + ctx->calibration[0].bias = sGyroPitchBias; + ctx->calibration[0].sensitivity = flNumerator / (sGyroPitchPlus - sGyroPitchMinus); + + ctx->calibration[1].bias = sGyroYawBias; + ctx->calibration[1].sensitivity = flNumerator / (sGyroYawPlus - sGyroYawMinus); + + ctx->calibration[2].bias = sGyroRollBias; + ctx->calibration[2].sensitivity = flNumerator / (sGyroRollPlus - sGyroRollMinus); + + sRange2g = sAccXPlus - sAccXMinus; + ctx->calibration[3].bias = sAccXPlus - sRange2g / 2; + ctx->calibration[3].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; + + sRange2g = sAccYPlus - sAccYMinus; + ctx->calibration[4].bias = sAccYPlus - sRange2g / 2; + ctx->calibration[4].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; + + sRange2g = sAccZPlus - sAccZMinus; + ctx->calibration[5].bias = sAccZPlus - sRange2g / 2; + ctx->calibration[5].sensitivity = 2.0f * ACCEL_RES_PER_G / (float)sRange2g; + + ctx->hardware_calibration = SDL_TRUE; + for (i = 0; i < 6; ++i) { + float divisor = (i < 3 ? 64.0f : 1.0f); +#ifdef DEBUG_PS4_CALIBRATION + SDL_Log("calibration[%d] bias = %d, sensitivity = %f\n", i, ctx->calibration[i].bias, ctx->calibration[i].sensitivity); +#endif + /* Some controllers have a bad calibration */ + if ((SDL_abs(ctx->calibration[i].bias) > 1024) || (SDL_fabs(1.0f - ctx->calibration[i].sensitivity / divisor) > 0.5f)) { +#ifdef DEBUG_PS4_CALIBRATION + SDL_Log("invalid calibration, ignoring\n"); +#endif + ctx->hardware_calibration = SDL_FALSE; + } + } + } else { +#ifdef DEBUG_PS4_CALIBRATION + SDL_Log("Calibration data not available\n"); +#endif + } +} + +static float +HIDAPI_DriverPS4_ApplyCalibrationData(SDL_DriverPS4_Context *ctx, int index, Sint16 value) +{ + float result; + + if (ctx->hardware_calibration) { + IMUCalibrationData *calibration = &ctx->calibration[index]; + + result = (value - calibration->bias) * calibration->sensitivity; + } else { + result = value; + } + + /* Convert the raw data to the units expected by SDL */ + if (index < 3) { + result = (result / GYRO_RES_PER_DEGREE) * M_PI / 180.0f; + } else { + result = (result / ACCEL_RES_PER_G) * SDL_STANDARD_GRAVITY; + } + return result; +} + static int HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device) { @@ -286,37 +468,24 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE); if (ctx->is_dongle) { ctx->is_bluetooth = SDL_FALSE; + ctx->official_controller = SDL_TRUE; } else if (device->vendor_id == USB_VENDOR_SONY) { - int i; Uint8 data[USB_PACKET_LENGTH]; - int length; + int size; /* This will fail if we're on Bluetooth */ - length = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data)); - if (length >= 7) { - SDL_bool had_data = SDL_FALSE; - - for (i = 0; i < length; ++i) { - if (data[i] != 0x00) { - had_data = SDL_TRUE; - break; - } - } - - if (had_data) { - char serial[18]; - - SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", - data[6], data[5], data[4], data[3], data[2], data[1]); - joystick->serial = SDL_strdup(serial); - } else { - /* Maybe the dongle without a connected controller? */ - } + size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data)); + if (size >= 7) { + char serial[18]; + SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", + data[6], data[5], data[4], data[3], data[2], data[1]); + joystick->serial = SDL_strdup(serial); ctx->is_bluetooth = SDL_FALSE; } else { ctx->is_bluetooth = SDL_TRUE; } + ctx->official_controller = SDL_TRUE; } else { /* Third party controllers appear to all be wired */ ctx->is_bluetooth = SDL_FALSE; @@ -351,6 +520,8 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; SDL_PrivateJoystickAddTouchpad(joystick, 2); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); return SDL_TRUE; } @@ -391,6 +562,19 @@ HIDAPI_DriverPS4_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystic return HIDAPI_DriverPS4_UpdateEffects(device); } +static int +HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context; + + if (enabled) { + HIDAPI_DriverPS4_LoadCalibrationData(device); + } + ctx->report_sensors = enabled; + + return 0; +} + static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet) { @@ -521,6 +705,20 @@ HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_ touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4); SDL_PrivateJoystickTouchpad(joystick, 0, 1, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f); + if (ctx->report_sensors) { + float data[3]; + + data[0] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1])); + data[1] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1])); + data[2] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1])); + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3); + + data[0] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1])); + data[1] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1])); + data[2] = HIDAPI_DriverPS4_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1])); + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3); + } + SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state)); } @@ -540,6 +738,9 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) } while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { +#ifdef DEBUG_PS4_PROTOCOL + HIDAPI_DumpPacket("PS4 packet: size = %d", data, size); +#endif switch (data[0]) { case k_EPS4ReportIdUsbState: HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]); @@ -603,6 +804,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 = HIDAPI_DriverPS4_RumbleJoystickTriggers, HIDAPI_DriverPS4_HasJoystickLED, HIDAPI_DriverPS4_SetJoystickLED, + HIDAPI_DriverPS4_SetJoystickSensorsEnabled, HIDAPI_DriverPS4_CloseJoystick, HIDAPI_DriverPS4_FreeDevice, NULL diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index 6580a29b3..833a29998 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -72,8 +72,12 @@ typedef struct Uint8 rgucButtonsAndHat[3]; /* 7 */ Uint8 ucZero; /* 10 */ Uint8 rgucPacketSequence[4]; /* 11 - 32 bit little endian */ - Uint8 rgucAccel[6]; /* 15 */ - Uint8 rgucGyro[6]; /* 21 */ + Uint8 rgucGyroX[2]; /* 15 */ + Uint8 rgucGyroY[2]; /* 17 */ + Uint8 rgucGyroZ[2]; /* 19 */ + Uint8 rgucAccelX[2]; /* 21 */ + Uint8 rgucAccelY[2]; /* 23 */ + Uint8 rgucAccelZ[2]; /* 25 */ Uint8 rgucTimer1[4]; /* 27 - 32 bit little endian */ Uint8 ucBatteryTemp; /* 31 */ Uint8 ucTouchpadCounter1; /* 32 - high bit clear + counter */ @@ -351,6 +355,12 @@ HIDAPI_DriverPS5_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystic return HIDAPI_DriverPS5_UpdateEffects(device); } +static int +HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + return 0; +} + static void HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS5_Context *ctx, PS5SimpleStatePacket_t *packet) { @@ -649,6 +659,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 = HIDAPI_DriverPS5_RumbleJoystickTriggers, HIDAPI_DriverPS5_HasJoystickLED, HIDAPI_DriverPS5_SetJoystickLED, + HIDAPI_DriverPS5_SetJoystickSensorsEnabled, HIDAPI_DriverPS5_CloseJoystick, HIDAPI_DriverPS5_FreeDevice, NULL diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c index be3aeb681..0ae4d2243 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam.c +++ b/src/joystick/hidapi/SDL_hidapi_steam.c @@ -1054,6 +1054,13 @@ HIDAPI_DriverSteam_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joyst return SDL_Unsupported(); } +static int +HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + /* You should use the full Steam Input API for sensor support */ + return SDL_Unsupported(); +} + static SDL_bool HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device) { @@ -1191,6 +1198,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam = HIDAPI_DriverSteam_RumbleJoystickTriggers, HIDAPI_DriverSteam_HasJoystickLED, HIDAPI_DriverSteam_SetJoystickLED, + HIDAPI_DriverSteam_SetSensorsEnabled, HIDAPI_DriverSteam_CloseJoystick, HIDAPI_DriverSteam_FreeDevice, NULL diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 0d9c1f208..16e1e242f 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -942,6 +942,12 @@ HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joys return SDL_Unsupported(); } +static int +HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchInputOnlyControllerStatePacket_t *packet) { Sint16 axis; @@ -1298,6 +1304,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch = HIDAPI_DriverSwitch_RumbleJoystickTriggers, HIDAPI_DriverSwitch_HasJoystickLED, HIDAPI_DriverSwitch_SetJoystickLED, + HIDAPI_DriverSwitch_SetJoystickSensorsEnabled, HIDAPI_DriverSwitch_CloseJoystick, HIDAPI_DriverSwitch_FreeDevice, NULL diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c index 77efb4c1a..dfc7c31a4 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c @@ -815,6 +815,12 @@ HIDAPI_DriverXbox360_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joy return SDL_Unsupported(); } +static int +HIDAPI_DriverXbox360_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + #ifdef __WIN32__ /* This is the packet format for Xbox 360 and Xbox One controllers on Windows, however with this interface there is no rumble support, no guide button, @@ -1326,6 +1332,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 = HIDAPI_DriverXbox360_RumbleJoystickTriggers, HIDAPI_DriverXbox360_HasJoystickLED, HIDAPI_DriverXbox360_SetJoystickLED, + HIDAPI_DriverXbox360_SetJoystickSensorsEnabled, HIDAPI_DriverXbox360_CloseJoystick, HIDAPI_DriverXbox360_FreeDevice, HIDAPI_DriverXbox360_PostUpdate, diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c index 3fe06eb2e..294139cf2 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c @@ -176,6 +176,12 @@ HIDAPI_DriverXbox360W_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *jo return SDL_Unsupported(); } +static int +HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void HIDAPI_DriverXbox360W_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360W_Context *ctx, Uint8 *data, int size) { @@ -316,6 +322,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W = HIDAPI_DriverXbox360W_RumbleJoystickTriggers, HIDAPI_DriverXbox360W_HasJoystickLED, HIDAPI_DriverXbox360W_SetJoystickLED, + HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled, HIDAPI_DriverXbox360W_CloseJoystick, HIDAPI_DriverXbox360W_FreeDevice, NULL diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index 9e622dd0a..3f89ac653 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -406,6 +406,12 @@ HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joy return SDL_Unsupported(); } +static int +HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size) { @@ -934,6 +940,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne = HIDAPI_DriverXboxOne_RumbleJoystickTriggers, HIDAPI_DriverXboxOne_HasJoystickLED, HIDAPI_DriverXboxOne_SetJoystickLED, + HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled, HIDAPI_DriverXboxOne_CloseJoystick, HIDAPI_DriverXboxOne_FreeDevice, NULL diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 9d7f65b94..f303440ee 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -1130,6 +1130,23 @@ HIDAPI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blu return result; } +static int +HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick * joystick, SDL_bool enabled) +{ + int result; + + if (joystick->hwdata) { + SDL_HIDAPI_Device *device = joystick->hwdata->device; + + result = device->driver->SetJoystickSensorsEnabled(device, joystick, enabled); + } else { + SDL_SetError("SetSensorsEnabled failed, device disconnected"); + result = -1; + } + + return result; +} + static void HIDAPI_JoystickUpdate(SDL_Joystick * joystick) { @@ -1206,6 +1223,7 @@ SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = HIDAPI_JoystickRumbleTriggers, HIDAPI_JoystickHasLED, HIDAPI_JoystickSetLED, + HIDAPI_JoystickSetSensorsEnabled, HIDAPI_JoystickUpdate, HIDAPI_JoystickClose, HIDAPI_JoystickQuit, diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h index f84c1ec3f..f5c995176 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -99,6 +99,7 @@ typedef struct _SDL_HIDAPI_DeviceDriver int (*RumbleJoystickTriggers)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble); SDL_bool (*HasJoystickLED)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick); int (*SetJoystickLED)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue); + int (*SetJoystickSensorsEnabled)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled); void (*CloseJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick); void (*FreeDevice)(SDL_HIDAPI_Device *device); void (*PostUpdate)(void); diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index 8946762d8..3a4c73f39 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -79,6 +79,7 @@ static id disconnectObserver = nil; #define ENABLE_MFI_BATTERY #define ENABLE_MFI_RUMBLE #define ENABLE_MFI_LIGHT +#define ENABLE_MFI_SENSORS #define ENABLE_PHYSICAL_INPUT_PROFILE #endif @@ -569,7 +570,7 @@ IOS_JoystickGetDeviceInstanceID(int device_index) } static int -IOS_JoystickOpen(SDL_Joystick * joystick, int device_index) +IOS_JoystickOpen(SDL_Joystick *joystick, int device_index) { SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); if (device == NULL) { @@ -611,6 +612,20 @@ IOS_JoystickOpen(SDL_Joystick * joystick, int device_index) } }; } + +#ifdef ENABLE_MFI_SENSORS + if (@available(iOS 14.0, tvOS 14.0, *)) { + GCController *controller = joystick->hwdata->controller; + GCMotion *motion = controller.motion; + if (motion && motion.hasRotationRate) { + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO); + } + if (motion && motion.hasGravityAndUserAcceleration) { + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL); + } + } +#endif /* ENABLE_MFI_SENSORS */ + #endif /* SDL_JOYSTICK_MFI */ } } @@ -622,7 +637,7 @@ IOS_JoystickOpen(SDL_Joystick * joystick, int device_index) } static void -IOS_AccelerometerUpdate(SDL_Joystick * joystick) +IOS_AccelerometerUpdate(SDL_Joystick *joystick) { #if !TARGET_OS_TV const float maxgforce = SDL_IPHONE_MAX_GFORCE; @@ -692,7 +707,7 @@ IOS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad) #endif static void -IOS_MFIJoystickUpdate(SDL_Joystick * joystick) +IOS_MFIJoystickUpdate(SDL_Joystick *joystick) { #if SDL_JOYSTICK_MFI @autoreleasepool { @@ -806,6 +821,31 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick) for (i = 0; i < button_count; i++) { SDL_PrivateJoystickButton(joystick, i, buttons[i]); } + +#ifdef ENABLE_MFI_SENSORS + if (@available(iOS 14.0, tvOS 14.0, *)) { + GCMotion *motion = controller.motion; + if (motion && motion.sensorsActive) { + float data[3]; + + if (motion.hasRotationRate) { + GCRotationRate rate = motion.rotationRate; + data[0] = rate.x; + data[1] = rate.z; + data[2] = -rate.y; + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3); + } + if (motion.hasGravityAndUserAcceleration) { + GCAcceleration accel = motion.acceleration; + data[0] = -accel.x * SDL_STANDARD_GRAVITY; + data[1] = -accel.y * SDL_STANDARD_GRAVITY; + data[2] = -accel.z * SDL_STANDARD_GRAVITY; + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3); + } + } + } +#endif /* ENABLE_MFI_SENSORS */ + } else if (controller.gamepad) { GCGamepad *gamepad = controller.gamepad; @@ -1103,7 +1143,7 @@ static SDL_RumbleContext *IOS_JoystickInitRumble(GCController *controller) #endif /* ENABLE_MFI_RUMBLE */ static int -IOS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +IOS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { #ifdef ENABLE_MFI_RUMBLE SDL_JoystickDeviceItem *device = joystick->hwdata; @@ -1129,7 +1169,7 @@ IOS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 } static int -IOS_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +IOS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { #ifdef ENABLE_MFI_RUMBLE SDL_JoystickDeviceItem *device = joystick->hwdata; @@ -1155,7 +1195,7 @@ IOS_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 r } static SDL_bool -IOS_JoystickHasLED(SDL_Joystick * joystick) +IOS_JoystickHasLED(SDL_Joystick *joystick) { #ifdef ENABLE_MFI_LIGHT @autoreleasepool { @@ -1173,7 +1213,7 @@ IOS_JoystickHasLED(SDL_Joystick * joystick) } static int -IOS_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +IOS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { #ifdef ENABLE_MFI_LIGHT @autoreleasepool { @@ -1193,8 +1233,27 @@ IOS_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) return SDL_Unsupported(); } +static int +IOS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ +#ifdef ENABLE_MFI_SENSORS + @autoreleasepool { + if (@available(iOS 14.0, tvOS 14.0, *)) { + GCController *controller = joystick->hwdata->controller; + GCMotion *motion = controller.motion; + if (motion) { + motion.sensorsActive = enabled ? YES : NO; + return 0; + } + } + } +#endif /* ENABLE_MFI_SENSORS */ + + return SDL_Unsupported(); +} + static void -IOS_JoystickUpdate(SDL_Joystick * joystick) +IOS_JoystickUpdate(SDL_Joystick *joystick) { SDL_JoystickDeviceItem *device = joystick->hwdata; @@ -1210,7 +1269,7 @@ IOS_JoystickUpdate(SDL_Joystick * joystick) } static void -IOS_JoystickClose(SDL_Joystick * joystick) +IOS_JoystickClose(SDL_Joystick *joystick) { SDL_JoystickDeviceItem *device = joystick->hwdata; @@ -1304,6 +1363,7 @@ SDL_JoystickDriver SDL_IOS_JoystickDriver = IOS_JoystickRumbleTriggers, IOS_JoystickHasLED, IOS_JoystickSetLED, + IOS_JoystickSetSensorsEnabled, IOS_JoystickUpdate, IOS_JoystickClose, IOS_JoystickQuit, diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 782f696b1..76b83c6e5 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -764,7 +764,7 @@ LINUX_JoystickGetDeviceInstanceID(int device_index) } static int -allocate_hatdata(SDL_Joystick * joystick) +allocate_hatdata(SDL_Joystick *joystick) { int i; @@ -782,7 +782,7 @@ allocate_hatdata(SDL_Joystick * joystick) } static int -allocate_balldata(SDL_Joystick * joystick) +allocate_balldata(SDL_Joystick *joystick) { int i; @@ -800,7 +800,7 @@ allocate_balldata(SDL_Joystick * joystick) } static void -ConfigJoystick(SDL_Joystick * joystick, int fd) +ConfigJoystick(SDL_Joystick *joystick, int fd) { int i, t; unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; @@ -926,7 +926,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd) It returns 0, or -1 if there is an error. */ static int -LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index) +LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index) { SDL_joylist_item *item = JoystickByDevIndex(device_index); @@ -985,7 +985,7 @@ LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index) } static int -LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { struct input_event event; @@ -1027,25 +1027,31 @@ LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint1 } static int -LINUX_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } static SDL_bool -LINUX_JoystickHasLED(SDL_Joystick * joystick) +LINUX_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -LINUX_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); } static SDL_INLINE void -HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value) +HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value) { struct hwdata_hat *the_hat; const Uint8 position_map[3][3] = { @@ -1070,14 +1076,14 @@ HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value) } static SDL_INLINE void -HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value) +HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value) { stick->hwdata->balls[ball].axis[axis] += value; } static SDL_INLINE int -AxisCorrect(SDL_Joystick * joystick, int which, int value) +AxisCorrect(SDL_Joystick *joystick, int which, int value) { struct axis_correct *correct; @@ -1106,7 +1112,7 @@ AxisCorrect(SDL_Joystick * joystick, int which, int value) } static SDL_INLINE void -PollAllValues(SDL_Joystick * joystick) +PollAllValues(SDL_Joystick *joystick) { struct input_absinfo absinfo; unsigned long keyinfo[NBITS(KEY_MAX)]; @@ -1166,7 +1172,7 @@ PollAllValues(SDL_Joystick * joystick) } static SDL_INLINE void -HandleInputEvents(SDL_Joystick * joystick) +HandleInputEvents(SDL_Joystick *joystick) { struct input_event events[32]; int i, len; @@ -1260,7 +1266,7 @@ HandleInputEvents(SDL_Joystick * joystick) } static void -LINUX_JoystickUpdate(SDL_Joystick * joystick) +LINUX_JoystickUpdate(SDL_Joystick *joystick) { int i; @@ -1287,7 +1293,7 @@ LINUX_JoystickUpdate(SDL_Joystick * joystick) /* Function to close a joystick after use */ static void -LINUX_JoystickClose(SDL_Joystick * joystick) +LINUX_JoystickClose(SDL_Joystick *joystick) { if (joystick->hwdata) { if (joystick->hwdata->effect.id >= 0) { @@ -1345,7 +1351,7 @@ LINUX_JoystickQuit(void) static SDL_bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) { - SDL_Joystick * joystick; + SDL_Joystick *joystick; joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1); if (joystick == NULL) { @@ -1527,6 +1533,7 @@ SDL_JoystickDriver SDL_LINUX_JoystickDriver = LINUX_JoystickRumbleTriggers, LINUX_JoystickHasLED, LINUX_JoystickSetLED, + LINUX_JoystickSetSensorsEnabled, LINUX_JoystickUpdate, LINUX_JoystickClose, LINUX_JoystickQuit, diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c index 9d441d7e8..e140b4fa0 100644 --- a/src/joystick/virtual/SDL_virtualjoystick.c +++ b/src/joystick/virtual/SDL_virtualjoystick.c @@ -358,6 +358,12 @@ VIRTUAL_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 bl return SDL_Unsupported(); } +static int +VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void VIRTUAL_JoystickUpdate(SDL_Joystick * joystick) @@ -432,6 +438,7 @@ SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = VIRTUAL_JoystickRumbleTriggers, VIRTUAL_JoystickHasLED, VIRTUAL_JoystickSetLED, + VIRTUAL_JoystickSetSensorsEnabled, VIRTUAL_JoystickUpdate, VIRTUAL_JoystickClose, VIRTUAL_JoystickQuit, diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c index b8f2d5f5c..4bd0f5d08 100644 --- a/src/joystick/windows/SDL_rawinputjoystick.c +++ b/src/joystick/windows/SDL_rawinputjoystick.c @@ -635,6 +635,12 @@ RAWINPUT_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 b return SDL_Unsupported(); } +static int +RAWINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void RAWINPUT_JoystickUpdate(SDL_Joystick * joystick) @@ -768,6 +774,7 @@ SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver = RAWINPUT_JoystickRumbleTriggers, RAWINPUT_JoystickHasLED, RAWINPUT_JoystickSetLED, + RAWINPUT_JoystickSetSensorsEnabled, RAWINPUT_JoystickUpdate, RAWINPUT_JoystickClose, RAWINPUT_JoystickQuit, diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c index 4aedf0d7a..1af18af72 100644 --- a/src/joystick/windows/SDL_windows_gaming_input.c +++ b/src/joystick/windows/SDL_windows_gaming_input.c @@ -607,6 +607,12 @@ WGI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) return SDL_Unsupported(); } +static int +WGI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static Uint8 ConvertHatValue(__x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition value) { @@ -752,6 +758,7 @@ SDL_JoystickDriver SDL_WGI_JoystickDriver = WGI_JoystickRumbleTriggers, WGI_JoystickHasLED, WGI_JoystickSetLED, + WGI_JoystickSetSensorsEnabled, WGI_JoystickUpdate, WGI_JoystickClose, WGI_JoystickQuit, diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index b66e6c7b3..fb18faa98 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -518,6 +518,12 @@ WINDOWS_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 bl return SDL_Unsupported(); } +static int +WINDOWS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ + return SDL_Unsupported(); +} + static void WINDOWS_JoystickUpdate(SDL_Joystick * joystick) { @@ -604,6 +610,7 @@ SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = WINDOWS_JoystickRumbleTriggers, WINDOWS_JoystickHasLED, WINDOWS_JoystickSetLED, + WINDOWS_JoystickSetSensorsEnabled, WINDOWS_JoystickUpdate, WINDOWS_JoystickClose, WINDOWS_JoystickQuit, diff --git a/src/sensor/coremotion/SDL_coremotionsensor.m b/src/sensor/coremotion/SDL_coremotionsensor.m index 276109f26..0c61df188 100644 --- a/src/sensor/coremotion/SDL_coremotionsensor.m +++ b/src/sensor/coremotion/SDL_coremotionsensor.m @@ -158,9 +158,9 @@ SDL_COREMOTION_SensorUpdate(SDL_Sensor *sensor) if (accelerometerData) { CMAcceleration acceleration = accelerometerData.acceleration; float data[3]; - data[0] = acceleration.x * SDL_STANDARD_GRAVITY; - data[1] = acceleration.y * SDL_STANDARD_GRAVITY; - data[2] = acceleration.z * SDL_STANDARD_GRAVITY; + data[0] = -acceleration.x * SDL_STANDARD_GRAVITY; + data[1] = -acceleration.y * SDL_STANDARD_GRAVITY; + data[2] = -acceleration.z * SDL_STANDARD_GRAVITY; if (SDL_memcmp(data, sensor->hwdata->data, sizeof(data)) != 0) { SDL_PrivateSensorUpdate(sensor, data, SDL_arraysize(data)); SDL_memcpy(sensor->hwdata->data, data, sizeof(data)); diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c index bc1f66dd5..f484e6c4f 100644 --- a/test/testgamecontroller.c +++ b/test/testgamecontroller.c @@ -98,26 +98,48 @@ LoadTexture(SDL_Renderer *renderer, const char *file, SDL_bool transparent) } static void -UpdateWindowTitle() +InitGameController() { const char *name = SDL_GameControllerName(gamecontroller); - const char *serial = SDL_GameControllerGetSerial(gamecontroller); - const char *basetitle = "Game Controller Test: "; - const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + (serial ? 3 + SDL_strlen(serial) : 0) + 1; - char *title = (char *)SDL_malloc(titlelen); - retval = SDL_FALSE; - done = SDL_FALSE; + SDL_Log("Opened game controller %s\n", name); - if (title) { - SDL_snprintf(title, titlelen, "%s%s", basetitle, name); - if (serial) { - SDL_strlcat(title, " (", titlelen); - SDL_strlcat(title, serial, titlelen); - SDL_strlcat(title, ")", titlelen); + if (SDL_GameControllerHasSensor(gamecontroller, SDL_SENSOR_ACCEL)) { + SDL_Log("Enabling accelerometer\n"); + SDL_GameControllerSetSensorEnabled(gamecontroller, SDL_SENSOR_ACCEL, SDL_TRUE); + } + + if (SDL_GameControllerHasSensor(gamecontroller, SDL_SENSOR_GYRO)) { + SDL_Log("Enabling gyro\n"); + SDL_GameControllerSetSensorEnabled(gamecontroller, SDL_SENSOR_GYRO, SDL_TRUE); + } +} + +static void +UpdateWindowTitle() +{ + if (gamecontroller) { + const char *name = SDL_GameControllerName(gamecontroller); + const char *serial = SDL_GameControllerGetSerial(gamecontroller); + const char *basetitle = "Game Controller Test: "; + const size_t titlelen = SDL_strlen(basetitle) + SDL_strlen(name) + (serial ? 3 + SDL_strlen(serial) : 0) + 1; + char *title = (char *)SDL_malloc(titlelen); + + retval = SDL_FALSE; + done = SDL_FALSE; + + if (title) { + SDL_snprintf(title, titlelen, "%s%s", basetitle, name); + if (serial) { + SDL_strlcat(title, " (", titlelen); + SDL_strlcat(title, serial, titlelen); + SDL_strlcat(title, ")", titlelen); + } + SDL_SetWindowTitle(window, title); + SDL_free(title); } - SDL_SetWindowTitle(window, title); - SDL_free(title); + } else { + SDL_SetWindowTitle(window, "Waiting for controller..."); } } @@ -146,10 +168,11 @@ loop(void *arg) if (!gamecontroller) { gamecontroller = SDL_GameControllerOpen(event.cdevice.which); if (gamecontroller) { - UpdateWindowTitle(); + InitGameController(); } else { SDL_Log("Couldn't open controller: %s\n", SDL_GetError()); } + UpdateWindowTitle(); } break; @@ -159,8 +182,9 @@ loop(void *arg) SDL_GameControllerClose(gamecontroller); gamecontroller = SDL_GameControllerOpen(0); if (gamecontroller) { - UpdateWindowTitle(); + InitGameController(); } + UpdateWindowTitle(); } break; @@ -178,6 +202,15 @@ loop(void *arg) event.ctouchpad.pressure); break; + case SDL_CONTROLLERSENSORUPDATE: + SDL_Log("Controller sensor %s: %.2f, %.2f, %.2f\n", + event.csensor.sensor == SDL_SENSOR_ACCEL ? "accelerometer" : + event.csensor.sensor == SDL_SENSOR_GYRO ? "gyro" : "unknown", + event.csensor.data[0], + event.csensor.data[1], + event.csensor.data[2]); + break; + case SDL_CONTROLLERAXISMOTION: SDL_Log("Controller axis %s changed to %d\n", SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)event.caxis.axis), event.caxis.value); break; @@ -414,6 +447,8 @@ main(int argc, char *argv[]) /* !!! FIXME: */ /*SDL_RenderSetLogicalSize(screen, background->w, background->h);*/ + UpdateWindowTitle(); + /* Loop, getting controller events! */ #ifdef __EMSCRIPTEN__ emscripten_set_main_loop_arg(loop, NULL, 0, 1);