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