winebus.sys: Use SDL_HAPTIC_INFINITY for the infinity durations in the SDL backend.
[wine.git] / dlls / winebus.sys / bus_sdl.c
blob37d75d0bc951139242b9f4c0e6bb727d7152ec21
1 /*
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
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <dlfcn.h>
34 #ifdef HAVE_SDL_H
35 # include <SDL.h>
36 #endif
38 #include <pthread.h>
40 #include "ntstatus.h"
41 #define WIN32_NO_STATUS
42 #include "windef.h"
43 #include "winbase.h"
44 #include "winnls.h"
45 #include "winreg.h"
46 #include "winternl.h"
47 #include "ddk/wdm.h"
48 #include "ddk/hidtypes.h"
49 #include "ddk/hidsdi.h"
50 #include "hidusage.h"
52 #include "wine/debug.h"
53 #include "wine/hid.h"
54 #include "wine/unixlib.h"
56 #include "unix_private.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(hid);
60 #ifdef SONAME_LIBSDL2
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)
129 struct sdl_device
131 struct unix_device unix_device;
133 SDL_Joystick *sdl_joystick;
134 SDL_GameController *sdl_controller;
135 SDL_JoystickID id;
137 DWORD effect_support;
138 SDL_Haptic *sdl_haptic;
139 int haptic_effect_id;
140 int effect_ids[256];
141 int effect_state[256];
142 LONG effect_flags;
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;
157 return NULL;
160 static void set_hat_value(struct unix_device *iface, int index, int value)
162 LONG x = 0, y = 0;
163 switch (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)
181 USHORT i, count = 0;
182 USAGE usages[16];
184 if (!pSDL_JoystickIsHaptic(impl->sdl_joystick) ||
185 !(impl->sdl_haptic = pSDL_HapticOpenFromJoystick(impl->sdl_joystick)))
186 impl->effect_support = 0;
187 else
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))
204 return FALSE;
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))
222 return FALSE;
225 impl->haptic_effect_id = -1;
226 for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) impl->effect_ids[i] = -1;
227 return TRUE;
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,
346 FALSE, 0, 32767))
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);
452 unsigned int i;
454 TRACE("iface %p, control %#04x.\n", iface, control);
456 switch (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;
512 switch (control)
514 case PID_USAGE_OP_EFFECT_START_SOLO:
515 pSDL_HapticStopAll(impl->sdl_haptic);
516 /* fallthrough */
517 case PID_USAGE_OP_EFFECT_START:
518 pSDL_HapticRunEffect(impl->sdl_haptic, id, (iterations == 0xff ? SDL_HAPTIC_INFINITY : iterations));
519 break;
520 case PID_USAGE_OP_EFFECT_STOP:
521 pSDL_HapticStopEffect(impl->sdl_haptic, id);
522 break;
525 return STATUS_SUCCESS;
528 static NTSTATUS set_effect_type_from_usage(SDL_HapticEffect *effect, USAGE type)
530 switch (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;
565 default:
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};
576 UINT16 direction;
577 NTSTATUS status;
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;
610 break;
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;
641 break;
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;
656 break;
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;
674 break;
676 case PID_USAGE_ET_CUSTOM_FORCE_DATA:
677 FIXME("not implemented!\n");
678 break;
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 =
689 sdl_device_destroy,
690 sdl_device_start,
691 sdl_device_stop,
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);
704 unsigned int i, ret;
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;
727 last_ticks = ticks;
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 */
742 switch (event->type)
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);
751 break;
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);
759 break;
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);
768 break;
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);
776 break;
778 default:
779 ERR("TODO: Process Report (0x%x)\n",event->type);
782 check_device_effects_state(impl);
783 return FALSE;
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;
791 switch (event->type)
793 case SDL_CONTROLLERBUTTONDOWN:
794 case SDL_CONTROLLERBUTTONUP:
796 SDL_ControllerButtonEvent *ie = &event->cbutton;
797 int button;
799 switch ((button = ie->button))
801 case SDL_CONTROLLER_BUTTON_DPAD_UP:
802 hid_device_set_hatswitch_y(iface, 0, ie->state ? -1 : 0);
803 break;
804 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
805 hid_device_set_hatswitch_y(iface, 0, ie->state ? +1 : 0);
806 break;
807 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
808 hid_device_set_hatswitch_x(iface, 0, ie->state ? -1 : 0);
809 break;
810 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
811 hid_device_set_hatswitch_x(iface, 0, ie->state ? +1 : 0);
812 break;
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);
824 break;
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);
832 break;
834 default:
835 ERR("TODO: Process Report (%x)\n",event->type);
838 check_device_effects_state(impl);
839 return FALSE;
842 static void sdl_add_device(unsigned int index)
844 struct device_desc desc =
846 .input = -1,
847 .manufacturer = {'S','D','L',0},
848 .serialnumber = {'0','0','0','0',0},
850 struct sdl_device *impl;
852 SDL_Joystick* joystick;
853 SDL_JoystickID id;
854 SDL_JoystickGUID guid;
855 SDL_GameController *controller = NULL;
856 const char *str;
857 char guid_str[33];
859 if ((joystick = pSDL_JoystickOpen(index)) == NULL)
861 WARN("Unable to open sdl device %i: %s\n", index, pSDL_GetError());
862 return;
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);
879 else
881 desc.vid = 0x01;
882 desc.pid = pSDL_JoystickInstanceID(joystick) + 1;
883 desc.version = 0;
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;
891 else
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;
906 impl->id = id;
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;
914 SDL_JoystickID id;
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)
949 const char *mapping;
950 int i;
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); \
965 goto failed; \
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);
1011 #undef LOAD_FUNCPTR
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());
1020 goto failed;
1023 if ((quit_event = pSDL_RegisterEvents(1)) == -1)
1025 ERR("error registering quit event\n");
1026 goto failed;
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;
1051 failed:
1052 dlclose(sdl_handle);
1053 sdl_handle = NULL;
1054 return STATUS_UNSUCCESSFUL;
1057 NTSTATUS sdl_bus_wait(void *args)
1059 struct bus_event *result = args;
1060 SDL_Event event;
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);
1075 sdl_handle = NULL;
1076 return STATUS_SUCCESS;
1079 NTSTATUS sdl_bus_stop(void *args)
1081 SDL_Event event;
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;
1095 #else
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 */