SDL  2.0
SDL_windowshaptic.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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  */
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
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
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
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
101 SDL_SYS_NumHaptics(void)
102 {
103  return numhaptics;
104 }
105 
106 static SDL_hapticlist_item *
107 HapticByDevIndex(int device_index)
108 {
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 *
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
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
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
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
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
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
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
248 SDL_SYS_HapticQuit(void)
249 {
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 
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
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
315 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
316  struct haptic_effect *effect,
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
330 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
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
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
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
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
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
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
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
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
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: */
int SDL_XINPUT_HapticInit(void)
int SDL_SYS_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
int SDL_XINPUT_HapticSetGain(SDL_Haptic *haptic, int gain)
int SDL_XINPUT_HapticUnpause(SDL_Haptic *haptic)
void SDL_DINPUT_HapticQuit(void)
int SDL_DINPUT_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
GLuint64EXT * result
int SDL_DINPUT_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
int SDL_XINPUT_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
int SDL_SYS_HapticOpen(SDL_Haptic *haptic)
int SDL_SYS_HapticMouse(void)
int SDL_SYS_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
int SDL_DINPUT_HapticSetGain(SDL_Haptic *haptic, int gain)
int SDL_SYS_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
const char * SDL_SYS_HapticName(int index)
int SDL_XINPUT_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
struct joystick_hwdata * next
The SDL haptic subsystem allows you to control haptic (force feedback) devices.
int SDL_SYS_HapticUnpause(SDL_Haptic *haptic)
int SDL_XINPUT_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
static int iterations
Definition: testsprite2.c:43
uint32_t Uint32
Definition: SDL_stdinc.h:181
int SDL_DINPUT_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
void SDL_DINPUT_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
int SDL_SYS_NumHaptics(void)
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
int SDL_DINPUT_HapticInit(void)
int SDL_SYS_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
int SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
int SDL_DINPUT_HapticOpen(SDL_Haptic *haptic, SDL_hapticlist_item *item)
int SDL_SYS_RemoveHapticDevice(SDL_hapticlist_item *prev, SDL_hapticlist_item *item)
SDL_hapticlist_item * SDL_hapticlist
struct SDL_hapticlist_item * next
SDL_bool retval
The generic template for any haptic effect.
Definition: SDL_haptic.h:789
int SDL_SYS_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
int SDL_DINPUT_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
int SDL_XINPUT_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
#define SDL_free
int SDL_XINPUT_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
int SDL_XINPUT_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
int SDL_SYS_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
int SDL_SYS_JoystickIsHaptic(SDL_Joystick *joystick)
void SDL_XINPUT_HapticClose(SDL_Haptic *haptic)
void SDL_DINPUT_HapticClose(SDL_Haptic *haptic)
int SDL_DINPUT_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
GLuint index
void SDL_SYS_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_XINPUT_HapticOpen(SDL_Haptic *haptic, SDL_hapticlist_item *item)
int SDL_DINPUT_HapticUnpause(SDL_Haptic *haptic)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
void SDL_XINPUT_HapticQuit(void)
static SDL_Haptic * haptic
Definition: testhaptic.c:25
int SDL_SYS_HapticInit(void)
void SDL_SYS_HapticQuit(void)
struct haptic_hweffect * hweffect
Definition: SDL_syshaptic.h:33
void SDL_SYS_HapticClose(SDL_Haptic *haptic)
int SDL_SYS_HapticPause(SDL_Haptic *haptic)
int SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
struct SDL_joylist_item * item
int SDL_DINPUT_HapticPause(SDL_Haptic *haptic)
#define SDL_AtomicSet
int SDL_XINPUT_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
int SDL_XINPUT_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
int SDL_XINPUT_HapticStopAll(SDL_Haptic *haptic)
int SDL_SYS_HapticStopAll(SDL_Haptic *haptic)
#define SDL_malloc
int SDL_DINPUT_HapticStopAll(SDL_Haptic *haptic)
int SDL_SYS_HapticSetGain(SDL_Haptic *haptic, int gain)
int SDL_DINPUT_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
int SDL_SYS_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
int SDL_XINPUT_HapticPause(SDL_Haptic *haptic)
void SDL_XINPUT_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
int SDL_SYS_AddHapticDevice(SDL_hapticlist_item *item)
#define SDL_WaitThread
int SDL_SYS_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
SDL_Haptic * SDL_haptics
Definition: SDL_haptic.c:29