SDL  2.0
SDL_dinputjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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_rawinputjoystick_c.h"
30 #include "SDL_xinputjoystick_c.h"
31 #include "../hidapi/SDL_hidapijoystick_c.h"
32 
33 #ifndef DIDFT_OPTIONAL
34 #define DIDFT_OPTIONAL 0x80000000
35 #endif
36 
37 #define INPUT_QSIZE 32 /* Buffer up to 32 input messages */
38 #define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100) /* 1% motion */
39 
40 #define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF)
41 
42 /* external variables referenced. */
43 extern HWND SDL_HelperWindow;
44 
45 /* local variables */
46 static SDL_bool coinitialized = SDL_FALSE;
47 static LPDIRECTINPUT8 dinput = NULL;
48 static PRAWINPUTDEVICELIST SDL_RawDevList = NULL;
49 static UINT SDL_RawDevListCount = 0;
50 
51 /* Taken from Wine - Thanks! */
52 static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
53  { &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
54  { &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
55  { &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
56  { &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
57  { &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
58  { &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
59  { &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
60  { &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
61  { &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
62  { &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
63  { &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
64  { &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
65  { NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
66  { NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
67  { NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
68  { NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
69  { NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
70  { NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
71  { NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
72  { NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
73  { NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
74  { NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
75  { NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
76  { NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
77  { NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
78  { NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
79  { NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
80  { NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
81  { NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
82  { NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
83  { NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
84  { NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
85  { NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
86  { NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
87  { NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
88  { NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
89  { NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
90  { NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
91  { NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
92  { NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
93  { NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
94  { NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
95  { NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
96  { NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
97  { NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
98  { NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
99  { NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
100  { NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
101  { NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
102  { NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
103  { NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
104  { NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
105  { NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
106  { NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
107  { NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
108  { NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
109  { NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
110  { NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
111  { NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
112  { NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
113  { NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
114  { NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
115  { NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
116  { NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
117  { NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
118  { NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
119  { NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
120  { NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
121  { NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
122  { NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
123  { NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
124  { NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
125  { NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
126  { NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
127  { NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
128  { NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
129  { NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
130  { NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
131  { NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
132  { NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
133  { NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
134  { NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
135  { NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
136  { NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
137  { NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
138  { NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
139  { NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
140  { NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
141  { NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
142  { NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
143  { NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
144  { NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
145  { NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
146  { NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
147  { NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
148  { NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
149  { NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
150  { NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
151  { NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
152  { NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
153  { NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
154  { NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
155  { NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
156  { NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
157  { NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
158  { NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
159  { NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
160  { NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
161  { NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
162  { NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
163  { NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
164  { NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
165  { NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
166  { NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
167  { NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
168  { NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
169  { NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
170  { NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
171  { NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
172  { NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
173  { NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
174  { NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
175  { NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
176  { NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
177  { NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
178  { NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
179  { NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
180  { NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
181  { NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
182  { NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
183  { NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
184  { NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
185  { NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
186  { NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
187  { NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
188  { NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
189  { NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
190  { NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
191  { NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
192  { NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
193  { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
194  { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
195  { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
196  { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
197  { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
198  { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
199  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
200  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
201  { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
202  { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
203  { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
204  { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
205  { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
206  { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
207  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
208  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
209  { &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
210  { &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
211  { &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
212  { &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
213  { &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
214  { &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
215  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
216  { &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
217 };
218 
219 const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
220  sizeof(DIDATAFORMAT),
221  sizeof(DIOBJECTDATAFORMAT),
222  DIDF_ABSAXIS,
223  sizeof(DIJOYSTATE2),
224  SDL_arraysize(dfDIJoystick2),
225  dfDIJoystick2
226 };
227 
228 /* Convert a DirectInput return code to a text message */
229 static int
230 SetDIerror(const char *function, HRESULT code)
231 {
232  return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
233 }
234 
235 #if 0 /* Microsoft recommended implementation, but slower than checking raw devices */
236 #define COBJMACROS
237 #include <wbemidl.h>
238 #include <oleauto.h>
239 
240 static const IID CLSID_WbemLocator = { 0x4590f811, 0x1d3a, 0x11d0,{ 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
241 static const IID IID_IWbemLocator = { 0xdc12a687, 0x737f, 0x11cf,{ 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24 } };
242 
243 static SDL_bool
244 WIN_IsXInputDevice(const WCHAR *name, const GUID* pGuidProductFromDirectInput)
245 {
246  IWbemLocator* pIWbemLocator = NULL;
247  IEnumWbemClassObject* pEnumDevices = NULL;
248  IWbemClassObject* pDevices[20];
249  IWbemServices* pIWbemServices = NULL;
250  BSTR bstrNamespace = NULL;
251  BSTR bstrDeviceID = NULL;
252  BSTR bstrClassName = NULL;
253  DWORD uReturned = 0;
254  SDL_bool bIsXinputDevice = SDL_FALSE;
255  UINT iDevice = 0;
256  VARIANT var;
257  HRESULT hr;
258 
259  if (!SDL_XINPUT_Enabled()) {
260  return SDL_FALSE;
261  }
262 
263  if (SDL_wcsstr(name, L" XINPUT ") != NULL) {
264  /* This is a duplicate interface for a controller that will show up with XInput,
265  e.g. Xbox One Elite Series 2 in Bluetooth mode.
266  */
267  return SDL_TRUE;
268  }
269 
270  SDL_zeroa(pDevices);
271 
272  // Create WMI
273  hr = CoCreateInstance(&CLSID_WbemLocator,
274  NULL,
275  CLSCTX_INPROC_SERVER,
276  &IID_IWbemLocator,
277  (LPVOID*)&pIWbemLocator);
278  if (FAILED(hr) || pIWbemLocator == NULL)
279  goto LCleanup;
280 
281  bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == NULL) goto LCleanup;
282  bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == NULL) goto LCleanup;
283  bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == NULL) goto LCleanup;
284 
285  // Connect to WMI
286  hr = IWbemLocator_ConnectServer(pIWbemLocator, bstrNamespace, NULL, NULL, 0L,
287  0L, NULL, NULL, &pIWbemServices);
288  if (FAILED(hr) || pIWbemServices == NULL) {
289  goto LCleanup;
290  }
291 
292  // Switch security level to IMPERSONATE.
293  CoSetProxyBlanket((IUnknown *)pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
294  RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
295 
296  hr = IWbemServices_CreateInstanceEnum(pIWbemServices, bstrClassName, 0, NULL, &pEnumDevices);
297  if (FAILED(hr) || pEnumDevices == NULL)
298  goto LCleanup;
299 
300  // Loop over all devices
301  for (;;) {
302  // Get 20 at a time
303  hr = IEnumWbemClassObject_Next(pEnumDevices, 10000, SDL_arraysize(pDevices), pDevices, &uReturned);
304  if (FAILED(hr)) {
305  goto LCleanup;
306  }
307  if (uReturned == 0) {
308  break;
309  }
310 
311  for (iDevice = 0; iDevice < uReturned; iDevice++) {
312  // For each device, get its device ID
313  hr = IWbemClassObject_Get(pDevices[iDevice], bstrDeviceID, 0L, &var, NULL, NULL);
314  if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL) {
315  // Check if the device ID contains "IG_". If it does, then it's an XInput device
316  // This information can not be found from DirectInput
317  if (SDL_wcsstr(var.bstrVal, L"IG_")) {
318  char *bstrVal = WIN_StringToUTF8(var.bstrVal);
319 
320  // If it does, then get the VID/PID from var.bstrVal
321  DWORD dwPid = 0, dwVid = 0, dwVidPid;
322  const char *strVid, *strPid;
323  strVid = SDL_strstr(bstrVal, "VID_");
324  if (strVid && SDL_sscanf(strVid, "VID_%4X", &dwVid) != 1)
325  dwVid = 0;
326  strPid = SDL_strstr(bstrVal, "PID_");
327  if (strPid && SDL_sscanf(strPid, "PID_%4X", &dwPid) != 1)
328  dwPid = 0;
329 
330  SDL_free(bstrVal);
331 
332  // Compare the VID/PID to the DInput device
333  dwVidPid = MAKELONG(dwVid, dwPid);
334  if (dwVidPid == pGuidProductFromDirectInput->Data1) {
335  bIsXinputDevice = SDL_TRUE;
336  goto LCleanup;
337  }
338  }
339  }
340  IWbemClassObject_Release(pDevices[iDevice]);
341  }
342  }
343 
344 LCleanup:
345  if (bstrNamespace) {
346  SysFreeString(bstrNamespace);
347  }
348  if (bstrDeviceID) {
349  SysFreeString(bstrDeviceID);
350  }
351  if (bstrClassName) {
352  SysFreeString(bstrClassName);
353  }
354  for (iDevice = 0; iDevice < SDL_arraysize(pDevices); iDevice++) {
355  if (pDevices[iDevice]) {
356  IWbemClassObject_Release(pDevices[iDevice]);
357  }
358  }
359  if (pEnumDevices) {
360  IEnumWbemClassObject_Release(pEnumDevices);
361  }
362  if (pIWbemLocator) {
363  IWbemLocator_Release(pIWbemLocator);
364  }
365  if (pIWbemServices) {
366  IWbemServices_Release(pIWbemServices);
367  }
368 
369  return bIsXinputDevice;
370 }
371 #endif /* 0 */
372 
373 static SDL_bool
374 SDL_IsXInputDevice(const WCHAR *name, const GUID* pGuidProductFromDirectInput)
375 {
376  UINT i;
377 
378  if (!SDL_XINPUT_Enabled()) {
379  return SDL_FALSE;
380  }
381 
382  if (SDL_wcsstr(name, L" XINPUT ") != NULL) {
383  /* This is a duplicate interface for a controller that will show up with XInput,
384  e.g. Xbox One Elite Series 2 in Bluetooth mode.
385  */
386  return SDL_TRUE;
387  }
388 
389  if (SDL_memcmp(&pGuidProductFromDirectInput->Data4[2], "PIDVID", 6) == 0) {
390  Uint16 vendor_id = (Uint16)LOWORD(pGuidProductFromDirectInput->Data1);
391  Uint16 product_id = (Uint16)HIWORD(pGuidProductFromDirectInput->Data1);
392  SDL_GameControllerType type = SDL_GetJoystickGameControllerType("", vendor_id, product_id, -1, 0, 0, 0);
395  (vendor_id == 0x28DE && product_id == 0x11FF)) {
396  return SDL_TRUE;
397  }
398  }
399 
400  /* Go through RAWINPUT (WinXP and later) to find HID devices. */
401  /* Cache this if we end up using it. */
402  if (SDL_RawDevList == NULL) {
403  if ((GetRawInputDeviceList(NULL, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) || (!SDL_RawDevListCount)) {
404  return SDL_FALSE; /* oh well. */
405  }
406 
407  SDL_RawDevList = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * SDL_RawDevListCount);
408  if (SDL_RawDevList == NULL) {
409  SDL_OutOfMemory();
410  return SDL_FALSE;
411  }
412 
413  if (GetRawInputDeviceList(SDL_RawDevList, &SDL_RawDevListCount, sizeof(RAWINPUTDEVICELIST)) == -1) {
414  SDL_free(SDL_RawDevList);
415  SDL_RawDevList = NULL;
416  return SDL_FALSE; /* oh well. */
417  }
418  }
419 
420  for (i = 0; i < SDL_RawDevListCount; i++) {
421  RID_DEVICE_INFO rdi;
422  char devName[MAX_PATH];
423  UINT rdiSize = sizeof(rdi);
424  UINT nameSize = SDL_arraysize(devName);
425 
426  rdi.cbSize = sizeof(rdi);
427  if ((SDL_RawDevList[i].dwType == RIM_TYPEHID) &&
428  (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
429  (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == ((LONG)pGuidProductFromDirectInput->Data1)) &&
430  (GetRawInputDeviceInfoA(SDL_RawDevList[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
431  (SDL_strstr(devName, "IG_") != NULL)) {
432  return SDL_TRUE;
433  }
434  }
435 
436  return SDL_FALSE;
437 }
438 
439 void FreeRumbleEffectData(DIEFFECT *effect)
440 {
441  if (!effect) {
442  return;
443  }
444  SDL_free(effect->rgdwAxes);
445  SDL_free(effect->rglDirection);
446  SDL_free(effect->lpvTypeSpecificParams);
447  SDL_free(effect);
448 }
449 
450 DIEFFECT *CreateRumbleEffectData(Sint16 magnitude)
451 {
452  DIEFFECT *effect;
453  DIPERIODIC *periodic;
454 
455  /* Create the effect */
456  effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect));
457  if (!effect) {
458  return NULL;
459  }
460  effect->dwSize = sizeof(*effect);
461  effect->dwGain = 10000;
462  effect->dwFlags = DIEFF_OBJECTOFFSETS;
463  effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; /* In microseconds. */
464  effect->dwTriggerButton = DIEB_NOTRIGGER;
465 
466  effect->cAxes = 2;
467  effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD));
468  if (!effect->rgdwAxes) {
469  FreeRumbleEffectData(effect);
470  return NULL;
471  }
472 
473  effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG));
474  if (!effect->rglDirection) {
475  FreeRumbleEffectData(effect);
476  return NULL;
477  }
478  effect->dwFlags |= DIEFF_CARTESIAN;
479 
480  periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic));
481  if (!periodic) {
482  FreeRumbleEffectData(effect);
483  return NULL;
484  }
485  periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
486  periodic->dwPeriod = 1000000;
487 
488  effect->cbTypeSpecificParams = sizeof(*periodic);
489  effect->lpvTypeSpecificParams = periodic;
490 
491  return effect;
492 }
493 
494 int
496 {
497  HRESULT result;
498  HINSTANCE instance;
499 
501  if (FAILED(result)) {
502  return SetDIerror("CoInitialize", result);
503  }
504 
505  coinitialized = SDL_TRUE;
506 
507  result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
508  &IID_IDirectInput8, (LPVOID *)&dinput);
509 
510  if (FAILED(result)) {
511  return SetDIerror("CoCreateInstance", result);
512  }
513 
514  /* Because we used CoCreateInstance, we need to Initialize it, first. */
515  instance = GetModuleHandle(NULL);
516  if (instance == NULL) {
517  IDirectInput8_Release(dinput);
518  dinput = NULL;
519  return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
520  }
521  result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
522 
523  if (FAILED(result)) {
524  IDirectInput8_Release(dinput);
525  dinput = NULL;
526  return SetDIerror("IDirectInput::Initialize", result);
527  }
528  return 0;
529 }
530 
531 /* helper function for direct input, gets called for each connected joystick */
532 static BOOL CALLBACK
533 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
534 {
535  JoyStick_DeviceData *pNewJoystick;
536  JoyStick_DeviceData *pPrevJoystick = NULL;
537  const DWORD devtype = (pdidInstance->dwDevType & 0xFF);
538  Uint16 *guid16;
539  Uint16 vendor = 0;
540  Uint16 product = 0;
541  Uint16 version = 0;
542  WCHAR hidPath[MAX_PATH];
543  char *name;
544 
545  if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
546  /* Add any supplemental devices that should be ignored here */
547 #define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID)
548  static DWORD ignored_devices[] = {
549  MAKE_TABLE_ENTRY(0, 0)
550  };
551 #undef MAKE_TABLE_ENTRY
552  unsigned int i;
553 
554  for (i = 0; i < SDL_arraysize(ignored_devices); ++i) {
555  if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) {
556  return DIENUM_CONTINUE;
557  }
558  }
559  }
560 
561  if (SDL_IsXInputDevice(pdidInstance->tszProductName, &pdidInstance->guidProduct)) {
562  return DIENUM_CONTINUE; /* ignore XInput devices here, keep going. */
563  }
564 
565  {
566  HRESULT result;
567  LPDIRECTINPUTDEVICE8 device;
568  LPDIRECTINPUTDEVICE8 InputDevice;
569  DIPROPGUIDANDPATH dipdw2;
570 
571  result = IDirectInput8_CreateDevice(dinput, &(pdidInstance->guidInstance), &device, NULL);
572  if (FAILED(result)) {
573  return DIENUM_CONTINUE; /* better luck next time? */
574  }
575 
576  /* Now get the IDirectInputDevice8 interface, instead. */
577  result = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *)&InputDevice);
578  /* We are done with this object. Use the stored one from now on. */
579  IDirectInputDevice8_Release(device);
580  if (FAILED(result)) {
581  return DIENUM_CONTINUE; /* better luck next time? */
582  }
583  dipdw2.diph.dwSize = sizeof(dipdw2);
584  dipdw2.diph.dwHeaderSize = sizeof(dipdw2.diph);
585  dipdw2.diph.dwObj = 0; // device property
586  dipdw2.diph.dwHow = DIPH_DEVICE;
587 
588  result = IDirectInputDevice8_GetProperty(InputDevice, DIPROP_GUIDANDPATH, &dipdw2.diph);
589  IDirectInputDevice8_Release(InputDevice);
590  if (FAILED(result)) {
591  return DIENUM_CONTINUE; /* better luck next time? */
592  }
593 
594  /* Get device path, compare that instead of GUID, additionally update GUIDs of joysticks with matching paths, in case they're not open yet. */
595  SDL_wcslcpy(hidPath, dipdw2.wszPath, SDL_arraysize(hidPath));
596  }
597 
598  pNewJoystick = *(JoyStick_DeviceData **)pContext;
599  while (pNewJoystick) {
600  if (SDL_wcscmp(pNewJoystick->hidPath, hidPath) == 0) {
601  /* if we are replacing the front of the list then update it */
602  if (pNewJoystick == *(JoyStick_DeviceData **)pContext) {
603  *(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
604  } else if (pPrevJoystick) {
605  pPrevJoystick->pNext = pNewJoystick->pNext;
606  }
607 
608  /* Update with new guid/etc, if it has changed */
609  SDL_memcpy(&pNewJoystick->dxdevice, pdidInstance, sizeof(DIDEVICEINSTANCE));
610 
611  pNewJoystick->pNext = SYS_Joystick;
612  SYS_Joystick = pNewJoystick;
613 
614  return DIENUM_CONTINUE; /* already have this joystick loaded, just keep going */
615  }
616 
617  pPrevJoystick = pNewJoystick;
618  pNewJoystick = pNewJoystick->pNext;
619  }
620 
621  pNewJoystick = (JoyStick_DeviceData *)SDL_malloc(sizeof(JoyStick_DeviceData));
622  if (!pNewJoystick) {
623  return DIENUM_CONTINUE; /* better luck next time? */
624  }
625 
626  SDL_zerop(pNewJoystick);
627  SDL_wcslcpy(pNewJoystick->hidPath, hidPath, SDL_arraysize(pNewJoystick->hidPath));
628  SDL_memcpy(&pNewJoystick->dxdevice, pdidInstance, sizeof(DIDEVICEINSTANCE));
629  SDL_memset(pNewJoystick->guid.data, 0, sizeof(pNewJoystick->guid.data));
630 
631  if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
632  vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1);
633  product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1);
634  }
635 
636  name = WIN_StringToUTF8(pdidInstance->tszProductName);
637  pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, NULL, name);
638  SDL_free(name);
639 
640  if (!pNewJoystick->joystickname) {
641  SDL_free(pNewJoystick);
642  return DIENUM_CONTINUE; /* better luck next time? */
643  }
644 
645  guid16 = (Uint16 *)pNewJoystick->guid.data;
646  if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
647  *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
648  *guid16++ = 0;
649  *guid16++ = SDL_SwapLE16(vendor);
650  *guid16++ = 0;
651  *guid16++ = SDL_SwapLE16(product);
652  *guid16++ = 0;
653  *guid16++ = SDL_SwapLE16(version);
654  *guid16++ = 0;
655  } else {
657  *guid16++ = 0;
658  SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4);
659  }
660 
661  if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
662  SDL_free(pNewJoystick->joystickname);
663  SDL_free(pNewJoystick);
664  return DIENUM_CONTINUE;
665  }
666 
667 #ifdef SDL_JOYSTICK_HIDAPI
668  if (HIDAPI_IsDevicePresent(vendor, product, 0, pNewJoystick->joystickname)) {
669  /* The HIDAPI driver is taking care of this device */
670  SDL_free(pNewJoystick->joystickname);
671  SDL_free(pNewJoystick);
672  return DIENUM_CONTINUE;
673  }
674 #endif
675 
676 #ifdef SDL_JOYSTICK_RAWINPUT
677  if (RAWINPUT_IsDevicePresent(vendor, product, 0, pNewJoystick->joystickname)) {
678  /* The RAWINPUT driver is taking care of this device */
679  SDL_free(pNewJoystick);
680  return DIENUM_CONTINUE;
681  }
682 #endif
683 
684  WINDOWS_AddJoystickDevice(pNewJoystick);
685 
686  return DIENUM_CONTINUE; /* get next device, please */
687 }
688 
689 void
691 {
692  IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY);
693 
694  if (SDL_RawDevList) {
695  SDL_free(SDL_RawDevList); /* in case we used this in DirectInput detection */
696  SDL_RawDevList = NULL;
697  }
698  SDL_RawDevListCount = 0;
699 }
700 
701 typedef struct
702 {
703  Uint16 vendor;
704  Uint16 product;
705  Uint16 version;
706  SDL_bool present;
707 } EnumJoystickPresentData;
708 
709 static BOOL CALLBACK
710 EnumJoystickPresentCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
711 {
712  EnumJoystickPresentData *data = (EnumJoystickPresentData *)pContext;
713  Uint16 vendor = 0;
714  Uint16 product = 0;
715  Uint16 version = 0;
716 
717  if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
718  vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1);
719  product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1);
720  if (data->vendor == vendor && data->product == product && data->version == version) {
721  data->present = SDL_TRUE;
722  return DIENUM_STOP;
723  }
724  }
725  return DIENUM_CONTINUE;
726 }
727 
728 SDL_bool
729 SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
730 {
731  EnumJoystickPresentData data;
732 
733  if (dinput == NULL) {
734  return SDL_FALSE;
735  }
736 
737  data.vendor = vendor;
738  data.product = product;
739  data.version = version;
740  data.present = SDL_FALSE;
741  IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY);
742 
743  return data.present;
744 }
745 
746 static BOOL CALLBACK
747 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
748 {
749  SDL_Joystick *joystick = (SDL_Joystick *)pvRef;
750  HRESULT result;
751  input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
752 
753  if (dev->dwType & DIDFT_BUTTON) {
754  in->type = BUTTON;
755  in->num = joystick->nbuttons;
756  in->ofs = DIJOFS_BUTTON(in->num);
757  joystick->nbuttons++;
758  } else if (dev->dwType & DIDFT_POV) {
759  in->type = HAT;
760  in->num = joystick->nhats;
761  in->ofs = DIJOFS_POV(in->num);
762  joystick->nhats++;
763  } else if (dev->dwType & DIDFT_AXIS) {
764  DIPROPRANGE diprg;
765  DIPROPDWORD dilong;
766 
767  in->type = AXIS;
768  in->num = joystick->naxes;
769  if (!SDL_memcmp(&dev->guidType, &GUID_XAxis, sizeof(dev->guidType)))
770  in->ofs = DIJOFS_X;
771  else if (!SDL_memcmp(&dev->guidType, &GUID_YAxis, sizeof(dev->guidType)))
772  in->ofs = DIJOFS_Y;
773  else if (!SDL_memcmp(&dev->guidType, &GUID_ZAxis, sizeof(dev->guidType)))
774  in->ofs = DIJOFS_Z;
775  else if (!SDL_memcmp(&dev->guidType, &GUID_RxAxis, sizeof(dev->guidType)))
776  in->ofs = DIJOFS_RX;
777  else if (!SDL_memcmp(&dev->guidType, &GUID_RyAxis, sizeof(dev->guidType)))
778  in->ofs = DIJOFS_RY;
779  else if (!SDL_memcmp(&dev->guidType, &GUID_RzAxis, sizeof(dev->guidType)))
780  in->ofs = DIJOFS_RZ;
781  else if (!SDL_memcmp(&dev->guidType, &GUID_Slider, sizeof(dev->guidType))) {
782  in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
783  ++joystick->hwdata->NumSliders;
784  } else {
785  return DIENUM_CONTINUE; /* not an axis we can grok */
786  }
787 
788  diprg.diph.dwSize = sizeof(diprg);
789  diprg.diph.dwHeaderSize = sizeof(diprg.diph);
790  diprg.diph.dwObj = dev->dwType;
791  diprg.diph.dwHow = DIPH_BYID;
792  diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
793  diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
794 
795  result =
796  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
797  DIPROP_RANGE, &diprg.diph);
798  if (FAILED(result)) {
799  return DIENUM_CONTINUE; /* don't use this axis */
800  }
801 
802  /* Set dead zone to 0. */
803  dilong.diph.dwSize = sizeof(dilong);
804  dilong.diph.dwHeaderSize = sizeof(dilong.diph);
805  dilong.diph.dwObj = dev->dwType;
806  dilong.diph.dwHow = DIPH_BYID;
807  dilong.dwData = 0;
808  result =
809  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
810  DIPROP_DEADZONE, &dilong.diph);
811  if (FAILED(result)) {
812  return DIENUM_CONTINUE; /* don't use this axis */
813  }
814 
815  joystick->naxes++;
816  } else {
817  /* not supported at this time */
818  return DIENUM_CONTINUE;
819  }
820 
821  joystick->hwdata->NumInputs++;
822 
823  if (joystick->hwdata->NumInputs == MAX_INPUTS) {
824  return DIENUM_STOP; /* too many */
825  }
826 
827  return DIENUM_CONTINUE;
828 }
829 
830 /* Sort using the data offset into the DInput struct.
831  * This gives a reasonable ordering for the inputs.
832  */
833 static int
834 SortDevFunc(const void *a, const void *b)
835 {
836  const input_t *inputA = (const input_t*)a;
837  const input_t *inputB = (const input_t*)b;
838 
839  if (inputA->ofs < inputB->ofs)
840  return -1;
841  if (inputA->ofs > inputB->ofs)
842  return 1;
843  return 0;
844 }
845 
846 /* Sort the input objects and recalculate the indices for each input. */
847 static void
848 SortDevObjects(SDL_Joystick *joystick)
849 {
850  input_t *inputs = joystick->hwdata->Inputs;
851  int nButtons = 0;
852  int nHats = 0;
853  int nAxis = 0;
854  int n;
855 
856  SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
857 
858  for (n = 0; n < joystick->hwdata->NumInputs; n++) {
859  switch (inputs[n].type) {
860  case BUTTON:
861  inputs[n].num = nButtons;
862  nButtons++;
863  break;
864 
865  case HAT:
866  inputs[n].num = nHats;
867  nHats++;
868  break;
869 
870  case AXIS:
871  inputs[n].num = nAxis;
872  nAxis++;
873  break;
874  }
875  }
876 }
877 
878 int
879 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
880 {
881  HRESULT result;
882  LPDIRECTINPUTDEVICE8 device;
883  DIPROPDWORD dipdw;
884 
885  joystick->hwdata->buffered = SDL_TRUE;
886  joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
887 
888  SDL_zero(dipdw);
889  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
890  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
891 
892  result =
893  IDirectInput8_CreateDevice(dinput,
894  &(joystickdevice->dxdevice.guidInstance), &device, NULL);
895  if (FAILED(result)) {
896  return SetDIerror("IDirectInput::CreateDevice", result);
897  }
898 
899  /* Now get the IDirectInputDevice8 interface, instead. */
900  result = IDirectInputDevice8_QueryInterface(device,
901  &IID_IDirectInputDevice8,
902  (LPVOID *)& joystick->
903  hwdata->InputDevice);
904  /* We are done with this object. Use the stored one from now on. */
905  IDirectInputDevice8_Release(device);
906 
907  if (FAILED(result)) {
908  return SetDIerror("IDirectInputDevice8::QueryInterface", result);
909  }
910 
911  /* Acquire shared access. Exclusive access is required for forces,
912  * though. */
913  result =
914  IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->
915  InputDevice, SDL_HelperWindow,
916  DISCL_EXCLUSIVE |
917  DISCL_BACKGROUND);
918  if (FAILED(result)) {
919  return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
920  }
921 
922  /* Use the extended data structure: DIJOYSTATE2. */
923  result =
924  IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
925  &SDL_c_dfDIJoystick2);
926  if (FAILED(result)) {
927  return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
928  }
929 
930  /* Get device capabilities */
931  result =
932  IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
933  &joystick->hwdata->Capabilities);
934  if (FAILED(result)) {
935  return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
936  }
937 
938  /* Force capable? */
939  if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
940  result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
941  if (FAILED(result)) {
942  return SetDIerror("IDirectInputDevice8::Acquire", result);
943  }
944 
945  /* reset all actuators. */
946  result =
947  IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->
948  InputDevice,
949  DISFFC_RESET);
950 
951  /* Not necessarily supported, ignore if not supported.
952  if (FAILED(result)) {
953  return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
954  }
955  */
956 
957  result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
958 
959  if (FAILED(result)) {
960  return SetDIerror("IDirectInputDevice8::Unacquire", result);
961  }
962 
963  /* Turn on auto-centering for a ForceFeedback device (until told
964  * otherwise). */
965  dipdw.diph.dwObj = 0;
966  dipdw.diph.dwHow = DIPH_DEVICE;
967  dipdw.dwData = DIPROPAUTOCENTER_ON;
968 
969  result =
970  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
971  DIPROP_AUTOCENTER, &dipdw.diph);
972 
973  /* Not necessarily supported, ignore if not supported.
974  if (FAILED(result)) {
975  return SetDIerror("IDirectInputDevice8::SetProperty", result);
976  }
977  */
978  }
979 
980  /* What buttons and axes does it have? */
981  IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
982  EnumDevObjectsCallback, joystick,
983  DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
984 
985  /* Reorder the input objects. Some devices do not report the X axis as
986  * the first axis, for example. */
987  SortDevObjects(joystick);
988 
989  dipdw.diph.dwObj = 0;
990  dipdw.diph.dwHow = DIPH_DEVICE;
991  dipdw.dwData = INPUT_QSIZE;
992 
993  /* Set the buffer size */
994  result =
995  IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
996  DIPROP_BUFFERSIZE, &dipdw.diph);
997 
998  if (result == DI_POLLEDDEVICE) {
999  /* This device doesn't support buffering, so we're forced
1000  * to use less reliable polling. */
1001  joystick->hwdata->buffered = SDL_FALSE;
1002  } else if (FAILED(result)) {
1003  return SetDIerror("IDirectInputDevice8::SetProperty", result);
1004  }
1005  return 0;
1006 }
1007 
1008 static int
1009 SDL_DINPUT_JoystickInitRumble(SDL_Joystick * joystick, Sint16 magnitude)
1010 {
1011  HRESULT result;
1012 
1013  /* Reset and then enable actuators */
1014  result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
1015  if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
1016  result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1017  if (SUCCEEDED(result)) {
1018  result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
1019  }
1020  }
1021  if (FAILED(result)) {
1022  return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result);
1023  }
1024 
1025  result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON);
1026  if (FAILED(result)) {
1027  return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result);
1028  }
1029 
1030  /* Create the effect */
1031  joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude);
1032  if (!joystick->hwdata->ffeffect) {
1033  return SDL_OutOfMemory();
1034  }
1035 
1036  result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine,
1037  joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL);
1038  if (FAILED(result)) {
1039  return SetDIerror("IDirectInputDevice8::CreateEffect", result);
1040  }
1041  return 0;
1042 }
1043 
1044 int
1045 SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1046 {
1047  HRESULT result;
1048 
1049  /* Scale and average the two rumble strengths */
1050  Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
1051 
1052  if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) {
1053  return SDL_Unsupported();
1054  }
1055 
1056  if (joystick->hwdata->ff_initialized) {
1057  DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams);
1058  periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
1059 
1060  result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
1061  if (result == DIERR_INPUTLOST) {
1062  result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1063  if (SUCCEEDED(result)) {
1064  result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
1065  }
1066  }
1067  if (FAILED(result)) {
1068  return SetDIerror("IDirectInputDevice8::SetParameters", result);
1069  }
1070  } else {
1071  if (SDL_DINPUT_JoystickInitRumble(joystick, magnitude) < 0) {
1072  return -1;
1073  }
1074  joystick->hwdata->ff_initialized = SDL_TRUE;
1075  }
1076 
1077  result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
1078  if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
1079  result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1080  if (SUCCEEDED(result)) {
1081  result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
1082  }
1083  }
1084  if (FAILED(result)) {
1085  return SetDIerror("IDirectInputDevice8::Start", result);
1086  }
1087  return 0;
1088 }
1089 
1090 static Uint8
1091 TranslatePOV(DWORD value)
1092 {
1093  const int HAT_VALS[] = {
1094  SDL_HAT_UP,
1096  SDL_HAT_RIGHT,
1098  SDL_HAT_DOWN,
1100  SDL_HAT_LEFT,
1102  };
1103 
1104  if (LOWORD(value) == 0xFFFF)
1105  return SDL_HAT_CENTERED;
1106 
1107  /* Round the value up: */
1108  value += 4500 / 2;
1109  value %= 36000;
1110  value /= 4500;
1111 
1112  if (value >= 8)
1113  return SDL_HAT_CENTERED; /* shouldn't happen */
1114 
1115  return HAT_VALS[value];
1116 }
1117 
1118 static void
1119 UpdateDINPUTJoystickState_Buffered(SDL_Joystick * joystick)
1120 {
1121  int i;
1122  HRESULT result;
1123  DWORD numevents;
1124  DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
1125 
1126  numevents = INPUT_QSIZE;
1127  result =
1128  IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
1129  sizeof(DIDEVICEOBJECTDATA), evtbuf,
1130  &numevents, 0);
1131  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
1132  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1133  result =
1134  IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
1135  sizeof(DIDEVICEOBJECTDATA),
1136  evtbuf, &numevents, 0);
1137  }
1138 
1139  /* Handle the events or punt */
1140  if (FAILED(result)) {
1141  return;
1142  }
1143 
1144  for (i = 0; i < (int)numevents; ++i) {
1145  int j;
1146 
1147  for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
1148  const input_t *in = &joystick->hwdata->Inputs[j];
1149 
1150  if (evtbuf[i].dwOfs != in->ofs)
1151  continue;
1152 
1153  switch (in->type) {
1154  case AXIS:
1155  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)evtbuf[i].dwData);
1156  break;
1157  case BUTTON:
1159  (Uint8)(evtbuf[i].dwData ? SDL_PRESSED : SDL_RELEASED));
1160  break;
1161  case HAT:
1162  {
1163  Uint8 pos = TranslatePOV(evtbuf[i].dwData);
1164  SDL_PrivateJoystickHat(joystick, in->num, pos);
1165  }
1166  break;
1167  }
1168  }
1169  }
1170 }
1171 
1172 /* Function to update the state of a joystick - called as a device poll.
1173  * This function shouldn't update the joystick structure directly,
1174  * but instead should call SDL_PrivateJoystick*() to deliver events
1175  * and update joystick device state.
1176  */
1177 static void
1178 UpdateDINPUTJoystickState_Polled(SDL_Joystick * joystick)
1179 {
1180  DIJOYSTATE2 state;
1181  HRESULT result;
1182  int i;
1183 
1184  result =
1185  IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
1186  sizeof(DIJOYSTATE2), &state);
1187  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
1188  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1189  result =
1190  IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
1191  sizeof(DIJOYSTATE2), &state);
1192  }
1193 
1194  if (result != DI_OK) {
1195  return;
1196  }
1197 
1198  /* Set each known axis, button and POV. */
1199  for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
1200  const input_t *in = &joystick->hwdata->Inputs[i];
1201 
1202  switch (in->type) {
1203  case AXIS:
1204  switch (in->ofs) {
1205  case DIJOFS_X:
1207  break;
1208  case DIJOFS_Y:
1210  break;
1211  case DIJOFS_Z:
1213  break;
1214  case DIJOFS_RX:
1216  break;
1217  case DIJOFS_RY:
1219  break;
1220  case DIJOFS_RZ:
1222  break;
1223  case DIJOFS_SLIDER(0):
1224  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[0]);
1225  break;
1226  case DIJOFS_SLIDER(1):
1227  SDL_PrivateJoystickAxis(joystick, in->num, (Sint16)state.rglSlider[1]);
1228  break;
1229  }
1230  break;
1231 
1232  case BUTTON:
1234  (Uint8)(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] ? SDL_PRESSED : SDL_RELEASED));
1235  break;
1236  case HAT:
1237  {
1238  Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
1239  SDL_PrivateJoystickHat(joystick, in->num, pos);
1240  break;
1241  }
1242  }
1243  }
1244 }
1245 
1246 void
1247 SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
1248 {
1249  HRESULT result;
1250 
1251  result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
1252  if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
1253  IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1254  IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
1255  }
1256 
1257  if (joystick->hwdata->buffered) {
1258  UpdateDINPUTJoystickState_Buffered(joystick);
1259  } else {
1260  UpdateDINPUTJoystickState_Polled(joystick);
1261  }
1262 }
1263 
1264 void
1265 SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
1266 {
1267  if (joystick->hwdata->ffeffect_ref) {
1268  IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref);
1269  joystick->hwdata->ffeffect_ref = NULL;
1270  }
1271  if (joystick->hwdata->ffeffect) {
1272  FreeRumbleEffectData(joystick->hwdata->ffeffect);
1273  joystick->hwdata->ffeffect = NULL;
1274  }
1275  IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
1276  IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
1277  joystick->hwdata->ff_initialized = SDL_FALSE;
1278 }
1279 
1280 void
1282 {
1283  if (dinput != NULL) {
1284  IDirectInput8_Release(dinput);
1285  dinput = NULL;
1286  }
1287 
1288  if (coinitialized) {
1290  coinitialized = SDL_FALSE;
1291  }
1292 }
1293 
1294 #else /* !SDL_JOYSTICK_DINPUT */
1295 
1297 
1298 int
1300 {
1301  return 0;
1302 }
1303 
1304 void
1306 {
1307 }
1308 
1309 SDL_bool
1311 {
1312  return SDL_FALSE;
1313 }
1314 
1315 int
1316 SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice)
1317 {
1318  return SDL_Unsupported();
1319 }
1320 
1321 int
1322 SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1323 {
1324  return SDL_Unsupported();
1325 }
1326 
1327 void
1329 {
1330 }
1331 
1332 void
1334 {
1335 }
1336 
1337 void
1339 {
1340 }
1341 
1342 #endif /* SDL_JOYSTICK_DINPUT */
1343 
1344 /* vi: set ts=4 sw=4 expandtab: */
void SDL_DINPUT_JoystickQuit(void)
int SDL_DINPUT_JoystickInit(void)
SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
int SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick)
int SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice)
void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick)
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
#define DIRECTINPUT_VERSION
Definition: SDL_directx.h:95
#define FIELD_OFFSET(type, field)
Definition: SDL_directx.h:87
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_SetError
#define SDL_memset
#define SDL_wcslcpy
#define SDL_qsort
#define SDL_malloc
#define SDL_wcsstr
#define SDL_strlcpy
#define SDL_free
#define SDL_memcmp
#define SDL_strstr
#define SDL_sscanf
#define SDL_memcpy
#define SDL_wcscmp
#define SDL_calloc
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:235
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
SDL_GameControllerType
@ SDL_CONTROLLER_TYPE_XBOX360
@ SDL_CONTROLLER_TYPE_XBOXONE
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
SDL_GameControllerType SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
char * SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:390
#define SDL_JOYSTICK_AXIS_MIN
Definition: SDL_joystick.h:359
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:388
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:389
#define SDL_HAT_UP
Definition: SDL_joystick.h:387
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:386
#define SDL_JOYSTICK_AXIS_MAX
Definition: SDL_joystick.h:358
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLboolean GLboolean GLboolean b
GLuint64EXT * result
GLboolean GLboolean GLboolean GLboolean a
GLuint in
GLuint const GLchar * name
GLuint num
GLdouble n
GLsizei const GLfloat * value
SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
uint16_t Uint16
Definition: SDL_stdinc.h:197
int16_t Sint16
Definition: SDL_stdinc.h:191
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
#define SDL_zeroa(x)
Definition: SDL_stdinc.h:428
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
uint8_t Uint8
Definition: SDL_stdinc.h:185
#define SDL_zerop(x)
Definition: SDL_stdinc.h:427
#define SDL_HARDWARE_BUS_USB
#define SDL_MAX_RUMBLE_DURATION_MS
#define SDL_HARDWARE_BUS_BLUETOOTH
struct xkb_state * state
HRESULT WIN_CoInitialize(void)
void WIN_CoUninitialize(void)
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device)
#define MAX_INPUTS
JoyStick_DeviceData * SYS_Joystick
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
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
SDL_bool SDL_XINPUT_Enabled(void)
#define NULL
Definition: begin_code.h:163
static SDL_AudioDeviceID device
Definition: loopwave.c:37
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
DIDEVICEINSTANCE dxdevice
struct JoyStick_DeviceData * pNext
Uint8 data[16]
Definition: SDL_joystick.h:71
static SDL_Joystick * joystick
Definition: testjoystick.c:37
struct HINSTANCE__ * HINSTANCE
Definition: vulkan.hpp:72
typedef int(__stdcall *FARPROC)()