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