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