1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if SDL_HAPTIC_DINPUT || SDL_HAPTIC_XINPUT
24
25 #include "SDL_assert.h"
26 #include "SDL_thread.h"
27 #include "SDL_mutex.h"
28 #include "SDL_timer.h"
29 #include "SDL_hints.h"
30 #include "SDL_haptic.h"
31 #include "../SDL_syshaptic.h"
32 #include "SDL_joystick.h"
33 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
34 #include "../../joystick/windows/SDL_windowsjoystick_c.h" /* For joystick hwdata */
35 #include "../../joystick/windows/SDL_xinputjoystick_c.h" /* For xinput rumble */
36
37 #include "SDL_windowshaptic_c.h"
38 #include "SDL_dinputhaptic_c.h"
39 #include "SDL_xinputhaptic_c.h"
40
41
42 /*
43 * Internal stuff.
44 */
45 SDL_hapticlist_item *SDL_hapticlist = NULL;
46 static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
47 static int numhaptics = 0;
48
49
50 /*
51 * Initializes the haptic subsystem.
52 */
53 int
SDL_SYS_HapticInit(void)54 SDL_SYS_HapticInit(void)
55 {
56 if (SDL_DINPUT_HapticInit() < 0) {
57 return -1;
58 }
59 if (SDL_XINPUT_HapticInit() < 0) {
60 return -1;
61 }
62 return numhaptics;
63 }
64
65 int
SDL_SYS_AddHapticDevice(SDL_hapticlist_item * item)66 SDL_SYS_AddHapticDevice(SDL_hapticlist_item *item)
67 {
68 if (SDL_hapticlist_tail == NULL) {
69 SDL_hapticlist = SDL_hapticlist_tail = item;
70 } else {
71 SDL_hapticlist_tail->next = item;
72 SDL_hapticlist_tail = item;
73 }
74
75 /* Device has been added. */
76 ++numhaptics;
77
78 return numhaptics;
79 }
80
81 int
SDL_SYS_RemoveHapticDevice(SDL_hapticlist_item * prev,SDL_hapticlist_item * item)82 SDL_SYS_RemoveHapticDevice(SDL_hapticlist_item *prev, SDL_hapticlist_item *item)
83 {
84 const int retval = item->haptic ? item->haptic->index : -1;
85 if (prev != NULL) {
86 prev->next = item->next;
87 } else {
88 SDL_assert(SDL_hapticlist == item);
89 SDL_hapticlist = item->next;
90 }
91 if (item == SDL_hapticlist_tail) {
92 SDL_hapticlist_tail = prev;
93 }
94 --numhaptics;
95 /* !!! TODO: Send a haptic remove event? */
96 SDL_free(item);
97 return retval;
98 }
99
100 int
SDL_SYS_NumHaptics()101 SDL_SYS_NumHaptics()
102 {
103 return numhaptics;
104 }
105
106 static SDL_hapticlist_item *
HapticByDevIndex(int device_index)107 HapticByDevIndex(int device_index)
108 {
109 SDL_hapticlist_item *item = SDL_hapticlist;
110
111 if ((device_index < 0) || (device_index >= numhaptics)) {
112 return NULL;
113 }
114
115 while (device_index > 0) {
116 SDL_assert(item != NULL);
117 --device_index;
118 item = item->next;
119 }
120 return item;
121 }
122
123 /*
124 * Return the name of a haptic device, does not need to be opened.
125 */
126 const char *
SDL_SYS_HapticName(int index)127 SDL_SYS_HapticName(int index)
128 {
129 SDL_hapticlist_item *item = HapticByDevIndex(index);
130 return item->name;
131 }
132
133 /*
134 * Opens a haptic device for usage.
135 */
136 int
SDL_SYS_HapticOpen(SDL_Haptic * haptic)137 SDL_SYS_HapticOpen(SDL_Haptic * haptic)
138 {
139 SDL_hapticlist_item *item = HapticByDevIndex(haptic->index);
140 if (item->bXInputHaptic) {
141 return SDL_XINPUT_HapticOpen(haptic, item);
142 } else {
143 return SDL_DINPUT_HapticOpen(haptic, item);
144 }
145 }
146
147
148 /*
149 * Opens a haptic device from first mouse it finds for usage.
150 */
151 int
SDL_SYS_HapticMouse(void)152 SDL_SYS_HapticMouse(void)
153 {
154 #if SDL_HAPTIC_DINPUT
155 SDL_hapticlist_item *item;
156 int index = 0;
157
158 /* Grab the first mouse haptic device we find. */
159 for (item = SDL_hapticlist; item != NULL; item = item->next) {
160 if (item->capabilities.dwDevType == DI8DEVCLASS_POINTER ) {
161 return index;
162 }
163 ++index;
164 }
165 #endif /* SDL_HAPTIC_DINPUT */
166 return -1;
167 }
168
169
170 /*
171 * Checks to see if a joystick has haptic features.
172 */
173 int
SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)174 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
175 {
176 const struct joystick_hwdata *hwdata = joystick->hwdata;
177 #if SDL_HAPTIC_XINPUT
178 if (hwdata->bXInputHaptic) {
179 return 1;
180 }
181 #endif
182 #if SDL_HAPTIC_DINPUT
183 if (hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
184 return 1;
185 }
186 #endif
187 return 0;
188 }
189
190 /*
191 * Checks to see if the haptic device and joystick are in reality the same.
192 */
193 int
SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic,SDL_Joystick * joystick)194 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
195 {
196 if (joystick->hwdata->bXInputHaptic != haptic->hwdata->bXInputHaptic) {
197 return 0; /* one is XInput, one is not; not the same device. */
198 } else if (joystick->hwdata->bXInputHaptic) {
199 return SDL_XINPUT_JoystickSameHaptic(haptic, joystick);
200 } else {
201 return SDL_DINPUT_JoystickSameHaptic(haptic, joystick);
202 }
203 }
204
205 /*
206 * Opens a SDL_Haptic from a SDL_Joystick.
207 */
208 int
SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic,SDL_Joystick * joystick)209 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
210 {
211 if (joystick->hwdata->bXInputDevice) {
212 return SDL_XINPUT_HapticOpenFromJoystick(haptic, joystick);
213 } else {
214 return SDL_DINPUT_HapticOpenFromJoystick(haptic, joystick);
215 }
216 }
217
218 /*
219 * Closes the haptic device.
220 */
221 void
SDL_SYS_HapticClose(SDL_Haptic * haptic)222 SDL_SYS_HapticClose(SDL_Haptic * haptic)
223 {
224 if (haptic->hwdata) {
225
226 /* Free effects. */
227 SDL_free(haptic->effects);
228 haptic->effects = NULL;
229 haptic->neffects = 0;
230
231 /* Clean up */
232 if (haptic->hwdata->bXInputHaptic) {
233 SDL_XINPUT_HapticClose(haptic);
234 } else {
235 SDL_DINPUT_HapticClose(haptic);
236 }
237
238 /* Free */
239 SDL_free(haptic->hwdata);
240 haptic->hwdata = NULL;
241 }
242 }
243
244 /*
245 * Clean up after system specific haptic stuff
246 */
247 void
SDL_SYS_HapticQuit(void)248 SDL_SYS_HapticQuit(void)
249 {
250 SDL_hapticlist_item *item;
251 SDL_hapticlist_item *next = NULL;
252 SDL_Haptic *hapticitem = NULL;
253
254 extern SDL_Haptic *SDL_haptics;
255 for (hapticitem = SDL_haptics; hapticitem; hapticitem = hapticitem->next) {
256 if ((hapticitem->hwdata->bXInputHaptic) && (hapticitem->hwdata->thread)) {
257 /* we _have_ to stop the thread before we free the XInput DLL! */
258 SDL_AtomicSet(&hapticitem->hwdata->stopThread, 1);
259 SDL_WaitThread(hapticitem->hwdata->thread, NULL);
260 hapticitem->hwdata->thread = NULL;
261 }
262 }
263
264 for (item = SDL_hapticlist; item; item = next) {
265 /* Opened and not closed haptics are leaked, this is on purpose.
266 * Close your haptic devices after usage. */
267 /* !!! FIXME: (...is leaking on purpose a good idea?) - No, of course not. */
268 next = item->next;
269 SDL_free(item->name);
270 SDL_free(item);
271 }
272
273 SDL_XINPUT_HapticQuit();
274 SDL_DINPUT_HapticQuit();
275
276 numhaptics = 0;
277 SDL_hapticlist = NULL;
278 SDL_hapticlist_tail = NULL;
279 }
280
281 /*
282 * Creates a new haptic effect.
283 */
284 int
SDL_SYS_HapticNewEffect(SDL_Haptic * haptic,struct haptic_effect * effect,SDL_HapticEffect * base)285 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
286 SDL_HapticEffect * base)
287 {
288 int result;
289
290 /* Alloc the effect. */
291 effect->hweffect = (struct haptic_hweffect *)
292 SDL_malloc(sizeof(struct haptic_hweffect));
293 if (effect->hweffect == NULL) {
294 SDL_OutOfMemory();
295 return -1;
296 }
297 SDL_zerop(effect->hweffect);
298
299 if (haptic->hwdata->bXInputHaptic) {
300 result = SDL_XINPUT_HapticNewEffect(haptic, effect, base);
301 } else {
302 result = SDL_DINPUT_HapticNewEffect(haptic, effect, base);
303 }
304 if (result < 0) {
305 SDL_free(effect->hweffect);
306 effect->hweffect = NULL;
307 }
308 return result;
309 }
310
311 /*
312 * Updates an effect.
313 */
314 int
SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,struct haptic_effect * effect,SDL_HapticEffect * data)315 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
316 struct haptic_effect *effect,
317 SDL_HapticEffect * data)
318 {
319 if (haptic->hwdata->bXInputHaptic) {
320 return SDL_XINPUT_HapticUpdateEffect(haptic, effect, data);
321 } else {
322 return SDL_DINPUT_HapticUpdateEffect(haptic, effect, data);
323 }
324 }
325
326 /*
327 * Runs an effect.
328 */
329 int
SDL_SYS_HapticRunEffect(SDL_Haptic * haptic,struct haptic_effect * effect,Uint32 iterations)330 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
331 Uint32 iterations)
332 {
333 if (haptic->hwdata->bXInputHaptic) {
334 return SDL_XINPUT_HapticRunEffect(haptic, effect, iterations);
335 } else {
336 return SDL_DINPUT_HapticRunEffect(haptic, effect, iterations);
337 }
338 }
339
340 /*
341 * Stops an effect.
342 */
343 int
SDL_SYS_HapticStopEffect(SDL_Haptic * haptic,struct haptic_effect * effect)344 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
345 {
346 if (haptic->hwdata->bXInputHaptic) {
347 return SDL_XINPUT_HapticStopEffect(haptic, effect);
348 } else {
349 return SDL_DINPUT_HapticStopEffect(haptic, effect);
350 }
351 }
352
353 /*
354 * Frees the effect.
355 */
356 void
SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic,struct haptic_effect * effect)357 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
358 {
359 if (haptic->hwdata->bXInputHaptic) {
360 SDL_XINPUT_HapticDestroyEffect(haptic, effect);
361 } else {
362 SDL_DINPUT_HapticDestroyEffect(haptic, effect);
363 }
364 SDL_free(effect->hweffect);
365 effect->hweffect = NULL;
366 }
367
368 /*
369 * Gets the status of a haptic effect.
370 */
371 int
SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,struct haptic_effect * effect)372 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
373 struct haptic_effect *effect)
374 {
375 if (haptic->hwdata->bXInputHaptic) {
376 return SDL_XINPUT_HapticGetEffectStatus(haptic, effect);
377 } else {
378 return SDL_DINPUT_HapticGetEffectStatus(haptic, effect);
379 }
380 }
381
382 /*
383 * Sets the gain.
384 */
385 int
SDL_SYS_HapticSetGain(SDL_Haptic * haptic,int gain)386 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
387 {
388 if (haptic->hwdata->bXInputHaptic) {
389 return SDL_XINPUT_HapticSetGain(haptic, gain);
390 } else {
391 return SDL_DINPUT_HapticSetGain(haptic, gain);
392 }
393 }
394
395 /*
396 * Sets the autocentering.
397 */
398 int
SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic,int autocenter)399 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
400 {
401 if (haptic->hwdata->bXInputHaptic) {
402 return SDL_XINPUT_HapticSetAutocenter(haptic, autocenter);
403 } else {
404 return SDL_DINPUT_HapticSetAutocenter(haptic, autocenter);
405 }
406 }
407
408 /*
409 * Pauses the device.
410 */
411 int
SDL_SYS_HapticPause(SDL_Haptic * haptic)412 SDL_SYS_HapticPause(SDL_Haptic * haptic)
413 {
414 if (haptic->hwdata->bXInputHaptic) {
415 return SDL_XINPUT_HapticPause(haptic);
416 } else {
417 return SDL_DINPUT_HapticPause(haptic);
418 }
419 }
420
421 /*
422 * Pauses the device.
423 */
424 int
SDL_SYS_HapticUnpause(SDL_Haptic * haptic)425 SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
426 {
427 if (haptic->hwdata->bXInputHaptic) {
428 return SDL_XINPUT_HapticUnpause(haptic);
429 } else {
430 return SDL_DINPUT_HapticUnpause(haptic);
431 }
432 }
433
434 /*
435 * Stops all the playing effects on the device.
436 */
437 int
SDL_SYS_HapticStopAll(SDL_Haptic * haptic)438 SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
439 {
440 if (haptic->hwdata->bXInputHaptic) {
441 return SDL_XINPUT_HapticStopAll(haptic);
442 } else {
443 return SDL_DINPUT_HapticStopAll(haptic);
444 }
445 }
446
447 #endif /* SDL_HAPTIC_DINPUT || SDL_HAPTIC_XINPUT */
448
449 /* vi: set ts=4 sw=4 expandtab: */
450