|
@@ -117,6 +117,14 @@ typedef struct
|
|
|
Uint8 ucVolumeSpeaker;
|
|
Uint8 ucVolumeSpeaker;
|
|
|
} DS4EffectsState_t;
|
|
} DS4EffectsState_t;
|
|
|
|
|
|
|
|
|
|
+// These enum values match with the validity flags in the PS4 output report
|
|
|
|
|
+typedef enum
|
|
|
|
|
+{
|
|
|
|
|
+ k_EPS4EffectRumble = (1 << 0),
|
|
|
|
|
+ k_EPS4EffectLED = (1 << 1),
|
|
|
|
|
+ k_EPS4EffectLEDBlink = (1 << 2),
|
|
|
|
|
+} EPS4Effect;
|
|
|
|
|
+
|
|
|
typedef struct
|
|
typedef struct
|
|
|
{
|
|
{
|
|
|
Sint16 bias;
|
|
Sint16 bias;
|
|
@@ -178,7 +186,7 @@ typedef struct
|
|
|
PS4StatePacket_t last_state;
|
|
PS4StatePacket_t last_state;
|
|
|
} SDL_DriverPS4_Context;
|
|
} SDL_DriverPS4_Context;
|
|
|
|
|
|
|
|
-static bool HIDAPI_DriverPS4_InternalSendJoystickEffect(SDL_DriverPS4_Context *ctx, const void *effect, int size, bool application_usage);
|
|
|
|
|
|
|
+static bool HIDAPI_DriverPS4_InternalSendJoystickEffect(SDL_DriverPS4_Context *ctx, const void *effect, int size, EPS4Effect mask, bool application_usage);
|
|
|
|
|
|
|
|
static void HIDAPI_DriverPS4_RegisterHints(SDL_HintCallback callback, void *userdata)
|
|
static void HIDAPI_DriverPS4_RegisterHints(SDL_HintCallback callback, void *userdata)
|
|
|
{
|
|
{
|
|
@@ -661,7 +669,7 @@ static float HIDAPI_DriverPS4_ApplyCalibrationData(SDL_DriverPS4_Context *ctx, i
|
|
|
return ((float)value - calibration->bias) * calibration->scale;
|
|
return ((float)value - calibration->bias) * calibration->scale;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static bool HIDAPI_DriverPS4_UpdateEffects(SDL_DriverPS4_Context *ctx, bool application_usage)
|
|
|
|
|
|
|
+static bool HIDAPI_DriverPS4_UpdateEffects(SDL_DriverPS4_Context *ctx, EPS4Effect mask, bool application_usage)
|
|
|
{
|
|
{
|
|
|
DS4EffectsState_t effects;
|
|
DS4EffectsState_t effects;
|
|
|
|
|
|
|
@@ -682,7 +690,7 @@ static bool HIDAPI_DriverPS4_UpdateEffects(SDL_DriverPS4_Context *ctx, bool appl
|
|
|
SetLedsForPlayerIndex(&effects, ctx->player_index);
|
|
SetLedsForPlayerIndex(&effects, ctx->player_index);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- return HIDAPI_DriverPS4_InternalSendJoystickEffect(ctx, &effects, sizeof(effects), application_usage);
|
|
|
|
|
|
|
+ return HIDAPI_DriverPS4_InternalSendJoystickEffect(ctx, &effects, sizeof(effects), mask, application_usage);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void HIDAPI_DriverPS4_TickleBluetooth(SDL_HIDAPI_Device *device)
|
|
static void HIDAPI_DriverPS4_TickleBluetooth(SDL_HIDAPI_Device *device)
|
|
@@ -749,7 +757,7 @@ static void HIDAPI_DriverPS4_SetEnhancedMode(SDL_DriverPS4_Context *ctx)
|
|
|
ctx->enhanced_mode = true;
|
|
ctx->enhanced_mode = true;
|
|
|
|
|
|
|
|
// Switch into enhanced report mode
|
|
// Switch into enhanced report mode
|
|
|
- HIDAPI_DriverPS4_UpdateEffects(ctx, false);
|
|
|
|
|
|
|
+ HIDAPI_DriverPS4_UpdateEffects(ctx, 0, false);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -825,7 +833,7 @@ static void SDLCALL SDL_PS4ReportIntervalHintChanged(void *userdata, const char
|
|
|
if (new_report_interval != ctx->report_interval) {
|
|
if (new_report_interval != ctx->report_interval) {
|
|
|
ctx->report_interval = (Uint8)new_report_interval;
|
|
ctx->report_interval = (Uint8)new_report_interval;
|
|
|
|
|
|
|
|
- HIDAPI_DriverPS4_UpdateEffects(ctx, false);
|
|
|
|
|
|
|
+ HIDAPI_DriverPS4_UpdateEffects(ctx, 0, false);
|
|
|
SDL_LockJoysticks();
|
|
SDL_LockJoysticks();
|
|
|
SDL_PrivateJoystickSensorRate(ctx->joystick, SDL_SENSOR_GYRO, (float)(1000 / ctx->report_interval));
|
|
SDL_PrivateJoystickSensorRate(ctx->joystick, SDL_SENSOR_GYRO, (float)(1000 / ctx->report_interval));
|
|
|
SDL_PrivateJoystickSensorRate(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
|
|
SDL_PrivateJoystickSensorRate(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
|
|
@@ -845,7 +853,7 @@ static void HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL
|
|
|
|
|
|
|
|
// This will set the new LED state based on the new player index
|
|
// This will set the new LED state based on the new player index
|
|
|
// SDL automatically calls this, so it doesn't count as an application action to enable enhanced mode
|
|
// SDL automatically calls this, so it doesn't count as an application action to enable enhanced mode
|
|
|
- HIDAPI_DriverPS4_UpdateEffects(ctx, false);
|
|
|
|
|
|
|
+ HIDAPI_DriverPS4_UpdateEffects(ctx, k_EPS4EffectLED, false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
static bool HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|
@@ -892,7 +900,7 @@ static bool HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joyst
|
|
|
ctx->rumble_left = (low_frequency_rumble >> 8);
|
|
ctx->rumble_left = (low_frequency_rumble >> 8);
|
|
|
ctx->rumble_right = (high_frequency_rumble >> 8);
|
|
ctx->rumble_right = (high_frequency_rumble >> 8);
|
|
|
|
|
|
|
|
- return HIDAPI_DriverPS4_UpdateEffects(ctx, true);
|
|
|
|
|
|
|
+ return HIDAPI_DriverPS4_UpdateEffects(ctx, k_EPS4EffectRumble, true);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool HIDAPI_DriverPS4_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
|
static bool HIDAPI_DriverPS4_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
|
@@ -930,10 +938,10 @@ static bool HIDAPI_DriverPS4_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joyst
|
|
|
ctx->led_green = green;
|
|
ctx->led_green = green;
|
|
|
ctx->led_blue = blue;
|
|
ctx->led_blue = blue;
|
|
|
|
|
|
|
|
- return HIDAPI_DriverPS4_UpdateEffects(ctx, true);
|
|
|
|
|
|
|
+ return HIDAPI_DriverPS4_UpdateEffects(ctx, k_EPS4EffectLED, true);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static bool HIDAPI_DriverPS4_InternalSendJoystickEffect(SDL_DriverPS4_Context *ctx, const void *effect, int size, bool application_usage)
|
|
|
|
|
|
|
+static bool HIDAPI_DriverPS4_InternalSendJoystickEffect(SDL_DriverPS4_Context *ctx, const void *effect, int size, EPS4Effect mask, bool application_usage)
|
|
|
{
|
|
{
|
|
|
Uint8 data[78];
|
|
Uint8 data[78];
|
|
|
int report_size, offset;
|
|
int report_size, offset;
|
|
@@ -959,13 +967,21 @@ static bool HIDAPI_DriverPS4_InternalSendJoystickEffect(SDL_DriverPS4_Context *c
|
|
|
if (ctx->device->is_bluetooth && ctx->official_controller) {
|
|
if (ctx->device->is_bluetooth && ctx->official_controller) {
|
|
|
data[0] = k_EPS4ReportIdBluetoothEffects;
|
|
data[0] = k_EPS4ReportIdBluetoothEffects;
|
|
|
data[1] = 0xC0 | ctx->report_interval; // Magic value HID + CRC, also sets update interval
|
|
data[1] = 0xC0 | ctx->report_interval; // Magic value HID + CRC, also sets update interval
|
|
|
- data[3] = 0x03; // 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Some third-party PS4 gamepads expect to receive both rumble and LED together,
|
|
|
|
|
+ // so we will only send them separately to official Sony gamepads. Unfortunately,
|
|
|
|
|
+ // this means that we'll fight with other apps that might be controlling one or
|
|
|
|
|
+ // the other separately for third-party PS4 gamepads. We can add a whitelist for
|
|
|
|
|
+ // compatible third-party gamepads later if we want.
|
|
|
|
|
+ data[3] = (Uint8)(ctx->official_controller ? mask : (k_EPS4EffectRumble | k_EPS4EffectLED));
|
|
|
|
|
|
|
|
report_size = 78;
|
|
report_size = 78;
|
|
|
offset = 6;
|
|
offset = 6;
|
|
|
} else {
|
|
} else {
|
|
|
data[0] = k_EPS4ReportIdUsbEffects;
|
|
data[0] = k_EPS4ReportIdUsbEffects;
|
|
|
- data[1] = 0x07; // Magic value
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // FIXME: Should we send a consistent default effect mask between BT and USB?
|
|
|
|
|
+ data[1] = (Uint8)(ctx->official_controller ? mask : (k_EPS4EffectRumble | k_EPS4EffectLED | k_EPS4EffectLEDBlink));
|
|
|
|
|
|
|
|
report_size = 32;
|
|
report_size = 32;
|
|
|
offset = 4;
|
|
offset = 4;
|
|
@@ -991,8 +1007,18 @@ static bool HIDAPI_DriverPS4_InternalSendJoystickEffect(SDL_DriverPS4_Context *c
|
|
|
static bool HIDAPI_DriverPS4_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size)
|
|
static bool HIDAPI_DriverPS4_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size)
|
|
|
{
|
|
{
|
|
|
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
|
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
|
|
|
|
+ EPS4Effect mask;
|
|
|
|
|
+
|
|
|
|
|
+ // Unlike the PS5 driver, the PS4 driver does not expect the validity bits as part of
|
|
|
|
|
+ // the provided effect data. The default values we provide also diverge for different
|
|
|
|
|
+ // gamepads and connection mediums. We should probably clean this up eventually.
|
|
|
|
|
+ if (ctx->device->is_bluetooth && ctx->official_controller) {
|
|
|
|
|
+ mask = k_EPS4EffectRumble | k_EPS4EffectLED;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mask = k_EPS4EffectRumble | k_EPS4EffectLED | k_EPS4EffectLEDBlink;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return HIDAPI_DriverPS4_InternalSendJoystickEffect(ctx, effect, size, true);
|
|
|
|
|
|
|
+ return HIDAPI_DriverPS4_InternalSendJoystickEffect(ctx, effect, size, mask, true);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
|
|
static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
|