diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index 4e3235580..6b29a1d9d 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -46,6 +46,7 @@ #define GYRO_RES_PER_DEGREE 1024.0f #define ACCEL_RES_PER_G 8192.0f +#define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500 #define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8)) @@ -131,6 +132,7 @@ typedef struct { SDL_bool report_sensors; SDL_bool hardware_calibration; IMUCalibrationData calibration[6]; + Uint32 last_packet; int player_index; Uint8 rumble_left; Uint8 rumble_right; @@ -440,6 +442,20 @@ HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device) return 0; } +static void +HIDAPI_DriverPS4_TickleBluetooth(SDL_HIDAPI_Device *device) +{ + /* This is just a dummy packet that should have no effect, since we don't set the CRC */ + Uint8 data[78]; + + SDL_zero(data); + + data[0] = k_EPS4ReportIdBluetoothEffects; + data[1] = 0xC0; /* Magic value HID + CRC */ + + SDL_HIDAPI_SendRumble(device, data, sizeof(data)); +} + static void HIDAPI_DriverPS4_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { @@ -494,6 +510,7 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) } ctx->device = device; ctx->joystick = joystick; + ctx->last_packet = SDL_GetTicks(); device->dev = hid_open_path(device->path, 0); if (!device->dev) { @@ -804,6 +821,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) SDL_Joystick *joystick = NULL; Uint8 data[USB_PACKET_LENGTH*2]; int size; + int packet_count = 0; if (device->num_joysticks > 0) { joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); @@ -816,6 +834,9 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) #ifdef DEBUG_PS4_PROTOCOL HIDAPI_DumpPacket("PS4 packet: size = %d", data, size); #endif + ++packet_count; + ctx->last_packet = SDL_GetTicks(); + switch (data[0]) { case k_EPS4ReportIdUsbState: HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]); @@ -846,6 +867,14 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) } } + if (ctx->is_bluetooth && packet_count == 0) { + /* Check to see if it looks like the device disconnected */ + if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { + /* Send an empty output report to tickle the Bluetooth stack */ + HIDAPI_DriverPS4_TickleBluetooth(device); + } + } + if (size < 0) { /* Read error, device is disconnected */ HIDAPI_JoystickDisconnected(device, joystick->instance_id); diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index 5b7553be7..974dc2902 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -507,6 +507,20 @@ HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device) } } +static void +HIDAPI_DriverPS5_TickleBluetooth(SDL_HIDAPI_Device *device) +{ + /* This is just a dummy packet that should have no effect, since we don't set the CRC */ + Uint8 data[78]; + + SDL_zero(data); + + data[0] = k_EPS5ReportIdBluetoothEffects; + data[1] = 0x02; /* Magic value */ + + SDL_HIDAPI_SendRumble(device, data, sizeof(data)); +} + static void HIDAPI_DriverPS5_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { @@ -991,7 +1005,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) /* Check to see if it looks like the device disconnected */ if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) { /* Send an empty output report to tickle the Bluetooth stack */ - HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectNone); + HIDAPI_DriverPS5_TickleBluetooth(device); } }