src/joystick/hidapi/SDL_hidapi_ps4.c
author Sam Lantinga
Sat, 08 Jun 2019 14:32:19 -0700
changeset 12790 5196f7a4d659
parent 12787 0411f841b035
child 12896 b91647e1a977
permissions -rw-r--r--
Fixed bug 4600 - Dualshock 4 touchpad press is not detectable with SDL_JoystickGetButton

Dexter Friedman

When using a Dualshock 4 controller (model numbers CUH-ZCT1U and CUH-ZCT2U), pressing anywhere on the center touchpad does not send an SDL_JOYBUTTONDOWN event. I have verified this with testjoystick:

Repro steps:
1. Plug in a DS4 over USB
2. Compile testjoystick and run: testjoystick.exe 0
3. Press and hold the touchpad. Observe that no lime green box appears

Expected behavior:
A lime green box appears while the touchpad is pressed.

Notes:
I've attached a patch here that works on my PC and produces the expected behavior in testjoystick, for both DS4 model numbers I listed earlier.

If I understand correctly, by exposing this as a joystick button, the gamecontroller API mapping can be modified with a change to gamecontrollerdb.txt in the future.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 /* This driver supports both simplified reports and the extended input reports enabled by Steam.
    22    Code and logic contributed by Valve Corporation under the SDL zlib license.
    23 */
    24 #include "../../SDL_internal.h"
    25 
    26 #ifdef SDL_JOYSTICK_HIDAPI
    27 
    28 #include "SDL_hints.h"
    29 #include "SDL_log.h"
    30 #include "SDL_events.h"
    31 #include "SDL_timer.h"
    32 #include "SDL_joystick.h"
    33 #include "SDL_gamecontroller.h"
    34 #include "../SDL_sysjoystick.h"
    35 #include "SDL_hidapijoystick_c.h"
    36 
    37 
    38 #ifdef SDL_JOYSTICK_HIDAPI_PS4
    39 
    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
    44 
    45 #define RAZER_USB_VID       0x1532
    46 #define RAZER_PANTHERA_PID  0X0401
    47 #define RAZER_PANTHERA_EVO_PID  0x1008
    48 
    49 #define USB_PACKET_LENGTH   64
    50 
    51 #define VOLUME_CHECK_INTERVAL_MS    (10 * 1000)
    52 
    53 typedef enum
    54 {
    55     k_EPS4ReportIdUsbState = 1,
    56     k_EPS4ReportIdUsbEffects = 5,
    57     k_EPS4ReportIdBluetoothState = 17,
    58     k_EPS4ReportIdBluetoothEffects = 17,
    59     k_EPS4ReportIdDisconnectMessage = 226,
    60 } EPS4ReportId;
    61 
    62 typedef enum 
    63 {
    64     k_ePS4FeatureReportIdGyroCalibration_USB = 0x02,
    65     k_ePS4FeatureReportIdGyroCalibration_BT = 0x05,
    66     k_ePS4FeatureReportIdSerialNumber = 0x12,
    67 } EPS4FeatureReportID;
    68 
    69 typedef struct
    70 {
    71     Uint8 ucLeftJoystickX;
    72     Uint8 ucLeftJoystickY;
    73     Uint8 ucRightJoystickX;
    74     Uint8 ucRightJoystickY;
    75     Uint8 rgucButtonsHatAndCounter[ 3 ];
    76     Uint8 ucTriggerLeft;
    77     Uint8 ucTriggerRight;
    78     Uint8 _rgucPad0[ 3 ];
    79     Sint16 sGyroX;
    80     Sint16 sGyroY;
    81     Sint16 sGyroZ;
    82     Sint16 sAccelX;
    83     Sint16 sAccelY;
    84     Sint16 sAccelZ;
    85     Uint8 _rgucPad1[ 5 ];
    86     Uint8 ucBatteryLevel;
    87     Uint8 _rgucPad2[ 4 ];
    88     Uint8 ucTrackpadCounter1;
    89     Uint8 rgucTrackpadData1[ 3 ];
    90     Uint8 ucTrackpadCounter2;
    91     Uint8 rgucTrackpadData2[ 3 ];
    92 } PS4StatePacket_t;
    93 
    94 typedef struct
    95 {
    96     Uint8 ucRumbleRight;
    97     Uint8 ucRumbleLeft;
    98     Uint8 ucLedRed;
    99     Uint8 ucLedGreen;
   100     Uint8 ucLedBlue;
   101     Uint8 ucLedDelayOn;
   102     Uint8 ucLedDelayOff;
   103     Uint8 _rgucPad0[ 8 ];
   104     Uint8 ucVolumeLeft;
   105     Uint8 ucVolumeRight;
   106     Uint8 ucVolumeMic;
   107     Uint8 ucVolumeSpeaker;
   108 } DS4EffectsState_t;
   109 
   110 typedef struct {
   111     SDL_JoystickID joystickID;
   112     SDL_bool is_dongle;
   113     SDL_bool is_bluetooth;
   114     SDL_bool audio_supported;
   115     SDL_bool rumble_supported;
   116     Uint8 volume;
   117     Uint32 last_volume_check;
   118     Uint32 rumble_expiration;
   119     PS4StatePacket_t last_state;
   120 } SDL_DriverPS4_Context;
   121 
   122 
   123 /* Public domain CRC implementation adapted from:
   124    http://home.thep.lu.se/~bjorn/crc/crc32_simple.c
   125 */
   126 static Uint32 crc32_for_byte(Uint32 r)
   127 {
   128     int i;
   129     for(i = 0; i < 8; ++i) {
   130         r = (r & 1? 0: (Uint32)0xEDB88320L) ^ r >> 1;
   131     }
   132     return r ^ (Uint32)0xFF000000L;
   133 }
   134 
   135 static Uint32 crc32(Uint32 crc, const void *data, int count)
   136 {
   137     int i;
   138     for(i = 0; i < count; ++i) {
   139         crc = crc32_for_byte((Uint8)crc ^ ((const Uint8*)data)[i]) ^ crc >> 8;
   140     }
   141     return crc;
   142 }
   143 
   144 #if defined(__WIN32__) && defined(HAVE_ENDPOINTVOLUME_H)
   145 #include "../../core/windows/SDL_windows.h"
   146 
   147 #ifndef NTDDI_VISTA
   148 #define NTDDI_VISTA    0x06000000
   149 #endif
   150 #ifndef _WIN32_WINNT_VISTA
   151 #define _WIN32_WINNT_VISTA 0x0600
   152 #endif
   153 
   154 /* Define Vista for the Audio related includes below to work */
   155 #undef NTDDI_VERSION
   156 #define NTDDI_VERSION NTDDI_VISTA
   157 #undef _WIN32_WINNT
   158 #define _WIN32_WINNT _WIN32_WINNT_VISTA
   159 #define COBJMACROS
   160 #include <mmdeviceapi.h>
   161 #include <audioclient.h>
   162 #include <endpointvolume.h>
   163 
   164 #undef DEFINE_GUID
   165 #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}}
   166 DEFINE_GUID(SDL_CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
   167 DEFINE_GUID(SDL_IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
   168 DEFINE_GUID(SDL_IID_IAudioEndpointVolume, 0x5CDF2C82, 0x841E, 0x4546, 0x97, 0x22, 0x0C, 0xF7, 0x40, 0x78, 0x22, 0x9A);
   169 #endif
   170 
   171 
   172 
   173 static float GetSystemVolume(void)
   174 {
   175     float volume = -1.0f;    /* Return this if we can't get system volume */
   176 
   177 #if defined(__WIN32__) && defined(HAVE_ENDPOINTVOLUME_H)
   178     HRESULT hr = WIN_CoInitialize();
   179     if (SUCCEEDED(hr)) {
   180         IMMDeviceEnumerator *pEnumerator;
   181 
   182         /* This should gracefully fail on XP and succeed on everything Vista and above */
   183         hr = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &SDL_IID_IMMDeviceEnumerator, (LPVOID*)&pEnumerator);
   184         if (SUCCEEDED(hr)) {
   185             IMMDevice *pDevice;
   186 
   187             hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eConsole, &pDevice);
   188             if (SUCCEEDED(hr)) {
   189                 IAudioEndpointVolume *pEndpointVolume;
   190 
   191                 hr = IMMDevice_Activate(pDevice, &SDL_IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (LPVOID*)&pEndpointVolume);
   192                 if (SUCCEEDED(hr)) {
   193                     IAudioEndpointVolume_GetMasterVolumeLevelScalar(pEndpointVolume, &volume);
   194                     IUnknown_Release(pEndpointVolume);
   195                 }
   196                 IUnknown_Release(pDevice);
   197             }
   198             IUnknown_Release(pEnumerator);
   199         }
   200         WIN_CoUninitialize();
   201     }
   202 #endif /* __WIN32__ */
   203 
   204     return volume;
   205 }
   206 
   207 static uint8_t GetPlaystationVolumeFromFloat(float fVolume)
   208 {
   209     const int k_nVolumeFitRatio = 15;
   210     const int k_nVolumeFitOffset = 9;
   211     float fVolLog;
   212 
   213     if (fVolume > 1.0f || fVolume < 0.0f) {
   214         fVolume = 0.30f;
   215     }
   216     fVolLog = SDL_logf(fVolume * 100);
   217 
   218     return (Uint8)((fVolLog * k_nVolumeFitRatio) + k_nVolumeFitOffset);
   219 }
   220 
   221 static SDL_bool
   222 HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
   223 {
   224     return SDL_IsJoystickPS4(vendor_id, product_id);
   225 }
   226 
   227 static const char *
   228 HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   229 {
   230     if (vendor_id == SONY_USB_VID) {
   231         return "PS4 Controller";
   232     }
   233     return NULL;
   234 }
   235 
   236 static SDL_bool ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *data, size_t size)
   237 {
   238     Uint8 report[USB_PACKET_LENGTH + 1];
   239 
   240     SDL_memset(report, 0, sizeof(report));
   241     report[0] = report_id;
   242     if (hid_get_feature_report(dev, report, sizeof(report)) < 0) {
   243         return SDL_FALSE;
   244     }
   245     SDL_memcpy(data, report, SDL_min(size, sizeof(report)));
   246     return SDL_TRUE;
   247 }
   248 
   249 static SDL_bool CheckUSBConnected(hid_device *dev)
   250 {
   251     int i;
   252     Uint8 data[16];
   253 
   254     /* This will fail if we're on Bluetooth */
   255     if (ReadFeatureReport(dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data))) {
   256         for (i = 0; i < sizeof(data); ++i) {
   257             if (data[i] != 0x00) {
   258                 return SDL_TRUE;
   259             }
   260         }
   261         /* Maybe the dongle without a connected controller? */
   262     }
   263     return SDL_FALSE;
   264 }
   265 
   266 static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id)
   267 {
   268     /* The Razer Panthera fight stick hangs when trying to rumble */
   269     if (vendor_id == RAZER_USB_VID &&
   270         (product_id == RAZER_PANTHERA_PID || product_id == RAZER_PANTHERA_EVO_PID)) {
   271         return SDL_FALSE;
   272     }
   273     return SDL_TRUE;
   274 }
   275 
   276 static SDL_bool
   277 HIDAPI_DriverPS4_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
   278 {
   279     SDL_DriverPS4_Context *ctx;
   280 
   281     ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
   282     if (!ctx) {
   283         SDL_OutOfMemory();
   284         return SDL_FALSE;
   285     }
   286     context->context = ctx;
   287 
   288     /* Check for type of connection */
   289     ctx->is_dongle = (vendor_id == SONY_USB_VID && product_id == SONY_DS4_DONGLE_PID);
   290     if (ctx->is_dongle) {
   291         ctx->is_bluetooth = SDL_FALSE;
   292     } else if (vendor_id == SONY_USB_VID) {
   293         ctx->is_bluetooth = !CheckUSBConnected(context->device);
   294     } else {
   295         /* Third party controllers appear to all be wired */
   296         ctx->is_bluetooth = SDL_FALSE;
   297     }
   298 #ifdef DEBUG_PS4
   299     SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
   300 #endif
   301 
   302     /* Check to see if audio is supported */
   303     if (vendor_id == SONY_USB_VID &&
   304         (product_id == SONY_DS4_SLIM_PID || product_id == SONY_DS4_DONGLE_PID )) {
   305         ctx->audio_supported = SDL_TRUE;
   306     }
   307 
   308     if (HIDAPI_DriverPS4_CanRumble(vendor_id, product_id)) {
   309         if (ctx->is_bluetooth) {
   310             ctx->rumble_supported = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE);
   311         } else {
   312             ctx->rumble_supported = SDL_TRUE;
   313         }
   314     }
   315 
   316     ctx->joystickID = SDL_GetNextJoystickInstanceID();
   317     *num_joysticks += 1;
   318     SDL_PrivateJoystickAdded(ctx->joystickID);
   319 
   320     return SDL_TRUE;
   321 }
   322 
   323 static void
   324 HIDAPI_DriverPS4_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
   325 {
   326     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
   327 
   328     *num_joysticks -= 1;
   329     if (send_event) {
   330         SDL_PrivateJoystickRemoved(ctx->joystickID);
   331     }
   332     SDL_free(context->context);
   333 }
   334 
   335 static int
   336 HIDAPI_DriverPS4_NumJoysticks(SDL_HIDAPI_DriverData *context)
   337 {
   338     return 1;
   339 }
   340 
   341 static int
   342 HIDAPI_DriverPS4_PlayerIndexForIndex(SDL_HIDAPI_DriverData *context, int index)
   343 {
   344     return -1;
   345 }
   346 
   347 static SDL_JoystickID
   348 HIDAPI_DriverPS4_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
   349 {
   350     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
   351     return ctx->joystickID;
   352 }
   353 
   354 static int HIDAPI_DriverPS4_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
   355 
   356 static SDL_bool
   357 HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
   358 {
   359     /* Initialize LED and effect state */
   360     HIDAPI_DriverPS4_Rumble(context, joystick, 0, 0, 0);
   361 
   362     /* Initialize the joystick capabilities */
   363     joystick->nbuttons = 16;
   364     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   365     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   366 
   367     return SDL_TRUE;
   368 }
   369 
   370 static int
   371 HIDAPI_DriverPS4_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   372 {
   373     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
   374     DS4EffectsState_t *effects;
   375     Uint8 data[78];
   376     int report_size, offset;
   377 
   378     if (!ctx->rumble_supported) {
   379         return SDL_Unsupported();
   380     }
   381 
   382     /* In order to send rumble, we have to send a complete effect packet */
   383     SDL_memset(data, 0, sizeof(data));
   384 
   385     if (ctx->is_bluetooth) {
   386         data[0] = k_EPS4ReportIdBluetoothEffects;
   387         data[1] = 0xC0 | 0x04;  /* Magic value HID + CRC, also sets interval to 4ms for samples */
   388         data[3] = 0x03;  /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
   389 
   390         report_size = 78;
   391         offset = 6;
   392     } else {
   393         data[0] = k_EPS4ReportIdUsbEffects;
   394         data[1] = 0x07;  /* Magic value */
   395 
   396         report_size = 32;
   397         offset = 4;
   398     }
   399     effects = (DS4EffectsState_t *)&data[offset];
   400 
   401     effects->ucRumbleLeft = (low_frequency_rumble >> 8);
   402     effects->ucRumbleRight = (high_frequency_rumble >> 8);
   403 
   404     effects->ucLedRed = 0;
   405     effects->ucLedGreen = 0;
   406     effects->ucLedBlue = 80;
   407 
   408     if (ctx->audio_supported) {
   409         Uint32 now = SDL_GetTicks();
   410         if (!ctx->last_volume_check ||
   411             SDL_TICKS_PASSED(now, ctx->last_volume_check + VOLUME_CHECK_INTERVAL_MS)) {
   412             ctx->volume = GetPlaystationVolumeFromFloat(GetSystemVolume());
   413             ctx->last_volume_check = now;
   414         }
   415 
   416         effects->ucVolumeRight = ctx->volume;
   417         effects->ucVolumeLeft = ctx->volume;
   418         effects->ucVolumeSpeaker = ctx->volume;
   419         effects->ucVolumeMic = 0xFF;
   420     }
   421 
   422     if (ctx->is_bluetooth) {
   423         /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
   424         Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
   425         Uint32 unCRC;
   426         unCRC = crc32(0, &ubHdr, 1);
   427         unCRC = crc32(unCRC, data, (Uint32)(report_size - sizeof(unCRC)));
   428         SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
   429     }
   430 
   431     if (hid_write(context->device, data, report_size) != report_size) {
   432         return SDL_SetError("Couldn't send rumble packet");
   433     }
   434 
   435     if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
   436         ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
   437     } else {
   438         ctx->rumble_expiration = 0;
   439     }
   440     return 0;
   441 }
   442 
   443 static void
   444 HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet)
   445 {
   446     Sint16 axis;
   447 
   448     if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
   449         {
   450             Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
   451 
   452             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   453             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   454             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   455             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   456         }
   457         {
   458             Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
   459             SDL_bool dpad_up = SDL_FALSE;
   460             SDL_bool dpad_down = SDL_FALSE;
   461             SDL_bool dpad_left = SDL_FALSE;
   462             SDL_bool dpad_right = SDL_FALSE;
   463 
   464             switch (data) {
   465             case 0:
   466                 dpad_up = SDL_TRUE;
   467                 break;
   468             case 1:
   469                 dpad_up = SDL_TRUE;
   470                 dpad_right = SDL_TRUE;
   471                 break;
   472             case 2:
   473                 dpad_right = SDL_TRUE;
   474                 break;
   475             case 3:
   476                 dpad_right = SDL_TRUE;
   477                 dpad_down = SDL_TRUE;
   478                 break;
   479             case 4:
   480                 dpad_down = SDL_TRUE;
   481                 break;
   482             case 5:
   483                 dpad_left = SDL_TRUE;
   484                 dpad_down = SDL_TRUE;
   485                 break;
   486             case 6:
   487                 dpad_left = SDL_TRUE;
   488                 break;
   489             case 7:
   490                 dpad_up = SDL_TRUE;
   491                 dpad_left = SDL_TRUE;
   492                 break;
   493             default:
   494                 break;
   495             }
   496             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   497             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   498             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   499             SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   500         }
   501     }
   502 
   503     if (ctx->last_state.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
   504         Uint8 data = packet->rgucButtonsHatAndCounter[1];
   505 
   506         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   507         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   508         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   509         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   510         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
   511         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
   512     }
   513 
   514     if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
   515         Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
   516 
   517         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   518         SDL_PrivateJoystickButton(joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   519     }
   520 
   521     axis = ((int)packet->ucTriggerLeft * 257) - 32768;
   522     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   523     axis = ((int)packet->ucTriggerRight * 257) - 32768;
   524     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   525     axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
   526     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   527     axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
   528     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   529     axis = ((int)packet->ucRightJoystickX * 257) - 32768;
   530     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   531     axis = ((int)packet->ucRightJoystickY * 257) - 32768;
   532     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   533 
   534     if (packet->ucBatteryLevel & 0x10) {
   535         joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   536     } else {
   537         /* Battery level ranges from 0 to 10 */
   538         int level = (packet->ucBatteryLevel & 0xF);
   539         if (level == 0) {
   540             joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
   541         } else if (level <= 2) {
   542             joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
   543         } else if (level <= 7) {
   544             joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
   545         } else {
   546             joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
   547         }
   548     }
   549 
   550     SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
   551 }
   552 
   553 static SDL_bool
   554 HIDAPI_DriverPS4_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
   555 {
   556     SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
   557     SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
   558     Uint8 data[USB_PACKET_LENGTH];
   559     int size;
   560 
   561     if (joystick == NULL) {
   562         return SDL_TRUE; /* Nothing to do right now! */
   563     }
   564 
   565     while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
   566         switch (data[0]) {
   567         case k_EPS4ReportIdUsbState:
   568             HIDAPI_DriverPS4_HandleStatePacket(joystick, context->device, ctx, (PS4StatePacket_t *)&data[1]);
   569             break;
   570         case k_EPS4ReportIdBluetoothState:
   571             /* Bluetooth state packets have two additional bytes at the beginning */
   572             HIDAPI_DriverPS4_HandleStatePacket(joystick, context->device, ctx, (PS4StatePacket_t *)&data[3]);
   573             break;
   574         default:
   575 #ifdef DEBUG_JOYSTICK
   576             SDL_Log("Unknown PS4 packet: 0x%.2x\n", data[0]);
   577 #endif
   578             break;
   579         }
   580     }
   581 
   582     if (ctx->rumble_expiration) {
   583         Uint32 now = SDL_GetTicks();
   584         if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
   585             HIDAPI_DriverPS4_Rumble(context, joystick, 0, 0, 0);
   586         }
   587     }
   588 
   589     return (size >= 0);
   590 }
   591 
   592 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
   593 {
   594     SDL_HINT_JOYSTICK_HIDAPI_PS4,
   595     SDL_TRUE,
   596     HIDAPI_DriverPS4_IsSupportedDevice,
   597     HIDAPI_DriverPS4_GetDeviceName,
   598     HIDAPI_DriverPS4_InitDriver,
   599     HIDAPI_DriverPS4_QuitDriver,
   600     HIDAPI_DriverPS4_UpdateDriver,
   601     HIDAPI_DriverPS4_NumJoysticks,
   602     HIDAPI_DriverPS4_PlayerIndexForIndex,
   603     HIDAPI_DriverPS4_InstanceIDForIndex,
   604     HIDAPI_DriverPS4_OpenJoystick,
   605     HIDAPI_DriverPS4_Rumble
   606 };
   607 
   608 #endif /* SDL_JOYSTICK_HIDAPI_PS4 */
   609 
   610 #endif /* SDL_JOYSTICK_HIDAPI */
   611 
   612 /* vi: set ts=4 sw=4 expandtab: */