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