Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/joystick/windows/SDL_dinputjoystick.c
9905 views
1
/*
2
Simple DirectMedia Layer
3
Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
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
#ifdef 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 128 // Buffer up to 128 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
46
// local variables
47
static bool coinitialized = false;
48
static LPDIRECTINPUT8 dinput = NULL;
49
50
// Taken from Wine - Thanks!
51
static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
52
{ &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
53
{ &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
54
{ &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
55
{ &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
56
{ &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
57
{ &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
58
{ &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
59
{ &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION },
60
{ &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
61
{ &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
62
{ &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
63
{ &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
64
{ NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
65
{ NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
66
{ NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
67
{ NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
68
{ NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
69
{ NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
70
{ NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
71
{ NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
72
{ NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
73
{ NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
74
{ NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
75
{ NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
76
{ NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
77
{ NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
78
{ NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
79
{ NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
80
{ NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
81
{ NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
82
{ NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
83
{ NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
84
{ NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
85
{ NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
86
{ NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
87
{ NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
88
{ NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
89
{ NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
90
{ NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
91
{ NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
92
{ NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
93
{ NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
94
{ NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
95
{ NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
96
{ NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
97
{ NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
98
{ NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
99
{ NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
100
{ NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
101
{ NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
102
{ NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
103
{ NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
104
{ NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
105
{ NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
106
{ NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
107
{ NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
108
{ NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
109
{ NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
110
{ NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
111
{ NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
112
{ NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
113
{ NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
114
{ NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
115
{ NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
116
{ NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
117
{ NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
118
{ NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
119
{ NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
120
{ NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
121
{ NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
122
{ NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
123
{ NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
124
{ NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
125
{ NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
126
{ NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
127
{ NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
128
{ NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
129
{ NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
130
{ NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
131
{ NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
132
{ NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
133
{ NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
134
{ NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
135
{ NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
136
{ NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
137
{ NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
138
{ NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
139
{ NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
140
{ NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
141
{ NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
142
{ NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
143
{ NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
144
{ NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
145
{ NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
146
{ NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
147
{ NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
148
{ NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
149
{ NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
150
{ NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
151
{ NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
152
{ NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
153
{ NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
154
{ NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
155
{ NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
156
{ NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
157
{ NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
158
{ NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
159
{ NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
160
{ NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
161
{ NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
162
{ NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
163
{ NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
164
{ NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
165
{ NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
166
{ NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
167
{ NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
168
{ NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
169
{ NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
170
{ NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
171
{ NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
172
{ NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
173
{ NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
174
{ NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
175
{ NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
176
{ NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
177
{ NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
178
{ NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
179
{ NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
180
{ NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
181
{ NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
182
{ NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
183
{ NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
184
{ NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
185
{ NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
186
{ NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
187
{ NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
188
{ NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
189
{ NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
190
{ NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
191
{ NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
192
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
193
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
194
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
195
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
196
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
197
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
198
// note: dwOfs value matches Windows
199
{ &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
200
{ &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTVELOCITY },
201
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
202
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
203
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
204
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
205
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
206
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
207
// note: dwOfs value matches Windows
208
{ &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
209
{ &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTACCEL },
210
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
211
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
212
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
213
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
214
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
215
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
216
// note: dwOfs value matches Windows
217
{ &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
218
{ &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, DIDOI_ASPECTFORCE },
219
};
220
221
const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
222
sizeof(DIDATAFORMAT),
223
sizeof(DIOBJECTDATAFORMAT),
224
DIDF_ABSAXIS,
225
sizeof(DIJOYSTATE2),
226
SDL_arraysize(dfDIJoystick2),
227
dfDIJoystick2
228
};
229
230
// Convert a DirectInput return code to a text message
231
static bool SetDIerror(const char *function, HRESULT code)
232
{
233
return SDL_SetError("%s() DirectX error 0x%8.8lx", function, code);
234
}
235
236
static bool SDL_IsXInputDevice(Uint16 vendor_id, Uint16 product_id, const char *hidPath)
237
{
238
#if defined(SDL_JOYSTICK_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT)
239
SDL_GamepadType type;
240
241
// XInput and RawInput backends will pick up XInput-compatible devices
242
if (!SDL_XINPUT_Enabled()
243
#ifdef SDL_JOYSTICK_RAWINPUT
244
&& !RAWINPUT_IsEnabled()
245
#endif
246
) {
247
return false;
248
}
249
250
// If device path contains "IG_" then its an XInput device
251
// See: https://docs.microsoft.com/windows/win32/xinput/xinput-and-directinput
252
if (SDL_strstr(hidPath, "IG_") != NULL) {
253
return true;
254
}
255
256
type = SDL_GetGamepadTypeFromVIDPID(vendor_id, product_id, NULL, false);
257
if (type == SDL_GAMEPAD_TYPE_XBOX360 ||
258
type == SDL_GAMEPAD_TYPE_XBOXONE ||
259
(vendor_id == USB_VENDOR_VALVE && product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD)) {
260
return true;
261
}
262
#endif // SDL_JOYSTICK_XINPUT || SDL_JOYSTICK_RAWINPUT
263
264
return false;
265
}
266
267
static bool QueryDeviceName(LPDIRECTINPUTDEVICE8 device, Uint16 vendor_id, Uint16 product_id, char **manufacturer_string, char **product_string)
268
{
269
DIPROPSTRING dipstr;
270
271
if (!device || !manufacturer_string || !product_string) {
272
return false;
273
}
274
275
#ifdef SDL_JOYSTICK_HIDAPI
276
*manufacturer_string = HIDAPI_GetDeviceManufacturerName(vendor_id, product_id);
277
*product_string = HIDAPI_GetDeviceProductName(vendor_id, product_id);
278
if (*product_string) {
279
return true;
280
}
281
#endif
282
283
dipstr.diph.dwSize = sizeof(dipstr);
284
dipstr.diph.dwHeaderSize = sizeof(dipstr.diph);
285
dipstr.diph.dwObj = 0;
286
dipstr.diph.dwHow = DIPH_DEVICE;
287
288
if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_PRODUCTNAME, &dipstr.diph))) {
289
return false;
290
}
291
292
*manufacturer_string = NULL;
293
*product_string = WIN_StringToUTF8(dipstr.wsz);
294
295
return true;
296
}
297
298
static bool QueryDevicePath(LPDIRECTINPUTDEVICE8 device, char **device_path)
299
{
300
DIPROPGUIDANDPATH dippath;
301
302
if (!device || !device_path) {
303
return false;
304
}
305
306
dippath.diph.dwSize = sizeof(dippath);
307
dippath.diph.dwHeaderSize = sizeof(dippath.diph);
308
dippath.diph.dwObj = 0;
309
dippath.diph.dwHow = DIPH_DEVICE;
310
311
if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_GUIDANDPATH, &dippath.diph))) {
312
return false;
313
}
314
315
*device_path = WIN_StringToUTF8W(dippath.wszPath);
316
317
// Normalize path to upper case.
318
SDL_strupr(*device_path);
319
320
return true;
321
}
322
323
static bool QueryDeviceInfo(LPDIRECTINPUTDEVICE8 device, Uint16 *vendor_id, Uint16 *product_id)
324
{
325
DIPROPDWORD dipdw;
326
327
if (!device || !vendor_id || !product_id) {
328
return false;
329
}
330
331
dipdw.diph.dwSize = sizeof(dipdw);
332
dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
333
dipdw.diph.dwObj = 0;
334
dipdw.diph.dwHow = DIPH_DEVICE;
335
dipdw.dwData = 0;
336
337
if (FAILED(IDirectInputDevice8_GetProperty(device, DIPROP_VIDPID, &dipdw.diph))) {
338
return false;
339
}
340
341
*vendor_id = LOWORD(dipdw.dwData);
342
*product_id = HIWORD(dipdw.dwData);
343
344
return true;
345
}
346
347
void FreeRumbleEffectData(DIEFFECT *effect)
348
{
349
if (!effect) {
350
return;
351
}
352
SDL_free(effect->rgdwAxes);
353
SDL_free(effect->rglDirection);
354
SDL_free(effect->lpvTypeSpecificParams);
355
SDL_free(effect);
356
}
357
358
DIEFFECT *CreateRumbleEffectData(Sint16 magnitude)
359
{
360
DIEFFECT *effect;
361
DIPERIODIC *periodic;
362
363
// Create the effect
364
effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect));
365
if (!effect) {
366
return NULL;
367
}
368
effect->dwSize = sizeof(*effect);
369
effect->dwGain = 10000;
370
effect->dwFlags = DIEFF_OBJECTOFFSETS;
371
effect->dwDuration = SDL_MAX_RUMBLE_DURATION_MS * 1000; // In microseconds.
372
effect->dwTriggerButton = DIEB_NOTRIGGER;
373
374
effect->cAxes = 2;
375
effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD));
376
if (!effect->rgdwAxes) {
377
FreeRumbleEffectData(effect);
378
return NULL;
379
}
380
381
effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG));
382
if (!effect->rglDirection) {
383
FreeRumbleEffectData(effect);
384
return NULL;
385
}
386
effect->dwFlags |= DIEFF_CARTESIAN;
387
388
periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic));
389
if (!periodic) {
390
FreeRumbleEffectData(effect);
391
return NULL;
392
}
393
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
394
periodic->dwPeriod = 1000000;
395
396
effect->cbTypeSpecificParams = sizeof(*periodic);
397
effect->lpvTypeSpecificParams = periodic;
398
399
return effect;
400
}
401
402
bool SDL_DINPUT_JoystickInit(void)
403
{
404
HRESULT result;
405
HINSTANCE instance;
406
407
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true)) {
408
// In some environments, IDirectInput8_Initialize / _EnumDevices can take a minute even with no controllers.
409
dinput = NULL;
410
return true;
411
}
412
413
result = WIN_CoInitialize();
414
if (FAILED(result)) {
415
return SetDIerror("CoInitialize", result);
416
}
417
418
coinitialized = true;
419
420
result = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
421
&IID_IDirectInput8, (LPVOID *)&dinput);
422
423
if (FAILED(result)) {
424
return SetDIerror("CoCreateInstance", result);
425
}
426
427
// Because we used CoCreateInstance, we need to Initialize it, first.
428
instance = GetModuleHandle(NULL);
429
if (!instance) {
430
IDirectInput8_Release(dinput);
431
dinput = NULL;
432
return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError());
433
}
434
result = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
435
436
if (FAILED(result)) {
437
IDirectInput8_Release(dinput);
438
dinput = NULL;
439
return SetDIerror("IDirectInput::Initialize", result);
440
}
441
return true;
442
}
443
444
static int GetSteamVirtualGamepadSlot(Uint16 vendor_id, Uint16 product_id, const char *device_path)
445
{
446
int slot = -1;
447
448
if (vendor_id == USB_VENDOR_VALVE &&
449
product_id == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) {
450
(void)SDL_sscanf(device_path, "\\\\?\\HID#VID_28DE&PID_11FF&IG_0%d", &slot);
451
}
452
return slot;
453
}
454
455
// helper function for direct input, gets called for each connected joystick
456
static BOOL CALLBACK EnumJoystickDetectCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext)
457
{
458
#define CHECK(expression) \
459
{ \
460
if (!(expression)) \
461
goto err; \
462
}
463
JoyStick_DeviceData *pNewJoystick = NULL;
464
JoyStick_DeviceData *pPrevJoystick = NULL;
465
Uint16 vendor = 0;
466
Uint16 product = 0;
467
Uint16 version = 0;
468
char *hidPath = NULL;
469
char *manufacturer_string = NULL;
470
char *product_string = NULL;
471
LPDIRECTINPUTDEVICE8 device = NULL;
472
473
// We are only supporting HID devices.
474
CHECK(pDeviceInstance->dwDevType & DIDEVTYPE_HID);
475
476
CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL)));
477
CHECK(QueryDevicePath(device, &hidPath));
478
CHECK(QueryDeviceInfo(device, &vendor, &product));
479
CHECK(QueryDeviceName(device, vendor, product, &manufacturer_string, &product_string));
480
481
CHECK(!SDL_IsXInputDevice(vendor, product, hidPath));
482
CHECK(!SDL_ShouldIgnoreJoystick(vendor, product, version, product_string));
483
CHECK(!SDL_JoystickHandledByAnotherDriver(&SDL_WINDOWS_JoystickDriver, vendor, product, version, product_string));
484
485
pNewJoystick = *(JoyStick_DeviceData **)pContext;
486
while (pNewJoystick) {
487
// update GUIDs of joysticks with matching paths, in case they're not open yet
488
if (SDL_strcmp(pNewJoystick->path, hidPath) == 0) {
489
// if we are replacing the front of the list then update it
490
if (pNewJoystick == *(JoyStick_DeviceData **)pContext) {
491
*(JoyStick_DeviceData **)pContext = pNewJoystick->pNext;
492
} else if (pPrevJoystick) {
493
pPrevJoystick->pNext = pNewJoystick->pNext;
494
}
495
496
// Update with new guid/etc, if it has changed
497
SDL_memcpy(&pNewJoystick->dxdevice, pDeviceInstance, sizeof(DIDEVICEINSTANCE));
498
499
pNewJoystick->pNext = SYS_Joystick;
500
SYS_Joystick = pNewJoystick;
501
502
pNewJoystick = NULL;
503
CHECK(FALSE);
504
}
505
506
pPrevJoystick = pNewJoystick;
507
pNewJoystick = pNewJoystick->pNext;
508
}
509
510
pNewJoystick = (JoyStick_DeviceData *)SDL_calloc(1, sizeof(JoyStick_DeviceData));
511
CHECK(pNewJoystick);
512
513
pNewJoystick->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(vendor, product, hidPath);
514
SDL_strlcpy(pNewJoystick->path, hidPath, SDL_arraysize(pNewJoystick->path));
515
SDL_memcpy(&pNewJoystick->dxdevice, pDeviceInstance, sizeof(DIDEVICEINSTANCE));
516
517
pNewJoystick->joystickname = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string);
518
CHECK(pNewJoystick->joystickname);
519
520
if (vendor && product) {
521
pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, vendor, product, version, manufacturer_string, product_string, 0, 0);
522
} else {
523
pNewJoystick->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_BLUETOOTH, vendor, product, version, manufacturer_string, product_string, 0, 0);
524
}
525
526
WINDOWS_AddJoystickDevice(pNewJoystick);
527
pNewJoystick = NULL;
528
529
err:
530
if (pNewJoystick) {
531
SDL_free(pNewJoystick->joystickname);
532
SDL_free(pNewJoystick);
533
}
534
535
SDL_free(hidPath);
536
SDL_free(manufacturer_string);
537
SDL_free(product_string);
538
539
if (device) {
540
IDirectInputDevice8_Release(device);
541
}
542
543
return DIENUM_CONTINUE; // get next device, please
544
#undef CHECK
545
}
546
547
void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
548
{
549
if (!dinput) {
550
return;
551
}
552
553
IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickDetectCallback, pContext, DIEDFL_ATTACHEDONLY);
554
}
555
556
// helper function for direct input, gets called for each connected joystick
557
typedef struct
558
{
559
Uint16 vendor;
560
Uint16 product;
561
bool present;
562
} Joystick_PresentData;
563
564
static BOOL CALLBACK EnumJoystickPresentCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext)
565
{
566
#define CHECK(expression) \
567
{ \
568
if (!(expression)) \
569
goto err; \
570
}
571
Joystick_PresentData *pData = (Joystick_PresentData *)pContext;
572
Uint16 vendor = 0;
573
Uint16 product = 0;
574
LPDIRECTINPUTDEVICE8 device = NULL;
575
BOOL result = DIENUM_CONTINUE;
576
577
// We are only supporting HID devices.
578
CHECK(pDeviceInstance->dwDevType & DIDEVTYPE_HID);
579
580
CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL)));
581
CHECK(QueryDeviceInfo(device, &vendor, &product));
582
583
if (vendor == pData->vendor && product == pData->product) {
584
pData->present = true;
585
result = DIENUM_STOP; // found it
586
}
587
588
err:
589
if (device) {
590
IDirectInputDevice8_Release(device);
591
}
592
593
return result;
594
#undef CHECK
595
}
596
597
bool SDL_DINPUT_JoystickPresent(Uint16 vendor_id, Uint16 product_id, Uint16 version_number)
598
{
599
Joystick_PresentData data;
600
601
if (!dinput) {
602
return false;
603
}
604
605
data.vendor = vendor_id;
606
data.product = product_id;
607
data.present = false;
608
IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY);
609
return data.present;
610
}
611
612
static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE pDeviceObject, LPVOID pContext)
613
{
614
SDL_Joystick *joystick = (SDL_Joystick *)pContext;
615
HRESULT result;
616
input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
617
618
if (pDeviceObject->dwType & DIDFT_BUTTON) {
619
in->type = BUTTON;
620
in->num = (Uint8)joystick->nbuttons;
621
in->ofs = DIJOFS_BUTTON(in->num);
622
joystick->nbuttons++;
623
} else if (pDeviceObject->dwType & DIDFT_POV) {
624
in->type = HAT;
625
in->num = (Uint8)joystick->nhats;
626
in->ofs = DIJOFS_POV(in->num);
627
joystick->nhats++;
628
} else if (pDeviceObject->dwType & DIDFT_AXIS) {
629
DIPROPRANGE diprg;
630
DIPROPDWORD dilong;
631
632
in->type = AXIS;
633
in->num = (Uint8)joystick->naxes;
634
if (SDL_memcmp(&pDeviceObject->guidType, &GUID_XAxis, sizeof(pDeviceObject->guidType)) == 0) {
635
in->ofs = DIJOFS_X;
636
} else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_YAxis, sizeof(pDeviceObject->guidType)) == 0) {
637
in->ofs = DIJOFS_Y;
638
} else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_ZAxis, sizeof(pDeviceObject->guidType)) == 0) {
639
in->ofs = DIJOFS_Z;
640
} else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RxAxis, sizeof(pDeviceObject->guidType)) == 0) {
641
in->ofs = DIJOFS_RX;
642
} else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RyAxis, sizeof(pDeviceObject->guidType)) == 0) {
643
in->ofs = DIJOFS_RY;
644
} else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_RzAxis, sizeof(pDeviceObject->guidType)) == 0) {
645
in->ofs = DIJOFS_RZ;
646
} else if (SDL_memcmp(&pDeviceObject->guidType, &GUID_Slider, sizeof(pDeviceObject->guidType)) == 0) {
647
in->ofs = DIJOFS_SLIDER(joystick->hwdata->NumSliders);
648
++joystick->hwdata->NumSliders;
649
} else {
650
return DIENUM_CONTINUE; // not an axis we can grok
651
}
652
653
diprg.diph.dwSize = sizeof(diprg);
654
diprg.diph.dwHeaderSize = sizeof(diprg.diph);
655
diprg.diph.dwObj = pDeviceObject->dwType;
656
diprg.diph.dwHow = DIPH_BYID;
657
diprg.lMin = SDL_JOYSTICK_AXIS_MIN;
658
diprg.lMax = SDL_JOYSTICK_AXIS_MAX;
659
660
result =
661
IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
662
DIPROP_RANGE, &diprg.diph);
663
if (FAILED(result)) {
664
return DIENUM_CONTINUE; // don't use this axis
665
}
666
667
// Set dead zone to 0.
668
dilong.diph.dwSize = sizeof(dilong);
669
dilong.diph.dwHeaderSize = sizeof(dilong.diph);
670
dilong.diph.dwObj = pDeviceObject->dwType;
671
dilong.diph.dwHow = DIPH_BYID;
672
dilong.dwData = 0;
673
result =
674
IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
675
DIPROP_DEADZONE, &dilong.diph);
676
if (FAILED(result)) {
677
return DIENUM_CONTINUE; // don't use this axis
678
}
679
680
joystick->naxes++;
681
} else {
682
// not supported at this time
683
return DIENUM_CONTINUE;
684
}
685
686
joystick->hwdata->NumInputs++;
687
688
if (joystick->hwdata->NumInputs == MAX_INPUTS) {
689
return DIENUM_STOP; // too many
690
}
691
692
return DIENUM_CONTINUE;
693
}
694
695
/* Sort using the data offset into the DInput struct.
696
* This gives a reasonable ordering for the inputs.
697
*/
698
static int SDLCALL SortDevFunc(const void *a, const void *b)
699
{
700
const input_t *inputA = (const input_t *)a;
701
const input_t *inputB = (const input_t *)b;
702
703
if (inputA->ofs < inputB->ofs) {
704
return -1;
705
}
706
if (inputA->ofs > inputB->ofs) {
707
return 1;
708
}
709
return 0;
710
}
711
712
// Sort the input objects and recalculate the indices for each input.
713
static void SortDevObjects(SDL_Joystick *joystick)
714
{
715
input_t *inputs = joystick->hwdata->Inputs;
716
Uint8 nButtons = 0;
717
Uint8 nHats = 0;
718
Uint8 nAxis = 0;
719
int n;
720
721
SDL_qsort(inputs, joystick->hwdata->NumInputs, sizeof(input_t), SortDevFunc);
722
723
for (n = 0; n < joystick->hwdata->NumInputs; n++) {
724
switch (inputs[n].type) {
725
case BUTTON:
726
inputs[n].num = nButtons;
727
nButtons++;
728
break;
729
730
case HAT:
731
inputs[n].num = nHats;
732
nHats++;
733
break;
734
735
case AXIS:
736
inputs[n].num = nAxis;
737
nAxis++;
738
break;
739
}
740
}
741
}
742
743
bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice)
744
{
745
HRESULT result;
746
DIPROPDWORD dipdw;
747
748
joystick->hwdata->buffered = true;
749
joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
750
751
SDL_zero(dipdw);
752
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
753
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
754
755
result =
756
IDirectInput8_CreateDevice(dinput,
757
&joystickdevice->dxdevice.guidInstance,
758
&joystick->hwdata->InputDevice,
759
NULL);
760
if (FAILED(result)) {
761
return SetDIerror("IDirectInput::CreateDevice", result);
762
}
763
764
/* Acquire shared access. Exclusive access is required for forces,
765
* though. */
766
result =
767
IDirectInputDevice8_SetCooperativeLevel(joystick->hwdata->InputDevice, SDL_HelperWindow,
768
DISCL_EXCLUSIVE |
769
DISCL_BACKGROUND);
770
if (FAILED(result)) {
771
return SetDIerror("IDirectInputDevice8::SetCooperativeLevel", result);
772
}
773
774
// Use the extended data structure: DIJOYSTATE2.
775
result =
776
IDirectInputDevice8_SetDataFormat(joystick->hwdata->InputDevice,
777
&SDL_c_dfDIJoystick2);
778
if (FAILED(result)) {
779
return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
780
}
781
782
// Get device capabilities
783
result =
784
IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
785
&joystick->hwdata->Capabilities);
786
if (FAILED(result)) {
787
return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
788
}
789
790
// Force capable?
791
if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
792
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
793
if (FAILED(result)) {
794
return SetDIerror("IDirectInputDevice8::Acquire", result);
795
}
796
797
// reset all actuators.
798
result =
799
IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice,
800
DISFFC_RESET);
801
802
/* Not necessarily supported, ignore if not supported.
803
if (FAILED(result)) {
804
return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand", result);
805
}
806
*/
807
808
result = IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
809
810
if (FAILED(result)) {
811
return SetDIerror("IDirectInputDevice8::Unacquire", result);
812
}
813
814
/* Turn on auto-centering for a ForceFeedback device (until told
815
* otherwise). */
816
dipdw.diph.dwObj = 0;
817
dipdw.diph.dwHow = DIPH_DEVICE;
818
dipdw.dwData = DIPROPAUTOCENTER_ON;
819
820
result =
821
IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
822
DIPROP_AUTOCENTER, &dipdw.diph);
823
824
/* Not necessarily supported, ignore if not supported.
825
if (FAILED(result)) {
826
return SetDIerror("IDirectInputDevice8::SetProperty", result);
827
}
828
*/
829
830
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
831
}
832
833
// What buttons and axes does it have?
834
IDirectInputDevice8_EnumObjects(joystick->hwdata->InputDevice,
835
EnumDevObjectsCallback, joystick,
836
DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
837
838
/* Reorder the input objects. Some devices do not report the X axis as
839
* the first axis, for example. */
840
SortDevObjects(joystick);
841
842
dipdw.diph.dwObj = 0;
843
dipdw.diph.dwHow = DIPH_DEVICE;
844
dipdw.dwData = INPUT_QSIZE;
845
846
// Set the buffer size
847
result =
848
IDirectInputDevice8_SetProperty(joystick->hwdata->InputDevice,
849
DIPROP_BUFFERSIZE, &dipdw.diph);
850
851
if (result == DI_POLLEDDEVICE) {
852
/* This device doesn't support buffering, so we're forced
853
* to use less reliable polling. */
854
joystick->hwdata->buffered = false;
855
} else if (FAILED(result)) {
856
return SetDIerror("IDirectInputDevice8::SetProperty", result);
857
}
858
joystick->hwdata->first_update = true;
859
860
// Poll and wait for initial device state to be populated
861
result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
862
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
863
IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
864
IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
865
}
866
SDL_Delay(50);
867
868
return true;
869
}
870
871
static bool SDL_DINPUT_JoystickInitRumble(SDL_Joystick *joystick, Sint16 magnitude)
872
{
873
HRESULT result;
874
875
// Reset and then enable actuators
876
result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
877
if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
878
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
879
if (SUCCEEDED(result)) {
880
result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
881
}
882
}
883
if (FAILED(result)) {
884
return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result);
885
}
886
887
result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON);
888
if (FAILED(result)) {
889
return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result);
890
}
891
892
// Create the effect
893
joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude);
894
if (!joystick->hwdata->ffeffect) {
895
return false;
896
}
897
898
result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine,
899
joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL);
900
if (FAILED(result)) {
901
return SetDIerror("IDirectInputDevice8::CreateEffect", result);
902
}
903
return true;
904
}
905
906
bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
907
{
908
HRESULT result;
909
910
// Scale and average the two rumble strengths
911
Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
912
913
if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) {
914
return SDL_Unsupported();
915
}
916
917
if (joystick->hwdata->ff_initialized) {
918
DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams);
919
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
920
921
result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
922
if (result == DIERR_INPUTLOST) {
923
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
924
if (SUCCEEDED(result)) {
925
result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
926
}
927
}
928
if (FAILED(result)) {
929
return SetDIerror("IDirectInputDevice8::SetParameters", result);
930
}
931
} else {
932
if (!SDL_DINPUT_JoystickInitRumble(joystick, magnitude)) {
933
return false;
934
}
935
joystick->hwdata->ff_initialized = true;
936
}
937
938
result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
939
if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
940
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
941
if (SUCCEEDED(result)) {
942
result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
943
}
944
}
945
if (FAILED(result)) {
946
return SetDIerror("IDirectInputDevice8::Start", result);
947
}
948
return true;
949
}
950
951
static Uint8 TranslatePOV(DWORD value)
952
{
953
const Uint8 HAT_VALS[] = {
954
SDL_HAT_UP,
955
SDL_HAT_UP | SDL_HAT_RIGHT,
956
SDL_HAT_RIGHT,
957
SDL_HAT_DOWN | SDL_HAT_RIGHT,
958
SDL_HAT_DOWN,
959
SDL_HAT_DOWN | SDL_HAT_LEFT,
960
SDL_HAT_LEFT,
961
SDL_HAT_UP | SDL_HAT_LEFT
962
};
963
964
if (LOWORD(value) == 0xFFFF) {
965
return SDL_HAT_CENTERED;
966
}
967
968
// Round the value up:
969
value += 4500 / 2;
970
value %= 36000;
971
value /= 4500;
972
973
if (value >= 8) {
974
return SDL_HAT_CENTERED; // shouldn't happen
975
}
976
977
return HAT_VALS[value];
978
}
979
980
/* Function to update the state of a joystick - called as a device poll.
981
* This function shouldn't update the joystick structure directly,
982
* but instead should call SDL_PrivateJoystick*() to deliver events
983
* and update joystick device state.
984
*/
985
static void UpdateDINPUTJoystickState_Polled(SDL_Joystick *joystick)
986
{
987
DIJOYSTATE2 state;
988
HRESULT result;
989
int i;
990
Uint64 timestamp = SDL_GetTicksNS();
991
992
result =
993
IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
994
sizeof(DIJOYSTATE2), &state);
995
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
996
IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
997
result =
998
IDirectInputDevice8_GetDeviceState(joystick->hwdata->InputDevice,
999
sizeof(DIJOYSTATE2), &state);
1000
}
1001
1002
if (result != DI_OK) {
1003
return;
1004
}
1005
1006
// Set each known axis, button and POV.
1007
for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
1008
const input_t *in = &joystick->hwdata->Inputs[i];
1009
1010
switch (in->type) {
1011
case AXIS:
1012
switch (in->ofs) {
1013
case DIJOFS_X:
1014
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lX);
1015
break;
1016
case DIJOFS_Y:
1017
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lY);
1018
break;
1019
case DIJOFS_Z:
1020
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lZ);
1021
break;
1022
case DIJOFS_RX:
1023
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRx);
1024
break;
1025
case DIJOFS_RY:
1026
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRy);
1027
break;
1028
case DIJOFS_RZ:
1029
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.lRz);
1030
break;
1031
case DIJOFS_SLIDER(0):
1032
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.rglSlider[0]);
1033
break;
1034
case DIJOFS_SLIDER(1):
1035
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)state.rglSlider[1]);
1036
break;
1037
}
1038
break;
1039
1040
case BUTTON:
1041
SDL_SendJoystickButton(timestamp, joystick, in->num,
1042
(state.rgbButtons[in->ofs - DIJOFS_BUTTON0] != 0));
1043
break;
1044
case HAT:
1045
{
1046
Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
1047
SDL_SendJoystickHat(timestamp, joystick, in->num, pos);
1048
break;
1049
}
1050
}
1051
}
1052
}
1053
1054
static void UpdateDINPUTJoystickState_Buffered(SDL_Joystick *joystick)
1055
{
1056
int i;
1057
HRESULT result;
1058
DWORD numevents;
1059
DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
1060
Uint64 timestamp = SDL_GetTicksNS();
1061
1062
numevents = INPUT_QSIZE;
1063
result =
1064
IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
1065
sizeof(DIDEVICEOBJECTDATA), evtbuf,
1066
&numevents, 0);
1067
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
1068
IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1069
result =
1070
IDirectInputDevice8_GetDeviceData(joystick->hwdata->InputDevice,
1071
sizeof(DIDEVICEOBJECTDATA),
1072
evtbuf, &numevents, 0);
1073
}
1074
1075
// Handle the events or punt
1076
if (FAILED(result)) {
1077
return;
1078
}
1079
1080
for (i = 0; i < (int)numevents; ++i) {
1081
int j;
1082
1083
for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
1084
const input_t *in = &joystick->hwdata->Inputs[j];
1085
1086
if (evtbuf[i].dwOfs != in->ofs) {
1087
continue;
1088
}
1089
1090
switch (in->type) {
1091
case AXIS:
1092
SDL_SendJoystickAxis(timestamp, joystick, in->num, (Sint16)evtbuf[i].dwData);
1093
break;
1094
case BUTTON:
1095
SDL_SendJoystickButton(timestamp, joystick, in->num,
1096
(evtbuf[i].dwData != 0));
1097
break;
1098
case HAT:
1099
{
1100
Uint8 pos = TranslatePOV(evtbuf[i].dwData);
1101
SDL_SendJoystickHat(timestamp, joystick, in->num, pos);
1102
} break;
1103
}
1104
}
1105
}
1106
1107
if (result == DI_BUFFEROVERFLOW) {
1108
/* Our buffer wasn't big enough to hold all the queued events,
1109
* so poll the device to make sure we have the complete state.
1110
*/
1111
UpdateDINPUTJoystickState_Polled(joystick);
1112
}
1113
}
1114
1115
void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick)
1116
{
1117
HRESULT result;
1118
1119
result = IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
1120
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
1121
IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
1122
IDirectInputDevice8_Poll(joystick->hwdata->InputDevice);
1123
}
1124
1125
if (joystick->hwdata->first_update) {
1126
// Poll to get the initial state of the joystick
1127
UpdateDINPUTJoystickState_Polled(joystick);
1128
joystick->hwdata->first_update = false;
1129
return;
1130
}
1131
1132
if (joystick->hwdata->buffered ) {
1133
UpdateDINPUTJoystickState_Buffered(joystick);
1134
} else {
1135
UpdateDINPUTJoystickState_Polled(joystick);
1136
}
1137
}
1138
1139
void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick)
1140
{
1141
if (joystick->hwdata->ffeffect_ref) {
1142
IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref);
1143
joystick->hwdata->ffeffect_ref = NULL;
1144
}
1145
if (joystick->hwdata->ffeffect) {
1146
FreeRumbleEffectData(joystick->hwdata->ffeffect);
1147
joystick->hwdata->ffeffect = NULL;
1148
}
1149
IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
1150
IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
1151
joystick->hwdata->ff_initialized = false;
1152
}
1153
1154
void SDL_DINPUT_JoystickQuit(void)
1155
{
1156
if (dinput != NULL) {
1157
IDirectInput8_Release(dinput);
1158
dinput = NULL;
1159
}
1160
1161
if (coinitialized) {
1162
WIN_CoUninitialize();
1163
coinitialized = false;
1164
}
1165
}
1166
1167
#else // !SDL_JOYSTICK_DINPUT
1168
1169
typedef struct JoyStick_DeviceData JoyStick_DeviceData;
1170
1171
bool SDL_DINPUT_JoystickInit(void)
1172
{
1173
return true;
1174
}
1175
1176
void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
1177
{
1178
}
1179
1180
bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
1181
{
1182
return false;
1183
}
1184
1185
bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joystickdevice)
1186
{
1187
return SDL_Unsupported();
1188
}
1189
1190
bool SDL_DINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1191
{
1192
return SDL_Unsupported();
1193
}
1194
1195
void SDL_DINPUT_JoystickUpdate(SDL_Joystick *joystick)
1196
{
1197
}
1198
1199
void SDL_DINPUT_JoystickClose(SDL_Joystick *joystick)
1200
{
1201
}
1202
1203
void SDL_DINPUT_JoystickQuit(void)
1204
{
1205
}
1206
1207
#endif // SDL_JOYSTICK_DINPUT
1208
1209