• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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