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 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 
244  static const GUID *s_XInputProductGUID[] = {
245  &IID_ValveStreamingGamepad,
246  &IID_X360WiredGamepad, /* Microsoft's wired X360 controller for Windows. */
247  &IID_X360WirelessGamepad /* Microsoft's wireless X360 controller for Windows. */
248  };
249 
250  size_t iDevice;
251  UINT i;
252 
253  if (!SDL_XINPUT_Enabled()) {
254  return SDL_FALSE;
255  }
256 
257  /* Check for well known XInput device GUIDs */
258  /* 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. */
259  for (iDevice = 0; iDevice < SDL_arraysize(s_XInputProductGUID); ++iDevice) {
260  if (SDL_memcmp(pGuidProductFromDirectInput, s_XInputProductGUID[iDevice], sizeof(GUID)) == 0) {
261  return SDL_TRUE;
262  }
263  }
264 
265  /* Go through RAWINPUT (WinXP and later) to find HID devices. */
266  /* Cache this if we end up using it. */
267  if (SDL_RawDevList == NULL) {
268  if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
269  return SDL_FALSE; /* oh well. */
270  }
271 
272  SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount);
273  if (SDL_RawDevList == NULL) {
274  SDL_OutOfMemory();
275  return SDL_FALSE;
276  }
277 
278  if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) {
279  SDL_free(SDL_RawDevList);
280  SDL_RawDevList = NULL;
281  return SDL_FALSE; /* oh well. */
282  }
283  }
284 
285  for (i = 0; i < SDL_RawDevListCount; i++) {
286  RID_DEVICE_INFO rdi;
287  char devName[128];
288  UINT rdiSize = sizeof(rdi);
289  UINT nameSize = SDL_arraysize(devName);
290 
291  rdi.cbSize = sizeof(rdi);
292  if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
293  (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
294  (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
295  (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
296  (SDL_strstr(devName, "IG_") != NULL)) {
297  return SDL_TRUE;
298  }
299  }
300 
301  return SDL_FALSE;
302 }
303 
304 int
306 {
307  HRESULT result;
308  HINSTANCE instance;
309 
310  result = WIN_CoInitialize();
311  if (FAILED(result)) {
312  return SetDIerror("CoInitialize", result);
313  }
314 
315  coinitialized = SDL_TRUE;
316 
317  result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
318  &IID_IDirectInput8, (LPVOID)&dinput);
319 
320  if (FAILED(result)) {
321  return SetDIerror("CoCreateInstance", result);
322  }
323 
324  /* Because we used CoCreateInstance, we need to Initialize it, first. */
325  instance = GetModuleHandle(NULL);
326  if (instance == NULL) {
327  return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
328  }
329  result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
330 
331  if (FAILED(result)) {
332  return SetDIerror("IDirectInput::Initialize", result);
333  }
334  return 0;
335 }
336 
337 /* helper function for direct input, gets called for each connected joystick */
338 static BOOL CALLBACK
339 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
340 {
341  JoyStick_DeviceData *pNewJoystick;
342  JoyStick_DeviceData *pPrevJoystick = NULL;
343  const DWORD devtype = (pdidInstance->dwDevType & 0xFF);
344 
345  if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
346  return DIENUM_CONTINUE; /* Ignore touchpads, etc. */
347  }
348 
349  if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) {
350  return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */
351  }
352 
353  pNewJoystick = *(JoyStick_DeviceData **)pContext;
354  while (pNewJoystick) {
355  if (!SDL_memcmp(&pNewJoystick->dxdevice.guidInstance, &pdidInstance->guidInstance, sizeof(pNewJoystick->dxdevice.guidInstance))) {
356  /* if we are replacing the front of the list then update it */
357  if (pNewJoystick == *(JoyStick_DeviceData **)pContext) {
358  *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
359  } else if (pPrevJoystick) {
360  pPrevJoystick->pNext = pNewJoystick->pNext;
361  }
362 
363  pNewJoystick->pNext = SYS_Joystick;
364  SYS_Joystick = pNewJoystick;
365 
366  return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
367  }
368 
369  pPrevJoystick = pNewJoystick;
370  pNewJoystick = pNewJoystick->pNext;
371  }
372 
373  pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
374  if (!pNewJoystick) {
375  return DIENUM_CONTINUE; /* better luck next time? */
376  }
377 
378  SDL_zerop(pNewJoystick);
379  pNewJoystick->joystickname = WIN_StringToUTF8(pdidInstance->tszProductName);
380  if (!pNewJoystick->joystickname) {
381  SDL_free(pNewJoystick);
382  return DIENUM_CONTINUE; /* better luck next time? */
383  }
384 
385  SDL_memcpy(&(pNewJoystick->dxdevice), pdidInstance,
386  sizeof(DIDEVICEINSTANCE));
387 
388  SDL_memcpy(&pNewJoystick->guid, &pdidInstance->guidProduct, sizeof(pNewJoystick->guid));
389  SDL_SYS_AddJoystickDevice(pNewJoystick);
390 
391  return DIENUM_CONTINUE; /* get next device, please */
392 }
393 
394 void
396 {
397  IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY);
398 
399  if (SDL_RawDevList) {
400  SDL_free(SDL_RawDevList); /* in case we used this in DirectInput detection */
401  SDL_RawDevList = NULL;
402  }
403  SDL_RawDevListCount = 0;
404 }
405 
406 static BOOL CALLBACK
407 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
408 {
409  SDL_Joystick *joystick = (SDL_Joystick *)pvRef;
410  HRESULT result;
411  input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
412 
413  if (dev->dwType & DIDFT_BUTTON) {
414  in->type = BUTTON;
415  in->num = joystick->nbuttons;
416  in->ofs = DIJOFS_BUTTON(in->num);
417  joystick->nbuttons++;
418  } else if (dev->dwType & DIDFT_POV) {
419  in->type = HAT;
420  in->num = joystick->nhats;
421  in->ofs = DIJOFS_POV(in->num);
422  joystick->nhats++;
423  } else if (dev->dwType & DIDFT_AXIS) {
424  DIPROPRANGE diprg;
425  DIPROPDWORD dilong;
426 
427  in->type = AXIS;
428  in->num = joystick->naxes;
429  if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType)))
430  in->ofs = DIJOFS_X;
431  else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType)))
432  in->ofs = DIJOFS_Y;
433  else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType)))
434  in->ofs = DIJOFS_Z;
435  else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType)))
436  in->ofs = DIJOFS_RX;
437  else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType)))
438  in->ofs = DIJOFS_RY;
439  else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType)))
440  in->ofs = DIJOFS_RZ;
441  else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) {
442  in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
443  ++joystick->hwdata->NumSliders;
444  } else {
445  return DIENUM_CONTINUE; /* not an axis we can grok */
446  }
447 
448  diprg.diph.dwSize = sizeof(diprg);
449  diprg.diph.dwHeaderSize = sizeof(diprg.diph);
450  diprg.diph.dwObj = dev->dwType;
451  diprg.diph.dwHow = DIPH_BYID;
452  diprg.lMin = AXIS_MIN;
453  diprg.lMax = AXIS_MAX;
454 
455  result =
456  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
457  DIPROP_RANGE, &diprg.diph);
458  if (FAILED(result)) {
459  return DIENUM_CONTINUE; /* don't use this axis */
460  }
461 
462  /* Set dead zone to 0. */
463  dilong.diph.dwSize = sizeof(dilong);
464  dilong.diph.dwHeaderSize = sizeof(dilong.diph);
465  dilong.diph.dwObj = dev->dwType;
466  dilong.diph.dwHow = DIPH_BYID;
467  dilong.dwData = 0;
468  result =
469  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
470  DIPROP_DEADZONE, &dilong.diph);
471  if (FAILED(result)) {
472  return DIENUM_CONTINUE; /* don't use this axis */
473  }
474 
475  joystick->naxes++;
476  } else {
477  /* not supported at this time */
478  return DIENUM_CONTINUE;
479  }
480 
481  joystick->hwdata->NumInputs++;
482 
483  if (joystick->hwdata->NumInputs == MAX_INPUTS) {
484  return DIENUM_STOP; /* too many */
485  }
486 
487  return DIENUM_CONTINUE;
488 }
489 
490 /* Sort using the data offset into the DInput struct.
491  * This gives a reasonable ordering for the inputs.
492  */
493 static int
494 SortDevFunc(const void *a, const void *b)
495 {
496  const input_t *inputA = (const input_t*)a;
497  const input_t *inputB = (const input_t*)b;
498 
499  if (inputA->ofs < inputB->ofs)
500  return -1;
501  if (inputA->ofs > inputB->ofs)
502  return 1;
503  return 0;
504 }
505 
506 /* Sort the input objects and recalculate the indices for each input. */
507 static void
508 SortDevObjects(SDL_Joystick *joystick)
509 {
510  input_t *inputs = joystick->hwdata->Inputs;
511  int nButtons = 0;
512  int nHats = 0;
513  int nAxis = 0;
514  int n;
515 
516  SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
517 
518  for (n = 0; n < joystick->hwdata->NumInputs; n++) {
519  switch (inputs[n].type) {
520  case BUTTON:
521  inputs[n].num = nButtons;
522  nButtons++;
523  break;
524 
525  case HAT:
526  inputs[n].num = nHats;
527  nHats++;
528  break;
529 
530  case AXIS:
531  inputs[n].num = nAxis;
532  nAxis++;
533  break;
534  }
535  }
536 }
537 
538 int
539 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
540 {
541  HRESULT result;
542  LPDIRECTINPUTDEVICE8 device;
543  DIPROPDWORD dipdw;
544 
545  joystick->hwdata->buffered = SDL_TRUE;
546  joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
547 
548  SDL_zero(dipdw);
549  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
550  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
551 
552  result =
553  IDirectInput8_CreateDevice(dinput,
554  &(joystickdevice->dxdevice.guidInstance), &device, NULL);
555  if (FAILED(result)) {
556  return SetDIerror("IDirectInput::CreateDevice", result);
557  }
558 
559  /* Now get the IDirectInputDevice8 interface, instead. */
560  result = IDirectInputDevice8_QueryInterface(device,
561  &IID_IDirectInputDevice8,
562  (LPVOID *)& joystick->
563  hwdata->InputDevice);
564  /* We are done with this object. Use the stored one from now on. */
565  IDirectInputDevice8_Release(device);
566 
567  if (FAILED(result)) {
568  return SetDIerror("IDirectInputDevice8::QueryInterface", result);
569  }
570 
571  /* Acquire shared access. Exclusive access is required for forces,
572  * though. */
573  result =
574  IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
575  InputDevice, SDL_HelperWindow,
576  DISCL_EXCLUSIVE |
577  DISCL_BACKGROUND);
578  if (FAILED(result)) {
579  return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
580  }
581 
582  /* Use the extended data structure: DIJOYSTATE2. */
583  result =
584  IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
585  &c_dfDIJoystick2);
586  if (FAILED(result)) {
587  return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
588  }
589 
590  /* Get device capabilities */
591  result =
592  IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
593  &joystick->hwdata->Capabilities);
594  if (FAILED(result)) {
595  return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
596  }
597 
598  /* Force capable? */
599  if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
600 
601  result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
602  if (FAILED(result)) {
603  return SetDIerror("IDirectInputDevice8::Acquire", result);
604  }
605 
606  /* reset all actuators. */
607  result =
608  IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
609  InputDevice,
610  DISFFC_RESET);
611 
612  /* Not necessarily supported, ignore if not supported.
613  if (FAILED(result)) {
614  return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
615  }
616  */
617 
618  result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
619 
620  if (FAILED(result)) {
621  return SetDIerror("IDirectInputDevice8::Unacquire", result);
622  }
623 
624  /* Turn on auto-centering for a ForceFeedback device (until told
625  * otherwise). */
626  dipdw.diph.dwObj = 0;
627  dipdw.diph.dwHow = DIPH_DEVICE;
628  dipdw.dwData = DIPROPAUTOCENTER_ON;
629 
630  result =
631  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
632  DIPROP_AUTOCENTER, &dipdw.diph);
633 
634  /* Not necessarily supported, ignore if not supported.
635  if (FAILED(result)) {
636  return SetDIerror("IDirectInputDevice8::SetProperty", result);
637  }
638  */
639  }
640 
641  /* What buttons and axes does it have? */
642  IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
643  EnumDevObjectsCallback, joystick,
644  DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
645 
646  /* Reorder the input objects. Some devices do not report the X axis as
647  * the first axis, for example. */
648  SortDevObjects(joystick);
649 
650  dipdw.diph.dwObj = 0;
651  dipdw.diph.dwHow = DIPH_DEVICE;
652  dipdw.dwData = INPUT_QSIZE;
653 
654  /* Set the buffer size */
655  result =
656  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
657  DIPROP_BUFFERSIZE, &dipdw.diph);
658 
659  if (result == DI_POLLEDDEVICE) {
660  /* This device doesn't support buffering, so we're forced
661  * to use less reliable polling. */
662  joystick->hwdata->buffered = SDL_FALSE;
663  } else if (FAILED(result)) {
664  return SetDIerror("IDirectInputDevice8::SetProperty", result);
665  }
666  return 0;
667 }
668 
669 static Uint8
670 TranslatePOV(DWORD value)
671 {
672  const int HAT_VALS[] = {
673  SDL_HAT_UP,
677  SDL_HAT_DOWN,
678  SDL_HAT_DOWN | SDL_HAT_LEFT,
679  SDL_HAT_LEFT,
680  SDL_HAT_UP | SDL_HAT_LEFT
681  };
682 
683  if (LOWORD(value) == 0xFFFF)
684  return SDL_HAT_CENTERED;
685 
686  /* Round the value up: */
687  value += 4500 / 2;
688  value %= 36000;
689  value /= 4500;
690 
691  if (value >= 8)
692  return SDL_HAT_CENTERED; /* shouldn't happen */
693 
694  return HAT_VALS[value];
695 }
696 
697 static void
698 UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
699 {
700  int i;
701  HRESULT result;
702  DWORD numevents;
703  DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
704 
705  numevents = INPUT_QSIZE;
706  result =
707  IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
708  sizeof(DIDEVICEOBJECTDATA), evtbuf,
709  &numevents, 0);
710  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
711  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
712  result =
713  IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
714  sizeof(DIDEVICEOBJECTDATA),
715  evtbuf, &numevents, 0);
716  }
717 
718  /* Handle the events or punt */
719  if (FAILED(result)) {
720  joystick->hwdata->send_remove_event = SDL_TRUE;
721  joystick->hwdata->removed = SDL_TRUE;
722  return;
723  }
724 
725  for (i = 0; i < (int)numevents; ++i) {
726  int j;
727 
728  for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
729  const input_t *in = &joystick->hwdata->Inputs[j];
730 
731  if (evtbuf[i].dwOfs != in->ofs)
732  continue;
733 
734  switch (in->type) {
735  case AXIS:
736  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
737  break;
738  case BUTTON:
739  SDL_PrivateJoystickButton(joystick, in->num,
740  (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
741  break;
742  case HAT:
743  {
744  Uint8 pos = TranslatePOV(evtbuf[i].dwData);
745  SDL_PrivateJoystickHat(joystick, in->num, pos);
746  }
747  break;
748  }
749  }
750  }
751 }
752 
753 /* Function to update the state of a joystick - called as a device poll.
754  * This function shouldn't update the joystick structure directly,
755  * but instead should call SDL_PrivateJoystick*() to deliver events
756  * and update joystick device state.
757  */
758 static void
759 UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
760 {
761  DIJOYSTATE2 state;
762  HRESULT result;
763  int i;
764 
765  result =
766  IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
767  sizeof(DIJOYSTATE2), &state);
768  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
769  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
770  result =
771  IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
772  sizeof(DIJOYSTATE2), &state);
773  }
774 
775  if (result != DI_OK) {
776  joystick->hwdata->send_remove_event = SDL_TRUE;
777  joystick->hwdata->removed = SDL_TRUE;
778  return;
779  }
780 
781  /* Set each known axis, button and POV. */
782  for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
783  const input_t *in = &joystick->hwdata->Inputs[i];
784 
785  switch (in->type) {
786  case AXIS:
787  switch (in->ofs) {
788  case DIJOFS_X:
789  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lX);
790  break;
791  case DIJOFS_Y:
792  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lY);
793  break;
794  case DIJOFS_Z:
795  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lZ);
796  break;
797  case DIJOFS_RX:
798  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRx);
799  break;
800  case DIJOFS_RY:
801  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRy);
802  break;
803  case DIJOFS_RZ:
804  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.lRz);
805  break;
806  case DIJOFS_SLIDER(0):
807  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]);
808  break;
809  case DIJOFS_SLIDER(1):
810  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]);
811  break;
812  }
813  break;
814 
815  case BUTTON:
816  SDL_PrivateJoystickButton(joystick, in->num,
817  (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED));
818  break;
819  case HAT:
820  {
821  Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
822  SDL_PrivateJoystickHat(joystick, in->num, pos);
823  break;
824  }
825  }
826  }
827 }
828 
829 void
830 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
831 {
832  HRESULT result;
833 
834  result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
835  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
836  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
837  IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
838  }
839 
840  if (joystick->hwdata->buffered) {
841  UpdateDINPUTJoystickState_Buffered(joystick);
842  } else {
843  UpdateDINPUTJoystickState_Polled(joystick);
844  }
845 }
846 
847 void
848 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
849 {
850  IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
851  IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
852 }
853 
854 void
856 {
857  if (dinput != NULL) {
858  IDirectInput8_Release(dinput);
859  dinput = NULL;
860  }
861 
862  if (coinitialized) {
864  coinitialized = SDL_FALSE;
865  }
866 }
867 
868 #else /* !SDL_JOYSTICK_DINPUT */
869 
871 
872 int
874 {
875  return 0;
876 }
877 
878 void
880 {
881 }
882 
883 int
884 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
885 {
886  return SDL_Unsupported();
887 }
888 
889 void
890 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
891 {
892 }
893 
894 void
895 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
896 {
897 }
898 
899 void
901 {
902 }
903 
904 #endif /* SDL_JOYSTICK_DINPUT */
905 
906 /* 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:542
#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:618
#define SDL_zerop(x)
Definition: SDL_stdinc.h:356
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:501
SDL_bool
Definition: SDL_stdinc.h:126
#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:139
void SDL_free(void *mem)
#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:355
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:42
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
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: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: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:143
#define SDL_strstr
#define MAX_INPUTS
void SDL_DINPUT_JoystickQuit(void)
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:42