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