SDL  2.0
SDL_hidapi_steam.c
Go to the documentation of this file.
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 
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 
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 
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 
221 static void ResetSteamControllerPacketAssembler( SteamControllerPacketAssembler *pAssembler )
222 {
223  memset( pAssembler->uBuffer, 0, sizeof( pAssembler->uBuffer ) );
224  pAssembler->nExpectedSegmentNumber = 0;
225 }
226 
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
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 
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 
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 
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 //---------------------------------------------------------------------------
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;
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;
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 );
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 );
488  ADD_SETTING( SETTING_WIRELESS_PACKET_VERSION, 2 );
490 #ifdef ENABLE_MOUSE_MODE
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
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 );
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 );
550  buf[2] = 6; // 2 settings x 3 bytes
552  buf[4] = DEVICE_MOUSE;
553  buf[5] = MOUSE_BTN_LEFT;
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 //---------------------------------------------------------------------------
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 //---------------------------------------------------------------------------
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 );
594  SetFeatureReport( dev, buf, 2 );
595 
596  // Reset the default settings
597  memset( buf, 0, 65 );
599  buf[2] = 0;
600  SetFeatureReport( dev, buf, 3 );
601 
602  // Reset mouse mode for lizard mode
603  memset( buf, 0, 65 );
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 //---------------------------------------------------------------------------
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 //---------------------------------------------------------------------------
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 }
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 //---------------------------------------------------------------------------
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 //---------------------------------------------------------------------------
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 //---------------------------------------------------------------------------
867 static bool UpdateSteamControllerState( const uint8_t *pData, int nDataSize, SteamControllerStateInternal_t *pState )
868 {
869  ValveInReport_t *pInReport = (ValveInReport_t*)pData;
870 
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
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 *
966 HIDAPI_DriverSteam_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
967 {
968  return "Steam Controller";
969 }
970 
971 static SDL_bool
972 HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device)
973 {
975 }
976 
977 static int
978 HIDAPI_DriverSteam_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
979 {
980  return -1;
981 }
982 
983 static void
984 HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
985 {
986 }
987 
988 static SDL_bool
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 = 17;
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
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 int
1038 HIDAPI_DriverSteam_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1039 {
1040  return SDL_Unsupported();
1041 }
1042 
1043 static SDL_bool
1044 HIDAPI_DriverSteam_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1045 {
1046  /* You should use the full Steam Input API for LED support */
1047  return SDL_FALSE;
1048 }
1049 
1050 static int
1051 HIDAPI_DriverSteam_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1052 {
1053  /* You should use the full Steam Input API for LED support */
1054  return SDL_Unsupported();
1055 }
1056 
1057 static int
1058 HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
1059 {
1060  /* You should use the full Steam Input API for sensor support */
1061  return SDL_Unsupported();
1062 }
1063 
1064 static SDL_bool
1065 HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
1066 {
1067  SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
1068  SDL_Joystick *joystick = NULL;
1069 
1070  if (device->num_joysticks > 0) {
1071  joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
1072  }
1073  if (!joystick) {
1074  return SDL_FALSE;
1075  }
1076 
1077  for (;;)
1078  {
1079  uint8_t data[128];
1080  int r, nPacketLength;
1081  const Uint8 *pPacket;
1082 
1083  r = ReadSteamController(device->dev, data, sizeof(data));
1084  if (r == 0)
1085  {
1086  break;
1087  }
1088 
1089  nPacketLength = 0;
1090  if (r > 0) {
1091  nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r);
1092  }
1093 
1094  pPacket = ctx->m_assembler.uBuffer;
1095 
1096  if (nPacketLength > 0 && UpdateSteamControllerState(pPacket, nPacketLength, &ctx->m_state)) {
1097  if (ctx->m_state.ulButtons != ctx->m_last_state.ulButtons) {
1099  (ctx->m_state.ulButtons & STEAM_BUTTON_3_MASK) ? SDL_PRESSED : SDL_RELEASED);
1100 
1102  (ctx->m_state.ulButtons & STEAM_BUTTON_1_MASK) ? SDL_PRESSED : SDL_RELEASED);
1103 
1105  (ctx->m_state.ulButtons & STEAM_BUTTON_2_MASK) ? SDL_PRESSED : SDL_RELEASED);
1106 
1108  (ctx->m_state.ulButtons & STEAM_BUTTON_0_MASK) ? SDL_PRESSED : SDL_RELEASED);
1109 
1111  (ctx->m_state.ulButtons & STEAM_LEFT_BUMPER_MASK) ? SDL_PRESSED : SDL_RELEASED);
1112 
1114  (ctx->m_state.ulButtons & STEAM_RIGHT_BUMPER_MASK) ? SDL_PRESSED : SDL_RELEASED);
1115 
1117  (ctx->m_state.ulButtons & STEAM_BUTTON_MENU_MASK) ? SDL_PRESSED : SDL_RELEASED);
1118 
1120  (ctx->m_state.ulButtons & STEAM_BUTTON_ESCAPE_MASK) ? SDL_PRESSED : SDL_RELEASED);
1121 
1123  (ctx->m_state.ulButtons & STEAM_BUTTON_STEAM_MASK) ? SDL_PRESSED : SDL_RELEASED);
1124 
1126  (ctx->m_state.ulButtons & STEAM_JOYSTICK_BUTTON_MASK) ? SDL_PRESSED : SDL_RELEASED);
1128  (ctx->m_state.ulButtons & STEAM_BUTTON_BACK_LEFT_MASK) ? SDL_PRESSED : SDL_RELEASED);
1130  (ctx->m_state.ulButtons & STEAM_BUTTON_BACK_RIGHT_MASK) ? SDL_PRESSED : SDL_RELEASED);
1131  }
1132  {
1133  /* Minimum distance from center of pad to register a direction */
1134  const int kPadDeadZone = 10000;
1135 
1136  /* Pad coordinates are like math grid coordinates: negative is bottom left */
1138  (ctx->m_state.sLeftPadY > kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1139 
1141  (ctx->m_state.sLeftPadY < -kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1142 
1144  (ctx->m_state.sLeftPadX < -kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1145 
1147  (ctx->m_state.sLeftPadX > kPadDeadZone) ? SDL_PRESSED : SDL_RELEASED);
1148  }
1149 
1150  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, (int)ctx->m_state.sTriggerL * 2 - 32768);
1151  SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, (int)ctx->m_state.sTriggerR * 2 - 32768);
1152 
1157 
1158  ctx->m_last_state = ctx->m_state;
1159  }
1160 
1161  if (r <= 0) {
1162  /* Failed to read from controller */
1163  HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
1164  return SDL_FALSE;
1165  }
1166  }
1167  return SDL_TRUE;
1168 }
1169 
1170 static void
1171 HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
1172 {
1173  CloseSteamController(device->dev);
1174  hid_close(device->dev);
1175  device->dev = NULL;
1176 
1177  SDL_free(device->context);
1178  device->context = NULL;
1179 }
1180 
1181 static void
1182 HIDAPI_DriverSteam_FreeDevice(SDL_HIDAPI_Device *device)
1183 {
1184 }
1185 
1187 {
1189  SDL_TRUE,
1190  HIDAPI_DriverSteam_IsSupportedDevice,
1191  HIDAPI_DriverSteam_GetDeviceName,
1192  HIDAPI_DriverSteam_InitDevice,
1193  HIDAPI_DriverSteam_GetDevicePlayerIndex,
1194  HIDAPI_DriverSteam_SetDevicePlayerIndex,
1195  HIDAPI_DriverSteam_UpdateDevice,
1196  HIDAPI_DriverSteam_OpenJoystick,
1197  HIDAPI_DriverSteam_RumbleJoystick,
1198  HIDAPI_DriverSteam_RumbleJoystickTriggers,
1199  HIDAPI_DriverSteam_HasJoystickLED,
1200  HIDAPI_DriverSteam_SetJoystickLED,
1201  HIDAPI_DriverSteam_SetSensorsEnabled,
1202  HIDAPI_DriverSteam_CloseJoystick,
1203  HIDAPI_DriverSteam_FreeDevice,
1204 };
1205 
1206 #endif /* SDL_JOYSTICK_HIDAPI_STEAM */
1207 
1208 #endif /* SDL_JOYSTICK_HIDAPI */
1209 
1210 /* vi: set ts=4 sw=4 expandtab: */
unsigned int uint32_t
unsigned long long uint64_t
unsigned char uint8_t
#define SDL_SetError
#define SDL_cosf
#define SDL_JoystickFromInstanceID
#define SDL_free
#define SDL_sinf
#define SDL_calloc
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
@ SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_LEFTY
@ SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_MISC1
@ SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_A
SDL_GameControllerType
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam
SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
#define SDL_HINT_JOYSTICK_HIDAPI_STEAM
A variable controlling whether the HIDAPI driver for Steam Controllers should be used.
Definition: SDL_hints.h:642
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define memcpy
Definition: SDL_malloc.c:630
#define memset
Definition: SDL_malloc.c:627
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLuint res
GLuint GLfloat * val
GLenum clamp
GLenum GLsizei len
GLuint const GLchar * name
GLenum GLuint GLenum GLsizei const GLchar * buf
GLbyte green
uint16_t Uint16
Definition: SDL_stdinc.h:197
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_MAX_SINT16
A signed 16-bit integer type.
Definition: SDL_stdinc.h:189
uint8_t Uint8
Definition: SDL_stdinc.h:185
#define SDL_MIN_SINT16
Definition: SDL_stdinc.h:190
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
@ IO_DIGITAL_BUTTON_LEFT_TRIGGER
@ IO_DIGITAL_BUTTON_RIGHT_TRIGGER
@ DEVICE_MOUSE
@ ID_LOAD_DEFAULT_SETTINGS
@ ID_GET_DIGITAL_MAPPINGS
@ ID_CLEAR_DIGITAL_MAPPINGS
@ ID_SET_DEFAULT_DIGITAL_MAPPINGS
@ ID_SET_SETTINGS_VALUES
@ ID_GET_ATTRIBUTES_VALUES
@ ID_SET_DIGITAL_MAPPINGS
@ SETTING_WIRELESS_PACKET_VERSION
@ SETTING_MOMENTUM_DECAY_AMMOUNT
@ SETTING_RIGHT_TRACKPAD_MODE
@ SETTING_MOMENTUM_MAXIMUM_VELOCITY
@ SETTING_LEFT_TRACKPAD_MODE
@ SETTING_SMOOTH_ABSOLUTE_MOUSE
@ TRACKPAD_ABSOLUTE_MOUSE
@ TRACKPAD_NONE
@ MOUSE_BTN_RIGHT
@ MOUSE_BTN_LEFT
@ k_EBLEReportState
@ k_EBLERightTrackpadChunk
@ k_EBLEButtonChunk2
@ k_EBLELeftTrackpadChunk
@ k_EBLEIMUAccelChunk
@ k_EBLEButtonChunk3
@ k_EBLELeftJoystickChunk
@ k_EBLEIMUGyroChunk
@ k_EBLEButtonChunk1
@ k_EBLEIMUQuatChunk
#define k_ValveInReportMsgVersion
@ ID_CONTROLLER_BLE_STATE
@ ID_CONTROLLER_STATE
EGLContext ctx
Definition: eglext.h:208
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length)
Read an Input report from a HID device.
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
Get a feature report from a HID device.
HID_API_EXPORT hid_device *HID_API_CALL hid_open_path(const char *path, int bExclusive)
Open a HID device by its path name.
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
Close a HID device.
struct hid_device_ hid_device
Definition: hidapi.h:54
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length)
Send a Feature report to the device.
static SDL_AudioDeviceID device
Definition: loopwave.c:37
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr
union ValveControllerStatePacket_t::@27 ButtonTriggerData
struct ValveControllerStatePacket_t::@27::@28 Triggers
ValveInReportHeader_t header
ValveControllerBLEStatePacket_t controllerBLEState
ValveControllerStatePacket_t controllerState
union ValveInReport_t::@31 payload
unsigned short unReportVersion
static SDL_Joystick * joystick
Definition: testjoystick.c:37
typedef int(__stdcall *FARPROC)()