src/joystick/windows/SDL_dxjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 01 Mar 2014 22:27:21 -0500
changeset 8280 860092ac58d6
parent 8279 7e22273aed11
child 8629 4c01875a4620
permissions -rw-r--r--
Added a FIXME.
slouken@1895
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@1895
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1895
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1895
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1895
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1895
    22
slouken@1895
    23
#ifdef SDL_JOYSTICK_DINPUT
slouken@1895
    24
slouken@1895
    25
/* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
slouken@7191
    26
 * A. Formiga's WINMM driver.
slouken@1895
    27
 *
slouken@1895
    28
 * Hats and sliders are completely untested; the app I'm writing this for mostly
slouken@7191
    29
 * doesn't use them and I don't own any joysticks with them.
slouken@1895
    30
 *
slouken@1895
    31
 * We don't bother to use event notification here.  It doesn't seem to work
slouken@6690
    32
 * with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and
slouken@1895
    33
 * let it return 0 events. */
slouken@1895
    34
slouken@1895
    35
#include "SDL_error.h"
icculus@6993
    36
#include "SDL_assert.h"
slouken@1895
    37
#include "SDL_events.h"
slouken@6690
    38
#include "SDL_thread.h"
slouken@6690
    39
#include "SDL_timer.h"
slouken@6690
    40
#include "SDL_mutex.h"
slouken@6690
    41
#include "SDL_events.h"
slouken@6971
    42
#include "SDL_hints.h"
slouken@7260
    43
#include "SDL_joystick.h"
slouken@7260
    44
#include "../SDL_sysjoystick.h"
slouken@6690
    45
#if !SDL_EVENTS_DISABLED
slouken@6690
    46
#include "../../events/SDL_events_c.h"
slouken@6690
    47
#endif
slouken@1895
    48
slouken@7260
    49
#define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
slouken@7260
    50
#include "SDL_dxjoystick_c.h"
slouken@7260
    51
icculus@8179
    52
#if SDL_HAPTIC_DINPUT
icculus@8179
    53
#include "../../haptic/windows/SDL_syshaptic_c.h"    /* For haptic hot plugging */
icculus@8179
    54
#endif
icculus@8179
    55
slouken@2761
    56
#ifndef DIDFT_OPTIONAL
slouken@7191
    57
#define DIDFT_OPTIONAL      0x80000000
slouken@2761
    58
#endif
slouken@2761
    59
slouken@7831
    60
DEFINE_GUID(GUID_DEVINTERFACE_HID, 0x4D1E55B2L, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30);
slouken@7831
    61
slouken@2761
    62
slouken@7191
    63
#define INPUT_QSIZE 32      /* Buffer up to 32 input messages */
slouken@7191
    64
#define AXIS_MIN    -32768  /* minimum value for axis coordinate */
slouken@7191
    65
#define AXIS_MAX    32767   /* maximum value for axis coordinate */
slouken@7191
    66
#define JOY_AXIS_THRESHOLD  (((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
slouken@1895
    67
slouken@2198
    68
/* external variables referenced. */
slouken@2713
    69
extern HWND SDL_HelperWindow;
slouken@2198
    70
slouken@2198
    71
slouken@2198
    72
/* local variables */
icculus@5591
    73
static SDL_bool coinitialized = SDL_FALSE;
icculus@6716
    74
static LPDIRECTINPUT8 dinput = NULL;
slouken@6690
    75
static SDL_bool s_bDeviceAdded = SDL_FALSE;
slouken@6690
    76
static SDL_bool s_bDeviceRemoved = SDL_FALSE;
slouken@6974
    77
static SDL_JoystickID s_nInstanceID = -1;
slouken@6690
    78
static SDL_cond *s_condJoystickThread = NULL;
slouken@6690
    79
static SDL_mutex *s_mutexJoyStickEnum = NULL;
slouken@6690
    80
static SDL_Thread *s_threadJoystick = NULL;
slouken@6690
    81
static SDL_bool s_bJoystickThreadQuit = SDL_FALSE;
urkle@6965
    82
static SDL_bool s_bXInputEnabled = SDL_TRUE;
slouken@6690
    83
icculus@6991
    84
XInputGetState_t SDL_XInputGetState = NULL;
icculus@6991
    85
XInputSetState_t SDL_XInputSetState = NULL;
icculus@6991
    86
XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL;
icculus@6991
    87
DWORD SDL_XInputVersion = 0;
icculus@6991
    88
icculus@6991
    89
static HANDLE s_pXInputDLL = 0;
icculus@6991
    90
static int s_XInputDLLRefCount = 0;
icculus@6991
    91
icculus@6991
    92
int
icculus@6991
    93
WIN_LoadXInputDLL(void)
icculus@6991
    94
{
icculus@6991
    95
    DWORD version = 0;
icculus@6991
    96
icculus@6991
    97
    if (s_pXInputDLL) {
icculus@6991
    98
        SDL_assert(s_XInputDLLRefCount > 0);
icculus@6991
    99
        s_XInputDLLRefCount++;
icculus@6991
   100
        return 0;  /* already loaded */
icculus@6991
   101
    }
icculus@6991
   102
icculus@6991
   103
    version = (1 << 16) | 4;
slouken@7191
   104
    s_pXInputDLL = LoadLibrary( L"XInput1_4.dll" );  /* 1.4 Ships with Windows 8. */
icculus@6991
   105
    if (!s_pXInputDLL) {
icculus@6991
   106
        version = (1 << 16) | 3;
slouken@7191
   107
        s_pXInputDLL = LoadLibrary( L"XInput1_3.dll" );  /* 1.3 Ships with Vista and Win7, can be installed as a redistributable component. */
icculus@6991
   108
    }
icculus@6991
   109
    if (!s_pXInputDLL) {
icculus@6991
   110
        s_pXInputDLL = LoadLibrary( L"bin\\XInput1_3.dll" );
icculus@6991
   111
    }
icculus@6991
   112
    if (!s_pXInputDLL) {
icculus@6991
   113
        return -1;
icculus@6991
   114
    }
icculus@6991
   115
icculus@6991
   116
    SDL_assert(s_XInputDLLRefCount == 0);
icculus@6991
   117
    SDL_XInputVersion = version;
icculus@6991
   118
    s_XInputDLLRefCount = 1;
icculus@6991
   119
icculus@6991
   120
    /* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think... */
icculus@6991
   121
    SDL_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 );
icculus@6991
   122
    SDL_XInputSetState = (XInputSetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputSetState" );
icculus@6991
   123
    SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetCapabilities" );
icculus@6991
   124
    if ( !SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities ) {
icculus@6991
   125
        WIN_UnloadXInputDLL();
icculus@6991
   126
        return -1;
icculus@6991
   127
    }
icculus@6991
   128
icculus@6991
   129
    return 0;
icculus@6991
   130
}
icculus@6991
   131
icculus@6991
   132
void
icculus@6991
   133
WIN_UnloadXInputDLL(void)
icculus@6991
   134
{
icculus@6991
   135
    if ( s_pXInputDLL ) {
icculus@6991
   136
        SDL_assert(s_XInputDLLRefCount > 0);
icculus@6991
   137
        if (--s_XInputDLLRefCount == 0) {
icculus@6991
   138
            FreeLibrary( s_pXInputDLL );
icculus@6991
   139
            s_pXInputDLL = NULL;
icculus@6991
   140
        }
icculus@6991
   141
    } else {
icculus@6991
   142
        SDL_assert(s_XInputDLLRefCount == 0);
icculus@6991
   143
    }
icculus@6991
   144
}
icculus@6991
   145
icculus@6991
   146
slouken@2198
   147
extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
slouken@2198
   148
                                       LPDIRECTINPUT * ppDI,
slouken@2198
   149
                                       LPUNKNOWN punkOuter);
slouken@6690
   150
struct JoyStick_DeviceData_
slouken@6690
   151
{
slouken@7191
   152
    SDL_JoystickGUID guid;
slouken@7191
   153
    DIDEVICEINSTANCE dxdevice;
slouken@7191
   154
    char *joystickname;
slouken@7191
   155
    Uint8 send_add_event;
slouken@7191
   156
    SDL_JoystickID nInstanceID;
slouken@7191
   157
    SDL_bool bXInputDevice;
slouken@7191
   158
    Uint8 XInputUserId;
slouken@7191
   159
    struct JoyStick_DeviceData_ *pNext;
slouken@6690
   160
};
slouken@2198
   161
slouken@6690
   162
typedef struct JoyStick_DeviceData_ JoyStick_DeviceData;
slouken@6690
   163
slouken@6690
   164
static JoyStick_DeviceData *SYS_Joystick;    /* array to hold joystick ID values */
slouken@6690
   165
slouken@2198
   166
/* local prototypes */
icculus@7037
   167
static int SetDIerror(const char *function, HRESULT code);
slouken@2198
   168
static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *
slouken@2198
   169
                                           pdidInstance, VOID * pContext);
slouken@2198
   170
static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
slouken@2198
   171
                                            LPVOID pvRef);
slouken@6220
   172
static void SortDevObjects(SDL_Joystick *joystick);
slouken@2198
   173
static Uint8 TranslatePOV(DWORD value);
slouken@2198
   174
static int SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis,
slouken@2198
   175
                                       Sint16 value);
slouken@2198
   176
static int SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat,
slouken@2198
   177
                                      Uint8 value);
slouken@2198
   178
static int SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick,
slouken@2198
   179
                                         Uint8 button, Uint8 state);
slouken@2198
   180
slouken@7191
   181
/* Taken from Wine - Thanks! */
slouken@2760
   182
