24 #include "../../SDL_internal.h" 26 #ifdef SDL_JOYSTICK_HIDAPI 34 #include "../SDL_sysjoystick.h" 38 #ifdef SDL_JOYSTICK_HIDAPI_PS4 40 #define SONY_USB_VID 0x054C 41 #define SONY_DS4_PID 0x05C4 42 #define SONY_DS4_DONGLE_PID 0x0BA0 43 #define SONY_DS4_SLIM_PID 0x09CC 45 #define RAZER_USB_VID 0x1532 46 #define RAZER_PANTHERA_PID 0X0401 47 #define RAZER_PANTHERA_EVO_PID 0x1008 49 #define USB_PACKET_LENGTH 64 51 #define VOLUME_CHECK_INTERVAL_MS (10 * 1000) 55 k_EPS4ReportIdUsbState = 1,
56 k_EPS4ReportIdUsbEffects = 5,
57 k_EPS4ReportIdBluetoothState = 17,
58 k_EPS4ReportIdBluetoothEffects = 17,
59 k_EPS4ReportIdDisconnectMessage = 226,
64 k_ePS4FeatureReportIdGyroCalibration_USB = 0x02,
65 k_ePS4FeatureReportIdGyroCalibration_BT = 0x05,
66 k_ePS4FeatureReportIdSerialNumber = 0x12,
67 } EPS4FeatureReportID;
71 Uint8 ucLeftJoystickX;
72 Uint8 ucLeftJoystickY;
73 Uint8 ucRightJoystickX;
74 Uint8 ucRightJoystickY;
75 Uint8 rgucButtonsHatAndCounter[ 3 ];
88 Uint8 ucTrackpadCounter1;
89 Uint8 rgucTrackpadData1[ 3 ];
90 Uint8 ucTrackpadCounter2;
91 Uint8 rgucTrackpadData2[ 3 ];
103 Uint8 _rgucPad0[ 8 ];
107 Uint8 ucVolumeSpeaker;
118 PS4StatePacket_t last_state;
119 } SDL_DriverPS4_Context;
128 for(i = 0; i < 8; ++
i) {
129 r = (r & 1? 0: (
Uint32)0xEDB88320L) ^ r >> 1;
131 return r ^ (
Uint32)0xFF000000L;
137 for(i = 0; i <
count; ++
i) {
138 crc = crc32_for_byte((
Uint8)crc ^ ((
const Uint8*)data)[i]) ^ crc >> 8;
143 #if defined(__WIN32__) && defined(HAVE_ENDPOINTVOLUME_H) 144 #include "../../core/windows/SDL_windows.h" 147 #define NTDDI_VISTA 0x06000000 149 #ifndef _WIN32_WINNT_VISTA 150 #define _WIN32_WINNT_VISTA 0x0600 155 #define NTDDI_VERSION NTDDI_VISTA 157 #define _WIN32_WINNT _WIN32_WINNT_VISTA 159 #include <mmdeviceapi.h> 160 #include <audioclient.h> 161 #include <endpointvolume.h> 164 #define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} 165 DEFINE_GUID(SDL_CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
166 DEFINE_GUID(SDL_IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
167 DEFINE_GUID(SDL_IID_IAudioEndpointVolume, 0x5CDF2C82, 0x841E, 0x4546, 0x97, 0x22, 0x0C, 0xF7, 0x40, 0x78, 0x22, 0x9A);
172 static float GetSystemVolume(
void)
174 float volume = -1.0f;
176 #if defined(__WIN32__) && defined(HAVE_ENDPOINTVOLUME_H) 179 IMMDeviceEnumerator *pEnumerator;
182 hr = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator,
NULL, CLSCTX_ALL, &SDL_IID_IMMDeviceEnumerator, (LPVOID*)&pEnumerator);
186 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eConsole, &pDevice);
188 IAudioEndpointVolume *pEndpointVolume;
190 hr = IMMDevice_Activate(pDevice, &SDL_IID_IAudioEndpointVolume, CLSCTX_ALL,
NULL, (LPVOID*)&pEndpointVolume);
192 IAudioEndpointVolume_GetMasterVolumeLevelScalar(pEndpointVolume, &volume);
193 IUnknown_Release(pEndpointVolume);
195 IUnknown_Release(pDevice);
197 IUnknown_Release(pEnumerator);
206 static uint8_t GetPlaystationVolumeFromFloat(
float fVolume)
208 const int k_nVolumeFitRatio = 15;
209 const int k_nVolumeFitOffset = 9;
212 if (fVolume > 1.0
f || fVolume < 0.0
f) {
217 return (
Uint8)((fVolLog * k_nVolumeFitRatio) + k_nVolumeFitOffset);
221 HIDAPI_DriverPS4_IsSupportedDevice(
Uint16 vendor_id,
Uint16 product_id,
Uint16 version,
int interface_number)
227 HIDAPI_DriverPS4_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
229 if (vendor_id == SONY_USB_VID) {
230 return "PS4 Controller";
237 Uint8 report[USB_PACKET_LENGTH + 1];
240 report[0] = report_id;
254 if (ReadFeatureReport(dev, k_ePS4FeatureReportIdSerialNumber, data,
sizeof(data))) {
255 for (i = 0; i <
sizeof(
data); ++
i) {
256 if (data[i] != 0x00) {
268 if (vendor_id == RAZER_USB_VID &&
269 (product_id == RAZER_PANTHERA_PID || product_id == RAZER_PANTHERA_EVO_PID)) {
280 SDL_DriverPS4_Context *
ctx;
282 ctx = (SDL_DriverPS4_Context *)
SDL_calloc(1,
sizeof(*ctx));
290 ctx->is_dongle = (vendor_id == SONY_USB_VID && product_id == SONY_DS4_DONGLE_PID);
291 if (ctx->is_dongle) {
293 }
else if (vendor_id == SONY_USB_VID) {
294 ctx->is_bluetooth = !CheckUSBConnected(dev);
300 SDL_Log(
"PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ?
"TRUE" :
"FALSE", ctx->is_bluetooth ?
"TRUE" :
"FALSE");
304 if (vendor_id == SONY_USB_VID &&
305 (product_id == SONY_DS4_SLIM_PID || product_id == SONY_DS4_DONGLE_PID )) {
309 if (HIDAPI_DriverPS4_CanRumble(vendor_id, product_id)) {
310 if (ctx->is_bluetooth) {
318 HIDAPI_DriverPS4_Rumble(joystick, dev, ctx, 0, 0, 0);
329 HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick,
hid_device *dev,
void *context,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble,
Uint32 duration_ms)
331 SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
332 DS4EffectsState_t *effects;
336 if (!ctx->rumble_supported) {
343 if (ctx->is_bluetooth) {
344 data[0] = k_EPS4ReportIdBluetoothEffects;
345 data[1] = 0xC0 | 0x04;
351 data[0] = k_EPS4ReportIdUsbEffects;
357 effects = (DS4EffectsState_t *)&data[offset];
359 effects->ucRumbleLeft = (low_frequency_rumble >> 8);
360 effects->ucRumbleRight = (high_frequency_rumble >> 8);
362 effects->ucLedRed = 0;
363 effects->ucLedGreen = 0;
364 effects->ucLedBlue = 80;
366 if (ctx->audio_supported) {
368 if (!ctx->last_volume_check ||
370 ctx->volume = GetPlaystationVolumeFromFloat(GetSystemVolume());
371 ctx->last_volume_check = now;
374 effects->ucVolumeRight = ctx->volume;
375 effects->ucVolumeLeft = ctx->volume;
376 effects->ucVolumeSpeaker = ctx->volume;
377 effects->ucVolumeMic = 0xFF;
380 if (ctx->is_bluetooth) {
384 unCRC = crc32(0, &ubHdr, 1);
385 unCRC = crc32(unCRC, data, (
Uint32)(report_size -
sizeof(unCRC)));
386 SDL_memcpy(&data[report_size -
sizeof(unCRC)], &unCRC,
sizeof(unCRC));
389 if (
hid_write(dev, data, report_size) != report_size) {
393 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
396 ctx->rumble_expiration = 0;
402 HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick,
hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet)
406 if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
408 Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
416 Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
461 if (ctx->last_state.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
462 Uint8 data = packet->rgucButtonsHatAndCounter[1];
472 if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
473 Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
478 axis = ((int)packet->ucTriggerLeft * 257) - 32768;
480 axis = ((int)packet->ucTriggerRight * 257) - 32768;
482 axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
484 axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
486 axis = ((int)packet->ucRightJoystickX * 257) - 32768;
488 axis = ((int)packet->ucRightJoystickY * 257) - 32768;
491 if (packet->ucBatteryLevel & 0x10) {
495 int level = (packet->ucBatteryLevel & 0xF);
498 }
else if (level <= 2) {
500 }
else if (level <= 7) {
507 SDL_memcpy(&ctx->last_state, packet,
sizeof(ctx->last_state));
511 HIDAPI_DriverPS4_Update(SDL_Joystick *joystick,
hid_device *dev,
void *context)
513 SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
514 Uint8 data[USB_PACKET_LENGTH];
519 case k_EPS4ReportIdUsbState:
520 HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[1]);
522 case k_EPS4ReportIdBluetoothState:
524 HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[3]);
527 #ifdef DEBUG_JOYSTICK 528 SDL_Log(
"Unknown PS4 packet: 0x%.2x\n", data[0]);
534 if (ctx->rumble_expiration) {
537 HIDAPI_DriverPS4_Rumble(joystick, dev, context, 0, 0, 0);
545 HIDAPI_DriverPS4_Quit(SDL_Joystick *joystick,
hid_device *dev,
void *context)
554 HIDAPI_DriverPS4_IsSupportedDevice,
555 HIDAPI_DriverPS4_GetDeviceName,
556 HIDAPI_DriverPS4_Init,
557 HIDAPI_DriverPS4_Rumble,
558 HIDAPI_DriverPS4_Update,
559 HIDAPI_DriverPS4_Quit
GLdouble GLdouble GLdouble r
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4
#define SDL_HINT_JOYSTICK_HIDAPI_PS4
A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
SDL_bool SDL_IsJoystickPS4(Uint16 vendor, Uint16 product)
GLuint GLuint GLsizei count
static screen_context_t context
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE
A variable controlling whether extended input reports should be used for PS4 controllers when using t...
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
Write an Output report to a HID device.
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
#define SDL_GetHintBoolean
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
HRESULT WIN_CoInitialize(void)
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
Get a feature report from a HID device.
struct hid_device_ hid_device
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
#define SDL_OutOfMemory()
void WIN_CoUninitialize(void)
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
#define SDL_Unsupported()