1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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 roundtrip". 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 SDL_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 uint8_t uSegmentHeader = pSegment[ 1 ];
243 int nSegmentNumber = uSegmentHeader & 0x07;
244
245 HEXDUMP( pSegment, nSegmentLength );
246
247 if ( pSegment[ 0 ] != BLE_REPORT_NUMBER )
248 {
249 // We may get keyboard/mouse input events until controller stops sending them
250 return 0;
251 }
252
253 if ( nSegmentLength != MAX_REPORT_SEGMENT_SIZE )
254 {
255 printf( "Bad segment size! %d\n", (int)nSegmentLength );
256 hexdump( pSegment, nSegmentLength );
257 ResetSteamControllerPacketAssembler( pAssembler );
258 return -1;
259 }
260
261 DPRINTF("GOT PACKET HEADER = 0x%x\n", uSegmentHeader);
262
263 if ( ( uSegmentHeader & REPORT_SEGMENT_DATA_FLAG ) == 0 )
264 {
265 // We get empty segments, just ignore them
266 return 0;
267 }
268
269 if ( nSegmentNumber != pAssembler->nExpectedSegmentNumber )
270 {
271 ResetSteamControllerPacketAssembler( pAssembler );
272
273 if ( nSegmentNumber )
274 {
275 // This happens occasionally
276 DPRINTF("Bad segment number, got %d, expected %d\n",
277 nSegmentNumber, pAssembler->nExpectedSegmentNumber );
278 return -1;
279 }
280 }
281
282 SDL_memcpy( pAssembler->uBuffer + nSegmentNumber * MAX_REPORT_SEGMENT_PAYLOAD_SIZE,
283 pSegment + 2, // ignore header and report number
284 MAX_REPORT_SEGMENT_PAYLOAD_SIZE );
285
286 if ( uSegmentHeader & REPORT_SEGMENT_LAST_FLAG )
287 {
288 pAssembler->nExpectedSegmentNumber = 0;
289 return ( nSegmentNumber + 1 ) * MAX_REPORT_SEGMENT_PAYLOAD_SIZE;
290 }
291
292 pAssembler->nExpectedSegmentNumber++;
293 }
294 else
295 {
296 // Just pass through
297 SDL_memcpy( pAssembler->uBuffer,
298 pSegment,
299 nSegmentLength );
300 return nSegmentLength;
301 }
302
303 return 0;
304 }
305
306 #define BLE_MAX_READ_RETRIES 8
307
SetFeatureReport(SDL_hid_device * dev,unsigned char uBuffer[65],int nActualDataLen)308 static int SetFeatureReport( SDL_hid_device *dev, unsigned char uBuffer[65], int nActualDataLen )
309 {
310 int nRet = -1;
311 bool bBle = true; // only wireless/BLE for now, though macOS could do wired in the future
312
313 DPRINTF("SetFeatureReport %p %p %d\n", dev, uBuffer, nActualDataLen);
314
315 if ( bBle )
316 {
317 int nSegmentNumber = 0;
318 uint8_t uPacketBuffer[ MAX_REPORT_SEGMENT_SIZE ];
319 unsigned char *pBufferPtr = uBuffer + 1;
320
321 if ( nActualDataLen < 1 )
322 return -1;
323
324 // Skip report number in data
325 nActualDataLen--;
326
327 while ( nActualDataLen > 0 )
328 {
329 int nBytesInPacket = nActualDataLen > MAX_REPORT_SEGMENT_PAYLOAD_SIZE ? MAX_REPORT_SEGMENT_PAYLOAD_SIZE : nActualDataLen;
330
331 nActualDataLen -= nBytesInPacket;
332
333 // Construct packet
334 SDL_memset( uPacketBuffer, 0, sizeof( uPacketBuffer ) );
335 uPacketBuffer[ 0 ] = BLE_REPORT_NUMBER;
336 uPacketBuffer[ 1 ] = GetSegmentHeader( nSegmentNumber, nActualDataLen == 0 );
337 SDL_memcpy( &uPacketBuffer[ 2 ], pBufferPtr, nBytesInPacket );
338
339 pBufferPtr += nBytesInPacket;
340 nSegmentNumber++;
341
342 nRet = SDL_hid_send_feature_report( dev, uPacketBuffer, sizeof( uPacketBuffer ) );
343 DPRINTF("SetFeatureReport() ret = %d\n", nRet);
344 }
345 }
346
347 return nRet;
348 }
349
GetFeatureReport(SDL_hid_device * dev,unsigned char uBuffer[65])350 static int GetFeatureReport( SDL_hid_device *dev, unsigned char uBuffer[65] )
351 {
352 int nRet = -1;
353 bool bBle = true;
354
355 DPRINTF("GetFeatureReport( %p %p )\n", dev, uBuffer );
356
357 if ( bBle )
358 {
359 int nRetries = 0;
360 uint8_t uSegmentBuffer[ MAX_REPORT_SEGMENT_SIZE ];
361
362 SteamControllerPacketAssembler assembler;
363 InitializeSteamControllerPacketAssembler( &assembler );
364
365 while( nRetries < BLE_MAX_READ_RETRIES )
366 {
367 SDL_memset( uSegmentBuffer, 0, sizeof( uSegmentBuffer ) );
368 uSegmentBuffer[ 0 ] = BLE_REPORT_NUMBER;
369 nRet = SDL_hid_get_feature_report( dev, uSegmentBuffer, sizeof( uSegmentBuffer ) );
370 DPRINTF( "GetFeatureReport ble ret=%d\n", nRet );
371 HEXDUMP( uSegmentBuffer, nRet );
372
373 // Zero retry counter if we got data
374 if ( nRet > 2 && ( uSegmentBuffer[ 1 ] & REPORT_SEGMENT_DATA_FLAG ) )
375 nRetries = 0;
376 else
377 nRetries++;
378
379 if ( nRet > 0 )
380 {
381 int nPacketLength = WriteSegmentToSteamControllerPacketAssembler( &assembler,
382 uSegmentBuffer,
383 nRet );
384
385 if ( nPacketLength > 0 && nPacketLength < 65 )
386 {
387 // Leave space for "report number"
388 uBuffer[ 0 ] = 0;
389 SDL_memcpy( uBuffer + 1, assembler.uBuffer, nPacketLength );
390 return nPacketLength;
391 }
392 }
393
394
395 }
396 printf("Could not get a full ble packet after %d retries\n", nRetries );
397 return -1;
398 }
399
400 return nRet;
401 }
402
ReadResponse(SDL_hid_device * dev,uint8_t uBuffer[65],int nExpectedResponse)403 static int ReadResponse( SDL_hid_device *dev, uint8_t uBuffer[65], int nExpectedResponse )
404 {
405 int nRet = GetFeatureReport( dev, uBuffer );
406
407 DPRINTF("ReadResponse( %p %p %d )\n", dev, uBuffer, nExpectedResponse );
408
409 if ( nRet < 0 )
410 return nRet;
411
412 DPRINTF("ReadResponse got %d bytes of data: ", nRet );
413 HEXDUMP( uBuffer, nRet );
414
415 if ( uBuffer[1] != nExpectedResponse )
416 return -1;
417
418 return nRet;
419 }
420
421 //---------------------------------------------------------------------------
422 // Reset steam controller (unmap buttons and pads) and re-fetch capability bits
423 //---------------------------------------------------------------------------
ResetSteamController(SDL_hid_device * dev,bool bSuppressErrorSpew,uint32_t * punUpdateRateUS)424 static bool ResetSteamController( SDL_hid_device *dev, bool bSuppressErrorSpew, uint32_t *punUpdateRateUS )
425 {
426 // Firmware quirk: Set Feature and Get Feature requests always require a 65-byte buffer.
427 unsigned char buf[65];
428 int res = -1, i;
429 int nSettings = 0;
430 int nAttributesLength;
431 FeatureReportMsg *msg;
432 uint32_t unUpdateRateUS = 9000; // Good default rate
433
434 DPRINTF( "ResetSteamController hid=%p\n", dev );
435
436 buf[0] = 0;
437 buf[1] = ID_GET_ATTRIBUTES_VALUES;
438 res = SetFeatureReport( dev, buf, 2 );
439 if ( res < 0 )
440 {
441 if ( !bSuppressErrorSpew )
442 printf( "GET_ATTRIBUTES_VALUES failed for controller %p\n", dev );
443 return false;
444 }
445
446 // Retrieve GET_ATTRIBUTES_VALUES result
447 // Wireless controller endpoints without a connected controller will return nAttrs == 0
448 res = ReadResponse( dev, buf, ID_GET_ATTRIBUTES_VALUES );
449 if ( res < 0 || buf[1] != ID_GET_ATTRIBUTES_VALUES )
450 {
451 HEXDUMP(buf, res);
452 if ( !bSuppressErrorSpew )
453 printf( "Bad GET_ATTRIBUTES_VALUES response for controller %p\n", dev );
454 return false;
455 }
456
457 nAttributesLength = buf[ 2 ];
458 if ( nAttributesLength > res )
459 {
460 if ( !bSuppressErrorSpew )
461 printf( "Bad GET_ATTRIBUTES_VALUES response for controller %p\n", dev );
462 return false;
463 }
464
465 msg = (FeatureReportMsg *)&buf[1];
466 for ( i = 0; i < (int)msg->header.length / sizeof( ControllerAttribute ); ++i )
467 {
468 uint8_t unAttribute = msg->payload.getAttributes.attributes[i].attributeTag;
469 uint32_t unValue = msg->payload.getAttributes.attributes[i].attributeValue;
470
471 switch ( unAttribute )
472 {
473 case ATTRIB_UNIQUE_ID:
474 break;
475 case ATTRIB_PRODUCT_ID:
476 break;
477 case ATTRIB_CAPABILITIES:
478 break;
479 case ATTRIB_CONNECTION_INTERVAL_IN_US:
480 unUpdateRateUS = unValue;
481 break;
482 default:
483 break;
484 }
485 }
486 if ( punUpdateRateUS )
487 {
488 *punUpdateRateUS = unUpdateRateUS;
489 }
490
491 // Clear digital button mappings
492 buf[0] = 0;
493 buf[1] = ID_CLEAR_DIGITAL_MAPPINGS;
494 res = SetFeatureReport( dev, buf, 2 );
495 if ( res < 0 )
496 {
497 if ( !bSuppressErrorSpew )
498 printf( "CLEAR_DIGITAL_MAPPINGS failed for controller %p\n", dev );
499 return false;
500 }
501
502 // Reset the default settings
503 SDL_memset( buf, 0, 65 );
504 buf[1] = ID_LOAD_DEFAULT_SETTINGS;
505 buf[2] = 0;
506 res = SetFeatureReport( dev, buf, 3 );
507 if ( res < 0 )
508 {
509 if ( !bSuppressErrorSpew )
510 printf( "LOAD_DEFAULT_SETTINGS failed for controller %p\n", dev );
511 return false;
512 }
513
514 // Apply custom settings - clear trackpad modes (cancel mouse emulation), etc
515 #define ADD_SETTING(SETTING, VALUE) \
516 buf[3+nSettings*3] = SETTING; \
517 buf[3+nSettings*3+1] = ((uint16_t)VALUE)&0xFF; \
518 buf[3+nSettings*3+2] = ((uint16_t)VALUE)>>8; \
519 ++nSettings;
520
521 SDL_memset( buf, 0, 65 );
522 buf[1] = ID_SET_SETTINGS_VALUES;
523 ADD_SETTING( SETTING_WIRELESS_PACKET_VERSION, 2 );
524 ADD_SETTING( SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE );
525 #ifdef ENABLE_MOUSE_MODE
526 ADD_SETTING( SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_ABSOLUTE_MOUSE );
527 ADD_SETTING( SETTING_SMOOTH_ABSOLUTE_MOUSE, 1 );
528 ADD_SETTING( SETTING_MOMENTUM_MAXIMUM_VELOCITY, 20000 ); // [0-20000] default 8000
529 ADD_SETTING( SETTING_MOMENTUM_DECAY_AMMOUNT, 50 ); // [0-50] default 5
530 #else
531 ADD_SETTING( SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE );
532 ADD_SETTING( SETTING_SMOOTH_ABSOLUTE_MOUSE, 0 );
533 #endif
534 buf[2] = nSettings*3;
535
536 res = SetFeatureReport( dev, buf, 3+nSettings*3 );
537 if ( res < 0 )
538 {
539 if ( !bSuppressErrorSpew )
540 printf( "SET_SETTINGS failed for controller %p\n", dev );
541 return false;
542 }
543
544 #ifdef ENABLE_MOUSE_MODE
545 // Wait for ID_CLEAR_DIGITAL_MAPPINGS to be processed on the controller
546 bool bMappingsCleared = false;
547 int iRetry;
548 for ( iRetry = 0; iRetry < 2; ++iRetry )
549 {
550 SDL_memset( buf, 0, 65 );
551 buf[1] = ID_GET_DIGITAL_MAPPINGS;
552 buf[2] = 1; // one byte - requesting from index 0
553 buf[3] = 0;
554 res = SetFeatureReport( dev, buf, 4 );
555 if ( res < 0 )
556 {
557 printf( "GET_DIGITAL_MAPPINGS failed for controller %p\n", dev );
558 return false;
559 }
560
561 res = ReadResponse( dev, buf, ID_GET_DIGITAL_MAPPINGS );
562 if ( res < 0 || buf[1] != ID_GET_DIGITAL_MAPPINGS )
563 {
564 printf( "Bad GET_DIGITAL_MAPPINGS response for controller %p\n", dev );
565 return false;
566 }
567
568 // If the length of the digital mappings result is not 1 (index byte, no mappings) then clearing hasn't executed
569 if ( buf[2] == 1 && buf[3] == 0xFF )
570 {
571 bMappingsCleared = true;
572 break;
573 }
574 usleep( CONTROLLER_CONFIGURATION_DELAY_US );
575 }
576
577 if ( !bMappingsCleared && !bSuppressErrorSpew )
578 {
579 printf( "Warning: CLEAR_DIGITAL_MAPPINGS never completed for controller %p\n", dev );
580 }
581
582 // Set our new mappings
583 SDL_memset( buf, 0, 65 );
584 buf[1] = ID_SET_DIGITAL_MAPPINGS;
585 buf[2] = 6; // 2 settings x 3 bytes
586 buf[3] = IO_DIGITAL_BUTTON_RIGHT_TRIGGER;
587 buf[4] = DEVICE_MOUSE;
588 buf[5] = MOUSE_BTN_LEFT;
589 buf[6] = IO_DIGITAL_BUTTON_LEFT_TRIGGER;
590 buf[7] = DEVICE_MOUSE;
591 buf[8] = MOUSE_BTN_RIGHT;
592
593 res = SetFeatureReport( dev, buf, 9 );
594 if ( res < 0 )
595 {
596 if ( !bSuppressErrorSpew )
597 printf( "SET_DIGITAL_MAPPINGS failed for controller %p\n", dev );
598 return false;
599 }
600 #endif // ENABLE_MOUSE_MODE
601
602 return true;
603 }
604
605
606 //---------------------------------------------------------------------------
607 // Read from a Steam Controller
608 //---------------------------------------------------------------------------
ReadSteamController(SDL_hid_device * dev,uint8_t * pData,int nDataSize)609 static int ReadSteamController( SDL_hid_device *dev, uint8_t *pData, int nDataSize )
610 {
611 SDL_memset( pData, 0, nDataSize );
612 pData[ 0 ] = BLE_REPORT_NUMBER; // hid_read will also overwrite this with the same value, 0x03
613 return SDL_hid_read( dev, pData, nDataSize );
614 }
615
616
617 //---------------------------------------------------------------------------
618 // Close a Steam Controller
619 //---------------------------------------------------------------------------
CloseSteamController(SDL_hid_device * dev)620 static void CloseSteamController( SDL_hid_device *dev )
621 {
622 // Switch the Steam Controller back to lizard mode so it works with the OS
623 unsigned char buf[65];
624 int nSettings = 0;
625
626 // Reset digital button mappings
627 SDL_memset( buf, 0, 65 );
628 buf[1] = ID_SET_DEFAULT_DIGITAL_MAPPINGS;
629 SetFeatureReport( dev, buf, 2 );
630
631 // Reset the default settings
632 SDL_memset( buf, 0, 65 );
633 buf[1] = ID_LOAD_DEFAULT_SETTINGS;
634 buf[2] = 0;
635 SetFeatureReport( dev, buf, 3 );
636
637 // Reset mouse mode for lizard mode
638 SDL_memset( buf, 0, 65 );
639 buf[1] = ID_SET_SETTINGS_VALUES;
640 ADD_SETTING( SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_ABSOLUTE_MOUSE );
641 buf[2] = nSettings*3;
642 SetFeatureReport( dev, buf, 3+nSettings*3 );
643 }
644
645
646 //---------------------------------------------------------------------------
647 // Scale and clamp values to a range
648 //---------------------------------------------------------------------------
RemapValClamped(float val,float A,float B,float C,float D)649 static float RemapValClamped( float val, float A, float B, float C, float D)
650 {
651 if ( A == B )
652 {
653 return ( val - B ) >= 0.0f ? D : C;
654 }
655 else
656 {
657 float cVal = (val - A) / (B - A);
658 cVal = clamp( cVal, 0.0f, 1.0f );
659
660 return C + (D - C) * cVal;
661 }
662 }
663
664
665 //---------------------------------------------------------------------------
666 // Rotate the pad coordinates
667 //---------------------------------------------------------------------------
RotatePad(int * pX,int * pY,float flAngleInRad)668 static void RotatePad( int *pX, int *pY, float flAngleInRad )
669 {
670 short int origX = *pX, origY = *pY;
671
672 *pX = (int)( SDL_cosf( flAngleInRad ) * origX - SDL_sinf( flAngleInRad ) * origY );
673 *pY = (int)( SDL_sinf( flAngleInRad ) * origX + SDL_cosf( flAngleInRad ) * origY );
674 }
RotatePadShort(short * pX,short * pY,float flAngleInRad)675 static void RotatePadShort( short *pX, short *pY, float flAngleInRad )
676 {
677 short int origX = *pX, origY = *pY;
678
679 *pX = (short)( SDL_cosf( flAngleInRad ) * origX - SDL_sinf( flAngleInRad ) * origY );
680 *pY = (short)( SDL_sinf( flAngleInRad ) * origX + SDL_cosf( flAngleInRad ) * origY );
681 }
682
683
684 //---------------------------------------------------------------------------
685 // Format the first part of the state packet
686 //---------------------------------------------------------------------------
FormatStatePacketUntilGyro(SteamControllerStateInternal_t * pState,ValveControllerStatePacket_t * pStatePacket)687 static void FormatStatePacketUntilGyro( SteamControllerStateInternal_t *pState, ValveControllerStatePacket_t *pStatePacket )
688 {
689 int nLeftPadX;
690 int nLeftPadY;
691 int nRightPadX;
692 int nRightPadY;
693 int nPadOffset;
694
695 // 15 degrees in rad
696 const float flRotationAngle = 0.261799f;
697
698 SDL_memset(pState, 0, offsetof(SteamControllerStateInternal_t, sBatteryLevel));
699
700 //pState->eControllerType = m_eControllerType;
701 pState->eControllerType = 2; // k_eControllerType_SteamController;
702 pState->unPacketNum = pStatePacket->unPacketNum;
703
704 // We have a chunk of trigger data in the packet format here, so zero it out afterwards
705 SDL_memcpy(&pState->ulButtons, &pStatePacket->ButtonTriggerData.ulButtons, 8);
706 pState->ulButtons &= ~0xFFFF000000LL;
707
708 // The firmware uses this bit to tell us what kind of data is packed into the left two axises
709 if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK)
710 {
711 // Finger-down bit not set; "left pad" is actually trackpad
712 pState->sLeftPadX = pState->sPrevLeftPad[0] = pStatePacket->sLeftPadX;
713 pState->sLeftPadY = pState->sPrevLeftPad[1] = pStatePacket->sLeftPadY;
714
715 if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_AND_JOYSTICK_MASK)
716 {
717 // The controller is interleaving both stick and pad data, both are active
718 pState->sLeftStickX = pState->sPrevLeftStick[0];
719 pState->sLeftStickY = pState->sPrevLeftStick[1];
720 }
721 else
722 {
723 // The stick is not active
724 pState->sPrevLeftStick[0] = 0;
725 pState->sPrevLeftStick[1] = 0;
726 }
727 }
728 else
729 {
730 // Finger-down bit not set; "left pad" is actually joystick
731
732 // XXX there's a firmware bug where sometimes padX is 0 and padY is a large number (acutally the battery voltage)
733 // If that happens skip this packet and report last frames stick
734 /*
735 if ( m_eControllerType == k_eControllerType_SteamControllerV2 && pStatePacket->sLeftPadY > 900 )
736 {
737 pState->sLeftStickX = pState->sPrevLeftStick[0];
738 pState->sLeftStickY = pState->sPrevLeftStick[1];
739 }
740 else
741 */
742 {
743 pState->sPrevLeftStick[0] = pState->sLeftStickX = pStatePacket->sLeftPadX;
744 pState->sPrevLeftStick[1] = pState->sLeftStickY = pStatePacket->sLeftPadY;
745 }
746 /*
747 if (m_eControllerType == k_eControllerType_SteamControllerV2)
748 {
749 UpdateV2JoystickCap(&state);
750 }
751 */
752
753 if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_AND_JOYSTICK_MASK)
754 {
755 // The controller is interleaving both stick and pad data, both are active
756 pState->sLeftPadX = pState->sPrevLeftPad[0];
757 pState->sLeftPadY = pState->sPrevLeftPad[1];
758 }
759 else
760 {
761 // The trackpad is not active
762 pState->sPrevLeftPad[0] = 0;
763 pState->sPrevLeftPad[1] = 0;
764
765 // Old controllers send trackpad click for joystick button when trackpad is not active
766 if (pState->ulButtons & STEAM_BUTTON_LEFTPAD_CLICKED_MASK)
767 {
768 pState->ulButtons &= ~STEAM_BUTTON_LEFTPAD_CLICKED_MASK;
769 pState->ulButtons |= STEAM_JOYSTICK_BUTTON_MASK;
770 }
771 }
772 }
773
774 // Fingerdown bit indicates if the packed left axis data was joystick or pad,
775 // but if we are interleaving both, the left finger is definitely on the pad.
776 if (pStatePacket->ButtonTriggerData.ulButtons & STEAM_LEFTPAD_AND_JOYSTICK_MASK)
777 pState->ulButtons |= STEAM_LEFTPAD_FINGERDOWN_MASK;
778
779 pState->sRightPadX = pStatePacket->sRightPadX;
780 pState->sRightPadY = pStatePacket->sRightPadY;
781
782 nLeftPadX = pState->sLeftPadX;
783 nLeftPadY = pState->sLeftPadY;
784 nRightPadX = pState->sRightPadX;
785 nRightPadY = pState->sRightPadY;
786
787 RotatePad(&nLeftPadX, &nLeftPadY, -flRotationAngle);
788 RotatePad(&nRightPadX, &nRightPadY, flRotationAngle);
789
790 if (pState->ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK)
791 nPadOffset = 1000;
792 else
793 nPadOffset = 0;
794
795 pState->sLeftPadX = clamp(nLeftPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
796 pState->sLeftPadY = clamp(nLeftPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
797
798 nPadOffset = 0;
799 if (pState->ulButtons & STEAM_RIGHTPAD_FINGERDOWN_MASK)
800 nPadOffset = 1000;
801 else
802 nPadOffset = 0;
803
804 pState->sRightPadX = clamp(nRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
805 pState->sRightPadY = clamp(nRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
806
807 pState->sTriggerL = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nLeft << 7) | pStatePacket->ButtonTriggerData.Triggers.nLeft, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
808 pState->sTriggerR = (unsigned short)RemapValClamped( (pStatePacket->ButtonTriggerData.Triggers.nRight << 7) | pStatePacket->ButtonTriggerData.Triggers.nRight, 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
809 }
810
811
812 //---------------------------------------------------------------------------
813 // Update Steam Controller state from a BLE data packet, returns true if it parsed data
814 //---------------------------------------------------------------------------
UpdateBLESteamControllerState(const uint8_t * pData,int nDataSize,SteamControllerStateInternal_t * pState)815 static bool UpdateBLESteamControllerState( const uint8_t *pData, int nDataSize, SteamControllerStateInternal_t *pState )
816 {
817 const float flRotationAngle = 0.261799f;
818 uint32_t ucOptionDataMask;
819
820 pState->unPacketNum++;
821 ucOptionDataMask = ( *pData++ & 0xF0 );
822 ucOptionDataMask |= (uint32_t)(*pData++) << 8;
823 if ( ucOptionDataMask & k_EBLEButtonChunk1 )
824 {
825 SDL_memcpy( &pState->ulButtons, pData, 3 );
826 pData += 3;
827 }
828 if ( ucOptionDataMask & k_EBLEButtonChunk2 )
829 {
830 // 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
831 pState->sTriggerL = (unsigned short)RemapValClamped( ( pData[ 0 ] << 7 ) | pData[ 0 ], 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
832 pState->sTriggerR = (unsigned short)RemapValClamped( ( pData[ 1 ] << 7 ) | pData[ 1 ], 0, STEAMCONTROLLER_TRIGGER_MAX_ANALOG, 0, SDL_MAX_SINT16 );
833 pData += 2;
834 }
835 if ( ucOptionDataMask & k_EBLEButtonChunk3 )
836 {
837 uint8_t *pButtonByte = (uint8_t *)&pState->ulButtons;
838 pButtonByte[ 5 ] = *pData++;
839 pButtonByte[ 6 ] = *pData++;
840 pButtonByte[ 7 ] = *pData++;
841 }
842 if ( ucOptionDataMask & k_EBLELeftJoystickChunk )
843 {
844 // This doesn't handle any of the special headcrab stuff for raw joystick which is OK for now since that FW doesn't support
845 // this protocol yet either
846 int nLength = sizeof( pState->sLeftStickX ) + sizeof( pState->sLeftStickY );
847 SDL_memcpy( &pState->sLeftStickX, pData, nLength );
848 pData += nLength;
849 }
850 if ( ucOptionDataMask & k_EBLELeftTrackpadChunk )
851 {
852 int nLength = sizeof( pState->sLeftPadX ) + sizeof( pState->sLeftPadY );
853 int nPadOffset;
854 SDL_memcpy( &pState->sLeftPadX, pData, nLength );
855 if ( pState->ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK )
856 nPadOffset = 1000;
857 else
858 nPadOffset = 0;
859
860 RotatePadShort( &pState->sLeftPadX, &pState->sLeftPadY, -flRotationAngle );
861 pState->sLeftPadX = clamp( pState->sLeftPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
862 pState->sLeftPadY = clamp( pState->sLeftPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
863 pData += nLength;
864 }
865 if ( ucOptionDataMask & k_EBLERightTrackpadChunk )
866 {
867 int nLength = sizeof( pState->sRightPadX ) + sizeof( pState->sRightPadY );
868 int nPadOffset = 0;
869
870 SDL_memcpy( &pState->sRightPadX, pData, nLength );
871
872 if ( pState->ulButtons & STEAM_RIGHTPAD_FINGERDOWN_MASK )
873 nPadOffset = 1000;
874 else
875 nPadOffset = 0;
876
877 RotatePadShort( &pState->sRightPadX, &pState->sRightPadY, flRotationAngle );
878 pState->sRightPadX = clamp( pState->sRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
879 pState->sRightPadY = clamp( pState->sRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16 );
880 pData += nLength;
881 }
882 if ( ucOptionDataMask & k_EBLEIMUAccelChunk )
883 {
884 int nLength = sizeof( pState->sAccelX ) + sizeof( pState->sAccelY ) + sizeof( pState->sAccelZ );
885 SDL_memcpy( &pState->sAccelX, pData, nLength );
886 pData += nLength;
887 }
888 if ( ucOptionDataMask & k_EBLEIMUGyroChunk )
889 {
890 int nLength = sizeof( pState->sAccelX ) + sizeof( pState->sAccelY ) + sizeof( pState->sAccelZ );
891 SDL_memcpy( &pState->sGyroX, pData, nLength );
892 pData += nLength;
893 }
894 if ( ucOptionDataMask & k_EBLEIMUQuatChunk )
895 {
896 int nLength = sizeof( pState->sGyroQuatW ) + sizeof( pState->sGyroQuatX ) + sizeof( pState->sGyroQuatY ) + sizeof( pState->sGyroQuatZ );
897 SDL_memcpy( &pState->sGyroQuatW, pData, nLength );
898 pData += nLength;
899 }
900 return true;
901 }
902
903
904 //---------------------------------------------------------------------------
905 // Update Steam Controller state from a data packet, returns true if it parsed data
906 //---------------------------------------------------------------------------
UpdateSteamControllerState(const uint8_t * pData,int nDataSize,SteamControllerStateInternal_t * pState)907 static bool UpdateSteamControllerState( const uint8_t *pData, int nDataSize, SteamControllerStateInternal_t *pState )
908 {
909 ValveInReport_t *pInReport = (ValveInReport_t*)pData;
910
911 if ( pInReport->header.unReportVersion != k_ValveInReportMsgVersion )
912 {
913 if ( ( pData[ 0 ] & 0x0F ) == k_EBLEReportState )
914 {
915 return UpdateBLESteamControllerState( pData, nDataSize, pState );
916 }
917 return false;
918 }
919
920 if ( ( pInReport->header.ucType != ID_CONTROLLER_STATE ) &&
921 ( pInReport->header.ucType != ID_CONTROLLER_BLE_STATE ) )
922 {
923 return false;
924 }
925
926 if ( pInReport->header.ucType == ID_CONTROLLER_STATE )
927 {
928 ValveControllerStatePacket_t *pStatePacket = &pInReport->payload.controllerState;
929
930 // No new data to process; indicate that we received a state packet, but otherwise do nothing.
931 if ( pState->unPacketNum == pStatePacket->unPacketNum )
932 return true;
933
934 FormatStatePacketUntilGyro( pState, pStatePacket );
935
936 pState->sAccelX = pStatePacket->sAccelX;
937 pState->sAccelY = pStatePacket->sAccelY;
938 pState->sAccelZ = pStatePacket->sAccelZ;
939
940 pState->sGyroQuatW = pStatePacket->sGyroQuatW;
941 pState->sGyroQuatX = pStatePacket->sGyroQuatX;
942 pState->sGyroQuatY = pStatePacket->sGyroQuatY;
943 pState->sGyroQuatZ = pStatePacket->sGyroQuatZ;
944
945 pState->sGyroX = pStatePacket->sGyroX;
946 pState->sGyroY = pStatePacket->sGyroY;
947 pState->sGyroZ = pStatePacket->sGyroZ;
948
949 }
950 else if ( pInReport->header.ucType == ID_CONTROLLER_BLE_STATE )
951 {
952 ValveControllerBLEStatePacket_t *pBLEStatePacket = &pInReport->payload.controllerBLEState;
953 ValveControllerStatePacket_t *pStatePacket = &pInReport->payload.controllerState;
954
955 // No new data to process; indicate that we received a state packet, but otherwise do nothing.
956 if ( pState->unPacketNum == pStatePacket->unPacketNum )
957 return true;
958
959 FormatStatePacketUntilGyro( pState, pStatePacket );
960
961 switch ( pBLEStatePacket->ucGyroDataType )
962 {
963 case 1:
964 pState->sGyroQuatW = (( float ) pBLEStatePacket->sGyro[0]);
965 pState->sGyroQuatX = (( float ) pBLEStatePacket->sGyro[1]);
966 pState->sGyroQuatY = (( float ) pBLEStatePacket->sGyro[2]);
967 pState->sGyroQuatZ = (( float ) pBLEStatePacket->sGyro[3]);
968 break;
969
970 case 2:
971 pState->sAccelX = pBLEStatePacket->sGyro[0];
972 pState->sAccelY = pBLEStatePacket->sGyro[1];
973 pState->sAccelZ = pBLEStatePacket->sGyro[2];
974 break;
975
976 case 3:
977 pState->sGyroX = pBLEStatePacket->sGyro[0];
978 pState->sGyroY = pBLEStatePacket->sGyro[1];
979 pState->sGyroZ = pBLEStatePacket->sGyro[2];
980 break;
981
982 default:
983 break;
984 }
985 }
986
987 return true;
988 }
989
990 /*****************************************************************************************************/
991
992 typedef struct {
993 SDL_bool report_sensors;
994 SteamControllerPacketAssembler m_assembler;
995 SteamControllerStateInternal_t m_state;
996 SteamControllerStateInternal_t m_last_state;
997 } SDL_DriverSteam_Context;
998
999
1000 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)1001 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)
1002 {
1003 return SDL_IsJoystickSteamController(vendor_id, product_id);
1004 }
1005
1006 static const char *
HIDAPI_DriverSteam_GetDeviceName(Uint16 vendor_id,Uint16 product_id)1007 HIDAPI_DriverSteam_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
1008 {
1009 return "Steam Controller";
1010 }
1011
1012 static SDL_bool
HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device * device)1013 HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device)
1014 {
1015 return HIDAPI_JoystickConnected(device, NULL);
1016 }
1017
1018 static int
HIDAPI_DriverSteam_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)1019 HIDAPI_DriverSteam_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
1020 {
1021 return -1;
1022 }
1023
1024 static void
HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)1025 HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
1026 {
1027 }
1028
1029 static SDL_bool
HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1030 HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1031 {
1032 SDL_DriverSteam_Context *ctx;
1033 uint32_t update_rate_in_us = 0;
1034 float update_rate_in_hz = 0.0f;
1035
1036 ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx));
1037 if (!ctx) {
1038 SDL_OutOfMemory();
1039 goto error;
1040 }
1041 device->context = ctx;
1042
1043 device->dev = SDL_hid_open_path(device->path, 0);
1044 if (!device->dev) {
1045 SDL_SetError("Couldn't open %s", device->path);
1046 goto error;
1047 }
1048 SDL_hid_set_nonblocking(device->dev, 1);
1049
1050 if (!ResetSteamController(device->dev, false, &update_rate_in_us)) {
1051 SDL_SetError("Couldn't reset controller");
1052 goto error;
1053 }
1054 if (update_rate_in_us > 0) {
1055 update_rate_in_hz = 1000000.0f / update_rate_in_us;
1056 }
1057
1058 InitializeSteamControllerPacketAssembler(&ctx->m_assembler);
1059
1060 /* Initialize the joystick capabilities */
1061 joystick->nbuttons = 17;
1062 joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
1063
1064 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, update_rate_in_hz);
1065 SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
1066
1067 return SDL_TRUE;
1068
1069 error:
1070 SDL_LockMutex(device->dev_lock);
1071 {
1072 if (device->dev) {
1073 SDL_hid_close(device->dev);
1074 device->dev = NULL;
1075 }
1076 if (device->context) {
1077 SDL_free(device->context);
1078 device->context = NULL;
1079 }
1080 }
1081 SDL_UnlockMutex(device->dev_lock);
1082 return SDL_FALSE;
1083 }
1084
1085 static int
HIDAPI_DriverSteam_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)1086 HIDAPI_DriverSteam_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1087 {
1088 /* You should use the full Steam Input API for rumble support */
1089 return SDL_Unsupported();
1090 }
1091
1092 static int
HIDAPI_DriverSteam_RumbleJoystickTriggers(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)1093 HIDAPI_DriverSteam_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1094 {
1095 return SDL_Unsupported();
1096 }
1097
1098 static Uint32
HIDAPI_DriverSteam_GetJoystickCapabilities(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1099 HIDAPI_DriverSteam_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1100 {
1101 /* You should use the full Steam Input API for LED support */
1102 return 0;
1103 }
1104
1105 static int
HIDAPI_DriverSteam_SetJoystickLED(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)1106 HIDAPI_DriverSteam_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1107 {
1108 /* You should use the full Steam Input API for LED support */
1109 return SDL_Unsupported();
1110 }
1111
1112 static int
HIDAPI_DriverSteam_SendJoystickEffect(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,const void * data,int size)1113 HIDAPI_DriverSteam_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
1114 {
1115 return SDL_Unsupported();
1116 }
1117
1118 static int
HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,SDL_bool enabled)1119 HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
1120 {
1121 SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
1122 unsigned char buf[65];
1123 int nSettings = 0;
1124
1125 SDL_memset( buf, 0, 65 );
1126 buf[1] = ID_SET_SETTINGS_VALUES;
1127 if (enabled) {
1128 ADD_SETTING( SETTING_GYRO_MODE, 0x18 /* SETTING_GYRO_SEND_RAW_ACCEL | SETTING_GYRO_MODE_SEND_RAW_GYRO */ );
1129 } else {
1130 ADD_SETTING( SETTING_GYRO_MODE, 0x00 /* SETTING_GYRO_MODE_OFF */ );
1131 }
1132 buf[2] = nSettings*3;
1133 if (SetFeatureReport( device->dev, buf, 3+nSettings*3 ) < 0) {
1134 return SDL_SetError("Couldn't write feature report");
1135 }
1136
1137 ctx->report_sensors = enabled;
1138
1139 return 0;
1140 }
1141
1142 static SDL_bool
HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device * device)1143 HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
1144 {
1145 SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
1146 SDL_Joystick *joystick = NULL;
1147
1148 if (device->num_joysticks > 0) {
1149 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
1150 }
1151 if (!joystick) {
1152 return SDL_FALSE;
1153 }
1154
1155 for (;;)
1156 {
1157 uint8_t data[128];
1158 int r, nPacketLength;
1159 const Uint8 *pPacket;
1160
1161 r = ReadSteamController(device->dev, data, sizeof(data));
1162 if (r == 0)
1163 {
1164 break;
1165 }
1166
1167 nPacketLength = 0;
1168 if (r > 0) {
1169 nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r);
1170 }
1171
1172 pPacket = ctx->m_assembler.uBuffer;
1173
1174 if (nPacketLength > 0 && UpdateSteamControllerState(pPacket, nPacketLength, &ctx->m_state)) {
1175 if (ctx->m_state.ulButtons != ctx->m_last_state.ulButtons) {
1176 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A,
1177 (ctx->m_state.ulButtons & STEAM_BUTTON_3_MASK) ? SDL_PRESSED : SDL_RELEASED);
1178
1179 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B,
1180 (ctx->m_state.ulButtons & STEAM_BUTTON_1_MASK) ? SDL_PRESSED : SDL_RELEASED);
1181
1182 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X,
1183 (ctx->m_state.ulButtons & STEAM_BUTTON_2_MASK) ? SDL_PRESSED : SDL_RELEASED);
1184
1185 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y,
1186 (ctx->m_state.ulButtons & STEAM_BUTTON_0_MASK) ? SDL_PRESSED : SDL_RELEASED);
1187
1188 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
1189 (ctx->m_state.ulButtons & STEAM_LEFT_BUMPER_MASK) ? SDL_PRESSED : SDL_RELEASED);
1190
1191 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
1192 (ctx->m_state.ulButtons & STEAM_RIGHT_BUMPER_MASK) ? SDL_PRESSED : SDL_RELEASED);
1193
1194 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK,
1195 (ctx->m_state.ulButtons & STEAM_BUTTON_MENU_MASK) ? SDL_PRESSED : SDL_RELEASED);
1196
1197 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START,
1198 (ctx->m_state.ulButtons & STEAM_BUTTON_ESCAPE_MASK) ? SDL_PRESSED : SDL_RELEASED);
1199
1200 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE,
1201 (ctx->m_state.ulButtons & STEAM_BUTTON_STEAM_MASK) ? SDL_PRESSED : SDL_RELEASED);
1202
1203 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK,
1204 (ctx->m_state.ulButtons & STEAM_JOYSTICK_BUTTON_MASK) ? SDL_PRESSED : SDL_RELEASED);
1205 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1 + 0,
1206 (ctx->m_state.ulButtons & STEAM_BUTTON_BACK_LEFT_MASK) ? SDL_PRESSED : SDL_RELEASED);
1207 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_MISC1 + 1,
1208 (ctx->m_state.ulButtons & STEAM_BUTTON_BACK_RIGHT_MASK) ? SDL_PRESSED : SDL_RELEASED);
1209 }
1210 {
1211 /* Minimum distance from center of pad to register a direction */
1212 const int kPadDeadZone = 10000;
1213
1214 /* Pad coordinates are like math grid coordinates: negative is bottom left */
1215 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP,
1216 (ctx->m_state.sLeftPadY > kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1217
1218 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN,
1219 (ctx->m_state.sLeftPadY < -kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1220
1221 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT,
1222 (ctx->m_state.sLeftPadX < -kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1223
1224 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
1225 (ctx->m_state.sLeftPadX > kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1226 }
1227
1228 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, (int)ctx->m_state.sTriggerL * 2 - 32768);
1229 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, (int)ctx->m_state.sTriggerR * 2 - 32768);
1230
1231 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, ctx->m_state.sLeftStickX);
1232 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~ctx->m_state.sLeftStickY);
1233 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, ctx->m_state.sRightPadX);
1234 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~ctx->m_state.sRightPadY);
1235
1236 if (ctx->report_sensors) {
1237 float values[3];
1238
1239 values[0] = (ctx->m_state.sGyroX / 32768.0f) * (2000.0f * (M_PI / 180.0f));
1240 values[1] = (ctx->m_state.sGyroZ / 32768.0f) * (2000.0f * (M_PI / 180.0f));
1241 values[2] = (ctx->m_state.sGyroY / 32768.0f) * (2000.0f * (M_PI / 180.0f));
1242 SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, values, 3);
1243
1244 values[0] = (ctx->m_state.sAccelX / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
1245 values[1] = (ctx->m_state.sAccelZ / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
1246 values[2] = (-ctx->m_state.sAccelY / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
1247 SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, values, 3);
1248 }
1249
1250 ctx->m_last_state = ctx->m_state;
1251 }
1252
1253 if (r <= 0) {
1254 /* Failed to read from controller */
1255 HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
1256 return SDL_FALSE;
1257 }
1258 }
1259 return SDL_TRUE;
1260 }
1261
1262 static void
HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)1263 HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1264 {
1265 SDL_LockMutex(device->dev_lock);
1266 {
1267 CloseSteamController(device->dev);
1268
1269 SDL_hid_close(device->dev);
1270 device->dev = NULL;
1271
1272 SDL_free(device->context);
1273 device->context = NULL;
1274 }
1275 SDL_UnlockMutex(device->dev_lock);
1276 }
1277
1278 static void
HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device * device)1279 HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device *device)
1280 {
1281 }
1282
1283 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam =
1284 {
1285 SDL_HINT_JOYSTICK_HIDAPI_STEAM,
1286 SDL_TRUE,
1287 SDL_FALSE,
1288 HIDAPI_DriverSteam_IsSupportedDevice,
1289 HIDAPI_DriverSteam_GetDeviceName,
1290 HIDAPI_DriverSteam_InitDevice,
1291 HIDAPI_DriverSteam_GetDevicePlayerIndex,
1292 HIDAPI_DriverSteam_SetDevicePlayerIndex,
1293 HIDAPI_DriverSteam_UpdateDevice,
1294 HIDAPI_DriverSteam_OpenJoystick,
1295 HIDAPI_DriverSteam_RumbleJoystick,
1296 HIDAPI_DriverSteam_RumbleJoystickTriggers,
1297 HIDAPI_DriverSteam_GetJoystickCapabilities,
1298 HIDAPI_DriverSteam_SetJoystickLED,
1299 HIDAPI_DriverSteam_SendJoystickEffect,
1300 HIDAPI_DriverSteam_SetSensorsEnabled,
1301 HIDAPI_DriverSteam_CloseJoystick,
1302 HIDAPI_DriverSteam_FreeDevice,
1303 };
1304
1305 #endif /* SDL_JOYSTICK_HIDAPI_STEAM */
1306
1307 #endif /* SDL_JOYSTICK_HIDAPI */
1308
1309 /* vi: set ts=4 sw=4 expandtab: */
1310