|
@@ -30,6 +30,7 @@
|
|
|
#include "SDL_timer.h"
|
|
|
#include "SDL_joystick.h"
|
|
|
#include "SDL_gamecontroller.h"
|
|
|
+#include "../../SDL_hints_c.h"
|
|
|
#include "../SDL_sysjoystick.h"
|
|
|
#include "SDL_hidapijoystick_c.h"
|
|
|
#include "SDL_hidapi_rumble.h"
|
|
@@ -119,11 +120,14 @@ typedef struct {
|
|
|
} IMUCalibrationData;
|
|
|
|
|
|
typedef struct {
|
|
|
+ SDL_HIDAPI_Device *device;
|
|
|
+ SDL_Joystick *joystick;
|
|
|
SDL_bool is_dongle;
|
|
|
SDL_bool is_bluetooth;
|
|
|
SDL_bool official_controller;
|
|
|
SDL_bool audio_supported;
|
|
|
SDL_bool effects_supported;
|
|
|
+ SDL_bool enhanced_mode;
|
|
|
SDL_bool report_sensors;
|
|
|
SDL_bool hardware_calibration;
|
|
|
IMUCalibrationData calibration[6];
|
|
@@ -387,6 +391,10 @@ HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device)
|
|
|
return SDL_Unsupported();
|
|
|
}
|
|
|
|
|
|
+ if (!ctx->enhanced_mode) {
|
|
|
+ return SDL_Unsupported();
|
|
|
+ }
|
|
|
+
|
|
|
SDL_zero(data);
|
|
|
|
|
|
if (ctx->is_bluetooth) {
|
|
@@ -432,6 +440,32 @@ HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+HIDAPI_DriverPS4_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
|
+{
|
|
|
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
|
|
+
|
|
|
+ if (!ctx->enhanced_mode) {
|
|
|
+ ctx->enhanced_mode = SDL_TRUE;
|
|
|
+
|
|
|
+ SDL_PrivateJoystickAddTouchpad(joystick, 2);
|
|
|
+ SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO);
|
|
|
+ SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL);
|
|
|
+
|
|
|
+ HIDAPI_DriverPS4_UpdateEffects(device);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void SDLCALL SDL_PS4RumbleHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
|
|
+{
|
|
|
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)userdata;
|
|
|
+
|
|
|
+ /* This is a one-way trip, you can't switch the controller back to simple report mode */
|
|
|
+ if (SDL_GetStringBoolean(hint, SDL_FALSE)) {
|
|
|
+ HIDAPI_DriverPS4_SetEnhancedMode(ctx->device, ctx->joystick);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
|
|
{
|
|
@@ -451,12 +485,15 @@ static SDL_bool
|
|
|
HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
|
{
|
|
|
SDL_DriverPS4_Context *ctx;
|
|
|
+ SDL_bool enhanced_mode = SDL_FALSE;
|
|
|
|
|
|
ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
|
|
|
if (!ctx) {
|
|
|
SDL_OutOfMemory();
|
|
|
return SDL_FALSE;
|
|
|
}
|
|
|
+ ctx->device = device;
|
|
|
+ ctx->joystick = joystick;
|
|
|
|
|
|
device->dev = hid_open_path(device->path, 0);
|
|
|
if (!device->dev) {
|
|
@@ -471,6 +508,7 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
|
if (ctx->is_dongle) {
|
|
|
ctx->is_bluetooth = SDL_FALSE;
|
|
|
ctx->official_controller = SDL_TRUE;
|
|
|
+ enhanced_mode = SDL_TRUE;
|
|
|
} else if (device->vendor_id == USB_VENDOR_SONY) {
|
|
|
Uint8 data[USB_PACKET_LENGTH];
|
|
|
int size;
|
|
@@ -484,13 +522,30 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
|
data[6], data[5], data[4], data[3], data[2], data[1]);
|
|
|
joystick->serial = SDL_strdup(serial);
|
|
|
ctx->is_bluetooth = SDL_FALSE;
|
|
|
+ enhanced_mode = SDL_TRUE;
|
|
|
} else {
|
|
|
ctx->is_bluetooth = SDL_TRUE;
|
|
|
+
|
|
|
+ /* Read a report to see if we're in enhanced mode */
|
|
|
+ size = hid_read_timeout(device->dev, data, sizeof(data), 16);
|
|
|
+#ifdef DEBUG_PS4_PROTOCOL
|
|
|
+ if (size > 0) {
|
|
|
+ HIDAPI_DumpPacket("PS4 first packet: size = %d", data, size);
|
|
|
+ } else {
|
|
|
+ SDL_Log("PS4 first packet: size = %d\n", size);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ if (size > 0 &&
|
|
|
+ data[0] >= k_EPS4ReportIdBluetoothState1 &&
|
|
|
+ data[0] <= k_EPS4ReportIdBluetoothState9) {
|
|
|
+ enhanced_mode = SDL_TRUE;
|
|
|
+ }
|
|
|
}
|
|
|
ctx->official_controller = SDL_TRUE;
|
|
|
} else {
|
|
|
/* Third party controllers appear to all be wired */
|
|
|
ctx->is_bluetooth = SDL_FALSE;
|
|
|
+ enhanced_mode = SDL_TRUE;
|
|
|
}
|
|
|
#ifdef DEBUG_PS4
|
|
|
SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
|
|
@@ -503,28 +558,42 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
|
}
|
|
|
|
|
|
if (HIDAPI_DriverPS4_CanRumble(device->vendor_id, device->product_id)) {
|
|
|
- if (ctx->is_bluetooth) {
|
|
|
- ctx->effects_supported = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE);
|
|
|
- } else {
|
|
|
- ctx->effects_supported = SDL_TRUE;
|
|
|
+ ctx->effects_supported = SDL_TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) {
|
|
|
+ int i, j;
|
|
|
+ char serial[18];
|
|
|
+
|
|
|
+ j = -1;
|
|
|
+ for (i = 0; i < 12; i += 2) {
|
|
|
+ j += 1;
|
|
|
+ SDL_memcpy(&serial[j], &device->serial[i], 2);
|
|
|
+ j += 2;
|
|
|
+ serial[j] = '-';
|
|
|
}
|
|
|
+ serial[j] = '\0';
|
|
|
+
|
|
|
+ joystick->serial = SDL_strdup(serial);
|
|
|
}
|
|
|
|
|
|
/* Initialize player index (needed for setting LEDs) */
|
|
|
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
|
|
|
|
|
|
- /* Initialize LED and effect state */
|
|
|
- HIDAPI_DriverPS4_UpdateEffects(device);
|
|
|
-
|
|
|
- /* Initialize the joystick capabilities */
|
|
|
+ /* Initialize the joystick capabilities
|
|
|
+ *
|
|
|
+ * We can't dynamically add the touchpad button, so always report it here
|
|
|
+ */
|
|
|
joystick->nbuttons = 16;
|
|
|
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
|
|
- joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
|
|
-
|
|
|
- SDL_PrivateJoystickAddTouchpad(joystick, 2);
|
|
|
- SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO);
|
|
|
- SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL);
|
|
|
+ joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
|
|
|
|
|
|
+ if (enhanced_mode) {
|
|
|
+ HIDAPI_DriverPS4_SetEnhancedMode(device, joystick);
|
|
|
+ } else {
|
|
|
+ SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE,
|
|
|
+ SDL_PS4RumbleHintChanged, ctx);
|
|
|
+ }
|
|
|
return SDL_TRUE;
|
|
|
}
|
|
|
|
|
@@ -569,6 +638,10 @@ HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joysti
|
|
|
{
|
|
|
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
|
|
|
|
|
+ if (!ctx->enhanced_mode) {
|
|
|
+ return SDL_Unsupported();
|
|
|
+ }
|
|
|
+
|
|
|
if (enabled) {
|
|
|
HIDAPI_DriverPS4_LoadCalibrationData(device);
|
|
|
}
|
|
@@ -729,7 +802,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
|
|
|
{
|
|
|
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
|
|
SDL_Joystick *joystick = NULL;
|
|
|
- Uint8 data[USB_PACKET_LENGTH];
|
|
|
+ Uint8 data[USB_PACKET_LENGTH*2];
|
|
|
int size;
|
|
|
|
|
|
if (device->num_joysticks > 0) {
|
|
@@ -756,6 +829,10 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
|
|
|
case k_EPS4ReportIdBluetoothState7:
|
|
|
case k_EPS4ReportIdBluetoothState8:
|
|
|
case k_EPS4ReportIdBluetoothState9:
|
|
|
+ if (!ctx->enhanced_mode) {
|
|
|
+ /* This is the extended report, we can enable effects now */
|
|
|
+ HIDAPI_DriverPS4_SetEnhancedMode(device, joystick);
|
|
|
+ }
|
|
|
/* Bluetooth state packets have two additional bytes at the beginning, the first notes if HID is present */
|
|
|
if (data[1] & 0x80) {
|
|
|
HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t*)&data[3]);
|
|
@@ -779,6 +856,11 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
|
|
|
static void
|
|
|
HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
|
{
|
|
|
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
|
|
+
|
|
|
+ SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE,
|
|
|
+ SDL_PS4RumbleHintChanged, ctx);
|
|
|
+
|
|
|
hid_close(device->dev);
|
|
|
device->dev = NULL;
|
|
|
|