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