Added API for sensors on game controllers

Added support for the PS4 controller gyro and accelerometer on iOS and HIDAPI drivers

Also fixed an issue with the accelerometer on iOS having inverted axes
This commit is contained in:
Sam Lantinga
2020-11-17 10:30:20 -08:00
parent b79e1baa36
commit fcb21aa883
33 changed files with 810 additions and 118 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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: */

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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));