2 * Plug and Play support for hid devices found through SDL2
4 * Copyright 2017 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include <sys/types.h>
41 #define WIN32_NO_STATUS
48 #include "ddk/hidtypes.h"
49 #include "ddk/hidsdi.h"
52 #include "wine/debug.h"
54 #include "wine/unixlib.h"
56 #include "unix_private.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(hid
);
62 static pthread_mutex_t sdl_cs
= PTHREAD_MUTEX_INITIALIZER
;
63 static struct sdl_bus_options options
;
65 static void *sdl_handle
= NULL
;
66 static UINT quit_event
= -1;
67 static struct list event_queue
= LIST_INIT(event_queue
);
68 static struct list device_list
= LIST_INIT(device_list
);
70 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
71 MAKE_FUNCPTR(SDL_GetError
);
72 MAKE_FUNCPTR(SDL_Init
);
73 MAKE_FUNCPTR(SDL_JoystickClose
);
74 MAKE_FUNCPTR(SDL_JoystickEventState
);
75 MAKE_FUNCPTR(SDL_JoystickGetGUID
);
76 MAKE_FUNCPTR(SDL_JoystickGetGUIDString
);
77 MAKE_FUNCPTR(SDL_JoystickInstanceID
);
78 MAKE_FUNCPTR(SDL_JoystickName
);
79 MAKE_FUNCPTR(SDL_JoystickNumAxes
);
80 MAKE_FUNCPTR(SDL_JoystickOpen
);
81 MAKE_FUNCPTR(SDL_WaitEventTimeout
);
82 MAKE_FUNCPTR(SDL_JoystickNumButtons
);
83 MAKE_FUNCPTR(SDL_JoystickNumBalls
);
84 MAKE_FUNCPTR(SDL_JoystickNumHats
);
85 MAKE_FUNCPTR(SDL_JoystickGetAxis
);
86 MAKE_FUNCPTR(SDL_JoystickGetHat
);
87 MAKE_FUNCPTR(SDL_IsGameController
);
88 MAKE_FUNCPTR(SDL_GameControllerClose
);
89 MAKE_FUNCPTR(SDL_GameControllerGetAxis
);
90 MAKE_FUNCPTR(SDL_GameControllerGetButton
);
91 MAKE_FUNCPTR(SDL_GameControllerName
);
92 MAKE_FUNCPTR(SDL_GameControllerOpen
);
93 MAKE_FUNCPTR(SDL_GameControllerEventState
);
94 MAKE_FUNCPTR(SDL_HapticClose
);
95 MAKE_FUNCPTR(SDL_HapticDestroyEffect
);
96 MAKE_FUNCPTR(SDL_HapticGetEffectStatus
);
97 MAKE_FUNCPTR(SDL_HapticNewEffect
);
98 MAKE_FUNCPTR(SDL_HapticOpenFromJoystick
);
99 MAKE_FUNCPTR(SDL_HapticPause
);
100 MAKE_FUNCPTR(SDL_HapticQuery
);
101 MAKE_FUNCPTR(SDL_HapticRumbleInit
);
102 MAKE_FUNCPTR(SDL_HapticRumblePlay
);
103 MAKE_FUNCPTR(SDL_HapticRumbleSupported
);
104 MAKE_FUNCPTR(SDL_HapticRunEffect
);
105 MAKE_FUNCPTR(SDL_HapticSetGain
);
106 MAKE_FUNCPTR(SDL_HapticStopAll
);
107 MAKE_FUNCPTR(SDL_HapticStopEffect
);
108 MAKE_FUNCPTR(SDL_HapticUnpause
);
109 MAKE_FUNCPTR(SDL_HapticUpdateEffect
);
110 MAKE_FUNCPTR(SDL_JoystickIsHaptic
);
111 MAKE_FUNCPTR(SDL_GameControllerAddMapping
);
112 MAKE_FUNCPTR(SDL_RegisterEvents
);
113 MAKE_FUNCPTR(SDL_PushEvent
);
114 MAKE_FUNCPTR(SDL_GetTicks
);
115 static int (*pSDL_JoystickRumble
)(SDL_Joystick
*joystick
, Uint16 low_frequency_rumble
, Uint16 high_frequency_rumble
, Uint32 duration_ms
);
116 static Uint16 (*pSDL_JoystickGetProduct
)(SDL_Joystick
* joystick
);
117 static Uint16 (*pSDL_JoystickGetProductVersion
)(SDL_Joystick
* joystick
);
118 static Uint16 (*pSDL_JoystickGetVendor
)(SDL_Joystick
* joystick
);
120 /* internal bits for extended rumble support, SDL_Haptic types are 16-bits */
121 #define WINE_SDL_JOYSTICK_RUMBLE 0x40000000 /* using SDL_JoystickRumble API */
122 #define WINE_SDL_HAPTIC_RUMBLE 0x80000000 /* using SDL_HapticRumble API */
124 #define EFFECT_SUPPORT_HAPTICS (SDL_HAPTIC_LEFTRIGHT|WINE_SDL_HAPTIC_RUMBLE|WINE_SDL_JOYSTICK_RUMBLE)
125 #define EFFECT_SUPPORT_PHYSICAL (SDL_HAPTIC_CONSTANT|SDL_HAPTIC_RAMP|SDL_HAPTIC_SINE|SDL_HAPTIC_TRIANGLE| \
126 SDL_HAPTIC_SAWTOOTHUP|SDL_HAPTIC_SAWTOOTHDOWN|SDL_HAPTIC_SPRING|SDL_HAPTIC_DAMPER|SDL_HAPTIC_INERTIA| \
127 SDL_HAPTIC_FRICTION|SDL_HAPTIC_CUSTOM)
131 struct unix_device unix_device
;
133 SDL_Joystick
*sdl_joystick
;
134 SDL_GameController
*sdl_controller
;
137 DWORD effect_support
;
138 SDL_Haptic
*sdl_haptic
;
139 int haptic_effect_id
;
141 int effect_state
[256];
145 static inline struct sdl_device
*impl_from_unix_device(struct unix_device
*iface
)
147 return CONTAINING_RECORD(iface
, struct sdl_device
, unix_device
);
150 static struct sdl_device
*find_device_from_id(SDL_JoystickID id
)
152 struct sdl_device
*impl
;
154 LIST_FOR_EACH_ENTRY(impl
, &device_list
, struct sdl_device
, unix_device
.entry
)
155 if (impl
->id
== id
) return impl
;
160 static void set_hat_value(struct unix_device
*iface
, int index
, int value
)
165 case SDL_HAT_CENTERED
: break;
166 case SDL_HAT_DOWN
: y
= 1; break;
167 case SDL_HAT_RIGHTDOWN
: y
= x
= 1; break;
168 case SDL_HAT_RIGHT
: x
= 1; break;
169 case SDL_HAT_RIGHTUP
: x
= 1; y
= -1; break;
170 case SDL_HAT_UP
: y
= -1; break;
171 case SDL_HAT_LEFTUP
: x
= y
= -1; break;
172 case SDL_HAT_LEFT
: x
= -1; break;
173 case SDL_HAT_LEFTDOWN
: x
= -1; y
= 1; break;
175 hid_device_set_hatswitch_x(iface
, index
, x
);
176 hid_device_set_hatswitch_y(iface
, index
, y
);
179 static BOOL
descriptor_add_haptic(struct sdl_device
*impl
)
184 if (!pSDL_JoystickIsHaptic(impl
->sdl_joystick
) ||
185 !(impl
->sdl_haptic
= pSDL_HapticOpenFromJoystick(impl
->sdl_joystick
)))
186 impl
->effect_support
= 0;
189 impl
->effect_support
= pSDL_HapticQuery(impl
->sdl_haptic
);
190 if (pSDL_HapticRumbleSupported(impl
->sdl_haptic
))
191 impl
->effect_support
|= WINE_SDL_HAPTIC_RUMBLE
;
193 pSDL_HapticStopAll(impl
->sdl_haptic
);
194 pSDL_HapticRumbleInit(impl
->sdl_haptic
);
197 if (!(impl
->effect_support
& EFFECT_SUPPORT_HAPTICS
) && pSDL_JoystickRumble
&&
198 !pSDL_JoystickRumble(impl
->sdl_joystick
, 0, 0, 0))
199 impl
->effect_support
|= WINE_SDL_JOYSTICK_RUMBLE
;
201 if (impl
->effect_support
& EFFECT_SUPPORT_HAPTICS
)
203 if (!hid_device_add_haptics(&impl
->unix_device
))
207 if ((impl
->effect_support
& EFFECT_SUPPORT_PHYSICAL
))
209 /* SDL_HAPTIC_SQUARE doesn't exist */
210 if (impl
->effect_support
& SDL_HAPTIC_SINE
) usages
[count
++] = PID_USAGE_ET_SINE
;
211 if (impl
->effect_support
& SDL_HAPTIC_TRIANGLE
) usages
[count
++] = PID_USAGE_ET_TRIANGLE
;
212 if (impl
->effect_support
& SDL_HAPTIC_SAWTOOTHUP
) usages
[count
++] = PID_USAGE_ET_SAWTOOTH_UP
;
213 if (impl
->effect_support
& SDL_HAPTIC_SAWTOOTHDOWN
) usages
[count
++] = PID_USAGE_ET_SAWTOOTH_DOWN
;
214 if (impl
->effect_support
& SDL_HAPTIC_SPRING
) usages
[count
++] = PID_USAGE_ET_SPRING
;
215 if (impl
->effect_support
& SDL_HAPTIC_DAMPER
) usages
[count
++] = PID_USAGE_ET_DAMPER
;
216 if (impl
->effect_support
& SDL_HAPTIC_INERTIA
) usages
[count
++] = PID_USAGE_ET_INERTIA
;
217 if (impl
->effect_support
& SDL_HAPTIC_FRICTION
) usages
[count
++] = PID_USAGE_ET_FRICTION
;
218 if (impl
->effect_support
& SDL_HAPTIC_CONSTANT
) usages
[count
++] = PID_USAGE_ET_CONSTANT_FORCE
;
219 if (impl
->effect_support
& SDL_HAPTIC_RAMP
) usages
[count
++] = PID_USAGE_ET_RAMP
;
221 if (!hid_device_add_physical(&impl
->unix_device
, usages
, count
))
225 impl
->haptic_effect_id
= -1;
226 for (i
= 0; i
< ARRAY_SIZE(impl
->effect_ids
); ++i
) impl
->effect_ids
[i
] = -1;
230 static NTSTATUS
build_joystick_report_descriptor(struct unix_device
*iface
)
232 static const USAGE_AND_PAGE absolute_usages
[] =
234 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_X
},
235 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_Y
},
236 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_Z
},
237 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_RX
},
238 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_RY
},
239 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_RZ
},
240 {.UsagePage
= HID_USAGE_PAGE_SIMULATION
, .Usage
= HID_USAGE_SIMULATION_THROTTLE
},
241 {.UsagePage
= HID_USAGE_PAGE_SIMULATION
, .Usage
= HID_USAGE_SIMULATION_RUDDER
},
242 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_WHEEL
},
243 {.UsagePage
= HID_USAGE_PAGE_SIMULATION
, .Usage
= HID_USAGE_SIMULATION_ACCELERATOR
},
244 {.UsagePage
= HID_USAGE_PAGE_SIMULATION
, .Usage
= HID_USAGE_SIMULATION_BRAKE
},
246 static const USAGE_AND_PAGE relative_usages
[] =
248 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_X
},
249 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_Y
},
250 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_RX
},
251 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_RY
},
252 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_Z
},
253 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_RZ
},
254 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_SLIDER
},
255 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_DIAL
},
256 {.UsagePage
= HID_USAGE_PAGE_GENERIC
, .Usage
= HID_USAGE_GENERIC_WHEEL
},
258 struct sdl_device
*impl
= impl_from_unix_device(iface
);
259 int i
, button_count
, axis_count
, ball_count
, hat_count
;
261 axis_count
= pSDL_JoystickNumAxes(impl
->sdl_joystick
);
262 if (axis_count
> ARRAY_SIZE(absolute_usages
))
264 FIXME("More than %zu absolute axes found, ignoring.\n", ARRAY_SIZE(absolute_usages
));
265 axis_count
= ARRAY_SIZE(absolute_usages
);
268 ball_count
= pSDL_JoystickNumBalls(impl
->sdl_joystick
);
269 if (ball_count
> ARRAY_SIZE(relative_usages
) / 2)
271 FIXME("More than %zu relative axes found, ignoring.\n", ARRAY_SIZE(relative_usages
));
272 ball_count
= ARRAY_SIZE(relative_usages
) / 2;
275 hat_count
= pSDL_JoystickNumHats(impl
->sdl_joystick
);
276 button_count
= pSDL_JoystickNumButtons(impl
->sdl_joystick
);
278 if (!hid_device_begin_report_descriptor(iface
, HID_USAGE_PAGE_GENERIC
, HID_USAGE_GENERIC_JOYSTICK
))
279 return STATUS_NO_MEMORY
;
281 if (!hid_device_begin_input_report(iface
))
282 return STATUS_NO_MEMORY
;
284 for (i
= 0; i
< axis_count
; i
++)
286 if (!hid_device_add_axes(iface
, 1, absolute_usages
[i
].UsagePage
,
287 &absolute_usages
[i
].Usage
, FALSE
, -32768, 32767))
288 return STATUS_NO_MEMORY
;
291 for (i
= 0; i
< ball_count
; i
++)
293 if (!hid_device_add_axes(iface
, 2, relative_usages
[2 * i
].UsagePage
,
294 &relative_usages
[2 * i
].Usage
, TRUE
, INT32_MIN
, INT32_MAX
))
295 return STATUS_NO_MEMORY
;
298 if (hat_count
&& !hid_device_add_hatswitch(iface
, hat_count
))
299 return STATUS_NO_MEMORY
;
301 if (button_count
&& !hid_device_add_buttons(iface
, HID_USAGE_PAGE_BUTTON
, 1, button_count
))
302 return STATUS_NO_MEMORY
;
304 if (!hid_device_end_input_report(iface
))
305 return STATUS_NO_MEMORY
;
307 if (!descriptor_add_haptic(impl
))
308 return STATUS_NO_MEMORY
;
310 if (!hid_device_end_report_descriptor(iface
))
311 return STATUS_NO_MEMORY
;
313 /* Initialize axis in the report */
314 for (i
= 0; i
< axis_count
; i
++)
315 hid_device_set_abs_axis(iface
, i
, pSDL_JoystickGetAxis(impl
->sdl_joystick
, i
));
316 for (i
= 0; i
< hat_count
; i
++)
317 set_hat_value(iface
, i
, pSDL_JoystickGetHat(impl
->sdl_joystick
, i
));
319 return STATUS_SUCCESS
;
322 static NTSTATUS
build_controller_report_descriptor(struct unix_device
*iface
)
324 static const USAGE left_axis_usages
[] = {HID_USAGE_GENERIC_X
, HID_USAGE_GENERIC_Y
};
325 static const USAGE right_axis_usages
[] = {HID_USAGE_GENERIC_RX
, HID_USAGE_GENERIC_RY
};
326 static const USAGE trigger_axis_usages
[] = {HID_USAGE_GENERIC_Z
, HID_USAGE_GENERIC_RZ
};
327 struct sdl_device
*impl
= impl_from_unix_device(iface
);
328 ULONG i
, button_count
= SDL_CONTROLLER_BUTTON_MAX
- 1;
329 C_ASSERT(SDL_CONTROLLER_AXIS_MAX
== 6);
331 if (!hid_device_begin_report_descriptor(iface
, HID_USAGE_PAGE_GENERIC
, HID_USAGE_GENERIC_GAMEPAD
))
332 return STATUS_NO_MEMORY
;
334 if (!hid_device_begin_input_report(iface
))
335 return STATUS_NO_MEMORY
;
337 if (!hid_device_add_axes(iface
, 2, HID_USAGE_PAGE_GENERIC
, left_axis_usages
,
338 FALSE
, -32768, 32767))
339 return STATUS_NO_MEMORY
;
341 if (!hid_device_add_axes(iface
, 2, HID_USAGE_PAGE_GENERIC
, right_axis_usages
,
342 FALSE
, -32768, 32767))
343 return STATUS_NO_MEMORY
;
345 if (!hid_device_add_axes(iface
, 2, HID_USAGE_PAGE_GENERIC
, trigger_axis_usages
,
347 return STATUS_NO_MEMORY
;
349 if (!hid_device_add_hatswitch(iface
, 1))
350 return STATUS_NO_MEMORY
;
352 if (!hid_device_add_buttons(iface
, HID_USAGE_PAGE_BUTTON
, 1, button_count
))
353 return STATUS_NO_MEMORY
;
355 if (!hid_device_end_input_report(iface
))
356 return STATUS_NO_MEMORY
;
358 if (!descriptor_add_haptic(impl
))
359 return STATUS_NO_MEMORY
;
361 if (!hid_device_end_report_descriptor(iface
))
362 return STATUS_NO_MEMORY
;
364 /* Initialize axis in the report */
365 for (i
= SDL_CONTROLLER_AXIS_LEFTX
; i
< SDL_CONTROLLER_AXIS_MAX
; i
++)
366 hid_device_set_abs_axis(iface
, i
, pSDL_GameControllerGetAxis(impl
->sdl_controller
, i
));
367 if (pSDL_GameControllerGetButton(impl
->sdl_controller
, SDL_CONTROLLER_BUTTON_DPAD_UP
))
368 hid_device_set_hatswitch_y(iface
, 0, -1);
369 if (pSDL_GameControllerGetButton(impl
->sdl_controller
, SDL_CONTROLLER_BUTTON_DPAD_DOWN
))
370 hid_device_set_hatswitch_y(iface
, 0, +1);
371 if (pSDL_GameControllerGetButton(impl
->sdl_controller
, SDL_CONTROLLER_BUTTON_DPAD_LEFT
))
372 hid_device_set_hatswitch_x(iface
, 0, -1);
373 if (pSDL_GameControllerGetButton(impl
->sdl_controller
, SDL_CONTROLLER_BUTTON_DPAD_RIGHT
))
374 hid_device_set_hatswitch_x(iface
, 0, +1);
376 return STATUS_SUCCESS
;
379 static void sdl_device_destroy(struct unix_device
*iface
)
383 static NTSTATUS
sdl_device_start(struct unix_device
*iface
)
385 struct sdl_device
*impl
= impl_from_unix_device(iface
);
386 if (impl
->sdl_controller
) return build_controller_report_descriptor(iface
);
387 return build_joystick_report_descriptor(iface
);
390 static void sdl_device_stop(struct unix_device
*iface
)
392 struct sdl_device
*impl
= impl_from_unix_device(iface
);
394 pSDL_JoystickClose(impl
->sdl_joystick
);
395 if (impl
->sdl_controller
) pSDL_GameControllerClose(impl
->sdl_controller
);
396 if (impl
->sdl_haptic
) pSDL_HapticClose(impl
->sdl_haptic
);
398 pthread_mutex_lock(&sdl_cs
);
399 list_remove(&impl
->unix_device
.entry
);
400 pthread_mutex_unlock(&sdl_cs
);
403 NTSTATUS
sdl_device_haptics_start(struct unix_device
*iface
, DWORD duration_ms
,
404 USHORT rumble_intensity
, USHORT buzz_intensity
)
406 struct sdl_device
*impl
= impl_from_unix_device(iface
);
407 SDL_HapticEffect effect
;
409 TRACE("iface %p, duration_ms %u, rumble_intensity %u, buzz_intensity %u.\n", iface
, duration_ms
,
410 rumble_intensity
, buzz_intensity
);
412 if (!(impl
->effect_support
& EFFECT_SUPPORT_HAPTICS
)) return STATUS_NOT_SUPPORTED
;
414 memset(&effect
, 0, sizeof(SDL_HapticEffect
));
415 effect
.type
= SDL_HAPTIC_LEFTRIGHT
;
416 effect
.leftright
.length
= duration_ms
;
417 effect
.leftright
.large_magnitude
= rumble_intensity
;
418 effect
.leftright
.small_magnitude
= buzz_intensity
;
420 if (impl
->effect_support
& WINE_SDL_JOYSTICK_RUMBLE
)
421 pSDL_JoystickRumble(impl
->sdl_joystick
, 0, 0, 0);
422 else if (impl
->sdl_haptic
)
423 pSDL_HapticStopAll(impl
->sdl_haptic
);
424 if (!effect
.leftright
.large_magnitude
&& !effect
.leftright
.small_magnitude
)
425 return STATUS_SUCCESS
;
427 if (impl
->effect_support
& SDL_HAPTIC_LEFTRIGHT
)
429 if (impl
->haptic_effect_id
>= 0)
430 pSDL_HapticDestroyEffect(impl
->sdl_haptic
, impl
->haptic_effect_id
);
431 impl
->haptic_effect_id
= pSDL_HapticNewEffect(impl
->sdl_haptic
, &effect
);
432 if (impl
->haptic_effect_id
>= 0)
433 pSDL_HapticRunEffect(impl
->sdl_haptic
, impl
->haptic_effect_id
, 1);
435 else if (impl
->effect_support
& WINE_SDL_HAPTIC_RUMBLE
)
437 float magnitude
= (effect
.leftright
.large_magnitude
+ effect
.leftright
.small_magnitude
) / 2.0 / 32767.0;
438 pSDL_HapticRumblePlay(impl
->sdl_haptic
, magnitude
, effect
.leftright
.length
);
440 else if (impl
->effect_support
& WINE_SDL_JOYSTICK_RUMBLE
)
442 pSDL_JoystickRumble(impl
->sdl_joystick
, effect
.leftright
.large_magnitude
,
443 effect
.leftright
.small_magnitude
, duration_ms
);
446 return STATUS_SUCCESS
;
449 static NTSTATUS
sdl_device_physical_device_control(struct unix_device
*iface
, USAGE control
)
451 struct sdl_device
*impl
= impl_from_unix_device(iface
);
454 TRACE("iface %p, control %#04x.\n", iface
, control
);
458 case PID_USAGE_DC_ENABLE_ACTUATORS
:
459 pSDL_HapticSetGain(impl
->sdl_haptic
, 100);
460 InterlockedOr(&impl
->effect_flags
, EFFECT_STATE_ACTUATORS_ENABLED
);
461 return STATUS_SUCCESS
;
462 case PID_USAGE_DC_DISABLE_ACTUATORS
:
463 pSDL_HapticSetGain(impl
->sdl_haptic
, 0);
464 InterlockedAnd(&impl
->effect_flags
, ~EFFECT_STATE_ACTUATORS_ENABLED
);
465 return STATUS_SUCCESS
;
466 case PID_USAGE_DC_STOP_ALL_EFFECTS
:
467 pSDL_HapticStopAll(impl
->sdl_haptic
);
468 return STATUS_SUCCESS
;
469 case PID_USAGE_DC_DEVICE_RESET
:
470 pSDL_HapticStopAll(impl
->sdl_haptic
);
471 for (i
= 0; i
< ARRAY_SIZE(impl
->effect_ids
); ++i
)
473 if (impl
->effect_ids
[i
] < 0) continue;
474 pSDL_HapticDestroyEffect(impl
->sdl_haptic
, impl
->effect_ids
[i
]);
475 impl
->effect_ids
[i
] = -1;
477 return STATUS_SUCCESS
;
478 case PID_USAGE_DC_DEVICE_PAUSE
:
479 pSDL_HapticPause(impl
->sdl_haptic
);
480 InterlockedOr(&impl
->effect_flags
, EFFECT_STATE_DEVICE_PAUSED
);
481 return STATUS_SUCCESS
;
482 case PID_USAGE_DC_DEVICE_CONTINUE
:
483 pSDL_HapticUnpause(impl
->sdl_haptic
);
484 InterlockedAnd(&impl
->effect_flags
, ~EFFECT_STATE_DEVICE_PAUSED
);
485 return STATUS_SUCCESS
;
488 return STATUS_NOT_SUPPORTED
;
491 static NTSTATUS
sdl_device_physical_device_set_gain(struct unix_device
*iface
, BYTE percent
)
493 struct sdl_device
*impl
= impl_from_unix_device(iface
);
495 TRACE("iface %p, percent %#x.\n", iface
, percent
);
497 pSDL_HapticSetGain(impl
->sdl_haptic
, percent
);
499 return STATUS_SUCCESS
;
502 static NTSTATUS
sdl_device_physical_effect_control(struct unix_device
*iface
, BYTE index
,
503 USAGE control
, BYTE iterations
)
505 struct sdl_device
*impl
= impl_from_unix_device(iface
);
506 int id
= impl
->effect_ids
[index
];
508 TRACE("iface %p, index %u, control %04x, iterations %u.\n", iface
, index
, control
, iterations
);
510 if (impl
->effect_ids
[index
] < 0) return STATUS_UNSUCCESSFUL
;
514 case PID_USAGE_OP_EFFECT_START_SOLO
:
515 pSDL_HapticStopAll(impl
->sdl_haptic
);
517 case PID_USAGE_OP_EFFECT_START
:
518 pSDL_HapticRunEffect(impl
->sdl_haptic
, id
, (iterations
== 0xff ? SDL_HAPTIC_INFINITY
: iterations
));
520 case PID_USAGE_OP_EFFECT_STOP
:
521 pSDL_HapticStopEffect(impl
->sdl_haptic
, id
);
525 return STATUS_SUCCESS
;
528 static NTSTATUS
set_effect_type_from_usage(SDL_HapticEffect
*effect
, USAGE type
)
532 case PID_USAGE_ET_SINE
:
533 effect
->type
= SDL_HAPTIC_SINE
;
534 return STATUS_SUCCESS
;
535 case PID_USAGE_ET_TRIANGLE
:
536 effect
->type
= SDL_HAPTIC_TRIANGLE
;
537 return STATUS_SUCCESS
;
538 case PID_USAGE_ET_SAWTOOTH_UP
:
539 effect
->type
= SDL_HAPTIC_SAWTOOTHUP
;
540 return STATUS_SUCCESS
;
541 case PID_USAGE_ET_SAWTOOTH_DOWN
:
542 effect
->type
= SDL_HAPTIC_SAWTOOTHDOWN
;
543 return STATUS_SUCCESS
;
544 case PID_USAGE_ET_SPRING
:
545 effect
->type
= SDL_HAPTIC_SPRING
;
546 return STATUS_SUCCESS
;
547 case PID_USAGE_ET_DAMPER
:
548 effect
->type
= SDL_HAPTIC_DAMPER
;
549 return STATUS_SUCCESS
;
550 case PID_USAGE_ET_INERTIA
:
551 effect
->type
= SDL_HAPTIC_INERTIA
;
552 return STATUS_SUCCESS
;
553 case PID_USAGE_ET_FRICTION
:
554 effect
->type
= SDL_HAPTIC_FRICTION
;
555 return STATUS_SUCCESS
;
556 case PID_USAGE_ET_CONSTANT_FORCE
:
557 effect
->type
= SDL_HAPTIC_CONSTANT
;
558 return STATUS_SUCCESS
;
559 case PID_USAGE_ET_RAMP
:
560 effect
->type
= SDL_HAPTIC_RAMP
;
561 return STATUS_SUCCESS
;
562 case PID_USAGE_ET_CUSTOM_FORCE_DATA
:
563 effect
->type
= SDL_HAPTIC_CUSTOM
;
564 return STATUS_SUCCESS
;
566 return STATUS_NOT_SUPPORTED
;
570 static NTSTATUS
sdl_device_physical_effect_update(struct unix_device
*iface
, BYTE index
,
571 struct effect_params
*params
)
573 struct sdl_device
*impl
= impl_from_unix_device(iface
);
574 int id
= impl
->effect_ids
[index
];
575 SDL_HapticEffect effect
= {0};
579 TRACE("iface %p, index %u, params %p.\n", iface
, index
, params
);
581 if (params
->effect_type
== PID_USAGE_UNDEFINED
) return STATUS_SUCCESS
;
582 if ((status
= set_effect_type_from_usage(&effect
, params
->effect_type
))) return status
;
584 /* The first direction we get from PID is in polar coordinate space, so we need to
585 * remove 90° to make it match SDL spherical coordinates. */
586 direction
= (params
->direction
[0] - 9000) % 36000;
588 switch (params
->effect_type
)
590 case PID_USAGE_ET_SINE
:
591 case PID_USAGE_ET_SQUARE
:
592 case PID_USAGE_ET_TRIANGLE
:
593 case PID_USAGE_ET_SAWTOOTH_UP
:
594 case PID_USAGE_ET_SAWTOOTH_DOWN
:
595 effect
.periodic
.length
= (params
->duration
== 0xffff ? SDL_HAPTIC_INFINITY
: params
->duration
);
596 effect
.periodic
.delay
= params
->start_delay
;
597 effect
.periodic
.button
= params
->trigger_button
;
598 effect
.periodic
.interval
= params
->trigger_repeat_interval
;
599 effect
.periodic
.direction
.type
= SDL_HAPTIC_SPHERICAL
;
600 effect
.periodic
.direction
.dir
[0] = direction
;
601 effect
.periodic
.direction
.dir
[1] = params
->direction
[1];
602 effect
.periodic
.period
= params
->periodic
.period
;
603 effect
.periodic
.magnitude
= params
->periodic
.magnitude
;
604 effect
.periodic
.offset
= params
->periodic
.offset
;
605 effect
.periodic
.phase
= params
->periodic
.phase
;
606 effect
.periodic
.attack_length
= params
->envelope
.attack_time
;
607 effect
.periodic
.attack_level
= params
->envelope
.attack_level
;
608 effect
.periodic
.fade_length
= params
->envelope
.fade_time
;
609 effect
.periodic
.fade_level
= params
->envelope
.fade_level
;
612 case PID_USAGE_ET_SPRING
:
613 case PID_USAGE_ET_DAMPER
:
614 case PID_USAGE_ET_INERTIA
:
615 case PID_USAGE_ET_FRICTION
:
616 effect
.condition
.length
= (params
->duration
== 0xffff ? SDL_HAPTIC_INFINITY
: params
->duration
);
617 effect
.condition
.delay
= params
->start_delay
;
618 effect
.condition
.button
= params
->trigger_button
;
619 effect
.condition
.interval
= params
->trigger_repeat_interval
;
620 effect
.condition
.direction
.type
= SDL_HAPTIC_SPHERICAL
;
621 effect
.condition
.direction
.dir
[0] = direction
;
622 effect
.condition
.direction
.dir
[1] = params
->direction
[1];
623 if (params
->condition_count
>= 1)
625 effect
.condition
.right_sat
[0] = params
->condition
[0].positive_saturation
;
626 effect
.condition
.left_sat
[0] = params
->condition
[0].negative_saturation
;
627 effect
.condition
.right_coeff
[0] = params
->condition
[0].positive_coefficient
;
628 effect
.condition
.left_coeff
[0] = params
->condition
[0].negative_coefficient
;
629 effect
.condition
.deadband
[0] = params
->condition
[0].dead_band
;
630 effect
.condition
.center
[0] = params
->condition
[0].center_point_offset
;
632 if (params
->condition_count
>= 2)
634 effect
.condition
.right_sat
[1] = params
->condition
[1].positive_saturation
;
635 effect
.condition
.left_sat
[1] = params
->condition
[1].negative_saturation
;
636 effect
.condition
.right_coeff
[1] = params
->condition
[1].positive_coefficient
;
637 effect
.condition
.left_coeff
[1] = params
->condition
[1].negative_coefficient
;
638 effect
.condition
.deadband
[1] = params
->condition
[1].dead_band
;
639 effect
.condition
.center
[1] = params
->condition
[1].center_point_offset
;
643 case PID_USAGE_ET_CONSTANT_FORCE
:
644 effect
.constant
.length
= (params
->duration
== 0xffff ? SDL_HAPTIC_INFINITY
: params
->duration
);
645 effect
.constant
.delay
= params
->start_delay
;
646 effect
.constant
.button
= params
->trigger_button
;
647 effect
.constant
.interval
= params
->trigger_repeat_interval
;
648 effect
.constant
.direction
.type
= SDL_HAPTIC_SPHERICAL
;
649 effect
.constant
.direction
.dir
[0] = direction
;
650 effect
.constant
.direction
.dir
[1] = params
->direction
[1];
651 effect
.constant
.level
= params
->constant_force
.magnitude
;
652 effect
.constant
.attack_length
= params
->envelope
.attack_time
;
653 effect
.constant
.attack_level
= params
->envelope
.attack_level
;
654 effect
.constant
.fade_length
= params
->envelope
.fade_time
;
655 effect
.constant
.fade_level
= params
->envelope
.fade_level
;
658 /* According to the SDL documentation, ramp effect doesn't
659 * support SDL_HAPTIC_INFINITY. */
660 case PID_USAGE_ET_RAMP
:
661 effect
.ramp
.length
= params
->duration
;
662 effect
.ramp
.delay
= params
->start_delay
;
663 effect
.ramp
.button
= params
->trigger_button
;
664 effect
.ramp
.interval
= params
->trigger_repeat_interval
;
665 effect
.ramp
.direction
.type
= SDL_HAPTIC_SPHERICAL
;
666 effect
.ramp
.direction
.dir
[0] = params
->direction
[0];
667 effect
.ramp
.direction
.dir
[1] = params
->direction
[1];
668 effect
.ramp
.start
= params
->ramp_force
.ramp_start
;
669 effect
.ramp
.end
= params
->ramp_force
.ramp_end
;
670 effect
.ramp
.attack_length
= params
->envelope
.attack_time
;
671 effect
.ramp
.attack_level
= params
->envelope
.attack_level
;
672 effect
.ramp
.fade_length
= params
->envelope
.fade_time
;
673 effect
.ramp
.fade_level
= params
->envelope
.fade_level
;
676 case PID_USAGE_ET_CUSTOM_FORCE_DATA
:
677 FIXME("not implemented!\n");
681 if (id
< 0) impl
->effect_ids
[index
] = pSDL_HapticNewEffect(impl
->sdl_haptic
, &effect
);
682 else pSDL_HapticUpdateEffect(impl
->sdl_haptic
, id
, &effect
);
684 return STATUS_SUCCESS
;
687 static const struct hid_device_vtbl sdl_device_vtbl
=
692 sdl_device_haptics_start
,
693 sdl_device_physical_device_control
,
694 sdl_device_physical_device_set_gain
,
695 sdl_device_physical_effect_control
,
696 sdl_device_physical_effect_update
,
699 static void check_device_effects_state(struct sdl_device
*impl
)
701 struct unix_device
*iface
= &impl
->unix_device
;
702 struct hid_effect_state
*effect_state
= &iface
->hid_physical
.effect_state
;
703 ULONG effect_flags
= InterlockedOr(&impl
->effect_flags
, 0);
706 if (!impl
->sdl_haptic
) return;
707 if (!(impl
->effect_support
& SDL_HAPTIC_STATUS
)) return;
709 for (i
= 0; i
< ARRAY_SIZE(impl
->effect_ids
); ++i
)
711 if (impl
->effect_ids
[i
] == -1) continue;
712 ret
= pSDL_HapticGetEffectStatus(impl
->sdl_haptic
, impl
->effect_ids
[i
]);
713 if (impl
->effect_state
[i
] == ret
) continue;
714 impl
->effect_state
[i
] = ret
;
715 hid_device_set_effect_state(iface
, i
, effect_flags
| (ret
== 1 ? EFFECT_STATE_EFFECT_PLAYING
: 0));
716 bus_event_queue_input_report(&event_queue
, iface
, effect_state
->report_buf
, effect_state
->report_len
);
720 static void check_all_devices_effects_state(void)
722 static UINT last_ticks
= 0;
723 UINT ticks
= pSDL_GetTicks();
724 struct sdl_device
*impl
;
726 if (ticks
- last_ticks
< 10) return;
729 pthread_mutex_lock(&sdl_cs
);
730 LIST_FOR_EACH_ENTRY(impl
, &device_list
, struct sdl_device
, unix_device
.entry
)
731 check_device_effects_state(impl
);
732 pthread_mutex_unlock(&sdl_cs
);
735 static BOOL
set_report_from_joystick_event(struct sdl_device
*impl
, SDL_Event
*event
)
737 struct unix_device
*iface
= &impl
->unix_device
;
738 struct hid_device_state
*state
= &iface
->hid_device_state
;
740 if (impl
->sdl_controller
) return TRUE
; /* use controller events instead */
744 case SDL_JOYBUTTONDOWN
:
745 case SDL_JOYBUTTONUP
:
747 SDL_JoyButtonEvent
*ie
= &event
->jbutton
;
749 hid_device_set_button(iface
, ie
->button
, ie
->state
);
750 bus_event_queue_input_report(&event_queue
, iface
, state
->report_buf
, state
->report_len
);
753 case SDL_JOYAXISMOTION
:
755 SDL_JoyAxisEvent
*ie
= &event
->jaxis
;
757 hid_device_set_abs_axis(iface
, ie
->axis
, ie
->value
);
758 bus_event_queue_input_report(&event_queue
, iface
, state
->report_buf
, state
->report_len
);
761 case SDL_JOYBALLMOTION
:
763 SDL_JoyBallEvent
*ie
= &event
->jball
;
765 hid_device_set_rel_axis(iface
, 2 * ie
->ball
, ie
->xrel
);
766 hid_device_set_rel_axis(iface
, 2 * ie
->ball
+ 1, ie
->yrel
);
767 bus_event_queue_input_report(&event_queue
, iface
, state
->report_buf
, state
->report_len
);
770 case SDL_JOYHATMOTION
:
772 SDL_JoyHatEvent
*ie
= &event
->jhat
;
774 set_hat_value(iface
, ie
->hat
, ie
->value
);
775 bus_event_queue_input_report(&event_queue
, iface
, state
->report_buf
, state
->report_len
);
779 ERR("TODO: Process Report (0x%x)\n",event
->type
);
782 check_device_effects_state(impl
);
786 static BOOL
set_report_from_controller_event(struct sdl_device
*impl
, SDL_Event
*event
)
788 struct unix_device
*iface
= &impl
->unix_device
;
789 struct hid_device_state
*state
= &iface
->hid_device_state
;
793 case SDL_CONTROLLERBUTTONDOWN
:
794 case SDL_CONTROLLERBUTTONUP
:
796 SDL_ControllerButtonEvent
*ie
= &event
->cbutton
;
799 switch ((button
= ie
->button
))
801 case SDL_CONTROLLER_BUTTON_DPAD_UP
:
802 hid_device_set_hatswitch_y(iface
, 0, ie
->state
? -1 : 0);
804 case SDL_CONTROLLER_BUTTON_DPAD_DOWN
:
805 hid_device_set_hatswitch_y(iface
, 0, ie
->state
? +1 : 0);
807 case SDL_CONTROLLER_BUTTON_DPAD_LEFT
:
808 hid_device_set_hatswitch_x(iface
, 0, ie
->state
? -1 : 0);
810 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT
:
811 hid_device_set_hatswitch_x(iface
, 0, ie
->state
? +1 : 0);
813 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER
: button
= 4; break;
814 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
: button
= 5; break;
815 case SDL_CONTROLLER_BUTTON_BACK
: button
= 6; break;
816 case SDL_CONTROLLER_BUTTON_START
: button
= 7; break;
817 case SDL_CONTROLLER_BUTTON_LEFTSTICK
: button
= 8; break;
818 case SDL_CONTROLLER_BUTTON_RIGHTSTICK
: button
= 9; break;
819 case SDL_CONTROLLER_BUTTON_GUIDE
: button
= 10; break;
822 hid_device_set_button(iface
, button
, ie
->state
);
823 bus_event_queue_input_report(&event_queue
, iface
, state
->report_buf
, state
->report_len
);
826 case SDL_CONTROLLERAXISMOTION
:
828 SDL_ControllerAxisEvent
*ie
= &event
->caxis
;
830 hid_device_set_abs_axis(iface
, ie
->axis
, ie
->value
);
831 bus_event_queue_input_report(&event_queue
, iface
, state
->report_buf
, state
->report_len
);
835 ERR("TODO: Process Report (%x)\n",event
->type
);
838 check_device_effects_state(impl
);
842 static void sdl_add_device(unsigned int index
)
844 struct device_desc desc
=
847 .manufacturer
= {'S','D','L',0},
848 .serialnumber
= {'0','0','0','0',0},
850 struct sdl_device
*impl
;
852 SDL_Joystick
* joystick
;
854 SDL_JoystickGUID guid
;
855 SDL_GameController
*controller
= NULL
;
859 if ((joystick
= pSDL_JoystickOpen(index
)) == NULL
)
861 WARN("Unable to open sdl device %i: %s\n", index
, pSDL_GetError());
865 if (options
.map_controllers
&& pSDL_IsGameController(index
))
866 controller
= pSDL_GameControllerOpen(index
);
868 if (controller
) str
= pSDL_GameControllerName(controller
);
869 else str
= pSDL_JoystickName(joystick
);
870 if (str
) ntdll_umbstowcs(str
, strlen(str
) + 1, desc
.product
, ARRAY_SIZE(desc
.product
));
872 id
= pSDL_JoystickInstanceID(joystick
);
874 if (pSDL_JoystickGetProductVersion
!= NULL
) {
875 desc
.vid
= pSDL_JoystickGetVendor(joystick
);
876 desc
.pid
= pSDL_JoystickGetProduct(joystick
);
877 desc
.version
= pSDL_JoystickGetProductVersion(joystick
);
882 desc
.pid
= pSDL_JoystickInstanceID(joystick
) + 1;
886 guid
= pSDL_JoystickGetGUID(joystick
);
887 pSDL_JoystickGetGUIDString(guid
, guid_str
, sizeof(guid_str
));
888 ntdll_umbstowcs(guid_str
, strlen(guid_str
) + 1, desc
.serialnumber
, ARRAY_SIZE(desc
.serialnumber
));
890 if (controller
) desc
.is_gamepad
= TRUE
;
893 int button_count
, axis_count
;
895 axis_count
= pSDL_JoystickNumAxes(joystick
);
896 button_count
= pSDL_JoystickNumButtons(joystick
);
897 desc
.is_gamepad
= (axis_count
== 6 && button_count
>= 14);
900 TRACE("%s id %d, desc %s.\n", controller
? "controller" : "joystick", id
, debugstr_device_desc(&desc
));
902 if (!(impl
= hid_device_create(&sdl_device_vtbl
, sizeof(struct sdl_device
)))) return;
903 list_add_tail(&device_list
, &impl
->unix_device
.entry
);
904 impl
->sdl_joystick
= joystick
;
905 impl
->sdl_controller
= controller
;
908 bus_event_queue_device_created(&event_queue
, &impl
->unix_device
, &desc
);
911 static void process_device_event(SDL_Event
*event
)
913 struct sdl_device
*impl
;
916 TRACE("Received action %x\n", event
->type
);
918 pthread_mutex_lock(&sdl_cs
);
920 if (event
->type
== SDL_JOYDEVICEADDED
)
921 sdl_add_device(((SDL_JoyDeviceEvent
*)event
)->which
);
922 else if (event
->type
== SDL_JOYDEVICEREMOVED
)
924 id
= ((SDL_JoyDeviceEvent
*)event
)->which
;
925 impl
= find_device_from_id(id
);
926 if (impl
) bus_event_queue_device_removed(&event_queue
, &impl
->unix_device
);
927 else WARN("failed to find device with id %d\n", id
);
929 else if (event
->type
>= SDL_JOYAXISMOTION
&& event
->type
<= SDL_JOYBUTTONUP
)
931 id
= ((SDL_JoyButtonEvent
*)event
)->which
;
932 impl
= find_device_from_id(id
);
933 if (impl
) set_report_from_joystick_event(impl
, event
);
934 else WARN("failed to find device with id %d\n", id
);
936 else if (event
->type
>= SDL_CONTROLLERAXISMOTION
&& event
->type
<= SDL_CONTROLLERBUTTONUP
)
938 id
= ((SDL_ControllerButtonEvent
*)event
)->which
;
939 impl
= find_device_from_id(id
);
940 if (impl
) set_report_from_controller_event(impl
, event
);
941 else WARN("failed to find device with id %d\n", id
);
944 pthread_mutex_unlock(&sdl_cs
);
947 NTSTATUS
sdl_bus_init(void *args
)
952 TRACE("args %p\n", args
);
954 options
= *(struct sdl_bus_options
*)args
;
956 if (!(sdl_handle
= dlopen(SONAME_LIBSDL2
, RTLD_NOW
)))
958 WARN("could not load %s\n", SONAME_LIBSDL2
);
959 return STATUS_UNSUCCESSFUL
;
961 #define LOAD_FUNCPTR(f) \
962 if ((p##f = dlsym(sdl_handle, #f)) == NULL) \
964 WARN("could not find symbol %s\n", #f); \
967 LOAD_FUNCPTR(SDL_GetError
);
968 LOAD_FUNCPTR(SDL_Init
);
969 LOAD_FUNCPTR(SDL_JoystickClose
);
970 LOAD_FUNCPTR(SDL_JoystickEventState
);
971 LOAD_FUNCPTR(SDL_JoystickGetGUID
);
972 LOAD_FUNCPTR(SDL_JoystickGetGUIDString
);
973 LOAD_FUNCPTR(SDL_JoystickInstanceID
);
974 LOAD_FUNCPTR(SDL_JoystickName
);
975 LOAD_FUNCPTR(SDL_JoystickNumAxes
);
976 LOAD_FUNCPTR(SDL_JoystickOpen
);
977 LOAD_FUNCPTR(SDL_WaitEventTimeout
);
978 LOAD_FUNCPTR(SDL_JoystickNumButtons
);
979 LOAD_FUNCPTR(SDL_JoystickNumBalls
);
980 LOAD_FUNCPTR(SDL_JoystickNumHats
);
981 LOAD_FUNCPTR(SDL_JoystickGetAxis
);
982 LOAD_FUNCPTR(SDL_JoystickGetHat
);
983 LOAD_FUNCPTR(SDL_IsGameController
);
984 LOAD_FUNCPTR(SDL_GameControllerClose
);
985 LOAD_FUNCPTR(SDL_GameControllerGetAxis
);
986 LOAD_FUNCPTR(SDL_GameControllerGetButton
);
987 LOAD_FUNCPTR(SDL_GameControllerName
);
988 LOAD_FUNCPTR(SDL_GameControllerOpen
);
989 LOAD_FUNCPTR(SDL_GameControllerEventState
);
990 LOAD_FUNCPTR(SDL_HapticClose
);
991 LOAD_FUNCPTR(SDL_HapticDestroyEffect
);
992 LOAD_FUNCPTR(SDL_HapticGetEffectStatus
);
993 LOAD_FUNCPTR(SDL_HapticNewEffect
);
994 LOAD_FUNCPTR(SDL_HapticOpenFromJoystick
);
995 LOAD_FUNCPTR(SDL_HapticPause
);
996 LOAD_FUNCPTR(SDL_HapticQuery
);
997 LOAD_FUNCPTR(SDL_HapticRumbleInit
);
998 LOAD_FUNCPTR(SDL_HapticRumblePlay
);
999 LOAD_FUNCPTR(SDL_HapticRumbleSupported
);
1000 LOAD_FUNCPTR(SDL_HapticRunEffect
);
1001 LOAD_FUNCPTR(SDL_HapticSetGain
);
1002 LOAD_FUNCPTR(SDL_HapticStopAll
);
1003 LOAD_FUNCPTR(SDL_HapticStopEffect
);
1004 LOAD_FUNCPTR(SDL_HapticUnpause
);
1005 LOAD_FUNCPTR(SDL_HapticUpdateEffect
);
1006 LOAD_FUNCPTR(SDL_JoystickIsHaptic
);
1007 LOAD_FUNCPTR(SDL_GameControllerAddMapping
);
1008 LOAD_FUNCPTR(SDL_RegisterEvents
);
1009 LOAD_FUNCPTR(SDL_PushEvent
);
1010 LOAD_FUNCPTR(SDL_GetTicks
);
1012 pSDL_JoystickRumble
= dlsym(sdl_handle
, "SDL_JoystickRumble");
1013 pSDL_JoystickGetProduct
= dlsym(sdl_handle
, "SDL_JoystickGetProduct");
1014 pSDL_JoystickGetProductVersion
= dlsym(sdl_handle
, "SDL_JoystickGetProductVersion");
1015 pSDL_JoystickGetVendor
= dlsym(sdl_handle
, "SDL_JoystickGetVendor");
1017 if (pSDL_Init(SDL_INIT_GAMECONTROLLER
| SDL_INIT_HAPTIC
) < 0)
1019 ERR("could not init SDL: %s\n", pSDL_GetError());
1023 if ((quit_event
= pSDL_RegisterEvents(1)) == -1)
1025 ERR("error registering quit event\n");
1029 pSDL_JoystickEventState(SDL_ENABLE
);
1030 pSDL_GameControllerEventState(SDL_ENABLE
);
1032 /* Process mappings */
1033 if (pSDL_GameControllerAddMapping
)
1035 if ((mapping
= getenv("SDL_GAMECONTROLLERCONFIG")))
1037 TRACE("Setting environment mapping %s\n", debugstr_a(mapping
));
1038 if (pSDL_GameControllerAddMapping(mapping
) < 0)
1039 WARN("Failed to add environment mapping %s\n", pSDL_GetError());
1041 else for (i
= 0; i
< options
.mappings_count
; ++i
)
1043 TRACE("Setting registry mapping %s\n", debugstr_a(options
.mappings
[i
]));
1044 if (pSDL_GameControllerAddMapping(options
.mappings
[i
]) < 0)
1045 WARN("Failed to add registry mapping %s\n", pSDL_GetError());
1049 return STATUS_SUCCESS
;
1052 dlclose(sdl_handle
);
1054 return STATUS_UNSUCCESSFUL
;
1057 NTSTATUS
sdl_bus_wait(void *args
)
1059 struct bus_event
*result
= args
;
1062 /* cleanup previously returned event */
1063 bus_event_cleanup(result
);
1067 if (bus_event_queue_pop(&event_queue
, result
)) return STATUS_PENDING
;
1068 if (pSDL_WaitEventTimeout(&event
, 10) != 0) process_device_event(&event
);
1069 else check_all_devices_effects_state();
1070 } while (event
.type
!= quit_event
);
1072 TRACE("SDL main loop exiting\n");
1073 bus_event_queue_destroy(&event_queue
);
1074 dlclose(sdl_handle
);
1076 return STATUS_SUCCESS
;
1079 NTSTATUS
sdl_bus_stop(void *args
)
1083 if (!sdl_handle
) return STATUS_SUCCESS
;
1085 event
.type
= quit_event
;
1086 if (pSDL_PushEvent(&event
) != 1)
1088 ERR("error pushing quit event\n");
1089 return STATUS_UNSUCCESSFUL
;
1092 return STATUS_SUCCESS
;
1097 NTSTATUS
sdl_bus_init(void *args
)
1099 WARN("SDL support not compiled in!\n");
1100 return STATUS_NOT_IMPLEMENTED
;
1103 NTSTATUS
sdl_bus_wait(void *args
)
1105 WARN("SDL support not compiled in!\n");
1106 return STATUS_NOT_IMPLEMENTED
;
1109 NTSTATUS
sdl_bus_stop(void *args
)
1111 WARN("SDL support not compiled in!\n");
1112 return STATUS_NOT_IMPLEMENTED
;
1115 #endif /* SONAME_LIBSDL2 */