SDL  2.0
SDL_dinputjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #include "../SDL_sysjoystick.h"
24 
25 #if SDL_JOYSTICK_DINPUT
26 
27 #include "SDL_windowsjoystick_c.h"
28 #include "SDL_dinputjoystick_c.h"
29 #include "SDL_xinputjoystick_c.h"
30 
31 #ifndef DIDFT_OPTIONAL
32 #define DIDFT_OPTIONAL 0x80000000
33 #endif
34 
35 #define INPUT_QSIZE 32 /* Buffer up to 32 input messages */
36 #define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100) /* 1% motion */
37 
38 /* external variables referenced. */
39 extern HWND SDL_HelperWindow;
40 
41 /* local variables */
42 static SDL_bool coinitialized = SDL_FALSE;
43 static LPDIRECTINPUT8 dinput = NULL;
44 static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
45 static UINT SDL_RawDevListCount = 0;
46 
47 /* Taken from Wine - Thanks! */
48 static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
49  { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
50  { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
51  { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
52  { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
53  { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
54  { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
55  { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
56  { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
57  { &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
58  { &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
59  { &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
60  { &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
61  { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
62  { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
63  { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
64  { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
65  { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
66  { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
67  { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
68  { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
69  { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
70  { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
71  { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
72  { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
73  { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
74  { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
75  { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
76  { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
77  { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
78  { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
79  { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
80  { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
81  { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
82  { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
83  { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
84  { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
85  { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
86  { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
87  { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
88  { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
89  { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
90  { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
91  { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
92  { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
93  { NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
94  { NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
95  { NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
96  { NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
97  { NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
98  { NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
99  { NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
100  { NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
101  { NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
102  { NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
103  { NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
104  { NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
105  { NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
106  { NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
107  { NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
108  { NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
109  { NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
110  { NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
111  { NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
112  { NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
113  { NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
114  { NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
115  { NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
116  { NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
117  { NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
118  { NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
119  { NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
120  { NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
121  { NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
122  { NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
123  { NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
124  { NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
125  { NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
126  { NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
127  { NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
128  { NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
129  { NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
130  { NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
131  { NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
132  { NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
133  { NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
134  { NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
135  { NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
136  { NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
137  { NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
138  { NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
139  { NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
140  { NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
141  { NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
142  { NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
143  { NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
144  { NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
145  { NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
146  { NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
147  { NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
148  { NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
149  { NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
150  { NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
151  { NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
152  { NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
153  { NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
154  { NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
155  { NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
156  { NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
157  { NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
158  { NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
159  { NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
160  { NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
161  { NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
162  { NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
163  { NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
164  { NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
165  { NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
166  { NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
167  { NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
168  { NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
169  { NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
170  { NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
171  { NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
172  { NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
173  { NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
174  { NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
175  { NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
176  { NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
177  { NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
178  { NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
179  { NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
180  { NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
181  { NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
182  { NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
183  { NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
184  { NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
185  { NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
186  { NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
187  { NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
188  { NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
189  { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
190  { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
191  { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
192  { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
193  { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
194  { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
195  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
196  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
197  { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
198  { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
199  { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
200  { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
201  { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
202  { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
203  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
204  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
205  { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
206  { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
207  { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
208  { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
209  { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
210  { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
211  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
212  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
213 };
214 
215 const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
216  sizeof(DIDATAFORMAT),
217  sizeof(DIOBJECTDATAFORMAT),
218  DIDF_ABSAXIS,
219  sizeof(DIJOYSTATE2),
220  SDL_arraysize(dfDIJoystick2),
221  dfDIJoystick2
222 };
223 
224 /* Convert a DirectInput return code to a text message */
225 static int
226 SetDIerror(const char *function, HRESULT code)
227 {
228  /*
229  return SDL_SetError("%s() [%s]: %s", function,
230  DXGetErrorString9A(code), DXGetErrorDescription9A(code));
231  */
232  return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
233 }
234 
235 static SDL_bool
236 SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
237 {
238  static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
239  static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
240  static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
241  static GUID IID_XOneWiredGamepad = { MAKELONG(0x045E, 0x02FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
242  static GUID IID_XOneWirelessGamepad = { MAKELONG(0x045E, 0x02DD), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
243  static GUID IID_XOneNewWirelessGamepad = { MAKELONG(0x045E, 0x02D1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
244  static GUID IID_XOneSWirelessGamepad = { MAKELONG(0x045E, 0x02EA), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
245  static GUID IID_XOneSBluetoothGamepad = { MAKELONG(0x045E, 0x02E0), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
246  static GUID IID_XOneEliteWirelessGamepad = { MAKELONG(0x045E, 0x02E3), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
247 
248  static const GUID *s_XInputProductGUID[] = {
249  &IID_ValveStreamingGamepad,
250  &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */
251  &IID_X360WirelessGamepad, /* Microsoft's wireless X360 controller for Windows. */
252  &IID_XOneWiredGamepad, /* Microsoft's wired Xbox One controller for Windows. */
253  &IID_XOneWirelessGamepad, /* Microsoft's wireless Xbox One controller for Windows. */
254  &IID_XOneNewWirelessGamepad, /* Microsoft's updated wireless Xbox One controller (w/ 3.5 mm jack) for Windows. */
255  &IID_XOneSWirelessGamepad, /* Microsoft's wireless Xbox One S controller for Windows. */
256  &IID_XOneSBluetoothGamepad, /* Microsoft's Bluetooth Xbox One S controller for Windows. */
257  &IID_XOneEliteWirelessGamepad /* Microsoft's wireless Xbox One Elite controller for Windows. */
258  };
259 
260  size_t iDevice;
261  UINT i;
262 
263  if (!SDL_XINPUT_Enabled()) {
264  return SDL_FALSE;
265  }
266 
267  /* Check for well known XInput device GUIDs */
268  /* This lets us skip RAWINPUT for popular devices. Also, we need to do this for the Valve Streaming Gamepad because it's virtualized and doesn't show up in the device list. */
269  for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) {
270  if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) {
271  return SDL_TRUE;
272  }
273  }
274 
275  /* Go through RAWINPUT (WinXP and later) to find HID devices. */
276  /* Cache this if we end up using it. */
277  if (SDL_RawDevList == NULL) {
278  if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
279  return SDL_FALSE; /* oh well. */
280  }
281 
282  SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount);
283  if (SDL_RawDevList == NULL) {
284  SDL_OutOfMemory();
285  return SDL_FALSE;
286  }
287 
288  if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) {
289  SDL_free(SDL_RawDevList);
290  SDL_RawDevList = NULL;
291  return SDL_FALSE; /* oh well. */
292  }
293  }
294 
295  for (i = 0; i < SDL_RawDevListCount; i++) {
296  RID_DEVICE_INFO rdi;
297  char devName[128];
298  UINT rdiSize = sizeof(rdi);
299  UINT nameSize = SDL_arraysize(devName);
300 
301  rdi.cbSize = sizeof(rdi);
302  if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
303  (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
304  (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
305  (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
306  (SDL_strstr(devName, "IG_") != NULL)) {
307  return SDL_TRUE;
308  }
309  }
310 
311  return SDL_FALSE;
312 }
313 
314 int
316 {
317  HRESULT result;
318  HINSTANCE instance;
319 
320  result = WIN_CoInitialize();
321  if (FAILED(result)) {
322  return SetDIerror("CoInitialize", result);
323  }
324 
325  coinitialized = SDL_TRUE;
326 
327  result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
328  &IID_IDirectInput8, (LPVOID)&dinput);
329 
330  if (FAILED(result)) {
331  return SetDIerror("CoCreateInstance", result);
332  }
333 
334  /* Because we used CoCreateInstance, we need to Initialize it, first. */
335  instance = GetModuleHandle(NULL);
336  if (instance == NULL) {
337  return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
338  }
339  result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
340 
341  if (FAILED(result)) {
342  return SetDIerror("IDirectInput::Initialize", result);
343  }
344  return 0;
345 }
346 
347 /* helper function for direct input, gets called for each connected joystick */
348 static BOOL CALLBACK
349 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
350 {
351  const Uint16 BUS_USB = 0x03;
352  const Uint16 BUS_BLUETOOTH = 0x05;
353  JoyStick_DeviceData *pNewJoystick;
354  JoyStick_DeviceData *pPrevJoystick = NULL;
355  const DWORD devtype = (pdidInstance->dwDevType & 0xFF);
356  Uint16 *guid16;
357  WCHAR hidPath[MAX_PATH];
358 
359  if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
360  /* Add any supplemental devices that should be ignored here */
361 #define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID)
362  static DWORD ignored_devices[] = {
363  MAKE_TABLE_ENTRY(0, 0)
364  };
365 #undef MAKE_TABLE_ENTRY
366  unsigned int i;
367 
368  for (i = 0; i < SDL_arraysize(ignored_devices); ++i) {
369  if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) {
370  return DIENUM_CONTINUE;
371  }
372  }
373  }
374 
375  if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) {
376  return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */
377  }
378 
379  {
380  HRESULT result;
381  LPDIRECTINPUTDEVICE8 device;
382  LPDIRECTINPUTDEVICE8 InputDevice;
383  DIPROPGUIDANDPATH dipdw2;
384 
385  result = IDirectInput8_CreateDevice(dinput, &(pdidInstance->guidInstance), &device, NULL);
386  if (FAILED(result)) {
387  return DIENUM_CONTINUE; /* better luck next time? */
388  }
389 
390  /* Now get the IDirectInputDevice8 interface, instead. */
391  result = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *)&InputDevice);
392  /* We are done with this object. Use the stored one from now on. */
393  IDirectInputDevice8_Release(device);
394  if (FAILED(result)) {
395  return DIENUM_CONTINUE; /* better luck next time? */
396  }
397  dipdw2.diph.dwSize = sizeof(dipdw2);
398  dipdw2.diph.dwHeaderSize = sizeof(dipdw2.diph);
399  dipdw2.diph.dwObj = 0; // device property
400  dipdw2.diph.dwHow = DIPH_DEVICE;
401 
402  result = IDirectInputDevice8_GetProperty(InputDevice, DIPROP_GUIDANDPATH, &dipdw2.diph);
403  IDirectInputDevice8_Release(InputDevice);
404  if (FAILED(result)) {
405  return DIENUM_CONTINUE; /* better luck next time? */
406  }
407 
408  /* Get device path, compare that instead of GUID, additionally update GUIDs of joysticks with matching paths, in case they're not open yet. */
409  SDL_wcslcpy(hidPath, dipdw2.wszPath, SDL_arraysize(hidPath));
410  }
411 
412  pNewJoystick = *(JoyStick_DeviceData **)pContext;
413  while (pNewJoystick) {
414  if (SDL_wcscmp(pNewJoystick->hidPath, hidPath) == 0) {
415  /* if we are replacing the front of the list then update it */
416  if (pNewJoystick == *(JoyStick_DeviceData **)pContext) {
417  *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
418  } else if (pPrevJoystick) {
419  pPrevJoystick->pNext = pNewJoystick->pNext;
420  }
421 
422  // Update with new guid/etc, if it has changed
423  pNewJoystick->dxdevice = *pdidInstance;
424 
425  pNewJoystick->pNext = SYS_Joystick;
426  SYS_Joystick = pNewJoystick;
427 
428  return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
429  }
430 
431  pPrevJoystick = pNewJoystick;
432  pNewJoystick = pNewJoystick->pNext;
433  }
434 
435  pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
436  if (!pNewJoystick) {
437  return DIENUM_CONTINUE; /* better luck next time? */
438  }
439 
440  SDL_zerop(pNewJoystick);
441  SDL_wcslcpy(pNewJoystick->hidPath, hidPath, SDL_arraysize(pNewJoystick->hidPath));
442  pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
443  if (!pNewJoystick->joystickname) {
444  SDL_free(pNewJoystick);
445  return DIENUM_CONTINUE; /* better luck next time? */
446  }
447 
448  SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
449  sizeof(DIDEVICEINSTANCE));
450 
451  SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data));
452 
453  guid16 = (Uint16 *)pNewJoystick->guid.data;
454  if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
455  *guid16++ = SDL_SwapLE16(BUS_USB);
456  *guid16++ = 0;
457  *guid16++ = SDL_SwapLE16((Uint16)LOWORD(pdidInstance->guidProduct.Data1)); /* vendor */
458  *guid16++ = 0;
459  *guid16++ = SDL_SwapLE16((Uint16)HIWORD(pdidInstance->guidProduct.Data1)); /* product */
460  *guid16++ = 0;
461  *guid16++ = 0; /* version */
462  *guid16++ = 0;
463  } else {
464  *guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
465  *guid16++ = 0;
466  SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4);
467  }
468 
469  if (SDL_IsGameControllerNameAndGUID(pNewJoystick->joystickname, pNewJoystick->guid) &&
470  SDL_ShouldIgnoreGameController(pNewJoystick->joystickname, pNewJoystick->guid)) {
471  SDL_free(pNewJoystick);
472  return DIENUM_CONTINUE;
473  }
474 
475  SDL_SYS_AddJoystickDevice(pNewJoystick);
476 
477  return DIENUM_CONTINUE; /* get next device, please */
478 }
479 
480 void
482 {
483  IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY);
484 
485  if (SDL_RawDevList) {
486  SDL_free(SDL_RawDevList); /* in case we used this in DirectInput detection */
487  SDL_RawDevList = NULL;
488  }
489  SDL_RawDevListCount = 0;
490 }
491 
492 static BOOL CALLBACK
493 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
494 {
495  SDL_Joystick *joystick = (SDL_Joystick *)pvRef;
496  HRESULT result;
497  input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
498 
499  if (dev->dwType & DIDFT_BUTTON) {
500  in->type = BUTTON;
501  in->num = joystick->nbuttons;
502  in->ofs = DIJOFS_BUTTON(in->num);
503  joystick->nbuttons++;
504  } else if (dev->dwType & DIDFT_POV) {
505  in->type = HAT;
506  in->num = joystick->nhats;
507  in->ofs = DIJOFS_POV(in->num);
508  joystick->nhats++;
509  } else if (dev->dwType & DIDFT_AXIS) {
510  DIPROPRANGE diprg;
511  DIPROPDWORD dilong;
512 
513  in->type = AXIS;
514  in->num = joystick->naxes;
515  if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType)))
516  in->ofs = DIJOFS_X;
517  else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType)))
518  in->ofs = DIJOFS_Y;
519  else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType)))
520  in->ofs = DIJOFS_Z;
521  else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType)))
522  in->ofs = DIJOFS_RX;
523  else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType)))
524  in->ofs = DIJOFS_RY;
525  else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType)))
526  in->ofs = DIJOFS_RZ;
527  else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) {
528  in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
529  ++joystick->hwdata->NumSliders;
530  } else {
531  return DIENUM_CONTINUE; /* not an axis we can grok */
532  }
533 
534  diprg.diph.dwSize = sizeof(diprg);
535  diprg.diph.dwHeaderSize = sizeof(diprg.diph);
536  diprg.diph.dwObj = dev->dwType;
537  diprg.diph.dwHow = DIPH_BYID;
538  diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
539  diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
540 
541  result =
542  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
543  DIPROP_RANGE, &diprg.diph);
544  if (FAILED(result)) {
545  return DIENUM_CONTINUE; /* don't use this axis */
546  }
547 
548  /* Set dead zone to 0. */
549  dilong.diph.dwSize = sizeof(dilong);
550  dilong.diph.dwHeaderSize = sizeof(dilong.diph);
551  dilong.diph.dwObj = dev->dwType;
552  dilong.diph.dwHow = DIPH_BYID;
553  dilong.dwData = 0;
554  result =
555  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
556  DIPROP_DEADZONE, &dilong.diph);
557  if (FAILED(result)) {
558  return DIENUM_CONTINUE; /* don't use this axis */
559  }
560 
561  joystick->naxes++;
562  } else {
563  /* not supported at this time */
564  return DIENUM_CONTINUE;
565  }
566 
567  joystick->hwdata->NumInputs++;
568 
569  if (joystick->hwdata->NumInputs == MAX_INPUTS) {
570  return DIENUM_STOP; /* too many */
571  }
572 
573  return DIENUM_CONTINUE;
574 }
575 
576 /* Sort using the data offset into the DInput struct.
577  * This gives a reasonable ordering for the inputs.
578  */
579 static int
580 SortDevFunc(const void *a, const void *b)
581 {
582  const input_t *inputA = (const input_t*)a;
583  const input_t *inputB = (const input_t*)b;
584 
585  if (inputA->ofs < inputB->ofs)
586  return -1;
587  if (inputA->ofs > inputB->ofs)
588  return 1;
589  return 0;
590 }
591 
592 /* Sort the input objects and recalculate the indices for each input. */
593 static void
594 SortDevObjects(SDL_Joystick *joystick)
595 {
596  input_t *inputs = joystick->hwdata->Inputs;
597  int nButtons = 0;
598  int nHats = 0;
599  int nAxis = 0;
600  int n;
601 
602  SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
603 
604  for (n = 0; n < joystick->hwdata->NumInputs; n++) {
605  switch (inputs[n].type) {
606  case BUTTON:
607  inputs[n].num = nButtons;
608  nButtons++;
609  break;
610 
611  case HAT:
612  inputs[n].num = nHats;
613  nHats++;
614  break;
615 
616  case AXIS:
617  inputs[n].num = nAxis;
618  nAxis++;
619  break;
620  }
621  }
622 }
623 
624 int
625 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
626 {
627  HRESULT result;
628  LPDIRECTINPUTDEVICE8 device;
629  DIPROPDWORD dipdw;
630 
631  joystick->hwdata->buffered = SDL_TRUE;
632  joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
633 
634  SDL_zero(dipdw);
635  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
636  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
637 
638  result =
639  IDirectInput8_CreateDevice(dinput,
640  &(joystickdevice->dxdevice.guidInstance), &device, NULL);
641  if (FAILED(result)) {
642  return SetDIerror("IDirectInput::CreateDevice", result);
643  }
644 
645  /* Now get the IDirectInputDevice8 interface, instead. */
646  result = IDirectInputDevice8_QueryInterface(device,
647  &IID_IDirectInputDevice8,
648  (LPVOID *)& joystick->
649  hwdata->InputDevice);
650  /* We are done with this object. Use the stored one from now on. */
651  IDirectInputDevice8_Release(device);
652 
653  if (FAILED(result)) {
654  return SetDIerror("IDirectInputDevice8::QueryInterface", result);
655  }
656 
657  /* Acquire shared access. Exclusive access is required for forces,
658  * though. */
659  result =
660  IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
661  InputDevice, SDL_HelperWindow,
662  DISCL_EXCLUSIVE |
663  DISCL_BACKGROUND);
664  if (FAILED(result)) {
665  return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
666  }
667 
668  /* Use the extended data structure: DIJOYSTATE2. */
669  result =
670  IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
671  &SDL_c_dfDIJoystick2);
672  if (FAILED(result)) {
673  return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
674  }
675 
676  /* Get device capabilities */
677  result =
678  IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
679  &joystick->hwdata->Capabilities);
680  if (FAILED(result)) {
681  return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
682  }
683 
684  /* Force capable? */
685  if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
686 
687  result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
688  if (FAILED(result)) {
689  return SetDIerror("IDirectInputDevice8::Acquire", result);
690  }
691 
692  /* reset all actuators. */
693  result =
694  IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
695  InputDevice,
696  DISFFC_RESET);
697 
698  /* Not necessarily supported, ignore if not supported.
699  if (FAILED(result)) {
700  return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
701  }
702  */
703 
704  result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
705 
706  if (FAILED(result)) {
707  return SetDIerror("IDirectInputDevice8::Unacquire", result);
708  }
709 
710  /* Turn on auto-centering for a ForceFeedback device (until told
711  * otherwise). */
712  dipdw.diph.dwObj = 0;
713  dipdw.diph.dwHow = DIPH_DEVICE;
714  dipdw.dwData = DIPROPAUTOCENTER_ON;
715 
716  result =
717  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
718  DIPROP_AUTOCENTER, &dipdw.diph);
719 
720  /* Not necessarily supported, ignore if not supported.
721  if (FAILED(result)) {
722  return SetDIerror("IDirectInputDevice8::SetProperty", result);
723  }
724  */
725  }
726 
727  /* What buttons and axes does it have? */
728  IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
729  EnumDevObjectsCallback, joystick,
730  DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
731 
732  /* Reorder the input objects. Some devices do not report the X axis as
733  * the first axis, for example. */
734  SortDevObjects(joystick);
735 
736  dipdw.diph.dwObj = 0;
737  dipdw.diph.dwHow = DIPH_DEVICE;
738  dipdw.dwData = INPUT_QSIZE;
739 
740  /* Set the buffer size */
741  result =
742  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
743  DIPROP_BUFFERSIZE, &dipdw.diph);
744 
745  if (result == DI_POLLEDDEVICE) {
746  /* This device doesn't support buffering, so we're forced
747  * to use less reliable polling. */
748  joystick->hwdata->buffered = SDL_FALSE;
749  } else if (FAILED(result)) {
750  return SetDIerror("IDirectInputDevice8::SetProperty", result);
751  }
752  return 0;
753 }
754 
755 static Uint8
756 TranslatePOV(DWORD value)
757 {
758  const int HAT_VALS[] = {
759  SDL_HAT_UP,
763  SDL_HAT_DOWN,
764  SDL_HAT_DOWN | SDL_HAT_LEFT,
765  SDL_HAT_LEFT,
766  SDL_HAT_UP | SDL_HAT_LEFT
767  };
768 
769  if (LOWORD(value) == 0xFFFF)
770  return SDL_HAT_CENTERED;
771 
772  /* Round the value up: */
773  value += 4500 / 2;
774  value %= 36000;
775  value /= 4500;
776 
777  if (value >= 8)
778  return SDL_HAT_CENTERED; /* shouldn't happen */
779 
780  return HAT_VALS[value];
781 }
782 
783 static void
784 UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
785 {
786  int i;
787  HRESULT result;
788  DWORD numevents;
789  DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
790 
791  numevents = INPUT_QSIZE;
792  result =
793  IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
794  sizeof(DIDEVICEOBJECTDATA), evtbuf,
795  &numevents, 0);
796  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
797  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
798  result =
799  IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
800  sizeof(DIDEVICEOBJECTDATA),
801  evtbuf, &numevents, 0);
802  }
803 
804  /* Handle the events or punt */
805  if (FAILED(result)) {
806  joystick->hwdata->send_remove_event = SDL_TRUE;
807  joystick->hwdata->removed = SDL_TRUE;
808  return;
809  }
810 
811  for (i = 0; i < (int)numevents; ++i) {
812  int j;
813 
814  for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
815  const input_t *in = &joystick->hwdata->Inputs[j];
816 
817  if (evtbuf[i].dwOfs != in->ofs)
818  continue;
819 
820  switch (in->type) {
821  case AXIS:
822  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
823  break;
824  case BUTTON:
825  SDL_PrivateJoystickButton(joystick, in->num,
826  (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
827  break;
828  case HAT:
829  {
830  Uint8 pos = TranslatePOV(evtbuf[i].dwData);
831  SDL_PrivateJoystickHat(joystick, in->num, pos);
832  }
833  break;
834  }
835  }
836  }
837 }
838 
839 /* Function to update the state of a joystick - called as a device poll.
840  * This function shouldn't update the joystick structure directly,
841  * but instead should call SDL_PrivateJoystick*() to deliver events
842  * and update joystick device state.
843  */
844 static void
845 UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
846 {
847  DIJOYSTATE2 state;
848  HRESULT result;
849  int i;
850 
851  result =
852  IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
853  sizeof(DIJOYSTATE2), &state);
854  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
855  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
856  result =
857  IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
858  sizeof(DIJOYSTATE2), &state);
859  }
860 
861  if (result != DI_OK) {
862  joystick->hwdata->send_remove_event = SDL_TRUE;
863  joystick->hwdata->removed = SDL_TRUE;
864  return;
865  }
866 
867  /* Set each known axis, button and POV. */
868  for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
869  const input_t *in = &joystick->hwdata->Inputs[i];
870 
871  switch (in->type) {
872  case AXIS:
873  switch (in->ofs) {
874  case DIJOFS_X:
875  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX);
876  break;
877  case DIJOFS_Y:
878  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY);
879  break;
880  case DIJOFS_Z:
881  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ);
882  break;
883  case DIJOFS_RX:
884  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx);
885  break;
886  case DIJOFS_RY:
887  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy);
888  break;
889  case DIJOFS_RZ:
890  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz);
891  break;
892  case DIJOFS_SLIDER(0):
893  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]);
894  break;
895  case DIJOFS_SLIDER(1):
896  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]);
897  break;
898  }
899  break;
900 
901  case BUTTON:
902  SDL_PrivateJoystickButton(joystick, in->num,
903  (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED));
904  break;
905  case HAT:
906  {
907  Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
908  SDL_PrivateJoystickHat(joystick, in->num, pos);
909  break;
910  }
911  }
912  }
913 }
914 
915 void
916 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
917 {
918  HRESULT result;
919 
920  result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
921  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
922  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
923  IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
924  }
925 
926  if (joystick->hwdata->buffered) {
927  UpdateDINPUTJoystickState_Buffered(joystick);
928  } else {
929  UpdateDINPUTJoystickState_Polled(joystick);
930  }
931 }
932 
933 void
934 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
935 {
936  IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
937  IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
938 }
939 
940 void
942 {
943  if (dinput != NULL) {
944  IDirectInput8_Release(dinput);
945  dinput = NULL;
946  }
947 
948  if (coinitialized) {
950  coinitialized = SDL_FALSE;
951  }
952 }
953 
954 #else /* !SDL_JOYSTICK_DINPUT */
955 
957 
958 int
960 {
961  return 0;
962 }
963 
964 void
966 {
967 }
968 
969 int
970 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
971 {
972  return SDL_Unsupported();
973 }
974 
975 void
976 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
977 {
978 }
979 
980 void
981 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
982 {
983 }
984 
985 void
987 {
988 }
989 
990 #endif /* SDL_JOYSTICK_DINPUT */
991 
992 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_strlcpy
JoyStick_DeviceData * SYS_Joystick
GLuint num
#define SDL_qsort
GLuint64EXT * result
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
Definition: SDL_joystick.c:712
#define DIRECTINPUT_VERSION
Definition: SDL_directx.h:95
struct JoyStick_DeviceData * pNext
void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device)
int SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice)
struct xkb_state * state
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:788
Uint8 data[16]
Definition: SDL_joystick.h:71
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:655
static SDL_AudioDeviceID device
Definition: loopwave.c:37
#define SDL_JOYSTICK_AXIS_MIN
Definition: SDL_joystick.h:289
#define FAILED(x)
Definition: SDL_directx.h:54
struct joystick_hwdata * hwdata
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:318
#define SDL_memcpy
int SDL_DINPUT_JoystickInit(void)
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:288
#define SDL_wcscmp
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:320
HRESULT WIN_CoInitialize(void)
uint8_t Uint8
Definition: SDL_stdinc.h:157
#define SDL_free
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
#define SDL_memcmp
SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
GLsizei const GLfloat * value
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
SDL_bool SDL_XINPUT_Enabled(void)
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define SDL_wcslcpy
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
void WIN_CoUninitialize(void)
#define SDL_SetError
void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick)
void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
GLdouble n
uint16_t Uint16
Definition: SDL_stdinc.h:169
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick)
#define SDL_PRESSED
Definition: SDL_events.h:50
DIDEVICEINSTANCE dxdevice
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:316
GLboolean GLboolean GLboolean GLboolean a
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:232
#define SDL_RELEASED
Definition: SDL_events.h:49
GLuint in
#define SDL_HAT_UP
Definition: SDL_joystick.h:317
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:319
GLboolean GLboolean GLboolean b
#define FIELD_OFFSET(type, field)
Definition: SDL_directx.h:87
#define SDL_Unsupported()
Definition: SDL_error.h:53
#define SDL_memset
int16_t Sint16
Definition: SDL_stdinc.h:163
#define SDL_strstr
#define MAX_INPUTS
void SDL_DINPUT_JoystickQuit(void)