SDL  2.0
SDL_dinputhaptic.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 #include "SDL_error.h"
24 #include "SDL_haptic.h"
25 #include "../SDL_syshaptic.h"
26 
27 #if SDL_HAPTIC_DINPUT
28 
29 #include "SDL_stdinc.h"
30 #include "SDL_timer.h"
31 #include "SDL_windowshaptic_c.h"
32 #include "SDL_dinputhaptic_c.h"
33 #include "../../joystick/windows/SDL_windowsjoystick_c.h"
34 
35 /*
36  * External stuff.
37  */
38 extern HWND SDL_HelperWindow;
39 
40 
41 /*
42  * Internal stuff.
43  */
44 static SDL_bool coinitialized = SDL_FALSE;
45 static LPDIRECTINPUT8 dinput = NULL;
46 
47 
48 /*
49  * Like SDL_SetError but for DX error codes.
50  */
51 static int
52 DI_SetError(const char *str, HRESULT err)
53 {
54  /*
55  SDL_SetError("Haptic: %s - %s: %s", str,
56  DXGetErrorString8A(err), DXGetErrorDescription8A(err));
57  */
58  return SDL_SetError("Haptic error %s", str);
59 }
60 
61 /*
62  * Callback to find the haptic devices.
63  */
64 static BOOL CALLBACK
65 EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
66 {
67  (void) pContext;
68  SDL_DINPUT_MaybeAddDevice(pdidInstance);
69  return DIENUM_CONTINUE; /* continue enumerating */
70 }
71 
72 int
74 {
75  HRESULT ret;
76  HINSTANCE instance;
77 
78  if (dinput != NULL) { /* Already open. */
79  return SDL_SetError("Haptic: SubSystem already open.");
80  }
81 
82  ret = WIN_CoInitialize();
83  if (FAILED(ret)) {
84  return DI_SetError("Coinitialize", ret);
85  }
86 
87  coinitialized = SDL_TRUE;
88 
89  ret = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER,
90  &IID_IDirectInput8, (LPVOID)& dinput);
91  if (FAILED(ret)) {
93  return DI_SetError("CoCreateInstance", ret);
94  }
95 
96  /* Because we used CoCreateInstance, we need to Initialize it, first. */
97  instance = GetModuleHandle(NULL);
98  if (instance == NULL) {
100  return SDL_SetError("GetModuleHandle() failed with error code %lu.",
101  GetLastError());
102  }
103  ret = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION);
104  if (FAILED(ret)) {
106  return DI_SetError("Initializing DirectInput device", ret);
107  }
108 
109  /* Look for haptic devices. */
110  ret = IDirectInput8_EnumDevices(dinput,
111  0,
112  EnumHapticsCallback,
113  NULL,
114  DIEDFL_FORCEFEEDBACK |
115  DIEDFL_ATTACHEDONLY);
116  if (FAILED(ret)) {
118  return DI_SetError("Enumerating DirectInput devices", ret);
119  }
120  return 0;
121 }
122 
123 int
124 SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
125 {
126  HRESULT ret;
127  LPDIRECTINPUTDEVICE8 device;
128  const DWORD needflags = DIDC_ATTACHED | DIDC_FORCEFEEDBACK;
129  DIDEVCAPS capabilities;
130  SDL_hapticlist_item *item = NULL;
131 
132  if (dinput == NULL) {
133  return -1; /* not initialized. We'll pick these up on enumeration if we init later. */
134  }
135 
136  /* Make sure we don't already have it */
137  for (item = SDL_hapticlist; item; item = item->next) {
138  if ((!item->bXInputHaptic) && (SDL_memcmp(&item->instance, pdidInstance, sizeof(*pdidInstance)) == 0)) {
139  return -1; /* Already added */
140  }
141  }
142 
143  /* Open the device */
144  ret = IDirectInput8_CreateDevice(dinput, &pdidInstance->guidInstance, &device, NULL);
145  if (FAILED(ret)) {
146  /* DI_SetError("Creating DirectInput device",ret); */
147  return -1;
148  }
149 
150  /* Get capabilities. */
151  SDL_zero(capabilities);
152  capabilities.dwSize = sizeof(DIDEVCAPS);
153  ret = IDirectInputDevice8_GetCapabilities(device, &capabilities);
154  IDirectInputDevice8_Release(device);
155  if (FAILED(ret)) {
156  /* DI_SetError("Getting device capabilities",ret); */
157  return -1;
158  }
159 
160  if ((capabilities.dwFlags & needflags) != needflags) {
161  return -1; /* not a device we can use. */
162  }
163 
164  item = (SDL_hapticlist_item *)SDL_calloc(1, sizeof(SDL_hapticlist_item));
165  if (item == NULL) {
166  return SDL_OutOfMemory();
167  }
168 
169  item->name = WIN_StringToUTF8(pdidInstance->tszProductName);
170  if (!item->name) {
171  SDL_free(item);
172  return -1;
173  }
174 
175  /* Copy the instance over, useful for creating devices. */
176  SDL_memcpy(&item->instance, pdidInstance, sizeof(DIDEVICEINSTANCE));
177  SDL_memcpy(&item->capabilities, &capabilities, sizeof(capabilities));
178 
179  return SDL_SYS_AddHapticDevice(item);
180 }
181 
182 int
184 {
185  SDL_hapticlist_item *item;
186  SDL_hapticlist_item *prev = NULL;
187 
188  if (dinput == NULL) {
189  return -1; /* not initialized, ignore this. */
190  }
191 
192  for (item = SDL_hapticlist; item != NULL; item = item->next) {
193  if (!item->bXInputHaptic && SDL_memcmp(&item->instance, pdidInstance, sizeof(*pdidInstance)) == 0) {
194  /* found it, remove it. */
195  return SDL_SYS_RemoveHapticDevice(prev, item);
196  }
197  prev = item;
198  }
199  return -1;
200 }
201 
202 /*
203  * Callback to get supported axes.
204  */
205 static BOOL CALLBACK
206 DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
207 {
208  SDL_Haptic *haptic = (SDL_Haptic *) pvRef;
209 
210  if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) {
211  const GUID *guid = &dev->guidType;
212  DWORD offset = 0;
213  if (WIN_IsEqualGUID(guid, &GUID_XAxis)) {
214  offset = DIJOFS_X;
215  } else if (WIN_IsEqualGUID(guid, &GUID_YAxis)) {
216  offset = DIJOFS_Y;
217  } else if (WIN_IsEqualGUID(guid, &GUID_ZAxis)) {
218  offset = DIJOFS_Z;
219  } else if (WIN_IsEqualGUID(guid, &GUID_RxAxis)) {
220  offset = DIJOFS_RX;
221  } else if (WIN_IsEqualGUID(guid, &GUID_RyAxis)) {
222  offset = DIJOFS_RY;
223  } else if (WIN_IsEqualGUID(guid, &GUID_RzAxis)) {
224  offset = DIJOFS_RZ;
225  } else {
226  return DIENUM_CONTINUE; /* can't use this, go on. */
227  }
228 
229  haptic->hwdata->axes[haptic->naxes] = offset;
230  haptic->naxes++;
231 
232  /* Currently using the artificial limit of 3 axes. */
233  if (haptic->naxes >= 3) {
234  return DIENUM_STOP;
235  }
236  }
237 
238  return DIENUM_CONTINUE;
239 }
240 
241 /*
242  * Callback to get all supported effects.
243  */
244 #define EFFECT_TEST(e,s) \
245 if (WIN_IsEqualGUID(&pei->guid, &(e))) \
246  haptic->supported |= (s)
247 static BOOL CALLBACK
248 DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv)
249 {
250  /* Prepare the haptic device. */
251  SDL_Haptic *haptic = (SDL_Haptic *) pv;
252 
253  /* Get supported. */
254  EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING);
255  EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER);
256  EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA);
257  EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION);
258  EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT);
259  EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM);
260  EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE);
261  /* !!! FIXME: put this back when we have more bits in 2.1 */
262  /* EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE); */
263  EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE);
264  EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP);
265  EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN);
266  EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP);
267 
268  /* Check for more. */
269  return DIENUM_CONTINUE;
270 }
271 
272 /*
273  * Opens the haptic device.
274  *
275  * Steps:
276  * - Set cooperative level.
277  * - Set data format.
278  * - Acquire exclusiveness.
279  * - Reset actuators.
280  * - Get supported features.
281  */
282 static int
283 SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device8, SDL_bool is_joystick)
284 {
285  HRESULT ret;
286  DIPROPDWORD dipdw;
287 
288  /* Allocate the hwdata */
289  haptic->hwdata = (struct haptic_hwdata *)SDL_malloc(sizeof(*haptic->hwdata));
290  if (haptic->hwdata == NULL) {
291  return SDL_OutOfMemory();
292  }
293  SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
294 
295  /* We'll use the device8 from now on. */
296  haptic->hwdata->device = device8;
297  haptic->hwdata->is_joystick = is_joystick;
298 
299  /* !!! FIXME: opening a haptic device here first will make an attempt to
300  !!! FIXME: SDL_JoystickOpen() that same device fail later, since we
301  !!! FIXME: have it open in exclusive mode. But this will allow
302  !!! FIXME: SDL_JoystickOpen() followed by SDL_HapticOpenFromJoystick()
303  !!! FIXME: to work, and that's probably the common case. Still,
304  !!! FIXME: ideally, We need to unify the opening code. */
305 
306  if (!is_joystick) { /* if is_joystick, we already set this up elsewhere. */
307  /* Grab it exclusively to use force feedback stuff. */
308  ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device,
309  SDL_HelperWindow,
310  DISCL_EXCLUSIVE |
311  DISCL_BACKGROUND);
312  if (FAILED(ret)) {
313  DI_SetError("Setting cooperative level to exclusive", ret);
314  goto acquire_err;
315  }
316 
317  /* Set data format. */
318  ret = IDirectInputDevice8_SetDataFormat(haptic->hwdata->device,
319  &SDL_c_dfDIJoystick2);
320  if (FAILED(ret)) {
321  DI_SetError("Setting data format", ret);
322  goto acquire_err;
323  }
324 
325 
326  /* Acquire the device. */
327  ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
328  if (FAILED(ret)) {
329  DI_SetError("Acquiring DirectInput device", ret);
330  goto acquire_err;
331  }
332  }
333 
334  /* Get number of axes. */
335  ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device,
336  DI_DeviceObjectCallback,
337  haptic, DIDFT_AXIS);
338  if (FAILED(ret)) {
339  DI_SetError("Getting device axes", ret);
340  goto acquire_err;
341  }
342 
343  /* Reset all actuators - just in case. */
344  ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
345  DISFFC_RESET);
346  if (FAILED(ret)) {
347  DI_SetError("Resetting device", ret);
348  goto acquire_err;
349  }
350 
351  /* Enabling actuators. */
352  ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
353  DISFFC_SETACTUATORSON);
354  if (FAILED(ret)) {
355  DI_SetError("Enabling actuators", ret);
356  goto acquire_err;
357  }
358 
359  /* Get supported effects. */
360  ret = IDirectInputDevice8_EnumEffects(haptic->hwdata->device,
361  DI_EffectCallback, haptic,
362  DIEFT_ALL);
363  if (FAILED(ret)) {
364  DI_SetError("Enumerating supported effects", ret);
365  goto acquire_err;
366  }
367  if (haptic->supported == 0) { /* Error since device supports nothing. */
368  SDL_SetError("Haptic: Internal error on finding supported effects.");
369  goto acquire_err;
370  }
371 
372  /* Check autogain and autocenter. */
373  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
374  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
375  dipdw.diph.dwObj = 0;
376  dipdw.diph.dwHow = DIPH_DEVICE;
377  dipdw.dwData = 10000;
378  ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
379  DIPROP_FFGAIN, &dipdw.diph);
380  if (!FAILED(ret)) { /* Gain is supported. */
381  haptic->supported |= SDL_HAPTIC_GAIN;
382  }
383  dipdw.diph.dwObj = 0;
384  dipdw.diph.dwHow = DIPH_DEVICE;
385  dipdw.dwData = DIPROPAUTOCENTER_OFF;
386  ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
387  DIPROP_AUTOCENTER, &dipdw.diph);
388  if (!FAILED(ret)) { /* Autocenter is supported. */
389  haptic->supported |= SDL_HAPTIC_AUTOCENTER;
390  }
391 
392  /* Status is always supported. */
393  haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
394 
395  /* Check maximum effects. */
396  haptic->neffects = 128; /* This is not actually supported as thus under windows,
397  there is no way to tell the number of EFFECTS that a
398  device can hold, so we'll just use a "random" number
399  instead and put warnings in SDL_haptic.h */
400  haptic->nplaying = 128; /* Even more impossible to get this then neffects. */
401 
402  /* Prepare effects memory. */
403  haptic->effects = (struct haptic_effect *)
404  SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
405  if (haptic->effects == NULL) {
406  SDL_OutOfMemory();
407  goto acquire_err;
408  }
409  /* Clear the memory */
410  SDL_memset(haptic->effects, 0,
411  sizeof(struct haptic_effect) * haptic->neffects);
412 
413  return 0;
414 
415  /* Error handling */
416  acquire_err:
417  IDirectInputDevice8_Unacquire(haptic->hwdata->device);
418  return -1;
419 }
420 
421 int
422 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
423 {
424  HRESULT ret;
425  LPDIRECTINPUTDEVICE8 device;
426  LPDIRECTINPUTDEVICE8 device8;
427 
428  /* Open the device */
429  ret = IDirectInput8_CreateDevice(dinput, &item->instance.guidInstance,
430  &device, NULL);
431  if (FAILED(ret)) {
432  DI_SetError("Creating DirectInput device", ret);
433  return -1;
434  }
435 
436  /* Now get the IDirectInputDevice8 interface, instead. */
437  ret = IDirectInputDevice8_QueryInterface(device,
438  &IID_IDirectInputDevice8,
439  (LPVOID *)&device8);
440  /* Done with the temporary one now. */
441  IDirectInputDevice8_Release(device);
442  if (FAILED(ret)) {
443  DI_SetError("Querying DirectInput interface", ret);
444  return -1;
445  }
446 
447  if (SDL_DINPUT_HapticOpenFromDevice(haptic, device8, SDL_FALSE) < 0) {
448  IDirectInputDevice8_Release(device8);
449  return -1;
450  }
451  return 0;
452 }
453 
454 int
455 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
456 {
457  HRESULT ret;
458  DIDEVICEINSTANCE hap_instance, joy_instance;
459 
460  hap_instance.dwSize = sizeof(DIDEVICEINSTANCE);
461  joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
462 
463  /* Get the device instances. */
464  ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device,
465  &hap_instance);
466  if (FAILED(ret)) {
467  return 0;
468  }
469  ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
470  &joy_instance);
471  if (FAILED(ret)) {
472  return 0;
473  }
474 
475  return WIN_IsEqualGUID(&hap_instance.guidInstance, &joy_instance.guidInstance);
476 }
477 
478 int
479 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
480 {
481  SDL_hapticlist_item *item;
482  int index = 0;
483  HRESULT ret;
484  DIDEVICEINSTANCE joy_instance;
485 
486  joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
487  ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance);
488  if (FAILED(ret)) {
489  return -1;
490  }
491 
492  /* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */
493  for (item = SDL_hapticlist; item != NULL; item = item->next) {
494  if (!item->bXInputHaptic && WIN_IsEqualGUID(&item->instance.guidInstance, &joy_instance.guidInstance)) {
495  haptic->index = index;
496  return SDL_DINPUT_HapticOpenFromDevice(haptic, joystick->hwdata->InputDevice, SDL_TRUE);
497  }
498  ++index;
499  }
500 
501  SDL_SetError("Couldn't find joystick in haptic device list");
502  return -1;
503 }
504 
505 void
506 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
507 {
508  IDirectInputDevice8_Unacquire(haptic->hwdata->device);
509 
510  /* Only release if isn't grabbed by a joystick. */
511  if (haptic->hwdata->is_joystick == 0) {
512  IDirectInputDevice8_Release(haptic->hwdata->device);
513  }
514 }
515 
516 void
518 {
519  if (dinput != NULL) {
520  IDirectInput8_Release(dinput);
521  dinput = NULL;
522  }
523 
524  if (coinitialized) {
526  coinitialized = SDL_FALSE;
527  }
528 }
529 
530 /*
531  * Converts an SDL trigger button to an DIEFFECT trigger button.
532  */
533 static DWORD
534 DIGetTriggerButton(Uint16 button)
535 {
536  DWORD dwTriggerButton;
537 
538  dwTriggerButton = DIEB_NOTRIGGER;
539 
540  if (button != 0) {
541  dwTriggerButton = DIJOFS_BUTTON(button - 1);
542  }
543 
544  return dwTriggerButton;
545 }
546 
547 
548 /*
549  * Sets the direction.
550  */
551 static int
552 SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
553 {
554  LONG *rglDir;
555 
556  /* Handle no axes a part. */
557  if (naxes == 0) {
558  effect->dwFlags |= DIEFF_SPHERICAL; /* Set as default. */
559  effect->rglDirection = NULL;
560  return 0;
561  }
562 
563  /* Has axes. */
564  rglDir = SDL_malloc(sizeof(LONG) * naxes);
565  if (rglDir == NULL) {
566  return SDL_OutOfMemory();
567  }
568  SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
569  effect->rglDirection = rglDir;
570 
571  switch (dir->type) {
572  case SDL_HAPTIC_POLAR:
573  effect->dwFlags |= DIEFF_POLAR;
574  rglDir[0] = dir->dir[0];
575  return 0;
577  effect->dwFlags |= DIEFF_CARTESIAN;
578  rglDir[0] = dir->dir[0];
579  if (naxes > 1)
580  rglDir[1] = dir->dir[1];
581  if (naxes > 2)
582  rglDir[2] = dir->dir[2];
583  return 0;
585  effect->dwFlags |= DIEFF_SPHERICAL;
586  rglDir[0] = dir->dir[0];
587  if (naxes > 1)
588  rglDir[1] = dir->dir[1];
589  if (naxes > 2)
590  rglDir[2] = dir->dir[2];
591  return 0;
592 
593  default:
594  return SDL_SetError("Haptic: Unknown direction type.");
595  }
596 }
597 
598 /* Clamps and converts. */
599 #define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
600 /* Just converts. */
601 #define CONVERT(x) (((x)*10000) / 0x7FFF)
602 /*
603  * Creates the DIEFFECT from a SDL_HapticEffect.
604  */
605 static int
606 SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
608 {
609  int i;
610  DICONSTANTFORCE *constant;
611  DIPERIODIC *periodic;
612  DICONDITION *condition; /* Actually an array of conditions - one per axis. */
613  DIRAMPFORCE *ramp;
614  DICUSTOMFORCE *custom;
615  DIENVELOPE *envelope;
616  SDL_HapticConstant *hap_constant;
617  SDL_HapticPeriodic *hap_periodic;
618  SDL_HapticCondition *hap_condition;
619  SDL_HapticRamp *hap_ramp;
620  SDL_HapticCustom *hap_custom;
621  DWORD *axes;
622 
623  /* Set global stuff. */
624  SDL_memset(dest, 0, sizeof(DIEFFECT));
625  dest->dwSize = sizeof(DIEFFECT); /* Set the structure size. */
626  dest->dwSamplePeriod = 0; /* Not used by us. */
627  dest->dwGain = 10000; /* Gain is set globally, not locally. */
628  dest->dwFlags = DIEFF_OBJECTOFFSETS; /* Seems obligatory. */
629 
630  /* Envelope. */
631  envelope = SDL_malloc(sizeof(DIENVELOPE));
632  if (envelope == NULL) {
633  return SDL_OutOfMemory();
634  }
635  SDL_memset(envelope, 0, sizeof(DIENVELOPE));
636  dest->lpEnvelope = envelope;
637  envelope->dwSize = sizeof(DIENVELOPE); /* Always should be this. */
638 
639  /* Axes. */
640  dest->cAxes = haptic->naxes;
641  if (dest->cAxes > 0) {
642  axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
643  if (axes == NULL) {
644  return SDL_OutOfMemory();
645  }
646  axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */
647  if (dest->cAxes > 1) {
648  axes[1] = haptic->hwdata->axes[1];
649  }
650  if (dest->cAxes > 2) {
651  axes[2] = haptic->hwdata->axes[2];
652  }
653  dest->rgdwAxes = axes;
654  }
655 
656  /* The big type handling switch, even bigger than Linux's version. */
657  switch (src->type) {
658  case SDL_HAPTIC_CONSTANT:
659  hap_constant = &src->constant;
660  constant = SDL_malloc(sizeof(DICONSTANTFORCE));
661  if (constant == NULL) {
662  return SDL_OutOfMemory();
663  }
664  SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
665 
666  /* Specifics */
667  constant->lMagnitude = CONVERT(hap_constant->level);
668  dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
669  dest->lpvTypeSpecificParams = constant;
670 
671  /* Generics */
672  dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
673  dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
674  dest->dwTriggerRepeatInterval = hap_constant->interval;
675  dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */
676 
677  /* Direction. */
678  if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) {
679  return -1;
680  }
681 
682  /* Envelope */
683  if ((hap_constant->attack_length == 0)
684  && (hap_constant->fade_length == 0)) {
685  SDL_free(dest->lpEnvelope);
686  dest->lpEnvelope = NULL;
687  } else {
688  envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
689  envelope->dwAttackTime = hap_constant->attack_length * 1000;
690  envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
691  envelope->dwFadeTime = hap_constant->fade_length * 1000;
692  }
693 
694  break;
695 
696  case SDL_HAPTIC_SINE:
697  /* !!! FIXME: put this back when we have more bits in 2.1 */
698  /* case SDL_HAPTIC_SQUARE: */
699  case SDL_HAPTIC_TRIANGLE:
702  hap_periodic = &src->periodic;
703  periodic = SDL_malloc(sizeof(DIPERIODIC));
704  if (periodic == NULL) {
705  return SDL_OutOfMemory();
706  }
707  SDL_memset(periodic, 0, sizeof(DIPERIODIC));
708 
709  /* Specifics */
710  periodic->dwMagnitude = CONVERT(SDL_abs(hap_periodic->magnitude));
711  periodic->lOffset = CONVERT(hap_periodic->offset);
712  periodic->dwPhase =
713  (hap_periodic->phase + (hap_periodic->magnitude < 0 ? 18000 : 0)) % 36000;
714  periodic->dwPeriod = hap_periodic->period * 1000;
715  dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
716  dest->lpvTypeSpecificParams = periodic;
717 
718  /* Generics */
719  dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
720  dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
721  dest->dwTriggerRepeatInterval = hap_periodic->interval;
722  dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */
723 
724  /* Direction. */
725  if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
726  < 0) {
727  return -1;
728  }
729 
730  /* Envelope */
731  if ((hap_periodic->attack_length == 0)
732  && (hap_periodic->fade_length == 0)) {
733  SDL_free(dest->lpEnvelope);
734  dest->lpEnvelope = NULL;
735  } else {
736  envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
737  envelope->dwAttackTime = hap_periodic->attack_length * 1000;
738  envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
739  envelope->dwFadeTime = hap_periodic->fade_length * 1000;
740  }
741 
742  break;
743 
744  case SDL_HAPTIC_SPRING:
745  case SDL_HAPTIC_DAMPER:
746  case SDL_HAPTIC_INERTIA:
747  case SDL_HAPTIC_FRICTION:
748  hap_condition = &src->condition;
749  condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
750  if (condition == NULL) {
751  return SDL_OutOfMemory();
752  }
753  SDL_memset(condition, 0, sizeof(DICONDITION));
754 
755  /* Specifics */
756  for (i = 0; i < (int) dest->cAxes; i++) {
757  condition[i].lOffset = CONVERT(hap_condition->center[i]);
758  condition[i].lPositiveCoefficient =
759  CONVERT(hap_condition->right_coeff[i]);
760  condition[i].lNegativeCoefficient =
761  CONVERT(hap_condition->left_coeff[i]);
762  condition[i].dwPositiveSaturation =
763  CCONVERT(hap_condition->right_sat[i] / 2);
764  condition[i].dwNegativeSaturation =
765  CCONVERT(hap_condition->left_sat[i] / 2);
766  condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
767  }
768  dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
769  dest->lpvTypeSpecificParams = condition;
770 
771  /* Generics */
772  dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */
773  dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
774  dest->dwTriggerRepeatInterval = hap_condition->interval;
775  dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */
776 
777  /* Direction. */
778  if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
779  < 0) {
780  return -1;
781  }
782 
783  /* Envelope - Not actually supported by most CONDITION implementations. */
784  SDL_free(dest->lpEnvelope);
785  dest->lpEnvelope = NULL;
786 
787  break;
788 
789  case SDL_HAPTIC_RAMP:
790  hap_ramp = &src->ramp;
791  ramp = SDL_malloc(sizeof(DIRAMPFORCE));
792  if (ramp == NULL) {
793  return SDL_OutOfMemory();
794  }
795  SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
796 
797  /* Specifics */
798  ramp->lStart = CONVERT(hap_ramp->start);
799  ramp->lEnd = CONVERT(hap_ramp->end);
800  dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
801  dest->lpvTypeSpecificParams = ramp;
802 
803  /* Generics */
804  dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */
805  dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
806  dest->dwTriggerRepeatInterval = hap_ramp->interval;
807  dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */
808 
809  /* Direction. */
810  if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
811  return -1;
812  }
813 
814  /* Envelope */
815  if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
816  SDL_free(dest->lpEnvelope);
817  dest->lpEnvelope = NULL;
818  } else {
819  envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
820  envelope->dwAttackTime = hap_ramp->attack_length * 1000;
821  envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
822  envelope->dwFadeTime = hap_ramp->fade_length * 1000;
823  }
824 
825  break;
826 
827  case SDL_HAPTIC_CUSTOM:
828  hap_custom = &src->custom;
829  custom = SDL_malloc(sizeof(DICUSTOMFORCE));
830  if (custom == NULL) {
831  return SDL_OutOfMemory();
832  }
833  SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
834 
835  /* Specifics */
836  custom->cChannels = hap_custom->channels;
837  custom->dwSamplePeriod = hap_custom->period * 1000;
838  custom->cSamples = hap_custom->samples;
839  custom->rglForceData =
840  SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
841  for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) { /* Copy data. */
842  custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
843  }
844  dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
845  dest->lpvTypeSpecificParams = custom;
846 
847  /* Generics */
848  dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */
849  dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
850  dest->dwTriggerRepeatInterval = hap_custom->interval;
851  dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */
852 
853  /* Direction. */
854  if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
855  return -1;
856  }
857 
858  /* Envelope */
859  if ((hap_custom->attack_length == 0)
860  && (hap_custom->fade_length == 0)) {
861  SDL_free(dest->lpEnvelope);
862  dest->lpEnvelope = NULL;
863  } else {
864  envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
865  envelope->dwAttackTime = hap_custom->attack_length * 1000;
866  envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
867  envelope->dwFadeTime = hap_custom->fade_length * 1000;
868  }
869 
870  break;
871 
872  default:
873  return SDL_SetError("Haptic: Unknown effect type.");
874  }
875 
876  return 0;
877 }
878 
879 
880 /*
881  * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
882  */
883 static void
884 SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
885 {
886  DICUSTOMFORCE *custom;
887 
888  SDL_free(effect->lpEnvelope);
889  effect->lpEnvelope = NULL;
890  SDL_free(effect->rgdwAxes);
891  effect->rgdwAxes = NULL;
892  if (effect->lpvTypeSpecificParams != NULL) {
893  if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */
894  custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
895  SDL_free(custom->rglForceData);
896  custom->rglForceData = NULL;
897  }
898  SDL_free(effect->lpvTypeSpecificParams);
899  effect->lpvTypeSpecificParams = NULL;
900  }
901  SDL_free(effect->rglDirection);
902  effect->rglDirection = NULL;
903 }
904 
905 /*
906  * Gets the effect type from the generic SDL haptic effect wrapper.
907  */
908 static REFGUID
909 SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
910 {
911  switch (effect->type) {
912  case SDL_HAPTIC_CONSTANT:
913  return &GUID_ConstantForce;
914 
915  case SDL_HAPTIC_RAMP:
916  return &GUID_RampForce;
917 
918  /* !!! FIXME: put this back when we have more bits in 2.1 */
919  /* case SDL_HAPTIC_SQUARE:
920  return &GUID_Square; */
921 
922  case SDL_HAPTIC_SINE:
923  return &GUID_Sine;
924 
925  case SDL_HAPTIC_TRIANGLE:
926  return &GUID_Triangle;
927 
929  return &GUID_SawtoothUp;
930 
932  return &GUID_SawtoothDown;
933 
934  case SDL_HAPTIC_SPRING:
935  return &GUID_Spring;
936 
937  case SDL_HAPTIC_DAMPER:
938  return &GUID_Damper;
939 
940  case SDL_HAPTIC_INERTIA:
941  return &GUID_Inertia;
942 
943  case SDL_HAPTIC_FRICTION:
944  return &GUID_Friction;
945 
946  case SDL_HAPTIC_CUSTOM:
947  return &GUID_CustomForce;
948 
949  default:
950  return NULL;
951  }
952 }
953 int
954 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
955 {
956  HRESULT ret;
957  REFGUID type = SDL_SYS_HapticEffectType(base);
958 
959  if (type == NULL) {
960  SDL_SetError("Haptic: Unknown effect type.");
961  return -1;
962  }
963 
964  /* Get the effect. */
965  if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
966  goto err_effectdone;
967  }
968 
969  /* Create the actual effect. */
970  ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type,
971  &effect->hweffect->effect,
972  &effect->hweffect->ref, NULL);
973  if (FAILED(ret)) {
974  DI_SetError("Unable to create effect", ret);
975  goto err_effectdone;
976  }
977 
978  return 0;
979 
980 err_effectdone:
981  SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
982  return -1;
983 }
984 
985 int
986 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
987 {
988  HRESULT ret;
989  DWORD flags;
990  DIEFFECT temp;
991 
992  /* Get the effect. */
993  SDL_memset(&temp, 0, sizeof(DIEFFECT));
994  if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
995  goto err_update;
996  }
997 
998  /* Set the flags. Might be worthwhile to diff temp with loaded effect and
999  * only change those parameters. */
1000  flags = DIEP_DIRECTION |
1001  DIEP_DURATION |
1002  DIEP_ENVELOPE |
1003  DIEP_STARTDELAY |
1004  DIEP_TRIGGERBUTTON |
1005  DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
1006 
1007  /* Create the actual effect. */
1008  ret =
1009  IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
1010  if (ret == DIERR_NOTEXCLUSIVEACQUIRED) {
1011  IDirectInputDevice8_Unacquire(haptic->hwdata->device);
1012  ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device, SDL_HelperWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND);
1013  if (SUCCEEDED(ret)) {
1014  ret = DIERR_NOTACQUIRED;
1015  }
1016  }
1017  if (ret == DIERR_INPUTLOST || ret == DIERR_NOTACQUIRED) {
1018  ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
1019  if (SUCCEEDED(ret)) {
1020  ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
1021  }
1022  }
1023  if (FAILED(ret)) {
1024  DI_SetError("Unable to update effect", ret);
1025  goto err_update;
1026  }
1027 
1028  /* Copy it over. */
1029  SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
1030  SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
1031 
1032  return 0;
1033 
1034 err_update:
1035  SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
1036  return -1;
1037 }
1038 
1039 int
1040 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
1041 {
1042  HRESULT ret;
1043  DWORD iter;
1044 
1045  /* Check if it's infinite. */
1046  if (iterations == SDL_HAPTIC_INFINITY) {
1047  iter = INFINITE;
1048  } else {
1049  iter = iterations;
1050  }
1051 
1052  /* Run the effect. */
1053  ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
1054  if (FAILED(ret)) {
1055  return DI_SetError("Running the effect", ret);
1056  }
1057  return 0;
1058 }
1059 
1060 int
1061 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1062 {
1063  HRESULT ret;
1064 
1065  ret = IDirectInputEffect_Stop(effect->hweffect->ref);
1066  if (FAILED(ret)) {
1067  return DI_SetError("Unable to stop effect", ret);
1068  }
1069  return 0;
1070 }
1071 
1072 void
1073 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1074 {
1075  HRESULT ret;
1076 
1077  ret = IDirectInputEffect_Unload(effect->hweffect->ref);
1078  if (FAILED(ret)) {
1079  DI_SetError("Removing effect from the device", ret);
1080  }
1081  SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type);
1082 }
1083 
1084 int
1085 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
1086 {
1087  HRESULT ret;
1088  DWORD status;
1089 
1090  ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
1091  if (FAILED(ret)) {
1092  return DI_SetError("Getting effect status", ret);
1093  }
1094 
1095  if (status == 0)
1096  return SDL_FALSE;
1097  return SDL_TRUE;
1098 }
1099 
1100 int
1101 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
1102 {
1103  HRESULT ret;
1104  DIPROPDWORD dipdw;
1105 
1106  /* Create the weird structure thingy. */
1107  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1108  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1109  dipdw.diph.dwObj = 0;
1110  dipdw.diph.dwHow = DIPH_DEVICE;
1111  dipdw.dwData = gain * 100; /* 0 to 10,000 */
1112 
1113  /* Try to set the autocenter. */
1114  ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
1115  DIPROP_FFGAIN, &dipdw.diph);
1116  if (FAILED(ret)) {
1117  return DI_SetError("Setting gain", ret);
1118  }
1119  return 0;
1120 }
1121 
1122 int
1123 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1124 {
1125  HRESULT ret;
1126  DIPROPDWORD dipdw;
1127 
1128  /* Create the weird structure thingy. */
1129  dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1130  dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1131  dipdw.diph.dwObj = 0;
1132  dipdw.diph.dwHow = DIPH_DEVICE;
1133  dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
1134  DIPROPAUTOCENTER_ON;
1135 
1136  /* Try to set the autocenter. */
1137  ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
1138  DIPROP_AUTOCENTER, &dipdw.diph);
1139  if (FAILED(ret)) {
1140  return DI_SetError("Setting autocenter", ret);
1141  }
1142  return 0;
1143 }
1144 
1145 int
1146 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
1147 {
1148  HRESULT ret;
1149 
1150  /* Pause the device. */
1151  ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
1152  DISFFC_PAUSE);
1153  if (FAILED(ret)) {
1154  return DI_SetError("Pausing the device", ret);
1155  }
1156  return 0;
1157 }
1158 
1159 int
1160 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
1161 {
1162  HRESULT ret;
1163 
1164  /* Unpause the device. */
1165  ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
1166  DISFFC_CONTINUE);
1167  if (FAILED(ret)) {
1168  return DI_SetError("Pausing the device", ret);
1169  }
1170  return 0;
1171 }
1172 
1173 int
1174 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
1175 {
1176  HRESULT ret;
1177 
1178  /* Try to stop the effects. */
1179  ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
1180  DISFFC_STOPALL);
1181  if (FAILED(ret)) {
1182  return DI_SetError("Stopping the device", ret);
1183  }
1184  return 0;
1185 }
1186 
1187 #else /* !SDL_HAPTIC_DINPUT */
1188 
1189 typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE;
1191 
1192 int
1194 {
1195  return 0;
1196 }
1197 
1198 int
1200 {
1201  return SDL_Unsupported();
1202 }
1203 
1204 int
1206 {
1207  return SDL_Unsupported();
1208 }
1209 
1210 int
1211 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
1212 {
1213  return SDL_Unsupported();
1214 }
1215 
1216 int
1217 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
1218 {
1219  return SDL_Unsupported();
1220 }
1221 
1222 int
1223 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
1224 {
1225  return SDL_Unsupported();
1226 }
1227 
1228 void
1229 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
1230 {
1231 }
1232 
1233 void
1235 {
1236 }
1237 
1238 int
1239 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
1240 {
1241  return SDL_Unsupported();
1242 }
1243 
1244 int
1245 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
1246 {
1247  return SDL_Unsupported();
1248 }
1249 
1250 int
1251 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
1252 {
1253  return SDL_Unsupported();
1254 }
1255 
1256 int
1257 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1258 {
1259  return SDL_Unsupported();
1260 }
1261 
1262 void
1263 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1264 {
1265 }
1266 
1267 int
1268 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
1269 {
1270  return SDL_Unsupported();
1271 }
1272 
1273 int
1274 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
1275 {
1276  return SDL_Unsupported();
1277 }
1278 
1279 int
1280 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1281 {
1282  return SDL_Unsupported();
1283 }
1284 
1285 int
1286 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
1287 {
1288  return SDL_Unsupported();
1289 }
1290 
1291 int
1292 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
1293 {
1294  return SDL_Unsupported();
1295 }
1296 
1297 int
1298 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
1299 {
1300  return SDL_Unsupported();
1301 }
1302 
1303 #endif /* SDL_HAPTIC_DINPUT */
1304 
1305 /* vi: set ts=4 sw=4 expandtab: */
Uint16 deadband[3]
Definition: SDL_haptic.h:611
#define SDL_abs
Structure that represents a haptic direction.
Definition: SDL_haptic.h:439
int SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE *pdidInstance)
#define SDL_HAPTIC_SPHERICAL
Uses spherical coordinates for the direction.
Definition: SDL_haptic.h:326
void SDL_DINPUT_HapticQuit(void)
int SDL_DINPUT_HapticUpdateEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *data)
SDL_Texture * button
int SDL_DINPUT_HapticSetAutocenter(SDL_Haptic *haptic, int autocenter)
#define SDL_HAPTIC_AUTOCENTER
Device can set autocenter.
Definition: SDL_haptic.h:280
A structure containing a template for a Periodic effect.
Definition: SDL_haptic.h:538
#define SDL_HAPTIC_GAIN
Device can set global gain.
Definition: SDL_haptic.h:271
#define DIRECTINPUT_VERSION
Definition: SDL_directx.h:95
#define SDL_HAPTIC_CUSTOM
Custom effect is supported.
Definition: SDL_haptic.h:258
#define SDL_HAPTIC_TRIANGLE
Triangle wave effect supported.
Definition: SDL_haptic.h:184
SDL_HapticDirection direction
Definition: SDL_haptic.h:596
SDL_HapticCustom custom
Definition: SDL_haptic.h:798
#define SDL_HAPTIC_INERTIA
Inertia effect supported - uses axes acceleration.
Definition: SDL_haptic.h:241
Uint16 fade_level
Definition: SDL_haptic.h:650
SDL_HapticRamp ramp
Definition: SDL_haptic.h:796
int SDL_DINPUT_HapticSetGain(SDL_Haptic *haptic, int gain)
int SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE *pdidInstance)
A structure containing a template for a Condition effect.
Definition: SDL_haptic.h:591
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLintptr offset
The SDL haptic subsystem allows you to control haptic (force feedback) devices.
static int iterations
Definition: testsprite2.c:43
Sint16 left_coeff[3]
Definition: SDL_haptic.h:610
Uint16 right_sat[3]
Definition: SDL_haptic.h:607
uint32_t Uint32
Definition: SDL_stdinc.h:181
Uint16 fade_length
Definition: SDL_haptic.h:716
BOOL WIN_IsEqualGUID(const GUID *a, const GUID *b)
int SDL_DINPUT_HapticRunEffect(SDL_Haptic *haptic, struct haptic_effect *effect, Uint32 iterations)
void SDL_DINPUT_HapticDestroyEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
Sint16 right_coeff[3]
Definition: SDL_haptic.h:609
GLenum src
#define SDL_HAPTIC_SINE
Sine wave effect supported.
Definition: SDL_haptic.h:161
int SDL_DINPUT_HapticInit(void)
int SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic *haptic, struct haptic_effect *effect)
A structure containing a template for a Constant effect.
Definition: SDL_haptic.h:457
int SDL_DINPUT_HapticOpen(SDL_Haptic *haptic, SDL_hapticlist_item *item)
int SDL_SYS_RemoveHapticDevice(SDL_hapticlist_item *prev, SDL_hapticlist_item *item)
#define SDL_HAPTIC_INFINITY
Used to play a device an infinite number of times.
Definition: SDL_haptic.h:341
Uint16 interval
Definition: SDL_haptic.h:640
#define SDL_HAPTIC_CARTESIAN
Uses cartesian coordinates for the direction.
Definition: SDL_haptic.h:319
SDL_hapticlist_item * SDL_hapticlist
struct SDL_hapticlist_item * next
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_HapticCondition condition
Definition: SDL_haptic.h:795
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_memcpy
The generic template for any haptic effect.
Definition: SDL_haptic.h:789
#define SDL_HAPTIC_CONSTANT
Constant effect supported.
Definition: SDL_haptic.h:152
int SDL_DINPUT_HapticNewEffect(SDL_Haptic *haptic, struct haptic_effect *effect, SDL_HapticEffect *base)
HRESULT WIN_CoInitialize(void)
#define SDL_free
#define SDL_HAPTIC_POLAR
Uses polar coordinates for the direction.
Definition: SDL_haptic.h:312
#define SDL_memcmp
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
SDL_HapticConstant constant
Definition: SDL_haptic.h:793
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define SDL_HAPTIC_PAUSE
Device can be paused.
Definition: SDL_haptic.h:299
void SDL_DINPUT_HapticClose(SDL_Haptic *haptic)
int SDL_DINPUT_JoystickSameHaptic(SDL_Haptic *haptic, SDL_Joystick *joystick)
SDL_HapticDirection direction
Definition: SDL_haptic.h:632
A structure containing a template for a Ramp effect.
Definition: SDL_haptic.h:628
GLuint index
Uint16 attack_length
Definition: SDL_haptic.h:647
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
Uint16 fade_length
Definition: SDL_haptic.h:649
int SDL_DINPUT_HapticUnpause(SDL_Haptic *haptic)
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
void WIN_CoUninitialize(void)
SDL_HapticEffect effect
Definition: SDL_syshaptic.h:32
static SDL_Haptic * haptic
Definition: testhaptic.c:25
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
void SDL_SYS_HapticQuit(void)
struct haptic_hweffect * hweffect
Definition: SDL_syshaptic.h:33
#define SDL_SetError
#define SDL_HAPTIC_STATUS
Device can be queried for effect status.
Definition: SDL_haptic.h:289
GLbitfield flags
#define SDL_calloc
SDL_HapticDirection direction
Definition: SDL_haptic.h:544
int SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic *haptic, SDL_Joystick *joystick)
Uint16 attack_level
Definition: SDL_haptic.h:715
#define SDL_HAPTIC_RAMP
Ramp effect supported.
Definition: SDL_haptic.h:211
#define SDL_HAPTIC_SPRING
Spring effect supported - uses axes position.
Definition: SDL_haptic.h:221
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 void
int SDL_DINPUT_HapticPause(SDL_Haptic *haptic)
GLenum condition
uint16_t Uint16
Definition: SDL_stdinc.h:169
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
A structure containing a template for the SDL_HAPTIC_CUSTOM effect.
Definition: SDL_haptic.h:693
#define SDL_malloc
#define SDL_HAPTIC_SAWTOOTHUP
Sawtoothup wave effect supported.
Definition: SDL_haptic.h:193
int SDL_DINPUT_HapticStopAll(SDL_Haptic *haptic)
int SDL_DINPUT_HapticStopEffect(SDL_Haptic *haptic, struct haptic_effect *effect)
SDL_HapticPeriodic periodic
Definition: SDL_haptic.h:794
Uint16 attack_level
Definition: SDL_haptic.h:648
Uint16 attack_length
Definition: SDL_haptic.h:714
#define SDL_HAPTIC_FRICTION
Friction effect supported - uses axes movement.
Definition: SDL_haptic.h:251
#define SDL_Unsupported()
Definition: SDL_error.h:53
#define SDL_HAPTIC_SAWTOOTHDOWN
Sawtoothdown wave effect supported.
Definition: SDL_haptic.h:202
#define SDL_memset
int SDL_SYS_AddHapticDevice(SDL_hapticlist_item *item)
SDL_HapticDirection direction
Definition: SDL_haptic.h:461
SDL_HapticDirection direction
Definition: SDL_haptic.h:697
#define SDL_HAPTIC_DAMPER
Damper effect supported - uses axes velocity.
Definition: SDL_haptic.h:231
Uint16 left_sat[3]
Definition: SDL_haptic.h:608