1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2018 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 #include "../../SDL_internal.h"
22 
23 #ifdef SDL_JOYSTICK_HIDAPI
24 
25 #include "SDL_hints.h"
26 #include "SDL_events.h"
27 #include "SDL_timer.h"
28 #include "SDL_joystick.h"
29 #include "SDL_gamecontroller.h"
30 #include "../SDL_sysjoystick.h"
31 #include "SDL_hidapijoystick_c.h"
32 
33 
34 
35 #ifdef SDL_JOYSTICK_HIDAPI_STEAM
36 
37 /*****************************************************************************************************/
38 
39 #include <stdint.h>
40 
41 typedef enum
42 {
43     false,
44     true
45 } bool;
46 
47 typedef uint32_t uint32;
48 typedef uint64_t uint64;
49 
50 #include "steam/controller_constants.h"
51 #include "steam/controller_structs.h"
52 
53 typedef struct SteamControllerStateInternal_t
54 {
55     // Controller Type for this Controller State
56     uint32 eControllerType;
57 
58     // If packet num matches that on your prior call, then the controller state hasn't been changed since
59     // your last call and there is no need to process it
60     uint32 unPacketNum;
61 
62     // bit flags for each of the buttons
63     uint64 ulButtons;
64 
65     // Left pad coordinates
66     short sLeftPadX;
67     short sLeftPadY;
68 
69     // Right pad coordinates
70     short sRightPadX;
71     short sRightPadY;
72 
73     // Center pad coordinates
74     short sCenterPadX;
75     short sCenterPadY;
76 
77     // Left analog stick coordinates
78     short sLeftStickX;
79     short sLeftStickY;
80 
81     // Right analog stick coordinates
82     short sRightStickX;
83     short sRightStickY;
84 
85     unsigned short sTriggerL;
86     unsigned short sTriggerR;
87 
88     short sAccelX;
89     short sAccelY;
90     short sAccelZ;
91 
92     short sGyroX;
93     short sGyroY;
94     short sGyroZ;
95 
96     float sGyroQuatW;
97     float sGyroQuatX;
98     float sGyroQuatY;
99     float sGyroQuatZ;
100 
101     short sGyroSteeringAngle;
102 
103     unsigned short sBatteryLevel;
104 
105     // Pressure sensor data.
106     unsigned short sPressurePadLeft;
107     unsigned short sPressurePadRight;
108 
109     unsigned short sPressureBumperLeft;
110     unsigned short sPressureBumperRight;
111 
112     // Internal state data
113     short sPrevLeftPad[2];
114     short sPrevLeftStick[2];
115 } SteamControllerStateInternal_t;
116 
117 
118 /* Defines for ulButtons in SteamControllerStateInternal_t */
119 #define STEAM_RIGHT_TRIGGER_MASK            0x00000001
120 #define STEAM_LEFT_TRIGGER_MASK             0x00000002
121 #define STEAM_RIGHT_BUMPER_MASK             0x00000004
122 #define STEAM_LEFT_BUMPER_MASK              0x00000008
123 #define STEAM_BUTTON_0_MASK                 0x00000010    /* Y */
124 #define STEAM_BUTTON_1_MASK                 0x00000020    /* B */
125 #define STEAM_BUTTON_2_MASK                 0x00000040    /* X */
126 #define STEAM_BUTTON_3_MASK                 0x00000080    /* A */
127 #define STEAM_TOUCH_0_MASK                  0x00000100    /* DPAD UP */
128 #define STEAM_TOUCH_1_MASK                  0x00000200    /* DPAD RIGHT */
129 #define STEAM_TOUCH_2_MASK                  0x00000400    /* DPAD LEFT */
130 #define STEAM_TOUCH_3_MASK                  0x00000800    /* DPAD DOWN */
131 #define STEAM_BUTTON_MENU_MASK              0x00001000    /* SELECT */
132 #define STEAM_BUTTON_STEAM_MASK             0x00002000    /* GUIDE */
133 #define STEAM_BUTTON_ESCAPE_MASK            0x00004000    /* START */
134 #define STEAM_BUTTON_BACK_LEFT_MASK         0x00008000
135 #define STEAM_BUTTON_BACK_RIGHT_MASK        0x00010000
136 #define STEAM_BUTTON_LEFTPAD_CLICKED_MASK   0x00020000
137 #define STEAM_BUTTON_RIGHTPAD_CLICKED_MASK  0x00040000
138 #define STEAM_LEFTPAD_FINGERDOWN_MASK       0x00080000
139 #define STEAM_RIGHTPAD_FINGERDOWN_MASK      0x00100000
140 #define STEAM_JOYSTICK_BUTTON_MASK            0x00400000
141 #define STEAM_LEFTPAD_AND_JOYSTICK_MASK        0x00800000
142 
143 
144 // Look for report version 0x0001, type WIRELESS (3), length >= 1 byte
145 #define D0G_IS_VALID_WIRELESS_EVENT(data, len)    ((len) >= 5 && (data)[0] == 1 && (data)[1] == 0 && (data)[2] == 3 && (data)[3] >= 1)
146 #define D0G_GET_WIRELESS_EVENT_TYPE(data)        ((data)[4])
147 #define D0G_WIRELESS_DISCONNECTED    1
148 #define D0G_WIRELESS_ESTABLISHED    2
149 #define D0G_WIRELESS_NEWLYPAIRED    3
150 
151 #define D0G_IS_WIRELESS_DISCONNECT(data, len)    ( D0G_IS_VALID_WIRELESS_EVENT(data,len) && D0G_GET_WIRELESS_EVENT_TYPE(data) == D0G_WIRELESS_DISCONNECTED )
152 
153 #define MAX_REPORT_SEGMENT_PAYLOAD_SIZE    18
154 /*
155  * SteamControllerPacketAssembler has to be used when reading output repots from controllers.
156  */
157 typedef struct
158 {
159     uint8_t uBuffer[ MAX_REPORT_SEGMENT_PAYLOAD_SIZE * 8 + 1 ];
160     int nExpectedSegmentNumber;
161     bool bIsBle;
162 } SteamControllerPacketAssembler;
163 
164 
165 #undef clamp
166 #define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val)))
167 
168 #undef offsetof
169 #define offsetof(s,m)    (size_t)&(((s *)0)->m)
170 
171 #ifdef DEBUG_STEAM_CONTROLLER
172 #define DPRINTF(format, ...) printf(format, ##__VA_ARGS__)
173 #define HEXDUMP(ptr, len) hexdump(ptr, len)
174 #else
175 #define DPRINTF(format, ...)
176 #define HEXDUMP(ptr, len)
177 #endif
178 #define printf  SDL_Log
179 
180 #define MAX_REPORT_SEGMENT_SIZE        ( MAX_REPORT_SEGMENT_PAYLOAD_SIZE + 2 )
181 #define CALC_REPORT_SEGMENT_NUM(index)  ( ( index / MAX_REPORT_SEGMENT_PAYLOAD_SIZE ) & 0x07 )
182 #define REPORT_SEGMENT_DATA_FLAG    0x80
183 #define REPORT_SEGMENT_LAST_FLAG    0x40
184 #define BLE_REPORT_NUMBER        0x03
185 
186 #define STEAMCONTROLLER_TRIGGER_MAX_ANALOG 26000
187 
188 // Enable mouse mode when using the Steam Controller locally
189 #undef ENABLE_MOUSE_MODE
190 
191 
192 // Wireless firmware quirk: the firmware intentionally signals "failure" when performing
193 // SET_FEATURE / GET_FEATURE when it actually means "pending radio round-trip". The only
194 // way to make SET_FEATURE / GET_FEATURE work is to loop several times with a sleep. If
195 // it takes more than 50ms to get the response for SET_FEATURE / GET_FEATURE, we assume
196 // that the controller has failed.
197 #define RADIO_WORKAROUND_SLEEP_ATTEMPTS 50
198 #define RADIO_WORKAROUND_SLEEP_DURATION_US 500
199 
200 // This was defined by experimentation. 2000 seemed to work but to give that extra bit of margin, set to 3ms.
201 #define CONTROLLER_CONFIGURATION_DELAY_US 3000
202 
GetSegmentHeader(int nSegmentNumber,bool bLastPacket)203 static uint8_t GetSegmentHeader( int nSegmentNumber, bool bLastPacket )
204 {
205     uint8_t header = REPORT_SEGMENT_DATA_FLAG;
206     header |= nSegmentNumber;
207     if ( bLastPacket )
208         header |= REPORT_SEGMENT_LAST_FLAG;
209 
210     return header;
211 }
212 
hexdump(const uint8_t * ptr,int len)213 static void hexdump( const uint8_t *ptr, int len )
214 {
215     int i;
216     for ( i = 0; i < len ; ++i )
217         printf("%02x ", ptr[i]);
218     printf("\n");
219 }
220 
ResetSteamControllerPacketAssembler(SteamControllerPacketAssembler * pAssembler)221 static void ResetSteamControllerPacketAssembler( SteamControllerPacketAssembler *pAssembler )
222 {
223     memset( pAssembler->uBuffer, 0, sizeof( pAssembler->uBuffer ) );
224     pAssembler->nExpectedSegmentNumber = 0;
225 }
226 
InitializeSteamControllerPacketAssembler(SteamControllerPacketAssembler * pAssembler)227 static void InitializeSteamControllerPacketAssembler( SteamControllerPacketAssembler *pAssembler )
228 {
229     /* We only support BLE devices right now */
230     pAssembler->bIsBle = true;
231     ResetSteamControllerPacketAssembler( pAssembler );
232 }
233 
234 // Returns:
235 //     <0 on error
236 //     0 on not ready
237 //     Complete packet size on completion
WriteSegmentToSteamControllerPacketAssembler(SteamControllerPacketAssembler * pAssembler,const uint8_t * pSegment,int nSegmentLength)238 static int WriteSegmentToSteamControllerPacketAssembler( SteamControllerPacketAssembler *pAssembler, const uint8_t *pSegment, int nSegmentLength )
239 {
240     if ( pAssembler->bIsBle )
241     {
242         HEXDUMP( pSegment, nSegmentLength );
243 
244         if ( pSegment[ 0 ] != BLE_REPORT_NUMBER )
245         {
246             // We may get keyboard/mouse input events until controller stops sending them
247             return 0;
248         }
249 
250         if ( nSegmentLength != MAX_REPORT_SEGMENT_SIZE )
251         {
252             printf( "Bad segment size! %d\n", (int)nSegmentLength );
253             hexdump( pSegment, nSegmentLength );
254             ResetSteamControllerPacketAssembler( pAssembler );
255             return -1;
256         }
257 
258         uint8_t uSegmentHeader = pSegment[ 1 ];
259         DPRINTF("GOT PACKET HEADER = 0x%x\n", uSegmentHeader);
260 
261         if ( ( uSegmentHeader & REPORT_SEGMENT_DATA_FLAG ) == 0 )
262         {
263             // We get empty segments, just ignore them
264             return 0;
265         }
266 
267         int nSegmentNumber = uSegmentHeader & 0x07;
268         if ( nSegmentNumber != pAssembler->nExpectedSegmentNumber )
269         {
270             ResetSteamControllerPacketAssembler( pAssembler );
271 
272             if ( nSegmentNumber )
273             {
274                 // This happens occasionally
275                 DPRINTF("Bad segment number, got %d, expected %d\n",
276                     nSegmentNumber, pAssembler->nExpectedSegmentNumber );
277                 return -1;
278             }
279         }
280 
281         memcpy( pAssembler->uBuffer + nSegmentNumber * MAX_REPORT_SEGMENT_PAYLOAD_SIZE,
282                pSegment + 2, // ignore header and report number
283                MAX_REPORT_SEGMENT_PAYLOAD_SIZE );
284 
285         if ( uSegmentHeader & REPORT_SEGMENT_LAST_FLAG )
286         {
287             pAssembler->nExpectedSegmentNumber = 0;
288             return ( nSegmentNumber + 1 ) * MAX_REPORT_SEGMENT_PAYLOAD_SIZE;
289         }
290 
291         pAssembler->nExpectedSegmentNumber++;
292     }
293     else
294     {
295         // Just pass through
296         memcpy( pAssembler->uBuffer,
297                pSegment,
298                nSegmentLength );
299         return nSegmentLength;
300     }
301 
302     return 0;
303 }
304 
305 #define BLE_MAX_READ_RETRIES    8
306 
SetFeatureReport(hid_device * dev,unsigned char uBuffer[65],int nActualDataLen)307 static int SetFeatureReport( hid_device *dev, unsigned char uBuffer[65], int nActualDataLen )
308 {
309     DPRINTF("SetFeatureReport %p %p %d\n", dev, uBuffer, nActualDataLen);
310     int nRet = -1;
311     bool bBle = true; // only wireless/BLE for now, though macOS could do wired in the future
312 
313     if ( bBle )
314     {
315         if ( nActualDataLen < 1 )
316             return -1;
317 
318         int nSegmentNumber = 0;
319         uint8_t uPacketBuffer[ MAX_REPORT_SEGMENT_SIZE ];
320 
321         // Skip report number in data
322         unsigned char *pBufferPtr = uBuffer + 1;
323         nActualDataLen--;
324 
325         while ( nActualDataLen > 0 )
326         {
327             int nBytesInPacket = nActualDataLen > MAX_REPORT_SEGMENT_PAYLOAD_SIZE ? MAX_REPORT_SEGMENT_PAYLOAD_SIZE : nActualDataLen;
328 
329             nActualDataLen -= nBytesInPacket;
330 
331             // Construct packet
332             memset( uPacketBuffer, 0, sizeof( uPacketBuffer ) );
333             uPacketBuffer[ 0 ] = BLE_REPORT_NUMBER;
334             uPacketBuffer[ 1 ] = GetSegmentHeader( nSegmentNumber, nActualDataLen == 0 );
335             memcpy( &uPacketBuffer[ 2 ], pBufferPtr, nBytesInPacket );
336 
337             pBufferPtr += nBytesInPacket;
338             nSegmentNumber++;
339 
340             nRet = hid_send_feature_report( dev, uPacketBuffer, sizeof( uPacketBuffer ) );
341             DPRINTF("SetFeatureReport() ret = %d\n", nRet);
342         }
343     }
344 
345     return nRet;
346 }
347 
GetFeatureReport(hid_device * dev,unsigned char uBuffer[65])348 static int GetFeatureReport( hid_device *dev, unsigned char uBuffer[65] )
349 {
350     DPRINTF("GetFeatureReport( %p %p )\n", dev, uBuffer );
351     int nRet = -1;
352     bool bBle = true;
353 
354     if ( bBle )
355     {
356         SteamControllerPacketAssembler assembler;
357         InitializeSteamControllerPacketAssembler( &assembler );
358 
359         int nRetries = 0;
360         uint8_t uSegmentBuffer[ MAX_REPORT_SEGMENT_SIZE ];
361         while( nRetries < BLE_MAX_READ_RETRIES )
362         {
363             memset( uSegmentBuffer, 0, sizeof( uSegmentBuffer ) );
364             uSegmentBuffer[ 0 ] = BLE_REPORT_NUMBER;
365             nRet = hid_get_feature_report( dev, uSegmentBuffer, sizeof( uSegmentBuffer ) );
366             DPRINTF( "GetFeatureReport ble ret=%d\n", nRet );
367             HEXDUMP( uSegmentBuffer, nRet );
368 
369             // Zero retry counter if we got data
370             if ( nRet > 2 && ( uSegmentBuffer[ 1 ] & REPORT_SEGMENT_DATA_FLAG ) )
371                 nRetries = 0;
372             else
373                 nRetries++;
374 
375             if ( nRet > 0 )
376             {
377                 int nPacketLength = WriteSegmentToSteamControllerPacketAssembler( &assembler,
378                                                                                  uSegmentBuffer,
379                                                                                  nRet );
380 
381                 if ( nPacketLength > 0 && nPacketLength < 65 )
382                 {
383                     // Leave space for "report number"
384                     uBuffer[ 0 ] = 0;
385                     memcpy( uBuffer + 1, assembler.uBuffer, nPacketLength );
386                     return nPacketLength;
387                 }
388             }
389 
390 
391         }
392         printf("Could not get a full ble packet after %d retries\n", nRetries );
393         return -1;
394     }
395 
396     return nRet;
397 }
398 
ReadResponse(hid_device * dev,uint8_t uBuffer[65],int nExpectedResponse)399 static int ReadResponse( hid_device *dev, uint8_t uBuffer[65], int nExpectedResponse )
400 {
401     DPRINTF("ReadResponse( %p %p %d )\n", dev, uBuffer, nExpectedResponse );
402     int nRet = GetFeatureReport( dev, uBuffer );
403 
404     if ( nRet < 0 )
405         return nRet;
406 
407     DPRINTF("ReadResponse got %d bytes of data: ", nRet );
408     HEXDUMP( uBuffer, nRet );
409 
410     if ( uBuffer[1] != nExpectedResponse )
411         return -1;
412 
413     return nRet;
414 }
415 
416 //---------------------------------------------------------------------------
417 // Reset steam controller (unmap buttons and pads) and re-fetch capability bits
418 //---------------------------------------------------------------------------
ResetSteamController(hid_device * dev,bool bSuppressErrorSpew)419 static bool ResetSteamController( hid_device *dev, bool bSuppressErrorSpew )
420 {
421     DPRINTF( "ResetSteamController hid=%p\n", dev );
422     // Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
423     unsigned char buf[65];
424     int res = -1;
425 
426     buf[0] = 0;
427     buf[1] = ID_GET_ATTRIBUTES_VALUES;
428     res = SetFeatureReport( dev, buf, 2 );
429     if ( res < 0 )
430     {
431         if ( !bSuppressErrorSpew )
432             printf( "GET_ATTRIBUTES_VALUES failed for controller %p\n", dev );
433         return false;
434     }
435 
436     // Retrieve GET_ATTRIBUTES_VALUES result
437     // Wireless controller endpoints without a connected controller will return nAttrs == 0
438     res = ReadResponse( dev, buf, ID_GET_ATTRIBUTES_VALUES );
439     if ( res < 0 || buf[1] != ID_GET_ATTRIBUTES_VALUES )
440     {
441         HEXDUMP(buf, res);
442         if ( !bSuppressErrorSpew )
443             printf( "Bad GET_ATTRIBUTES_VALUES response for controller %p\n", dev );
444         return false;
445     }
446 
447     int nAttributesLength = buf[ 2 ];
448     if ( nAttributesLength > res )
449     {
450         if ( !bSuppressErrorSpew )
451             printf( "Bad GET_ATTRIBUTES_VALUES response for controller %p\n", dev );
452         return false;
453     }
454 
455     // Clear digital button mappings
456     buf[0] = 0;
457     buf[1] = ID_CLEAR_DIGITAL_MAPPINGS;
458     res = SetFeatureReport( dev, buf, 2 );
459     if ( res < 0 )
460     {
461         if ( !bSuppressErrorSpew )
462             printf( "CLEAR_DIGITAL_MAPPINGS failed for controller %p\n", dev );
463         return false;
464     }
465 
466     // Reset the default settings
467     memset( buf, 0, 65 );
468     buf[1] = ID_LOAD_DEFAULT_SETTINGS;
469     buf[2] = 0;
470     res = SetFeatureReport( dev, buf, 3 );
471     if ( res < 0 )
472     {
473         if ( !bSuppressErrorSpew )
474             printf( "LOAD_DEFAULT_SETTINGS failed for controller %p\n", dev );
475         return false;
476     }
477 
478     // Apply custom settings - clear trackpad modes (cancel mouse emulation), etc
479     int nSettings = 0;
480 #define ADD_SETTING(SETTING, VALUE)    \
481 buf[3+nSettings*3] = SETTING;    \
482 buf[3+nSettings*3+1] = ((uint16_t)VALUE)&0xFF; \
483 buf[3+nSettings*3+2] = ((uint16_t)VALUE)>>8; \
484 ++nSettings;
485 
486     memset( buf, 0, 65 );
487     buf[1] = ID_SET_SETTINGS_VALUES;
488     ADD_SETTING( SETTING_WIRELESS_PACKET_VERSION, 2 );
489     ADD_SETTING( SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE );
490 #ifdef ENABLE_MOUSE_MODE
491     ADD_SETTING( SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_ABSOLUTE_MOUSE );
492     ADD_SETTING( SETTING_SMOOTH_ABSOLUTE_MOUSE, 1 );
493     ADD_SETTING( SETTING_MOMENTUM_MAXIMUM_VELOCITY, 20000 );    // [0-20000] default 8000
494     ADD_SETTING( SETTING_MOMENTUM_DECAY_AMMOUNT, 50 );        // [0-50] default 5
495 #else
496     ADD_SETTING( SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE );
497     ADD_SETTING( SETTING_SMOOTH_ABSOLUTE_MOUSE, 0 );
498 #endif
499     buf[2] = nSettings*3;
500 
501     res = SetFeatureReport( dev, buf, 3+nSettings*3 );
502     if ( res < 0 )
503     {
504         if ( !bSuppressErrorSpew )
505             printf( "SET_SETTINGS failed for controller %p\n", dev );
506         return false;
507     }
508 
509 #ifdef ENABLE_MOUSE_MODE
510     // Wait for ID_CLEAR_DIGITAL_MAPPINGS to be processed on the controller
511     bool bMappingsCleared = false;
512     int iRetry;
513     for ( iRetry = 0; iRetry < 2; ++iRetry )
514     {
515         memset( buf, 0, 65 );
516         buf[1] = ID_GET_DIGITAL_MAPPINGS;
517         buf[2] = 1; // one byte - requesting from index 0
518         buf[3] = 0;
519         res = SetFeatureReport( dev, buf, 4 );
520         if ( res < 0 )
521         {
522             printf( "GET_DIGITAL_MAPPINGS failed for controller %p\n", dev );
523             return false;
524         }
525 
526         res = ReadResponse( dev, buf, ID_GET_DIGITAL_MAPPINGS );
527         if ( res < 0 || buf[1] != ID_GET_DIGITAL_MAPPINGS )
528         {
529             printf( "Bad GET_DIGITAL_MAPPINGS response for controller %p\n", dev );
530             return false;
531         }
532 
533         // If the length of the digital mappings result is not 1 (index byte, no mappings) then clearing hasn't executed
534         if ( buf[2] == 1 && buf[3] == 0xFF )
535         {
536             bMappingsCleared = true;
537             break;
538         }
539         usleep( CONTROLLER_CONFIGURATION_DELAY_US );
540     }
541 
542     if ( !bMappingsCleared && !bSuppressErrorSpew )
543     {
544         printf( "Warning: CLEAR_DIGITAL_MAPPINGS never completed for controller %p\n", dev );
545     }
546 
547     // Set our new mappings
548     memset( buf, 0, 65 );
549     buf[1] = ID_SET_DIGITAL_MAPPINGS;
550     buf[2] = 6; // 2 settings x 3 bytes
551     buf[3] = IO_DIGITAL_BUTTON_RIGHT_TRIGGER;
552     buf[4] = DEVICE_MOUSE;
553     buf[5] = MOUSE_BTN_LEFT;
554     buf[6] = IO_DIGITAL_BUTTON_LEFT_TRIGGER;
555     buf[7] = DEVICE_MOUSE;
556     buf[8] = MOUSE_BTN_RIGHT;
557 
558     res = SetFeatureReport( dev, buf, 9 );
559     if ( res < 0 )
560     {
561         if ( !bSuppressErrorSpew )
562             printf( "SET_DIGITAL_MAPPINGS failed for controller %p\n", dev );
563         return false;
564     }
565 #endif // ENABLE_MOUSE_MODE
566 
567     return true;
568 }
569 
570 
571 //---------------------------------------------------------------------------
572 // Read from a Steam Controller
573 //---------------------------------------------------------------------------
ReadSteamController(hid_device * dev,uint8_t * pData,int nDataSize)574 static int ReadSteamController( hid_device *dev, uint8_t *pData, int nDataSize )
575 {
576     memset( pData, 0, nDataSize );
577     pData[ 0 ] = BLE_REPORT_NUMBER; // hid_read will also overwrite this with the same value, 0x03
578     return hid_read( dev, pData, nDataSize );
579 }
580 
581 
582 //---------------------------------------------------------------------------
583 // Close a Steam Controller
584 //---------------------------------------------------------------------------
CloseSteamController(hid_device * dev)585 static void CloseSteamController( hid_device *dev )
586 {
587     // Switch the Steam Controller back to lizard mode so it works with the OS
588     unsigned char buf[65];
589     int nSettings = 0;
590 
591     // Reset digital button mappings
592     memset( buf, 0, 65 );
593     buf[1] = ID_SET_DEFAULT_DIGITAL_MAPPINGS;
594     SetFeatureReport( dev, buf, 2 );
595 
596     // Reset the default settings
597     memset( buf, 0, 65 );
598     buf[1] = ID_LOAD_DEFAULT_SETTINGS;
599     buf[2] = 0;
600     SetFeatureReport( dev, buf, 3 );
601 
602     // Reset mouse mode for lizard mode
603     memset( buf, 0, 65 );
604     buf[1] = ID_SET_SETTINGS_VALUES;
605     ADD_SETTING( SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_ABSOLUTE_MOUSE );
606     buf[2] = nSettings*3;
607     SetFeatureReport( dev, buf, 3+nSettings*3 );
608 }
609 
610 
611 //---------------------------------------------------------------------------
612 // Scale and clamp values to a range
613 //---------------------------------------------------------------------------
RemapValClamped(float val,float A,float B,float C,float D)614 static float RemapValClamped( float val, float A, float B, float C, float D)
615 {
616     if ( A == B )
617     {
618         return ( val - B ) >= 0.0f ? D : C;
619     }
620     else
621     {
622         float cVal = (val - A) / (B - A);
623         cVal = clamp( cVal, 0.0f, 1.0f );
624 
625         return C + (D - C) * cVal;
626     }
627 }
628 
629 
630 //---------------------------------------------------------------------------
631 // Rotate the pad coordinates
632 //---------------------------------------------------------------------------
RotatePad(int * pX,int * pY,float flAngleInRad)633 static void RotatePad( int *pX, int *pY, float flAngleInRad )
634 {
635     short int origX = *pX, origY = *pY;
636 
637     *pX = (int)( SDL_cosf( flAngleInRad ) * origX - SDL_sinf( flAngleInRad ) * origY );
638     *pY = (int)( SDL_sinf( flAngleInRad ) * origX + SDL_cosf( flAngleInRad ) * origY );
639 }
RotatePadShort(short * pX,short * pY,float flAngleInRad)640 static void RotatePadShort( short *pX, short *pY, float flAngleInRad )
641 {
642     short int origX = *pX, origY = *pY;
643 
644     *pX = (short)( SDL_cosf( flAngleInRad ) * origX - SDL_sinf( flAngleInRad ) * origY );
645     *pY = (short)( SDL_sinf( flAngleInRad ) * origX + SDL_cosf( flAngleInRad ) * origY );
646 }
647 
648 
649 //---------------------------------------------------------------------------
650 // Format the first part of the state packet
651 //---------------------------------------------------------------------------
FormatStatePacketUntilGyro(SteamControllerStateInternal_t * pState,ValveControllerStatePacket_t * pStatePacket)652 static void FormatStatePacketUntilGyro( SteamControllerStateInternal_t *pState, ValveControllerStatePacket_t *pStatePacket )
653 {
654     memset(pState, 0, offsetof(SteamControllerStateInternal_t, sBatteryLevel));
655 
656     //pState->eControllerType = m_eControllerType;
657     pState->eControllerType = 2; // k_eControllerType_SteamController;
658     pState->unPacketNum = pStatePacket->unPacketNum;
659 
660     // We have a chunk of trigger data in the packet format here, so zero it out afterwards
661     memcpy(&pState->ulButtons, &pStatePacket->ButtonTriggerData.ulButtons, 8);
662     pState->ulButtons &= ~0xFFFF000000LL;
663 
664     // The firmware uses this bit to tell us what kind of data is packed into the left two axises
665     if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK)
666     {
667         // Finger-down bit not set; "left pad" is actually trackpad
668         pState->sLeftPadX = pState->sPrevLeftPad[0] = pStatePacket->sLeftPadX;
669         pState->sLeftPadY = pState->sPrevLeftPad[1] = pStatePacket->sLeftPadY;
670 
671         if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_AND_JOYSTICK_MASK)
672         {
673             // The controller is interleaving both stick and pad data, both are active
674             pState->sLeftStickX = pState->sPrevLeftStick[0];
675             pState->sLeftStickY = pState->sPrevLeftStick[1];
676         }
677         else
678         {
679             // The stick is not active
680             pState->sPrevLeftStick[0] = 0;
681             pState->sPrevLeftStick[1] = 0;
682         }
683     }
684     else
685     {
686         // Finger-down bit not set; "left pad" is actually joystick
687 
688         // XXX there's a firmware bug where sometimes padX is 0 and padY is a large number (acutally the battery voltage)
689         // If that happens skip this packet and report last frames stick
690 /*
691         if ( m_eControllerType == k_eControllerType_SteamControllerV2 && pStatePacket->sLeftPadY > 900 )
692         {
693             pState->sLeftStickX = pState->sPrevLeftStick[0];
694             pState->sLeftStickY = pState->sPrevLeftStick[1];
695         }
696         else
697 */
698         {
699             pState->sPrevLeftStick[0] = pState->sLeftStickX = pStatePacket->sLeftPadX;
700             pState->sPrevLeftStick[1] = pState->sLeftStickY = pStatePacket->sLeftPadY;
701         }
702 /*
703         if (m_eControllerType == k_eControllerType_SteamControllerV2)
704         {
705             UpdateV2JoystickCap(&state);
706         }
707 */
708 
709         if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_AND_JOYSTICK_MASK)
710         {
711             // The controller is interleaving both stick and pad data, both are active
712             pState->sLeftPadX = pState->sPrevLeftPad[0];
713             pState->sLeftPadY = pState->sPrevLeftPad[1];
714         }
715         else
716         {
717             // The trackpad is not active
718             pState->sPrevLeftPad[0] = 0;
719             pState->sPrevLeftPad[1] = 0;
720 
721             // Old controllers send trackpad click for joystick button when trackpad is not active
722             if (pState->ulButtons & STEAM_BUTTON_LEFTPAD_CLICKED_MASK)
723             {
724                 pState->ulButtons &= ~STEAM_BUTTON_LEFTPAD_CLICKED_MASK;
725                 pState->ulButtons |= STEAM_JOYSTICK_BUTTON_MASK;
726             }
727         }
728     }
729 
730     // Fingerdown bit indicates if the packed left axis data was joystick or pad,
731     // but if we are interleaving both, the left finger is definitely on the pad.
732     if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_AND_JOYSTICK_MASK)
733         pState->ulButtons |= STEAM_LEFTPAD_FINGERDOWN_MASK;
734 
735     pState->sRightPadX = pStatePacket->sRightPadX;
736     pState->sRightPadY = pStatePacket->sRightPadY;
737 
738     int nLeftPadX = pState->sLeftPadX;
739     int nLeftPadY = pState->sLeftPadY;
740     int nRightPadX = pState->sRightPadX;
741     int nRightPadY = pState->sRightPadY;
742 
743     // 15 degrees in rad
744     const float flRotationAngle = 0.261799f;
745 
746     RotatePad(&nLeftPadX, &nLeftPadY, -flRotationAngle);
747     RotatePad(&nRightPadX, &nRightPadY, flRotationAngle);
748 
749     int nPadOffset;
750     if (pState->ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK)
751         nPadOffset = 1000;
752     else
753         nPadOffset = 0;
754 
755     pState->sLeftPadX = clamp(nLeftPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
756     pState->sLeftPadY = clamp(nLeftPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
757 
758     nPadOffset = 0;
759     if (pState->ulButtons & STEAM_RIGHTPAD_FINGERDOWN_MASK)
760         nPadOffset = 1000;
761     else
762         nPadOffset = 0;
763 
764     pState->sRightPadX = clamp(nRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
765     pState->sRightPadY = clamp(nRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
766 
767     pState->sTriggerL = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nLeft << 7) | pStatePacket->ButtonTriggerData.Triggers.nLeft, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
768     pState->sTriggerR = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nRight << 7) | pStatePacket->ButtonTriggerData.Triggers.nRight, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
769 }
770 
771 
772 //---------------------------------------------------------------------------
773 // Update Steam Controller state from a BLE data packet, returns true if it parsed data
774 //---------------------------------------------------------------------------
UpdateBLESteamControllerState(const uint8_t * pData,int nDataSize,SteamControllerStateInternal_t * pState)775 static bool UpdateBLESteamControllerState( const uint8_t *pData, int nDataSize, SteamControllerStateInternal_t *pState )
776 {
777     const float flRotationAngle = 0.261799f;
778     uint32_t ucOptionDataMask;
779 
780     pState->unPacketNum++;
781     ucOptionDataMask = ( *pData++ & 0xF0 );
782     ucOptionDataMask |= (uint32_t)(*pData++) << 8;
783     if ( ucOptionDataMask & k_EBLEButtonChunk1 )
784     {
785         memcpy( &pState->ulButtons, pData, 3 );
786         pData += 3;
787     }
788     if ( ucOptionDataMask & k_EBLEButtonChunk2 )
789     {
790         // The middle 2 bytes of the button bits over the wire are triggers when over the wire and non-SC buttons in the internal controller state packet
791         pState->sTriggerL = (unsigned short)RemapValClamped( ( pData[ 0 ] << 7 ) | pData[ 0 ], 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
792         pState->sTriggerR = (unsigned short)RemapValClamped( ( pData[ 1 ] << 7 ) | pData[ 1 ], 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
793         pData += 2;
794     }
795     if ( ucOptionDataMask & k_EBLEButtonChunk3 )
796     {
797         uint8_t *pButtonByte = (uint8_t *)&pState->ulButtons;
798         pButtonByte[ 5 ] = *pData++;
799         pButtonByte[ 6 ] = *pData++;
800         pButtonByte[ 7 ] = *pData++;
801     }
802     if ( ucOptionDataMask & k_EBLELeftJoystickChunk )
803     {
804         // This doesn't handle any of the special headcrab stuff for raw joystick which is OK for now since that FW doesn't support
805         // this protocol yet either
806         int nLength = sizeof( pState->sLeftStickX ) + sizeof( pState->sLeftStickY );
807         memcpy( &pState->sLeftStickX, pData, nLength );
808         pData += nLength;
809     }
810     if ( ucOptionDataMask & k_EBLELeftTrackpadChunk )
811     {
812         int nLength = sizeof( pState->sLeftPadX ) + sizeof( pState->sLeftPadY );
813         int nPadOffset;
814         memcpy( &pState->sLeftPadX, pData, nLength );
815         if ( pState->ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK )
816             nPadOffset = 1000;
817         else
818             nPadOffset = 0;
819 
820         RotatePadShort( &pState->sLeftPadX, &pState->sLeftPadY, -flRotationAngle );
821         pState->sLeftPadX = clamp( pState->sLeftPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
822         pState->sLeftPadY = clamp( pState->sLeftPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
823         pData += nLength;
824     }
825     if ( ucOptionDataMask & k_EBLERightTrackpadChunk )
826     {
827         int nLength = sizeof( pState->sRightPadX ) + sizeof( pState->sRightPadY );
828         int nPadOffset = 0;
829 
830         memcpy( &pState->sRightPadX, pData, nLength );
831 
832         if ( pState->ulButtons & STEAM_RIGHTPAD_FINGERDOWN_MASK )
833             nPadOffset = 1000;
834         else
835             nPadOffset = 0;
836 
837         RotatePadShort( &pState->sRightPadX, &pState->sRightPadY, flRotationAngle );
838         pState->sRightPadX = clamp( pState->sRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
839         pState->sRightPadY = clamp( pState->sRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
840         pData += nLength;
841     }
842     if ( ucOptionDataMask & k_EBLEIMUAccelChunk )
843     {
844         int nLength = sizeof( pState->sAccelX ) + sizeof( pState->sAccelY ) + sizeof( pState->sAccelZ );
845         memcpy( &pState->sAccelX, pData, nLength );
846         pData += nLength;
847     }
848     if ( ucOptionDataMask & k_EBLEIMUGyroChunk )
849     {
850         int nLength = sizeof( pState->sAccelX ) + sizeof( pState->sAccelY ) + sizeof( pState->sAccelZ );
851         memcpy( &pState->sGyroX, pData, nLength );
852         pData += nLength;
853     }
854     if ( ucOptionDataMask & k_EBLEIMUQuatChunk )
855     {
856         int nLength = sizeof( pState->sGyroQuatW ) + sizeof( pState->sGyroQuatX ) + sizeof( pState->sGyroQuatY ) + sizeof( pState->sGyroQuatZ );
857         memcpy( &pState->sGyroQuatW, pData, nLength );
858         pData += nLength;
859     }
860     return true;
861 }
862 
863 
864 //---------------------------------------------------------------------------
865 // Update Steam Controller state from a data packet, returns true if it parsed data
866 //---------------------------------------------------------------------------
UpdateSteamControllerState(const uint8_t * pData,int nDataSize,SteamControllerStateInternal_t * pState)867 static bool UpdateSteamControllerState( const uint8_t *pData, int nDataSize, SteamControllerStateInternal_t *pState )
868 {
869     ValveInReport_t *pInReport = (ValveInReport_t*)pData;
870 
871     if ( pInReport->header.unReportVersion != k_ValveInReportMsgVersion )
872     {
873         if ( ( pData[ 0 ] & 0x0F ) == k_EBLEReportState )
874         {
875             return UpdateBLESteamControllerState( pData, nDataSize, pState );
876         }
877         return false;
878     }
879 
880     if ( ( pInReport->header.ucType != ID_CONTROLLER_STATE ) &&
881          ( pInReport->header.ucType != ID_CONTROLLER_BLE_STATE ) )
882     {
883         return false;
884     }
885 
886     if ( pInReport->header.ucType == ID_CONTROLLER_STATE )
887     {
888         ValveControllerStatePacket_t *pStatePacket = &pInReport->payload.controllerState;
889 
890         // No new data to process; indicate that we received a state packet, but otherwise do nothing.
891         if ( pState->unPacketNum == pStatePacket->unPacketNum )
892             return true;
893 
894         FormatStatePacketUntilGyro( pState, pStatePacket );
895 
896         pState->sAccelX = pStatePacket->sAccelX;
897         pState->sAccelY = pStatePacket->sAccelY;
898         pState->sAccelZ = pStatePacket->sAccelZ;
899 
900         pState->sGyroQuatW = pStatePacket->sGyroQuatW;
901         pState->sGyroQuatX = pStatePacket->sGyroQuatX;
902         pState->sGyroQuatY = pStatePacket->sGyroQuatY;
903         pState->sGyroQuatZ = pStatePacket->sGyroQuatZ;
904 
905         pState->sGyroX = pStatePacket->sGyroX;
906         pState->sGyroY = pStatePacket->sGyroY;
907         pState->sGyroZ = pStatePacket->sGyroZ;
908 
909     }
910     else if ( pInReport->header.ucType == ID_CONTROLLER_BLE_STATE )
911     {
912         ValveControllerBLEStatePacket_t *pBLEStatePacket = &pInReport->payload.controllerBLEState;
913         ValveControllerStatePacket_t *pStatePacket = &pInReport->payload.controllerState;
914 
915         // No new data to process; indicate that we received a state packet, but otherwise do nothing.
916         if ( pState->unPacketNum == pStatePacket->unPacketNum )
917             return true;
918 
919         FormatStatePacketUntilGyro( pState, pStatePacket );
920 
921         switch ( pBLEStatePacket->ucGyroDataType )
922         {
923         case 1:
924             pState->sGyroQuatW = (( float ) pBLEStatePacket->sGyro[0]);
925             pState->sGyroQuatX = (( float ) pBLEStatePacket->sGyro[1]);
926             pState->sGyroQuatY = (( float ) pBLEStatePacket->sGyro[2]);
927             pState->sGyroQuatZ = (( float ) pBLEStatePacket->sGyro[3]);
928             break;
929 
930         case 2:
931             pState->sAccelX = pBLEStatePacket->sGyro[0];
932             pState->sAccelY = pBLEStatePacket->sGyro[1];
933             pState->sAccelZ = pBLEStatePacket->sGyro[2];
934             break;
935 
936         case 3:
937             pState->sGyroX = pBLEStatePacket->sGyro[0];
938             pState->sGyroY = pBLEStatePacket->sGyro[1];
939             pState->sGyroZ = pBLEStatePacket->sGyro[2];
940             break;
941 
942         default:
943             break;
944         }
945     }
946 
947     return true;
948 }
949 
950 /*****************************************************************************************************/
951 
952 typedef struct {
953     SteamControllerPacketAssembler m_assembler;
954     SteamControllerStateInternal_t m_state;
955     SteamControllerStateInternal_t m_last_state;
956 } SDL_DriverSteam_Context;
957 
958 
959 static SDL_bool
HIDAPI_DriverSteam_IsSupportedDevice(const char * name,SDL_GameControllerType type,Uint16 vendor_id,Uint16 product_id,Uint16 version,int interface_number,int interface_class,int interface_subclass,int interface_protocol)960 HIDAPI_DriverSteam_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
961 {
962     return SDL_IsJoystickSteamController(vendor_id, product_id);
963 }
964 
965 static const char *
HIDAPI_DriverSteam_GetDeviceName(Uint16 vendor_id,Uint16 product_id)966 HIDAPI_DriverSteam_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
967 {
968     return "Steam Controller";
969 }
970 
971 static SDL_bool
HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device * device)972 HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device)
973 {
974     return HIDAPI_JoystickConnected(device, NULL, SDL_FALSE);
975 }
976 
977 static int
HIDAPI_DriverSteam_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)978 HIDAPI_DriverSteam_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
979 {
980     return -1;
981 }
982 
983 static void
HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)984 HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
985 {
986 }
987 
988 static SDL_bool
HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)989 HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
990 {
991     SDL_DriverSteam_Context *ctx;
992 
993     ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx));
994     if (!ctx) {
995         SDL_OutOfMemory();
996         goto error;
997     }
998     device->context = ctx;
999 
1000     device->dev = hid_open_path(device->path, 0);
1001     if (!device->dev) {
1002         SDL_SetError("Couldn't open %s", device->path);
1003         goto error;
1004     }
1005 
1006     if (!ResetSteamController(device->dev, false)) {
1007         goto error;
1008     }
1009 
1010     InitializeSteamControllerPacketAssembler(&ctx->m_assembler);
1011 
1012     /* Initialize the joystick capabilities */
1013     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
1014     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
1015 
1016     return SDL_TRUE;
1017 
1018 error:
1019     if (device->dev) {
1020         hid_close(device->dev);
1021         device->dev = NULL;
1022     }
1023     if (device->context) {
1024         SDL_free(device->context);
1025         device->context = NULL;
1026     }
1027     return SDL_FALSE;
1028 }
1029 
1030 static int
HIDAPI_DriverSteam_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)1031 HIDAPI_DriverSteam_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1032 {
1033     /* You should use the full Steam Input API for rumble support */
1034     return SDL_Unsupported();
1035 }
1036 
1037 static SDL_bool
HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device * device)1038 HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
1039 {
1040     SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
1041     SDL_Joystick *joystick = NULL;
1042 
1043     if (device->num_joysticks > 0) {
1044         joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
1045     }
1046     if (!joystick) {
1047         return SDL_FALSE;
1048     }
1049 
1050     for (;;)
1051     {
1052         uint8_t data[128];
1053         int r, nPacketLength;
1054         const Uint8 *pPacket;
1055 
1056         r = ReadSteamController(device->dev, data, sizeof(data));
1057         if (r == 0)
1058         {
1059             break;
1060         }
1061 
1062         nPacketLength = 0;
1063         if (r > 0) {
1064             nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r);
1065         }
1066 
1067         pPacket = ctx->m_assembler.uBuffer;
1068 
1069         if (nPacketLength > 0 && UpdateSteamControllerState(pPacket, nPacketLength, &ctx->m_state)) {
1070             if (ctx->m_state.ulButtons != ctx->m_last_state.ulButtons) {
1071                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A,
1072                     (ctx->m_state.ulButtons & STEAM_BUTTON_3_MASK) ? SDL_PRESSED : SDL_RELEASED);
1073 
1074                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B,
1075                     (ctx->m_state.ulButtons & STEAM_BUTTON_1_MASK) ? SDL_PRESSED : SDL_RELEASED);
1076 
1077                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X,
1078                     (ctx->m_state.ulButtons & STEAM_BUTTON_2_MASK) ? SDL_PRESSED : SDL_RELEASED);
1079 
1080                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y,
1081                     (ctx->m_state.ulButtons & STEAM_BUTTON_0_MASK) ? SDL_PRESSED : SDL_RELEASED);
1082 
1083                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
1084                     (ctx->m_state.ulButtons & STEAM_LEFT_BUMPER_MASK) ? SDL_PRESSED : SDL_RELEASED);
1085 
1086                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
1087                     (ctx->m_state.ulButtons & STEAM_RIGHT_BUMPER_MASK) ? SDL_PRESSED : SDL_RELEASED);
1088 
1089                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK,
1090                     (ctx->m_state.ulButtons & STEAM_BUTTON_MENU_MASK) ? SDL_PRESSED : SDL_RELEASED);
1091 
1092                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START,
1093                     (ctx->m_state.ulButtons & STEAM_BUTTON_ESCAPE_MASK) ? SDL_PRESSED : SDL_RELEASED);
1094 
1095                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE,
1096                     (ctx->m_state.ulButtons & STEAM_BUTTON_STEAM_MASK) ? SDL_PRESSED : SDL_RELEASED);
1097 
1098                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK,
1099                     (ctx->m_state.ulButtons & STEAM_JOYSTICK_BUTTON_MASK) ? SDL_PRESSED : SDL_RELEASED);
1100             }
1101             {
1102                 /* Minimum distance from center of pad to register a direction */
1103                 const int kPadDeadZone = 10000;
1104 
1105                 /* Pad coordinates are like math grid coordinates: negative is bottom left */
1106                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP,
1107                     (ctx->m_state.sLeftPadY > kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1108 
1109                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN,
1110                     (ctx->m_state.sLeftPadY < -kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1111 
1112                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT,
1113                     (ctx->m_state.sLeftPadX < -kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1114 
1115                 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
1116                     (ctx->m_state.sLeftPadX > kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1117             }
1118 
1119             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, (int)ctx->m_state.sTriggerL * 2 - 32768);
1120             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, (int)ctx->m_state.sTriggerR * 2 - 32768);
1121 
1122             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, ctx->m_state.sLeftStickX);
1123             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~ctx->m_state.sLeftStickY);
1124             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, ctx->m_state.sRightPadX);
1125             SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~ctx->m_state.sRightPadY);
1126 
1127             ctx->m_last_state = ctx->m_state;
1128         }
1129 
1130         if (r <= 0) {
1131             /* Failed to read from controller */
1132             HIDAPI_JoystickDisconnected(device, device->joysticks[0], SDL_FALSE);
1133             return SDL_FALSE;
1134         }
1135     }
1136     return SDL_TRUE;
1137 }
1138 
1139 static void
HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1140 HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1141 {
1142     CloseSteamController(device->dev);
1143     hid_close(device->dev);
1144     device->dev = NULL;
1145 
1146     SDL_free(device->context);
1147     device->context = NULL;
1148 }
1149 
1150 static void
HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device * device)1151 HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device *device)
1152 {
1153 }
1154 
1155 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam =
1156 {
1157     SDL_HINT_JOYSTICK_HIDAPI_STEAM,
1158     SDL_TRUE,
1159     HIDAPI_DriverSteam_IsSupportedDevice,
1160     HIDAPI_DriverSteam_GetDeviceName,
1161     HIDAPI_DriverSteam_InitDevice,
1162     HIDAPI_DriverSteam_GetDevicePlayerIndex,
1163     HIDAPI_DriverSteam_SetDevicePlayerIndex,
1164     HIDAPI_DriverSteam_UpdateDevice,
1165     HIDAPI_DriverSteam_OpenJoystick,
1166     HIDAPI_DriverSteam_RumbleJoystick,
1167     HIDAPI_DriverSteam_CloseJoystick,
1168     HIDAPI_DriverSteam_FreeDevice,
1169 	NULL
1170 };
1171 
1172 #endif /* SDL_JOYSTICK_HIDAPI_STEAM */
1173 
1174 #endif /* SDL_JOYSTICK_HIDAPI */
1175 
1176 /* vi: set ts=4 sw=4 expandtab: */
1177