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