DIOBJECTDATAFORMAT dfDIJoystick2[] = {
slouken@3013
   183
  { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   184
  { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   185
  { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   186
  { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   187
  { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   188
  { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   189
  { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   190
  { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   191
  { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   192
  { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   193
  { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   194
  { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0},
slouken@3013
   195
  { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   196
  { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   197
  { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   198
  { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   199
  { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   200
  { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   201
  { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   202
  { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   203
  { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   204
  { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   205
  { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   206
  { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   207
  { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   208
  { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   209
  { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   210
  { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   211
  { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   212
  { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   213
  { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   214
  { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   215
  { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   216
  { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   217
  { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   218
  { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   219
  { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   220
  { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   221
  { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   222
  { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   223
  { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   224
  { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   225
  { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   226
  { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   227
  { NULL,DIJOFS_BUTTON(32),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   228
  { NULL,DIJOFS_BUTTON(33),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   229
  { NULL,DIJOFS_BUTTON(34),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   230
  { NULL,DIJOFS_BUTTON(35),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   231
  { NULL,DIJOFS_BUTTON(36),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   232
  { NULL,DIJOFS_BUTTON(37),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   233
  { NULL,DIJOFS_BUTTON(38),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   234
  { NULL,DIJOFS_BUTTON(39),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   235
  { NULL,DIJOFS_BUTTON(40),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   236
  { NULL,DIJOFS_BUTTON(41),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   237
  { NULL,DIJOFS_BUTTON(42),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   238
  { NULL,DIJOFS_BUTTON(43),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   239
  { NULL,DIJOFS_BUTTON(44),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   240
  { NULL,DIJOFS_BUTTON(45),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   241
  { NULL,DIJOFS_BUTTON(46),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   242
  { NULL,DIJOFS_BUTTON(47),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   243
  { NULL,DIJOFS_BUTTON(48),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   244
  { NULL,DIJOFS_BUTTON(49),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   245
  { NULL,DIJOFS_BUTTON(50),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   246
  { NULL,DIJOFS_BUTTON(51),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   247
  { NULL,DIJOFS_BUTTON(52),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   248
  { NULL,DIJOFS_BUTTON(53),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   249
  { NULL,DIJOFS_BUTTON(54),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   250
  { NULL,DIJOFS_BUTTON(55),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   251
  { NULL,DIJOFS_BUTTON(56),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   252
  { NULL,DIJOFS_BUTTON(57),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   253
  { NULL,DIJOFS_BUTTON(58),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   254
  { NULL,DIJOFS_BUTTON(59),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   255
  { NULL,DIJOFS_BUTTON(60),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   256
  { NULL,DIJOFS_BUTTON(61),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   257
  { NULL,DIJOFS_BUTTON(62),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   258
  { NULL,DIJOFS_BUTTON(63),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   259
  { NULL,DIJOFS_BUTTON(64),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   260
  { NULL,DIJOFS_BUTTON(65),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   261
  { NULL,DIJOFS_BUTTON(66),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   262
  { NULL,DIJOFS_BUTTON(67),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   263
  { NULL,DIJOFS_BUTTON(68),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   264
  { NULL,DIJOFS_BUTTON(69),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   265
  { NULL,DIJOFS_BUTTON(70),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   266
  { NULL,DIJOFS_BUTTON(71),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   267
  { NULL,DIJOFS_BUTTON(72),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   268
  { NULL,DIJOFS_BUTTON(73),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   269
  { NULL,DIJOFS_BUTTON(74),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   270
  { NULL,DIJOFS_BUTTON(75),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   271
  { NULL,DIJOFS_BUTTON(76),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   272
  { NULL,DIJOFS_BUTTON(77),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   273
  { NULL,DIJOFS_BUTTON(78),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   274
  { NULL,DIJOFS_BUTTON(79),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   275
  { NULL,DIJOFS_BUTTON(80),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   276
  { NULL,DIJOFS_BUTTON(81),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   277
  { NULL,DIJOFS_BUTTON(82),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   278
  { NULL,DIJOFS_BUTTON(83),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   279
  { NULL,DIJOFS_BUTTON(84),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   280
  { NULL,DIJOFS_BUTTON(85),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   281
  { NULL,DIJOFS_BUTTON(86),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   282
  { NULL,DIJOFS_BUTTON(87),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   283
  { NULL,DIJOFS_BUTTON(88),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   284
  { NULL,DIJOFS_BUTTON(89),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   285
  { NULL,DIJOFS_BUTTON(90),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   286
  { NULL,DIJOFS_BUTTON(91),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   287
  { NULL,DIJOFS_BUTTON(92),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   288
  { NULL,DIJOFS_BUTTON(93),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   289
  { NULL,DIJOFS_BUTTON(94),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   290
  { NULL,DIJOFS_BUTTON(95),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   291
  { NULL,DIJOFS_BUTTON(96),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   292
  { NULL,DIJOFS_BUTTON(97),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   293
  { NULL,DIJOFS_BUTTON(98),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   294
  { NULL,DIJOFS_BUTTON(99),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   295
  { NULL,DIJOFS_BUTTON(100),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   296
  { NULL,DIJOFS_BUTTON(101),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   297
  { NULL,DIJOFS_BUTTON(102),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   298
  { NULL,DIJOFS_BUTTON(103),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   299
  { NULL,DIJOFS_BUTTON(104),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   300
  { NULL,DIJOFS_BUTTON(105),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   301
  { NULL,DIJOFS_BUTTON(106),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   302
  { NULL,DIJOFS_BUTTON(107),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   303
  { NULL,DIJOFS_BUTTON(108),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   304
  { NULL,DIJOFS_BUTTON(109),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   305
  { NULL,DIJOFS_BUTTON(110),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   306
  { NULL,DIJOFS_BUTTON(111),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   307
  { NULL,DIJOFS_BUTTON(112),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   308
  { NULL,DIJOFS_BUTTON(113),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   309
  { NULL,DIJOFS_BUTTON(114),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   310
  { NULL,DIJOFS_BUTTON(115),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   311
  { NULL,DIJOFS_BUTTON(116),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   312
  { NULL,DIJOFS_BUTTON(117),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   313
  { NULL,DIJOFS_BUTTON(118),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   314
  { NULL,DIJOFS_BUTTON(119),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   315
  { NULL,DIJOFS_BUTTON(120),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   316
  { NULL,DIJOFS_BUTTON(121),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   317
  { NULL,DIJOFS_BUTTON(122),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   318
  { NULL,DIJOFS_BUTTON(123),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   319
  { NULL,DIJOFS_BUTTON(124),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   320
  { NULL,DIJOFS_BUTTON(125),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   321
  { NULL,DIJOFS_BUTTON(126),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   322
  { NULL,DIJOFS_BUTTON(127),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0},
slouken@3013
   323
  { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lVX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   324
  { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lVY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   325
  { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lVZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   326
  { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lVRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   327
  { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lVRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   328
  { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lVRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   329
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   330
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   331
  { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lAX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   332
  { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lAY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   333
  { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lAZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   334
  { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lARx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   335
  { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lARy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   336
  { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lARz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   337
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   338
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   339
  { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lFX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   340
  { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lFY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   341
  { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lFZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   342
  { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lFRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   343
  { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lFRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   344
  { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lFRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   345
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@3013
   346
  { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0},
slouken@2760
   347
};
slouken@2760
   348
slouken@2760
   349
const DIDATAFORMAT c_dfDIJoystick2 = {
slouken@2760
   350
    sizeof(DIDATAFORMAT),
slouken@2760
   351
    sizeof(DIOBJECTDATAFORMAT),
slouken@2760
   352
    DIDF_ABSAXIS,
slouken@2760
   353
    sizeof(DIJOYSTATE2),
slouken@2760
   354
    SDL_arraysize(dfDIJoystick2),
slouken@2760
   355
    dfDIJoystick2
slouken@2760
   356
};
slouken@2760
   357
slouken@2198
   358
slouken@1895
   359
/* Convert a DirectInput return code to a text message */
icculus@7037
   360
static int
slouken@2198
   361
SetDIerror(const char *function, HRESULT code)
slouken@1895
   362
{
slouken@2760
   363
    /*
icculus@7037
   364
    return SDL_SetError("%s() [%s]: %s", function,
slouken@3013
   365
                 DXGetErrorString9A(code), DXGetErrorDescription9A(code));
slouken@2760
   366
     */
icculus@7037
   367
    return SDL_SetError("%s() DirectX error %d", function, code);
slouken@1895
   368
}
slouken@1895
   369
slouken@1895
   370
slouken@6690
   371
#define SAFE_RELEASE(p)                             \
slouken@6690
   372
{                                                   \
slouken@7191
   373
    if (p) {                                        \
slouken@7191
   374
        (p)->lpVtbl->Release((p));                  \
slouken@7191
   375
        (p) = 0;                                    \
slouken@7191
   376
    }                                               \
slouken@6690
   377
}
slouken@6690
   378
icculus@7706
   379
DEFINE_GUID(IID_ValveStreamingGamepad,  MAKELONG( 0x28DE, 0x11FF ),0x0000,0x0000,0x00,0x00,0x50,0x49,0x44,0x56,0x49,0x44);
icculus@7706
   380
DEFINE_GUID(IID_X360WiredGamepad,  MAKELONG( 0x045E, 0x02A1 ),0x0000,0x0000,0x00,0x00,0x50,0x49,0x44,0x56,0x49,0x44);
icculus@7706
   381
DEFINE_GUID(IID_X360WirelessGamepad,  MAKELONG( 0x045E, 0x028E ),0x0000,0x0000,0x00,0x00,0x50,0x49,0x44,0x56,0x49,0x44);
slouken@6690
   382
icculus@7706
   383
static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
icculus@7706
   384
static UINT SDL_RawDevListCount = 0;
slouken@6690
   385
icculus@7706
   386
static SDL_bool
icculus@7706
   387
SDL_IsXInputDevice( const GUID* pGuidProductFromDirectInput )
slouken@6690
   388
{
slouken@7299
   389
    static const GUID *s_XInputProductGUID[] = {
icculus@7706
   390
        &IID_ValveStreamingGamepad,
icculus@7706
   391
        &IID_X360WiredGamepad,   /* Microsoft's wired X360 controller for Windows. */
icculus@7706
   392
        &IID_X360WirelessGamepad /* Microsoft's wireless X360 controller for Windows. */
slouken@7299
   393
    };
slouken@6690
   394
icculus@7706
   395
    size_t iDevice;
icculus@7706
   396
    UINT i;
icculus@7706
   397
icculus@7706
   398
    if (!s_bXInputEnabled) {
urkle@6965
   399
        return SDL_FALSE;
urkle@6965
   400
    }
urkle@6965
   401
gabomdq@7663
   402
    /* Check for well known XInput device GUIDs */
icculus@7706
   403
    /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */
slouken@7299
   404
    for ( iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice ) {
slouken@7299
   405
        if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) {
slouken@7299
   406
            return SDL_TRUE;
slouken@7299
   407
        }
slouken@7299
   408
    }
slouken@7299
   409
icculus@7706
   410
    /* Go through RAWINPUT (WinXP and later) to find HID devices. */
icculus@7706
   411
    /* Cache this if we end up using it. */
icculus@7706
   412
    if (SDL_RawDevList == NULL) {
icculus@7706
   413
        if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof (RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
icculus@7706
   414
            return SDL_FALSE;  /* oh well. */
icculus@7706
   415
        }
slouken@6690
   416
icculus@7706
   417
        SDL_RawDevList = (PRAWINPUTDEVICELIST) SDL_malloc(sizeof (RAWINPUTDEVICELIST) * SDL_RawDevListCount);
icculus@7706
   418
        if (SDL_RawDevList == NULL) {
icculus@7706
   419
            SDL_OutOfMemory();
icculus@7706
   420
            return SDL_FALSE;
icculus@7706
   421
        }
slouken@6690
   422
icculus@7706
   423
        if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof (RAWINPUTDEVICELIST)) == -1) {
icculus@7706
   424
             SDL_free(SDL_RawDevList);
icculus@7706
   425
             SDL_RawDevList = NULL;
icculus@7706
   426
             return SDL_FALSE;  /* oh well. */
slouken@7191
   427
        }
slouken@7191
   428
    }
slouken@7191
   429
icculus@7706
   430
    for (i = 0; i < SDL_RawDevListCount; i++) {
icculus@7706
   431
        RID_DEVICE_INFO rdi;
icculus@7706
   432
        char devName[128];
icculus@7706
   433
        UINT rdiSize = sizeof (rdi);
icculus@7706
   434
        UINT nameSize = SDL_arraysize(devName);
slouken@6690
   435
icculus@7706
   436
        rdi.cbSize = sizeof (rdi);
icculus@7706
   437
        if ( (SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
icculus@7706
   438
             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
icculus@7706
   439
             (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
icculus@7706
   440
             (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
icculus@7706
   441
             (SDL_strstr(devName, "IG_") != NULL) ) {
icculus@7706
   442
             return SDL_TRUE;
icculus@7706
   443
        }
icculus@7706
   444
    }
slouken@6690
   445
icculus@7706
   446
    return SDL_FALSE;
slouken@6690
   447
}
slouken@6690
   448
slouken@6690
   449
slouken@6690
   450
static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
slouken@6690
   451
philipp@7133
   452
/* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal
slouken@6690
   453
 */
slouken@6690
   454
LRESULT CALLBACK SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)    {
slouken@7191
   455
    switch (message)    {
slouken@7191
   456
    case WM_DEVICECHANGE:
slouken@7191
   457
        switch (wParam) {
slouken@7191
   458
        case DBT_DEVICEARRIVAL:
slouken@7191
   459
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)    {
slouken@7191
   460
                s_bWindowsDeviceChanged = SDL_TRUE;
slouken@7191
   461
            }
slouken@7191
   462
            break;
slouken@7191
   463
        case DBT_DEVICEREMOVECOMPLETE:
slouken@7191
   464
            if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)    {
slouken@7191
   465
                s_bWindowsDeviceChanged = SDL_TRUE;
slouken@7191
   466
            }
slouken@7191
   467
            break;
slouken@7191
   468
        }
slouken@7191
   469
        return 0;
slouken@7191
   470
    }
slouken@6690
   471
slouken@7191
   472
    return DefWindowProc (hwnd, message, wParam, lParam);
slouken@6690
   473
}
slouken@6690
   474
slouken@6690
   475
slouken@6690
   476
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
slouken@7191
   477
    0xC0, 0x4F, 0xB9, 0x51, 0xED);
slouken@6690
   478
slouken@6690
   479
/* Function/thread to scan the system for joysticks.
slouken@6690
   480
 */
slouken@6690
   481
static int
slouken@6690
   482
SDL_JoystickThread(void *_data)
slouken@6690
   483
{
slouken@7191
   484
    HWND messageWindow = 0;
slouken@7191
   485
    HDEVNOTIFY hNotify = 0;
slouken@7191
   486
    DEV_BROADCAST_DEVICEINTERFACE dbh;
icculus@7707
   487
    SDL_bool bOpenedXInputDevices[SDL_XINPUT_MAX_DEVICES];
slouken@7191
   488
    WNDCLASSEX wincl;
slouken@6710
   489
icculus@7707
   490
    SDL_zero(bOpenedXInputDevices);
slouken@6690
   491
slouken@7223
   492
    WIN_CoInitialize();
slouken@6690
   493
slouken@7191
   494
    SDL_memset( &wincl, 0x0, sizeof(wincl) );
slouken@7191
   495
    wincl.hInstance = GetModuleHandle( NULL );
slouken@7191
   496
    wincl.lpszClassName = L"Message";
slouken@7191
   497
    wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      /* This function is called by windows */
slouken@7191
   498
    wincl.cbSize = sizeof (WNDCLASSEX);
slouken@6712
   499
slouken@7191
   500
    if (!RegisterClassEx (&wincl))
slouken@7191
   501
    {
slouken@7191
   502
        return SDL_SetError("Failed to create register class for joystick autodetect.", GetLastError());
slouken@7191
   503
    }
slouken@6712
   504
slouken@7191
   505
    messageWindow = (HWND)CreateWindowEx( 0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
slouken@7191
   506
    if ( !messageWindow )
slouken@7191
   507
    {
slouken@7191
   508
        return SDL_SetError("Failed to create message window for joystick autodetect.", GetLastError());
slouken@7191
   509
    }
slouken@6690
   510
icculus@7707
   511
    SDL_zero(dbh);
slouken@6690
   512
slouken@7191
   513
    dbh.dbcc_size = sizeof(dbh);
slouken@7191
   514
    dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
slouken@7831
   515
    dbh.dbcc_classguid = GUID_DEVINTERFACE_HID;
slouken@6690
   516
slouken@7191
   517
    hNotify = RegisterDeviceNotification( messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE );
slouken@7191
   518
    if ( !hNotify )
slouken@7191
   519
    {
slouken@7191
   520
        return SDL_SetError("Failed to create notify device for joystick autodetect.", GetLastError());
slouken@7191
   521
    }
slouken@6690
   522
slouken@7191
   523
    SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
   524
    while ( s_bJoystickThreadQuit == SDL_FALSE )
slouken@7191
   525
    {
slouken@7191
   526
        MSG messages;
icculus@7707
   527
        SDL_bool bXInputChanged = SDL_FALSE;
icculus@7707
   528
slouken@7191
   529
        SDL_CondWaitTimeout( s_condJoystickThread, s_mutexJoyStickEnum, 300 );
slouken@6690
   530
slouken@7191
   531
        while ( s_bJoystickThreadQuit == SDL_FALSE && PeekMessage(&messages, messageWindow, 0, 0, PM_NOREMOVE) )
slouken@7191
   532
        {
slouken@7191
   533
            if ( GetMessage(&messages, messageWindow, 0, 0) != 0 )  {
slouken@7191
   534
                TranslateMessage(&messages);
slouken@7191
   535
                DispatchMessage(&messages);
slouken@7191
   536
            }
slouken@7191
   537
        }
slouken@6690
   538
icculus@7707
   539
        if ( s_bXInputEnabled && XINPUTGETCAPABILITIES ) {
slouken@7191
   540
            /* scan for any change in XInput devices */
icculus@7707
   541
            Uint8 userId;
icculus@7707
   542
            for (userId = 0; userId < SDL_XINPUT_MAX_DEVICES; userId++) {
slouken@7191
   543
                XINPUT_CAPABILITIES capabilities;
icculus@7707
   544
                const DWORD result = XINPUTGETCAPABILITIES( userId, XINPUT_FLAG_GAMEPAD, &capabilities );
icculus@7707
   545
                const SDL_bool available = (result == ERROR_SUCCESS);
icculus@7707
   546
                if (bOpenedXInputDevices[userId] != available) {
icculus@7707
   547
                    bXInputChanged = SDL_TRUE;
icculus@7707
   548
                    bOpenedXInputDevices[userId] = available;
slouken@7191
   549
                }
slouken@7191
   550
            }
slouken@7191
   551
        }
slouken@6710
   552
icculus@7707
   553
        if (s_bWindowsDeviceChanged || bXInputChanged) {
icculus@7707
   554
            SDL_UnlockMutex( s_mutexJoyStickEnum );  /* let main thread go while we SDL_Delay(). */
slouken@7191
   555
            SDL_Delay( 300 ); /* wait for direct input to find out about this device */
icculus@7707
   556
            SDL_LockMutex( s_mutexJoyStickEnum );
slouken@6690
   557
slouken@7191
   558
            s_bDeviceRemoved = SDL_TRUE;
slouken@7191
   559
            s_bDeviceAdded = SDL_TRUE;
slouken@7191
   560
            s_bWindowsDeviceChanged = SDL_FALSE;
slouken@7191
   561
        }
slouken@7191
   562
    }
slouken@7191
   563
    SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@6690
   564
slouken@7191
   565
    if ( hNotify )
slouken@7191
   566
        UnregisterDeviceNotification( hNotify );
slouken@6690
   567
slouken@7191
   568
    if ( messageWindow )
slouken@7191
   569
        DestroyWindow( messageWindow );
slouken@6712
   570
slouken@7191
   571
    UnregisterClass( wincl.lpszClassName, wincl.hInstance );
slouken@7191
   572
    messageWindow = 0;
slouken@7191
   573
    WIN_CoUninitialize();
slouken@7191
   574
    return 1;
slouken@6690
   575
}
slouken@6690
   576
slouken@6690
   577
slouken@1895
   578
/* Function to scan the system for joysticks.
slouken@1895
   579
 * This function should set SDL_numjoysticks to the number of available
slouken@1895
   580
 * joysticks.  Joystick 0 should be the system default joystick.
slouken@1895
   581
 * It should return 0, or -1 on an unrecoverable fatal error.
slouken@1895
   582
 */
slouken@1895
   583
int
slouken@1895
   584
SDL_SYS_JoystickInit(void)
slouken@1895
   585
{
slouken@1895
   586
    HRESULT result;
slouken@2713
   587
    HINSTANCE instance;
slouken@7191
   588
    const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED);
slouken@7191
   589
    if (env && !SDL_atoi(env)) {
slouken@7191
   590
        s_bXInputEnabled = SDL_FALSE;
slouken@7191
   591
    }
slouken@1895
   592
icculus@5591
   593
    result = WIN_CoInitialize();
slouken@2198
   594
    if (FAILED(result)) {
icculus@7037
   595
        return SetDIerror("CoInitialize", result);
slouken@1895
   596
    }
slouken@1895
   597
icculus@5591
   598
    coinitialized = SDL_TRUE;
icculus@5591
   599
slouken@6690
   600
    result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
slouken@6690
   601
                              &IID_IDirectInput8, (LPVOID)&dinput);
slouken@2198
   602
slouken@2198
   603
    if (FAILED(result)) {
icculus@5591
   604
        SDL_SYS_JoystickQuit();
icculus@7037
   605
        return SetDIerror("CoCreateInstance", result);
slouken@2198
   606
    }
slouken@2198
   607
slouken@2198
   608
    /* Because we used CoCreateInstance, we need to Initialize it, first. */
slouken@2713
   609
    instance = GetModuleHandle(NULL);
slouken@2713
   610
    if (instance == NULL) {
icculus@5591
   611
        SDL_SYS_JoystickQuit();
icculus@7037
   612
        return SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError());
slouken@2713
   613
    }
slouken@6690
   614
    result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
slouken@2198
   615
slouken@2198
   616
    if (FAILED(result)) {
icculus@5591
   617
        SDL_SYS_JoystickQuit();
icculus@7037
   618
        return SetDIerror("IDirectInput::Initialize", result);
slouken@2198
   619
    }
slouken@2198
   620
icculus@7707
   621
    if ((s_bXInputEnabled) && (WIN_LoadXInputDLL() == -1)) {
icculus@7707
   622
        s_bXInputEnabled = SDL_FALSE;  /* oh well. */
icculus@7707
   623
    }
icculus@7707
   624
icculus@6990
   625
    s_mutexJoyStickEnum = SDL_CreateMutex();
icculus@6990
   626
    s_condJoystickThread = SDL_CreateCond();
slouken@7191
   627
    s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */
icculus@7707
   628
icculus@6990
   629
    SDL_SYS_JoystickDetect();
slouken@1895
   630
slouken@7191
   631
    if ( !s_threadJoystick )
slouken@7191
   632
    {
slouken@7191
   633
        s_bJoystickThreadQuit = SDL_FALSE;
slouken@7191
   634
        /* spin up the thread to detect hotplug of devices */
slouken@6690
   635
#if defined(__WIN32__) && !defined(HAVE_LIBC)
slouken@6690
   636
#undef SDL_CreateThread
icculus@8094
   637
#if SDL_DYNAMIC_API
icculus@8094
   638
        s_threadJoystick= SDL_CreateThread_REAL( SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL );
icculus@8094
   639
#else
slouken@7191
   640
        s_threadJoystick= SDL_CreateThread( SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL );
icculus@8094
   641
#endif
slouken@6690
   642
#else
slouken@7191
   643
        s_threadJoystick = SDL_CreateThread( SDL_JoystickThread, "SDL_joystick", NULL );
slouken@6690
   644
#endif
slouken@7191
   645
    }
slouken@7191
   646
        return SDL_SYS_NumJoysticks();
slouken@2198
   647
}
slouken@2198
   648
slouken@6707
   649
/* return the number of joysticks that are connected right now */
slouken@6707
   650
int SDL_SYS_NumJoysticks()
slouken@6707
   651
{
slouken@7191
   652
    int nJoysticks = 0;
slouken@7191
   653
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   654
    while ( device )
slouken@7191
   655
    {
slouken@7191
   656
        nJoysticks++;
slouken@7191
   657
        device = device->pNext;
slouken@7191
   658
    }
slouken@6707
   659
slouken@7191
   660
    return nJoysticks;
slouken@6707
   661
}
slouken@6707
   662
slouken@6707
   663
/* helper function for direct input, gets called for each connected joystick */
slouken@6707
   664
static BOOL CALLBACK
slouken@7191
   665
    EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
slouken@6707
   666
{
slouken@7191
   667
    JoyStick_DeviceData *pNewJoystick;
slouken@7191
   668
    JoyStick_DeviceData *pPrevJoystick = NULL;
icculus@7707
   669
icculus@7707
   670
    if (SDL_IsXInputDevice( &pdidInstance->guidProduct )) {
icculus@7707
   671
        return DIENUM_CONTINUE;  /* ignore XInput devices here, keep going. */
icculus@7707
   672
    }
icculus@7707
   673
slouken@7191
   674
    pNewJoystick = *(JoyStick_DeviceData **)pContext;
slouken@7191
   675
    while ( pNewJoystick )
slouken@7191
   676
    {
slouken@7191
   677
        if ( !SDL_memcmp( &pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance) ) )
slouken@7191
   678
        {
slouken@7191
   679
            /* if we are replacing the front of the list then update it */
slouken@7191
   680
            if ( pNewJoystick == *(JoyStick_DeviceData **)pContext )
slouken@7191
   681
            {
slouken@7191
   682
                *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
slouken@7191
   683
            }
slouken@7191
   684
            else if ( pPrevJoystick )
slouken@7191
   685
            {
slouken@7191
   686
                pPrevJoystick->pNext = pNewJoystick->pNext;
slouken@7191
   687
            }
slouken@6712
   688
slouken@7191
   689
            pNewJoystick->pNext = SYS_Joystick;
slouken@7191
   690
            SYS_Joystick = pNewJoystick;
slouken@6707
   691
icculus@7707
   692
            return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
slouken@7191
   693
        }
slouken@6707
   694
slouken@7191
   695
        pPrevJoystick = pNewJoystick;
slouken@7191
   696
        pNewJoystick = pNewJoystick->pNext;
slouken@7191
   697
    }
slouken@6707
   698
icculus@7707
   699
    pNewJoystick = (JoyStick_DeviceData *)SDL_malloc( sizeof(JoyStick_DeviceData) );
icculus@7707
   700
    if (!pNewJoystick) {
icculus@7707
   701
        return DIENUM_CONTINUE; /* better luck next time? */
icculus@7707
   702
    }
slouken@6707
   703
icculus@7707
   704
    SDL_zerop(pNewJoystick);
icculus@7707
   705
    pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
icculus@7707
   706
    if (!pNewJoystick->joystickname) {
icculus@7707
   707
        SDL_free(pNewJoystick);
icculus@7707
   708
        return DIENUM_CONTINUE; /* better luck next time? */
slouken@7191
   709
    }
slouken@6712
   710
slouken@7191
   711
    SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
slouken@7191
   712
        sizeof(DIDEVICEINSTANCE));
slouken@6707
   713
icculus@7707
   714
    pNewJoystick->XInputUserId = INVALID_XINPUT_USERID;
slouken@7191
   715
    pNewJoystick->send_add_event = 1;
slouken@7191
   716
    pNewJoystick->nInstanceID = ++s_nInstanceID;
slouken@7191
   717
    SDL_memcpy( &pNewJoystick->guid, &pdidInstance->guidProduct, sizeof(pNewJoystick->guid) );
icculus@7707
   718
    pNewJoystick->pNext = SYS_Joystick;
slouken@7191
   719
    SYS_Joystick = pNewJoystick;
slouken@6707
   720
icculus@7707
   721
    s_bDeviceAdded = SDL_TRUE;
slouken@7191
   722
icculus@7707
   723
    return DIENUM_CONTINUE; /* get next device, please */
slouken@6707
   724
}
slouken@6707
   725
icculus@7707
   726
static void
icculus@7707
   727
AddXInputDevice(const Uint8 userid, JoyStick_DeviceData **pContext)
icculus@7707
   728
{
icculus@7707
   729
    char name[32];
icculus@7707
   730
    JoyStick_DeviceData *pPrevJoystick = NULL;
icculus@7707
   731
    JoyStick_DeviceData *pNewJoystick = *pContext;
icculus@7707
   732
icculus@7707
   733
    while (pNewJoystick) {
icculus@7707
   734
        if ((pNewJoystick->bXInputDevice) && (pNewJoystick->XInputUserId == userid)) {
icculus@7707
   735
            /* if we are replacing the front of the list then update it */
icculus@7707
   736
            if (pNewJoystick == *pContext) {
icculus@7707
   737
                *pContext = pNewJoystick->pNext;
icculus@7707
   738
            } else if (pPrevJoystick) {
icculus@7707
   739
                pPrevJoystick->pNext = pNewJoystick->pNext;
icculus@7707
   740
            }
icculus@7707
   741
icculus@7707
   742
            pNewJoystick->pNext = SYS_Joystick;
icculus@7707
   743
            SYS_Joystick = pNewJoystick;
icculus@7844
   744
            return;   /* already in the list. */
icculus@7707
   745
        }
icculus@7707
   746
icculus@7707
   747
        pPrevJoystick = pNewJoystick;
icculus@7707
   748
        pNewJoystick = pNewJoystick->pNext;
icculus@7707
   749
    }
icculus@7707
   750
icculus@7707
   751
    pNewJoystick = (JoyStick_DeviceData *) SDL_malloc(sizeof (JoyStick_DeviceData));
icculus@7707
   752
    if (!pNewJoystick) {
icculus@7707
   753
        return; /* better luck next time? */
icculus@7707
   754
    }
icculus@7707
   755
    SDL_zerop(pNewJoystick);
icculus@7707
   756
icculus@7709
   757
    SDL_snprintf(name, sizeof (name), "XInput Controller #%u", ((unsigned int) userid) + 1);
icculus@7707
   758
    pNewJoystick->joystickname = SDL_strdup(name);
icculus@7707
   759
    if (!pNewJoystick->joystickname) {
icculus@7707
   760
        SDL_free(pNewJoystick);
icculus@7707
   761
        return; /* better luck next time? */
icculus@7707
   762
    }
icculus@7707
   763
icculus@7707
   764
    pNewJoystick->bXInputDevice = SDL_TRUE;
icculus@7707
   765
    pNewJoystick->XInputUserId = userid;
icculus@7707
   766
    pNewJoystick->send_add_event = 1;
icculus@7707
   767
    pNewJoystick->nInstanceID = ++s_nInstanceID;
icculus@7707
   768
    pNewJoystick->pNext = SYS_Joystick;
icculus@7707
   769
    SYS_Joystick = pNewJoystick;
icculus@7707
   770
icculus@7707
   771
    s_bDeviceAdded = SDL_TRUE;
icculus@7707
   772
}
icculus@7707
   773
icculus@7707
   774
static void
icculus@7707
   775
EnumXInputDevices(JoyStick_DeviceData **pContext)
icculus@7707
   776
{
icculus@7707
   777
    if (s_bXInputEnabled) {
icculus@7712
   778
        int iuserid;
icculus@7712
   779
        /* iterate in reverse, so these are in the final list in ascending numeric order. */
icculus@7712
   780
        for (iuserid = SDL_XINPUT_MAX_DEVICES-1; iuserid >= 0; iuserid--) {
icculus@7712
   781
            const Uint8 userid = (Uint8) iuserid;
icculus@7707
   782
            XINPUT_CAPABILITIES capabilities;
icculus@7707
   783
            if (XINPUTGETCAPABILITIES(userid, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) {
icculus@7707
   784
                /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
icculus@8279
   785
                /* !!! FIXME: we might want to support steering wheels or guitars or whatever later. */
icculus@7707
   786
                if (capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD) {
icculus@7707
   787
                    AddXInputDevice(userid, pContext);
icculus@7707
   788
                }
icculus@7707
   789
            }
icculus@7707
   790
        }
icculus@7707
   791
    }
icculus@7707
   792
}
icculus@7707
   793
icculus@7707
   794
slouken@6707
   795
/* detect any new joysticks being inserted into the system */
slouken@6707
   796
void SDL_SYS_JoystickDetect()
slouken@6707
   797
{
slouken@7191
   798
    JoyStick_DeviceData *pCurList = NULL;
slouken@7191
   799
    /* only enum the devices if the joystick thread told us something changed */
slouken@7191
   800
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   801
    {
icculus@7707
   802
        SDL_LockMutex( s_mutexJoyStickEnum );
icculus@7707
   803
slouken@7191
   804
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   805
        s_bDeviceRemoved = SDL_FALSE;
slouken@6707
   806
slouken@7191
   807
        pCurList = SYS_Joystick;
slouken@7191
   808
        SYS_Joystick = NULL;
slouken@6707
   809
icculus@7707
   810
        /* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
slouken@7223
   811
        IDirectInput8_EnumDevices(dinput,
slouken@7191
   812
            DI8DEVCLASS_GAMECTRL,
slouken@7191
   813
            EnumJoysticksCallback,
slouken@7191
   814
            &pCurList, DIEDFL_ATTACHEDONLY);
slouken@6707
   815
icculus@7707
   816
        SDL_free(SDL_RawDevList);  /* in case we used this in DirectInput enumerator. */
icculus@7706
   817
        SDL_RawDevList = NULL;
icculus@7707
   818
        SDL_RawDevListCount = 0;
icculus@7706
   819
icculus@7712
   820
        /* Look for XInput devices. Do this last, so they're first in the final list. */
icculus@7712
   821
        EnumXInputDevices(&pCurList);
icculus@7712
   822
slouken@7191
   823
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
   824
    }
slouken@7191
   825
slouken@7191
   826
    if ( pCurList )
slouken@7191
   827
    {
slouken@7191
   828
        while ( pCurList )
slouken@7191
   829
        {
slouken@7191
   830
            JoyStick_DeviceData *pListNext = NULL;
icculus@8179
   831
icculus@8179
   832
#if SDL_HAPTIC_DINPUT
icculus@8179
   833
            if (pCurList->bXInputDevice) {
icculus@8179
   834
                XInputHaptic_MaybeRemoveDevice(pCurList->XInputUserId);
icculus@8179
   835
            } else {
icculus@8179
   836
                DirectInputHaptic_MaybeRemoveDevice(&pCurList->dxdevice);
icculus@8179
   837
            }
icculus@8179
   838
#endif
icculus@8179
   839
slouken@6707
   840
#if !SDL_EVENTS_DISABLED
icculus@8179
   841
            {
slouken@7191
   842
            SDL_Event event;
slouken@7191
   843
            event.type = SDL_JOYDEVICEREMOVED;
slouken@6707
   844
slouken@7191
   845
            if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   846
                event.jdevice.which = pCurList->nInstanceID;
slouken@7191
   847
                if ((SDL_EventOK == NULL)
slouken@7191
   848
                    || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   849
                        SDL_PushEvent(&event);
slouken@7191
   850
                }
slouken@7191
   851
            }
icculus@8179
   852
            }
slouken@7191
   853
#endif /* !SDL_EVENTS_DISABLED */
slouken@6707
   854
slouken@7191
   855
            pListNext = pCurList->pNext;
slouken@7191
   856
            SDL_free(pCurList->joystickname);
slouken@7719
   857
            SDL_free(pCurList);
slouken@7191
   858
            pCurList = pListNext;
slouken@7191
   859
        }
slouken@6707
   860
slouken@7191
   861
    }
slouken@6707
   862
slouken@7191
   863
    if ( s_bDeviceAdded )
slouken@7191
   864
    {
slouken@7191
   865
        JoyStick_DeviceData *pNewJoystick;
slouken@7191
   866
        int device_index = 0;
slouken@7191
   867
        s_bDeviceAdded = SDL_FALSE;
slouken@7191
   868
        pNewJoystick = SYS_Joystick;
slouken@7191
   869
        while ( pNewJoystick )
slouken@7191
   870
        {
slouken@7191
   871
            if ( pNewJoystick->send_add_event )
slouken@7191
   872
            {
icculus@8179
   873
#if SDL_HAPTIC_DINPUT
icculus@8179
   874
                if (pNewJoystick->bXInputDevice) {
icculus@8179
   875
                    XInputHaptic_MaybeAddDevice(pNewJoystick->XInputUserId);
icculus@8179
   876
                } else {
icculus@8179
   877
                    DirectInputHaptic_MaybeAddDevice(&pNewJoystick->dxdevice);
icculus@8179
   878
                }
icculus@8179
   879
#endif
icculus@8179
   880
slouken@6707
   881
#if !SDL_EVENTS_DISABLED
icculus@8179
   882
                {
slouken@7191
   883
                SDL_Event event;
slouken@7191
   884
                event.type = SDL_JOYDEVICEADDED;
slouken@6707
   885
slouken@7191
   886
                if (SDL_GetEventState(event.type) == SDL_ENABLE) {
slouken@7191
   887
                    event.jdevice.which = device_index;
slouken@7191
   888
                    if ((SDL_EventOK == NULL)
slouken@7191
   889
                        || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
slouken@7191
   890
                            SDL_PushEvent(&event);
slouken@7191
   891
                    }
slouken@7191
   892
                }
icculus@8179
   893
                }
slouken@6707
   894
#endif /* !SDL_EVENTS_DISABLED */
slouken@7191
   895
                pNewJoystick->send_add_event = 0;
slouken@7191
   896
            }
slouken@7191
   897
            device_index++;
slouken@7191
   898
            pNewJoystick = pNewJoystick->pNext;
slouken@7191
   899
        }
slouken@7191
   900
    }
slouken@6707
   901
}
slouken@6707
   902
slouken@6707
   903
/* we need to poll if we have pending hotplug device changes or connected devices */
slouken@6707
   904
SDL_bool SDL_SYS_JoystickNeedsPolling()
slouken@6707
   905
{
slouken@7191
   906
    /* we have a new device or one was pulled, we need to think this frame please */
slouken@7191
   907
    if ( s_bDeviceAdded || s_bDeviceRemoved )
slouken@7191
   908
        return SDL_TRUE;
slouken@6707
   909
slouken@7191
   910
    return SDL_FALSE;
slouken@6707
   911
}
slouken@6707
   912
slouken@1895
   913
/* Function to get the device-dependent name of a joystick */
slouken@1895
   914
const char *
slouken@6707
   915
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@1895
   916
{
slouken@7191
   917
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@6690
   918
slouken@7191
   919
    for (; device_index > 0; device_index--)
slouken@7191
   920
        device = device->pNext;
slouken@6690
   921
slouken@7191
   922
    return device->joystickname;
slouken@1895
   923
}
slouken@1895
   924
slouken@6707
   925
/* Function to perform the mapping between current device instance and this joysticks instance id */
slouken@6707
   926
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
   927
{
slouken@7191
   928
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
   929
    int index;
slouken@6707
   930
slouken@7191
   931
    for (index = device_index; index > 0; index--)
slouken@7191
   932
        device = device->pNext;
slouken@6707
   933
slouken@7191
   934
    return device->nInstanceID;
slouken@6707
   935
}
slouken@6707
   936
slouken@1895
   937
/* Function to open a joystick for use.
slouken@1895
   938
   The joystick to open is specified by the index field of the joystick.
slouken@1895
   939
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@1895
   940
   It returns 0, or -1 if there is an error.
slouken@1895
   941
 */
slouken@1895
   942
int
slouken@6690
   943
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@1895
   944
{
slouken@1895
   945
    HRESULT result;
slouken@7191
   946
    JoyStick_DeviceData *joystickdevice = SYS_Joystick;
slouken@6690
   947
slouken@7191
   948
    for (; device_index > 0; device_index--)
slouken@7191
   949
        joystickdevice = joystickdevice->pNext;
slouken@2198
   950
slouken@1895
   951
    /* allocate memory for system specific hardware data */
slouken@7191
   952
    joystick->instance_id = joystickdevice->nInstanceID;
urkle@6965
   953
    joystick->closed = 0;
slouken@1895
   954
    joystick->hwdata =
slouken@2713
   955
        (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   956
    if (joystick->hwdata == NULL) {
icculus@7037
   957
        return SDL_OutOfMemory();
slouken@1895
   958
    }
icculus@7707
   959
    SDL_zerop(joystick->hwdata);
slouken@1895
   960
icculus@7707
   961
    if (joystickdevice->bXInputDevice) {
icculus@7707
   962
        const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4));
icculus@7707
   963
        const Uint8 userId = joystickdevice->XInputUserId;
slouken@7191
   964
        XINPUT_CAPABILITIES capabilities;
slouken@1895
   965
icculus@7707
   966
        SDL_assert(s_bXInputEnabled);
icculus@7707
   967
        SDL_assert(XINPUTGETCAPABILITIES);
icculus@7707
   968
        SDL_assert(userId >= 0);
icculus@7707
   969
        SDL_assert(userId < SDL_XINPUT_MAX_DEVICES);
slouken@2198
   970
icculus@7707
   971
        joystick->hwdata->bXInputDevice = SDL_TRUE;
slouken@7684
   972
icculus@7707
   973
        if (XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities) != ERROR_SUCCESS) {
icculus@7707
   974
            SDL_free(joystick->hwdata);
icculus@7707
   975
            joystick->hwdata = NULL;
icculus@7707
   976
            return SDL_SetError("Failed to obtain XInput device capabilities. Device disconnected?");
icculus@7707
   977
        } else {
icculus@7707
   978
            /* Current version of XInput mistakenly returns 0 as the Type. Ignore it and ensure the subtype is a gamepad. */
icculus@7707
   979
            SDL_assert(capabilities.SubType == XINPUT_DEVSUBTYPE_GAMEPAD);
icculus@7707
   980
            if ((!bIs14OrLater) || (capabilities.Flags & XINPUT_CAPS_FFB_SUPPORTED)) {
icculus@7707
   981
                joystick->hwdata->bXInputHaptic = SDL_TRUE;
icculus@7707
   982
            }
icculus@7707
   983
            joystick->hwdata->userid = userId;
slouken@7684
   984
icculus@7707
   985
            /* The XInput API has a hard coded button/axis mapping, so we just match it */
icculus@7707
   986
            joystick->naxes = 6;
icculus@7707
   987
            joystick->nbuttons = 15;
icculus@7707
   988
            joystick->nballs = 0;
icculus@7707
   989
            joystick->nhats = 0;
icculus@7707
   990
		}
icculus@7707
   991
    } else {  /* use DirectInput, not XInput. */
icculus@7707
   992
        LPDIRECTINPUTDEVICE8 device;
icculus@7707
   993
        DIPROPDWORD dipdw;
slouken@1895
   994
icculus@7707
   995
        joystick->hwdata->buffered = 1;
icculus@7707
   996
        joystick->hwdata->removed = 0;
icculus@7707
   997
        joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
icculus@7707
   998
        joystick->hwdata->guid = joystickdevice->guid;
icculus@7707
   999
icculus@7707
  1000
        SDL_zero(dipdw);
icculus@7707
  1001
        dipdw.diph.dwSize = sizeof(DIPROPDWORD);
icculus@7707
  1002
        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@1895
  1003
slouken@7191
  1004
        result =
slouken@7191
  1005
            IDirectInput8_CreateDevice(dinput,
slouken@7191
  1006
                                      &(joystickdevice->dxdevice.guidInstance), &device, NULL);
slouken@7191
  1007
        if (FAILED(result)) {
slouken@7191
  1008
            return SetDIerror("IDirectInput::CreateDevice", result);
slouken@7191
  1009
        }
slouken@1895
  1010
slouken@7191
  1011
        /* Now get the IDirectInputDevice8 interface, instead. */
slouken@7191
  1012
        result = IDirectInputDevice8_QueryInterface(device,
slouken@7191
  1013
                                                   &IID_IDirectInputDevice8,
slouken@7191
  1014
                                                   (LPVOID *) & joystick->
slouken@7191
  1015
                                                   hwdata->InputDevice);
slouken@7191
  1016
        /* We are done with this object.  Use the stored one from now on. */
slouken@7191
  1017
        IDirectInputDevice8_Release(device);
slouken@1895
  1018
slouken@7191
  1019
        if (FAILED(result)) {
slouken@7191
  1020
            return SetDIerror("IDirectInputDevice8::QueryInterface", result);
slouken@7191
  1021
        }
slouken@2198
  1022
slouken@7191
  1023
        /* Acquire shared access. Exclusive access is required for forces,
slouken@7191
  1024
         * though. */
slouken@7191
  1025
        result =
slouken@7191
  1026
            IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
slouken@7191
  1027
                                                    InputDevice, SDL_HelperWindow,
slouken@7191
  1028
                                                    DISCL_NONEXCLUSIVE |
slouken@7191
  1029
                                                    DISCL_BACKGROUND);
slouken@7191
  1030
        if (FAILED(result)) {
slouken@7191
  1031
            return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
slouken@7191
  1032
        }
slouken@2198
  1033
slouken@7191
  1034
        /* Use the extended data structure: DIJOYSTATE2. */
slouken@7191
  1035
        result =
slouken@7191
  1036
            IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
slouken@7191
  1037
                                              &c_dfDIJoystick2);
slouken@7191
  1038
        if (FAILED(result)) {
slouken@7191
  1039
            return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
slouken@7191
  1040
        }
slouken@2198
  1041
slouken@7191
  1042
        /* Get device capabilities */
slouken@7191
  1043
        result =
slouken@7191
  1044
            IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
slouken@7191
  1045
                                                &joystick->hwdata->Capabilities);
slouken@2198
  1046
slouken@7191
  1047
        if (FAILED(result)) {
slouken@7191
  1048
            return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
slouken@7191
  1049
        }
slouken@2198
  1050
slouken@7191
  1051
        /* Force capable? */
slouken@7191
  1052
        if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
slouken@2198
  1053
slouken@7191
  1054
            result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1055
slouken@7191
  1056
            if (FAILED(result)) {
slouken@7191
  1057
                return SetDIerror("IDirectInputDevice8::Acquire", result);
slouken@7191
  1058
            }
slouken@2198
  1059
slouken@7191
  1060
            /* reset all accuators. */
slouken@7191
  1061
            result =
slouken@7191
  1062
                IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
slouken@7191
  1063
                                                             InputDevice,
slouken@7191
  1064
                                                             DISFFC_RESET);
slouken@2198
  1065
slouken@7191
  1066
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1067
            if (FAILED(result)) {
slouken@7191
  1068
                return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
slouken@7191
  1069
            }
slouken@7191
  1070
            */
slouken@1895
  1071
slouken@7191
  1072
            result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@1895
  1073
slouken@7191
  1074
            if (FAILED(result)) {
slouken@7191
  1075
                return SetDIerror("IDirectInputDevice8::Unacquire", result);
slouken@7191
  1076
            }
slouken@2198
  1077
slouken@7191
  1078
            /* Turn on auto-centering for a ForceFeedback device (until told
slouken@7191
  1079
             * otherwise). */
slouken@7191
  1080
            dipdw.diph.dwObj = 0;
slouken@7191
  1081
            dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1082
            dipdw.dwData = DIPROPAUTOCENTER_ON;
slouken@6220
  1083
slouken@7191
  1084
            result =
slouken@7191
  1085
                IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1086
                                                DIPROP_AUTOCENTER, &dipdw.diph);
slouken@2198
  1087
slouken@7191
  1088
            /* Not necessarily supported, ignore if not supported.
slouken@7191
  1089
            if (FAILED(result)) {
slouken@7191
  1090
                return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1091
            }
slouken@7191
  1092
            */
slouken@7191
  1093
        }
slouken@2198
  1094
slouken@7191
  1095
        /* What buttons and axes does it have? */
slouken@7191
  1096
        IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
slouken@7191
  1097
                                        EnumDevObjectsCallback, joystick,
slouken@7191
  1098
                                        DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
slouken@2198
  1099
slouken@7191
  1100
        /* Reorder the input objects. Some devices do not report the X axis as
slouken@7191
  1101
         * the first axis, for example. */
slouken@7191
  1102
        SortDevObjects(joystick);
slouken@6690
  1103
slouken@7191
  1104
        dipdw.diph.dwObj = 0;
slouken@7191
  1105
        dipdw.diph.dwHow = DIPH_DEVICE;
slouken@7191
  1106
        dipdw.dwData = INPUT_QSIZE;
slouken@6690
  1107
slouken@7191
  1108
        /* Set the buffer size */
slouken@7191
  1109
        result =
slouken@7191
  1110
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@7191
  1111
                                            DIPROP_BUFFERSIZE, &dipdw.diph);
slouken@6690
  1112
slouken@7191
  1113
        if (result == DI_POLLEDDEVICE) {
slouken@7191
  1114
            /* This device doesn't support buffering, so we're forced
slouken@7191
  1115
             * to use less reliable polling. */
slouken@7191
  1116
            joystick->hwdata->buffered = 0;
slouken@7191
  1117
        } else if (FAILED(result)) {
slouken@7191
  1118
            return SetDIerror("IDirectInputDevice8::SetProperty", result);
slouken@7191
  1119
        }
slouken@7191
  1120
    }
slouken@1895
  1121
    return (0);
slouken@1895
  1122
}
slouken@1895
  1123
slouken@6707
  1124
/* return true if this joystick is plugged in right now */
slouken@6707
  1125
SDL_bool SDL_SYS_JoystickAttached( SDL_Joystick * joystick )
slouken@6707
  1126
{
slouken@7191
  1127
    return joystick->closed == 0 && joystick->hwdata->removed == 0;
slouken@6707
  1128
}
slouken@6707
  1129
slouken@6707
  1130
slouken@6220
  1131
/* Sort using the data offset into the DInput struct.
slouken@6220
  1132
 * This gives a reasonable ordering for the inputs. */
slouken@6220
  1133
static int
slouken@6220
  1134
SortDevFunc(const void *a, const void *b)
slouken@6220
  1135
{
slouken@7191
  1136
    const input_t *inputA = (const input_t*)a;
slouken@7191
  1137
    const input_t *inputB = (const input_t*)b;
slouken@6220
  1138
slouken@7191
  1139
    if (inputA->ofs < inputB->ofs)
slouken@7191
  1140
        return -1;
slouken@7191
  1141
    if (inputA->ofs > inputB->ofs)
slouken@7191
  1142
        return 1;
slouken@7191
  1143
    return 0;
slouken@6220
  1144
}
slouken@6220
  1145
slouken@6220
  1146
/* Sort the input objects and recalculate the indices for each input. */
slouken@6220
  1147
static void
slouken@6220
  1148
SortDevObjects(SDL_Joystick *joystick)
slouken@6220
  1149
{
slouken@7191
  1150
    input_t *inputs = joystick->hwdata->Inputs;
slouken@7191
  1151
    int nButtons = 0;
slouken@7191
  1152
    int nHats = 0;
slouken@7191
  1153
    int nAxis = 0;
slouken@7191
  1154
    int n;
slouken@6220
  1155
slouken@7191
  1156
    SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
slouken@6220
  1157
slouken@7191
  1158
    for (n = 0; n < joystick->hwdata->NumInputs; n++)
slouken@7191
  1159
    {
slouken@7191
  1160
        switch (inputs[n].type)
slouken@7191
  1161
        {
slouken@7191
  1162
        case BUTTON:
slouken@7191
  1163
            inputs[n].num = nButtons;
slouken@7191
  1164
            nButtons++;
slouken@7191
  1165
            break;
slouken@6220
  1166
slouken@7191
  1167
        case HAT:
slouken@7191
  1168
            inputs[n].num = nHats;
slouken@7191
  1169
            nHats++;
slouken@7191
  1170
            break;
slouken@6220
  1171
slouken@7191
  1172
        case AXIS:
slouken@7191
  1173
            inputs[n].num = nAxis;
slouken@7191
  1174
            nAxis++;
slouken@7191
  1175
            break;
slouken@7191
  1176
        }
slouken@7191
  1177
    }
slouken@6220
  1178
}
slouken@6220
  1179
slouken@2198
  1180
static BOOL CALLBACK
slouken@2198
  1181
EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
slouken@2198
  1182
{
slouken@2198
  1183
    SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
slouken@2198
  1184
    HRESULT result;
slouken@2198
  1185
    input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
slouken@2198
  1186
slouken@2198
  1187
    if (dev->dwType & DIDFT_BUTTON) {
slouken@2198
  1188
        in->type = BUTTON;
slouken@2198
  1189
        in->num = joystick->nbuttons;
slouken@7191
  1190
        in->ofs = DIJOFS_BUTTON( in->num );
slouken@2198
  1191
        joystick->nbuttons++;
slouken@2198
  1192
    } else if (dev->dwType & DIDFT_POV) {
slouken@2198
  1193
        in->type = HAT;
slouken@2198
  1194
        in->num = joystick->nhats;
slouken@7191
  1195
        in->ofs = DIJOFS_POV( in->num );
slouken@2198
  1196
        joystick->nhats++;
slouken@2198
  1197
    } else if (dev->dwType & DIDFT_AXIS) {
slouken@2198
  1198
        DIPROPRANGE diprg;
slouken@2198
  1199
        DIPROPDWORD dilong;
slouken@2198
  1200
slouken@2198
  1201
        in->type = AXIS;
slouken@2198
  1202
        in->num = joystick->naxes;
slouken@7191
  1203
        /* work our the axis this guy maps too, thanks for the code icculus! */
slouken@7191
  1204
        if ( !SDL_memcmp( &dev->guidType, &GUID_XAxis, sizeof(dev->guidType) ) )
slouken@7191
  1205
            in->ofs = DIJOFS_X;
slouken@7191
  1206
        else if ( !SDL_memcmp( &dev->guidType, &GUID_YAxis, sizeof(dev->guidType) ) )
slouken@7191
  1207
            in->ofs = DIJOFS_Y;
slouken@7191
  1208
        else if ( !SDL_memcmp( &dev->guidType, &GUID_ZAxis, sizeof(dev->guidType) ) )
slouken@7191
  1209
            in->ofs = DIJOFS_Z;
slouken@7191
  1210
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RxAxis, sizeof(dev->guidType) ) )
slouken@7191
  1211
            in->ofs = DIJOFS_RX;
slouken@7191
  1212
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RyAxis, sizeof(dev->guidType) ) )
slouken@7191
  1213
            in->ofs = DIJOFS_RY;
slouken@7191
  1214
        else if ( !SDL_memcmp( &dev->guidType, &GUID_RzAxis, sizeof(dev->guidType) ) )
slouken@7191
  1215
            in->ofs = DIJOFS_RZ;
slouken@7191
  1216
        else if ( !SDL_memcmp( &dev->guidType, &GUID_Slider, sizeof(dev->guidType) ) )
slouken@7191
  1217
        {
slouken@7191
  1218
            in->ofs = DIJOFS_SLIDER( joystick->hwdata->NumSliders );
slouken@7191
  1219
            ++joystick->hwdata->NumSliders;
slouken@7191
  1220
        }
slouken@7191
  1221
        else
slouken@7191
  1222
        {
slouken@7191
  1223
             return DIENUM_CONTINUE; /* not an axis we can grok */
slouken@7191
  1224
        }
slouken@2198
  1225
slouken@2198
  1226
        diprg.diph.dwSize = sizeof(diprg);
slouken@2198
  1227
        diprg.diph.dwHeaderSize = sizeof(diprg.diph);
slouken@6690
  1228
        diprg.diph.dwObj = dev->dwType;
slouken@6690
  1229
        diprg.diph.dwHow = DIPH_BYID;
slouken@2198
  1230
        diprg.lMin = AXIS_MIN;
slouken@2198
  1231
        diprg.lMax = AXIS_MAX;
slouken@2198
  1232
slouken@2198
  1233
        result =
slouken@6690
  1234
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1235
                                            DIPROP_RANGE, &diprg.diph);
slouken@2198
  1236
        if (FAILED(result)) {
slouken@2198
  1237
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1238
        }
slouken@2198
  1239
slouken@2198
  1240
        /* Set dead zone to 0. */
slouken@2198
  1241
        dilong.diph.dwSize = sizeof(dilong);
slouken@2198
  1242
        dilong.diph.dwHeaderSize = sizeof(dilong.diph);
slouken@6690
  1243
        dilong.diph.dwObj = dev->dwType;
slouken@6690
  1244
        dilong.diph.dwHow = DIPH_BYID;
slouken@2198
  1245
        dilong.dwData = 0;
slouken@2198
  1246
        result =
slouken@6690
  1247
            IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
slouken@2198
  1248
                                            DIPROP_DEADZONE, &dilong.diph);
slouken@2198
  1249
        if (FAILED(result)) {
slouken@2198
  1250
            return DIENUM_CONTINUE;     /* don't use this axis */
slouken@2198
  1251
        }
slouken@2198
  1252
slouken@2198
  1253
        joystick->naxes++;
slouken@2198
  1254
    } else {
slouken@2198
  1255
        /* not supported at this time */
slouken@2198
  1256
        return DIENUM_CONTINUE;
slouken@2198
  1257
    }
slouken@2198
  1258
slouken@2198
  1259
    joystick->hwdata->NumInputs++;
slouken@2198
  1260
slouken@2198
  1261
    if (joystick->hwdata->NumInputs == MAX_INPUTS) {
slouken@2198
  1262
        return DIENUM_STOP;     /* too many */
slouken@2198
  1263
    }
slouken@2198
  1264
slouken@2198
  1265
    return DIENUM_CONTINUE;
slouken@2198
  1266
}
slouken@2198
  1267
slouken@2198
  1268
/* Function to update the state of a joystick - called as a device poll.
slouken@2198
  1269
 * This function shouldn't update the joystick structure directly,
slouken@2198
  1270
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@2198
  1271
 * and update joystick device state.
slouken@2198
  1272
 */
slouken@2198
  1273
void
slouken@2198
  1274
SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
slouken@2198
  1275
{
slouken@2198
  1276
    DIJOYSTATE2 state;
slouken@2198
  1277
    HRESULT result;
slouken@2198
  1278
    int i;
slouken@2198
  1279
slouken@2198
  1280
    result =
slouken@6690
  1281
        IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1282
                                           sizeof(DIJOYSTATE2), &state);
slouken@2198
  1283
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1284
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1285
        result =
slouken@6690
  1286
            IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
slouken@2198
  1287
                                               sizeof(DIJOYSTATE2), &state);
slouken@2198
  1288
    }
slouken@2198
  1289
slouken@7191
  1290
    if ( result != DI_OK )
slouken@7191
  1291
    {
slouken@7191
  1292
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1293
        joystick->hwdata->removed = 1;
slouken@7191
  1294
        return;
slouken@7191
  1295
    }
slouken@6690
  1296
slouken@2198
  1297
    /* Set each known axis, button and POV. */
slouken@2198
  1298
    for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
slouken@2198
  1299
        const input_t *in = &joystick->hwdata->Inputs[i];
slouken@2198
  1300
slouken@2198
  1301
        switch (in->type) {
slouken@2198
  1302
        case AXIS:
slouken@2198
  1303
            switch (in->ofs) {
slouken@2198
  1304
            case DIJOFS_X:
slouken@2198
  1305
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1306
                                            (Sint16) state.lX);
slouken@2198
  1307
                break;
slouken@2198
  1308
            case DIJOFS_Y:
slouken@2198
  1309
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1310
                                            (Sint16) state.lY);
slouken@2198
  1311
                break;
slouken@2198
  1312
            case DIJOFS_Z:
slouken@2198
  1313
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1314
                                            (Sint16) state.lZ);
slouken@2198
  1315
                break;
slouken@2198
  1316
            case DIJOFS_RX:
slouken@2198
  1317
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1318
                                            (Sint16) state.lRx);
slouken@2198
  1319
                break;
slouken@2198
  1320
            case DIJOFS_RY:
slouken@2198
  1321
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1322
                                            (Sint16) state.lRy);
slouken@2198
  1323
                break;
slouken@2198
  1324
            case DIJOFS_RZ:
slouken@2198
  1325
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1326
                                            (Sint16) state.lRz);
slouken@2198
  1327
                break;
slouken@2198
  1328
            case DIJOFS_SLIDER(0):
slouken@2198
  1329
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1330
                                            (Sint16) state.rglSlider[0]);
slouken@2198
  1331
                break;
slouken@2198
  1332
            case DIJOFS_SLIDER(1):
slouken@2198
  1333
                SDL_PrivateJoystickAxis_Int(joystick, in->num,
slouken@2198
  1334
                                            (Sint16) state.rglSlider[1]);
slouken@2198
  1335
                break;
slouken@2198
  1336
            }
slouken@2198
  1337
slouken@2198
  1338
            break;
slouken@2198
  1339
slouken@2198
  1340
        case BUTTON:
slouken@2198
  1341
            SDL_PrivateJoystickButton_Int(joystick, in->num,
slouken@3013
  1342
                                          (Uint8) (state.
slouken@3013
  1343
                                                   rgbButtons[in->ofs -
slouken@3013
  1344
                                                              DIJOFS_BUTTON0]
slouken@2198
  1345
                                                   ? SDL_PRESSED :
slouken@2198
  1346
                                                   SDL_RELEASED));
slouken@2198
  1347
            break;
slouken@2198
  1348
        case HAT:
slouken@2198
  1349
            {
slouken@2198
  1350
                Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
slouken@2198
  1351
                                                       DIJOFS_POV(0)]);
slouken@2198
  1352
                SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
slouken@2198
  1353
                break;
slouken@2198
  1354
            }
slouken@2198
  1355
        }
slouken@2198
  1356
    }
slouken@2198
  1357
}
slouken@2198
  1358
slouken@2198
  1359
void
slouken@2198
  1360
SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
slouken@2198
  1361
{
slouken@2198
  1362
    int i;
slouken@2198
  1363
    HRESULT result;
slouken@2198
  1364
    DWORD numevents;
slouken@2198
  1365
    DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
slouken@2198
  1366
slouken@2198
  1367
    numevents = INPUT_QSIZE;
slouken@2198
  1368
    result =
slouken@6690
  1369
        IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1370
                                          sizeof(DIDEVICEOBJECTDATA), evtbuf,
slouken@2198
  1371
                                          &numevents, 0);
slouken@2198
  1372
    if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@6690
  1373
        IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@2198
  1374
        result =
slouken@6690
  1375
            IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
slouken@2198
  1376
                                              sizeof(DIDEVICEOBJECTDATA),
slouken@2198
  1377
                                              evtbuf, &numevents, 0);
slouken@2198
  1378
    }
slouken@2198
  1379
slouken@2198
  1380
    /* Handle the events or punt */
slouken@2198
  1381
    if (FAILED(result))
slouken@7191
  1382
    {
slouken@7191
  1383
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1384
        joystick->hwdata->removed = 1;
slouken@2198
  1385
        return;
slouken@7191
  1386
    }
slouken@2198
  1387
slouken@2198
  1388
    for (i = 0; i < (int) numevents; ++i) {
slouken@2198
  1389
        int j;
slouken@2198
  1390
slouken@2198
  1391
        for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
slouken@2198
  1392
            const input_t *in = &joystick->hwdata->Inputs[j];
slouken@2198
  1393
slouken@2198
  1394
            if (evtbuf[i].dwOfs != in->ofs)
slouken@2198
  1395
                continue;
slouken@2198
  1396
slouken@2198
  1397
            switch (in->type) {
slouken@2198
  1398
            case AXIS:
slouken@2198
  1399
                SDL_PrivateJoystickAxis(joystick, in->num,
slouken@2198
  1400
                                        (Sint16) evtbuf[i].dwData);
slouken@2198
  1401
                break;
slouken@2198
  1402
            case BUTTON:
slouken@2198
  1403
                SDL_PrivateJoystickButton(joystick, in->num,
slouken@3013
  1404
                                          (Uint8) (evtbuf[i].
slouken@3013
  1405
                                                   dwData ? SDL_PRESSED :
slouken@2198
  1406
                                                   SDL_RELEASED));
slouken@2198
  1407
                break;
slouken@2198
  1408
            case HAT:
slouken@2198
  1409
                {
slouken@2198
  1410
                    Uint8 pos = TranslatePOV(evtbuf[i].dwData);
slouken@2198
  1411
                    SDL_PrivateJoystickHat(joystick, in->num, pos);
slouken@2198
  1412
                }
slouken@2198
  1413
            }
slouken@2198
  1414
        }
slouken@2198
  1415
    }
slouken@2198
  1416
}
slouken@2198
  1417
slouken@2198
  1418
slouken@6690
  1419
/* Function to return > 0 if a bit array of buttons differs after applying a mask
slouken@6690
  1420
*/
slouken@6690
  1421
int ButtonChanged( int ButtonsNow, int ButtonsPrev, int ButtonMask )
slouken@6690
  1422
{
slouken@7191
  1423
    return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
slouken@6690
  1424
}
slouken@6690
  1425
slouken@6690
  1426
/* Function to update the state of a XInput style joystick.
slouken@6690
  1427
*/
slouken@6690
  1428
void
slouken@6690
  1429
SDL_SYS_JoystickUpdate_XInput(SDL_Joystick * joystick)
slouken@6690
  1430
{
slouken@7191
  1431
    HRESULT result;
slouken@6690
  1432
slouken@7191
  1433
    if ( !XINPUTGETSTATE )
slouken@7191
  1434
        return;
slouken@6690
  1435
slouken@7191
  1436
    result = XINPUTGETSTATE( joystick->hwdata->userid, &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot] );
slouken@7191
  1437
    if ( result == ERROR_DEVICE_NOT_CONNECTED )
slouken@7191
  1438
    {
slouken@7191
  1439
        joystick->hwdata->send_remove_event = 1;
slouken@7191
  1440
        joystick->hwdata->removed = 1;
slouken@7191
  1441
        return;
slouken@7191
  1442
    }
slouken@6690
  1443
slouken@7191
  1444
    /* only fire events if the data changed from last time */
slouken@7191
  1445
    if ( joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != 0
slouken@7191
  1446
        && joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot].dwPacketNumber != joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot^1].dwPacketNumber )
slouken@7191
  1447
    {
slouken@7191
  1448
        XINPUT_STATE_EX *pXInputState = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot];
slouken@7191
  1449
        XINPUT_STATE_EX *pXInputStatePrev = &joystick->hwdata->XInputState[joystick->hwdata->currentXInputSlot ^ 1];
slouken@6690
  1450
icculus@8277
  1451
        /* !!! FIXME: why isn't this just using SDL_PrivateJoystickAxis_Int()? */
slouken@7296
  1452
        SDL_PrivateJoystickAxis( joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
slouken@7321
  1453
        SDL_PrivateJoystickAxis( joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)) );
slouken@7296
  1454
        SDL_PrivateJoystickAxis( joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
slouken@7321
  1455
        SDL_PrivateJoystickAxis( joystick, 3, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)) );
slouken@7296
  1456
        SDL_PrivateJoystickAxis( joystick, 4, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger*65535/255) - 32768));
slouken@7296
  1457
        SDL_PrivateJoystickAxis( joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger*65535/255) - 32768));
slouken@6690
  1458
icculus@8277
  1459
        /* !!! FIXME: why isn't this just using SDL_PrivateJoystickButton_Int(), instead of keeping these two alternating state buffers? */
slouken@7191
  1460
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
slouken@7191
  1461
            SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1462
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
slouken@7191
  1463
            SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1464
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
slouken@7191
  1465
            SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1466
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
slouken@7191
  1467
            SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1468
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
slouken@7191
  1469
            SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1470
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
slouken@7191
  1471
            SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED : SDL_RELEASED );
slouken@7191
  1472
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
slouken@7191
  1473
            SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1474
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
slouken@7191
  1475
            SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED :  SDL_RELEASED );
slouken@7191
  1476
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
slouken@7191
  1477
            SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED :    SDL_RELEASED );
slouken@7191
  1478
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
slouken@7191
  1479
            SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1480
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
slouken@7191
  1481
            SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1482
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
slouken@7191
  1483
            SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1484
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
slouken@7191
  1485
            SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1486
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
slouken@7191
  1487
            SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED :   SDL_RELEASED );
slouken@7191
  1488
        if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons,  0x400 ) )
slouken@7191
  1489
            SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED :  SDL_RELEASED ); /* 0x400 is the undocumented code for the guide button */
slouken@6690
  1490
slouken@7191
  1491
        joystick->hwdata->currentXInputSlot ^= 1;
slouken@6690
  1492
slouken@7191
  1493
    }
slouken@6690
  1494
}
slouken@6690
  1495
slouken@6690
  1496
slouken@1895
  1497
static Uint8
slouken@1895
  1498
TranslatePOV(DWORD value)
slouken@1895
  1499
{
slouken@1895
  1500
    const int HAT_VALS[] = {
slouken@1895
  1501
        SDL_HAT_UP,
slouken@1895
  1502
        SDL_HAT_UP | SDL_HAT_RIGHT,
slouken@1895
  1503
        SDL_HAT_RIGHT,
slouken@1895
  1504
        SDL_HAT_DOWN | SDL_HAT_RIGHT,
slouken@1895
  1505
        SDL_HAT_DOWN,
slouken@1895
  1506
        SDL_HAT_DOWN | SDL_HAT_LEFT,
slouken@1895
  1507
        SDL_HAT_LEFT,
slouken@1895
  1508
        SDL_HAT_UP | SDL_HAT_LEFT
slouken@1895
  1509
    };
slouken@1895
  1510
slouken@1895
  1511
    if (LOWORD(value) == 0xFFFF)
slouken@1895
  1512
        return SDL_HAT_CENTERED;
slouken@1895
  1513
slouken@1895
  1514
    /* Round the value up: */
slouken@1895
  1515
    value += 4500 / 2;
slouken@1895
  1516
    value %= 36000;
slouken@1895
  1517
    value /= 4500;
slouken@1895
  1518
slouken@1895
  1519
    if (value >= 8)
slouken@1895
  1520
        return SDL_HAT_CENTERED;        /* shouldn't happen */
slouken@1895
  1521
slouken@1895
  1522
    return HAT_VALS[value];
slouken@1895
  1523
}
slouken@1895
  1524
slouken@1895
  1525
/* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
slouken@1895
  1526
 * do it. */
icculus@8280
  1527
/* !!! FIXME: SDL_PrivateJoystickAxis _does_ discard duplicate events now. Ditch this code. */
slouken@1895
  1528
static int
slouken@1895
  1529
SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
slouken@1895
  1530
{
slouken@1895
  1531
    if (joystick->axes[axis] != value)
slouken@1895
  1532
        return SDL_PrivateJoystickAxis(joystick, axis, value);
slouken@1895
  1533
    return 0;
slouken@1895
  1534
}
slouken@1895
  1535
slouken@1895
  1536
static int
slouken@1895
  1537
SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
slouken@1895
  1538
{
slouken@1895
  1539
    if (joystick->hats[hat] != value)
slouken@1895
  1540
        return SDL_PrivateJoystickHat(joystick, hat, value);
slouken@1895
  1541
    return 0;
slouken@1895
  1542
}
slouken@1895
  1543
slouken@1895
  1544
static int
slouken@1895
  1545
SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
slouken@1895
  1546
                              Uint8 state)
slouken@1895
  1547
{
slouken@1895
  1548
    if (joystick->buttons[button] != state)
slouken@1895
  1549
        return SDL_PrivateJoystickButton(joystick, button, state);
slouken@1895
  1550
    return 0;
slouken@1895
  1551
}
slouken@1895
  1552
slouken@1895
  1553
void
slouken@1895
  1554
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
slouken@1895
  1555
{
slouken@1895
  1556
    HRESULT result;
slouken@1895
  1557
slouken@7191
  1558
    if ( joystick->closed || !joystick->hwdata )
slouken@7191
  1559
        return;
slouken@1895
  1560
slouken@7191
  1561
    if (joystick->hwdata->bXInputDevice)
slouken@7191
  1562
    {
slouken@7191
  1563
        SDL_SYS_JoystickUpdate_XInput(joystick);
slouken@7191
  1564
    }
slouken@7191
  1565
    else
slouken@7191
  1566
    {
slouken@7191
  1567
        result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1568
        if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
slouken@7191
  1569
            IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
slouken@7191
  1570
            IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
slouken@7191
  1571
        }
slouken@6690
  1572
slouken@7191
  1573
        if (joystick->hwdata->buffered)
slouken@7191
  1574
            SDL_SYS_JoystickUpdate_Buffered(joystick);
slouken@7191
  1575
        else
slouken@7191
  1576
            SDL_SYS_JoystickUpdate_Polled(joystick);
slouken@7191
  1577
    }
slouken@6690
  1578
slouken@7191
  1579
    if ( joystick->hwdata->removed )
slouken@7191
  1580
    {
slouken@7191
  1581
        joystick->closed = 1;
slouken@7191
  1582
        joystick->uncentered = 1;
slouken@7191
  1583
    }
slouken@1895
  1584
}
slouken@1895
  1585
slouken@1895
  1586
/* Function to close a joystick after use */
slouken@1895
  1587
void
slouken@1895
  1588
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
slouken@1895
  1589
{
icculus@7711
  1590
    if (!joystick->hwdata->bXInputDevice) {
slouken@7191
  1591
        IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
slouken@7191
  1592
        IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
slouken@7191
  1593
    }
slouken@1895
  1594
slouken@7719
  1595
    /* free system specific hardware data */
slouken@7719
  1596
    SDL_free(joystick->hwdata);
slouken@6690
  1597
slouken@7191
  1598
    joystick->closed = 1;
slouken@1895
  1599
}
slouken@1895
  1600
slouken@1895
  1601
/* Function to perform any system-specific joystick related cleanup */
slouken@1895
  1602
void
slouken@1895
  1603
SDL_SYS_JoystickQuit(void)
slouken@1895
  1604
{
slouken@7191
  1605
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@5090
  1606
slouken@7191
  1607
    while ( device )
slouken@7191
  1608
    {
slouken@7191
  1609
        JoyStick_DeviceData *device_next = device->pNext;
slouken@7191
  1610
        SDL_free(device->joystickname);
slouken@7191
  1611
        SDL_free(device);
slouken@7191
  1612
        device = device_next;
slouken@7191
  1613
    }
slouken@7191
  1614
    SYS_Joystick = NULL;
slouken@6690
  1615
slouken@7191
  1616
    if ( s_threadJoystick )
slouken@7191
  1617
    {
slouken@7191
  1618
        SDL_LockMutex( s_mutexJoyStickEnum );
slouken@7191
  1619
        s_bJoystickThreadQuit = SDL_TRUE;
slouken@7191
  1620
        SDL_CondBroadcast( s_condJoystickThread ); /* signal the joystick thread to quit */
slouken@7191
  1621
        SDL_UnlockMutex( s_mutexJoyStickEnum );
slouken@7191
  1622
        SDL_WaitThread( s_threadJoystick, NULL ); /* wait for it to bugger off */
slouken@6690
  1623
slouken@7191
  1624
        SDL_DestroyMutex( s_mutexJoyStickEnum );
slouken@7191
  1625
        SDL_DestroyCond( s_condJoystickThread );
slouken@7191
  1626
        s_condJoystickThread= NULL;
slouken@7191
  1627
        s_mutexJoyStickEnum = NULL;
slouken@7191
  1628
        s_threadJoystick = NULL;
slouken@7191
  1629
    }
slouken@5090
  1630
icculus@5591
  1631
    if (dinput != NULL) {
slouken@6690
  1632
        IDirectInput8_Release(dinput);
icculus@5591
  1633
        dinput = NULL;
icculus@5591
  1634
    }
icculus@5591
  1635
icculus@5591
  1636
    if (coinitialized) {
icculus@5591
  1637
        WIN_CoUninitialize();
icculus@5591
  1638
        coinitialized = SDL_FALSE;
icculus@5591
  1639
    }
slouken@6690
  1640
icculus@6990
  1641
    if (s_bXInputEnabled) {
icculus@6990
  1642
        WIN_UnloadXInputDLL();
icculus@6990
  1643
    }
slouken@6690
  1644
}
slouken@6690
  1645
slouken@6690
  1646
/* return the stable device guid for this device index */
slouken@6738
  1647
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6690
  1648
{
slouken@7191
  1649
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1650
    int index;
slouken@6690
  1651
slouken@7191
  1652
    for (index = device_index; index > 0; index--)
slouken@7191
  1653
        device = device->pNext;
slouken@6690
  1654
slouken@7191
  1655
    return device->guid;
slouken@6690
  1656
}
slouken@6690
  1657
slouken@6738
  1658
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6707
  1659
{
slouken@7191
  1660
    return joystick->hwdata->guid;
slouken@6707
  1661
}
slouken@6707
  1662
slouken@6707
  1663
/* return SDL_TRUE if this device is using XInput */
slouken@6707
  1664
SDL_bool SDL_SYS_IsXInputDeviceIndex(int device_index)
slouken@6690
  1665
{
slouken@7191
  1666
    JoyStick_DeviceData *device = SYS_Joystick;
slouken@7191
  1667
    int index;
slouken@6690
  1668
slouken@7191
  1669
    for (index = device_index; index > 0; index--)
slouken@7191
  1670
        device = device->pNext;
slouken@6690
  1671
slouken@7191
  1672
    return device->bXInputDevice;
slouken@6690
  1673
}
slouken@6690
  1674
slouken@7685
  1675
/* return SDL_TRUE if this device was opened with XInput */
slouken@7685
  1676
SDL_bool SDL_SYS_IsXInputJoystick(SDL_Joystick * joystick)
slouken@7685
  1677
{
slouken@7685
  1678
	return joystick->hwdata->bXInputDevice;
slouken@7685
  1679
}
slouken@7685
  1680
slouken@1895
  1681
#endif /* SDL_JOYSTICK_DINPUT */
slouken@3575
  1682
slouken@1895
  1683
/* vi: set ts=4 sw=4 expandtab: */