SDL 2.0
SDL_dinputhaptic.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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 */
38extern HWND SDL_HelperWindow;
39
40
41/*
42 * Internal stuff.
43 */
44static SDL_bool coinitialized = SDL_FALSE;
45static LPDIRECTINPUT8 dinput = NULL;
46
47
48/*
49 * Like SDL_SetError but for DX error codes.
50 */
51static int
52DI_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 */
64static BOOL CALLBACK
65EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
66{
67 (void) pContext;
68 SDL_DINPUT_MaybeAddDevice(pdidInstance);
69 return DIENUM_CONTINUE; /* continue enumerating */
70}
71
72int
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
123int
125{
126 HRESULT ret;
127 LPDIRECTINPUTDEVICE8 device;
128 const DWORD needflags = DIDC_ATTACHED | DIDC_FORCEFEEDBACK;
129 DIDEVCAPS capabilities;
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
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
182int
184{
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 */
205static BOOL CALLBACK
206DI_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) \
245if (WIN_IsEqualGUID(&pei->guid, &(e))) \
246 haptic->supported |= (s)
247static BOOL CALLBACK
248DI_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 */
282static int
283SDL_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. */
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) {
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
421int
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
454int
455SDL_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
478int
479SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
480{
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
505void
506SDL_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
516void
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 */
533static DWORD
534DIGetTriggerButton(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 */
551static int
552SDL_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 */
605static int
606SDL_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) {
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: */
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
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
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 */
883static void
884SDL_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 */
908static REFGUID
909SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
910{
911 switch (effect->type) {
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
926 return &GUID_Triangle;
927
929 return &GUID_SawtoothUp;
930
932 return &GUID_SawtoothDown;
933
935 return &GUID_Spring;
936
938 return &GUID_Damper;
939
941 return &GUID_Inertia;
942
944 return &GUID_Friction;
945
947 return &GUID_CustomForce;
948
949 default:
950 return NULL;
951 }
952}
953int
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
980err_effectdone:
981 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
982 return -1;
983}
984
985int
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
1034err_update:
1035 SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
1036 return -1;
1037}
1038
1039int
1041{
1042 HRESULT ret;
1043 DWORD iter;
1044
1045 /* Check if it's infinite. */
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
1060int
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
1072void
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
1084int
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
1100int
1101SDL_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
1122int
1123SDL_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
1145int
1146SDL_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
1159int
1160SDL_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
1173int
1174SDL_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
1189typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE;
1191
1192int
1194{
1195 return 0;
1196}
1197
1198int
1200{
1201 return SDL_Unsupported();
1202}
1203
1204int
1206{
1207 return SDL_Unsupported();
1208}
1209
1210int
1212{
1213 return SDL_Unsupported();
1214}
1215
1216int
1217SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
1218{
1219 return SDL_Unsupported();
1220}
1221
1222int
1223SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
1224{
1225 return SDL_Unsupported();
1226}
1227
1228void
1230{
1231}
1232
1233void
1235{
1236}
1237
1238int
1240{
1241 return SDL_Unsupported();
1242}
1243
1244int
1246{
1247 return SDL_Unsupported();
1248}
1249
1250int
1252{
1253 return SDL_Unsupported();
1254}
1255
1256int
1258{
1259 return SDL_Unsupported();
1260}
1261
1262void
1264{
1265}
1266
1267int
1269{
1270 return SDL_Unsupported();
1271}
1272
1273int
1274SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
1275{
1276 return SDL_Unsupported();
1277}
1278
1279int
1280SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1281{
1282 return SDL_Unsupported();
1283}
1284
1285int
1287{
1288 return SDL_Unsupported();
1289}
1290
1291int
1293{
1294 return SDL_Unsupported();
1295}
1296
1297int
1299{
1300 return SDL_Unsupported();
1301}
1302
1303#endif /* SDL_HAPTIC_DINPUT */
1304
1305/* 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:52
#define SDL_Unsupported()
Definition: SDL_error.h:53
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:352
#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_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
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint32_t Uint32
Definition: SDL_stdinc.h:203
uint16_t Uint16
Definition: SDL_stdinc.h:191
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:167
static SDL_AudioDeviceID device
Definition: loopwave.c:37
A structure containing a template for a Condition effect.
Definition: SDL_haptic.h:603
Sint16 left_coeff[3]
Definition: SDL_haptic.h:621
Sint16 right_coeff[3]
Definition: SDL_haptic.h:620
SDL_HapticDirection direction
Definition: SDL_haptic.h:607
Uint16 right_sat[3]
Definition: SDL_haptic.h:618
Uint16 left_sat[3]
Definition: SDL_haptic.h:619
Uint16 deadband[3]
Definition: SDL_haptic.h:622
A structure containing a template for a Constant effect.
Definition: SDL_haptic.h:469
SDL_HapticDirection direction
Definition: SDL_haptic.h:472
A structure containing a template for the SDL_HAPTIC_CUSTOM effect.
Definition: SDL_haptic.h:705
Uint16 attack_length
Definition: SDL_haptic.h:725
Uint16 fade_length
Definition: SDL_haptic.h:727
Uint16 attack_level
Definition: SDL_haptic.h:726
SDL_HapticDirection direction
Definition: SDL_haptic.h:708
Structure that represents a haptic direction.
Definition: SDL_haptic.h:451
A structure containing a template for a Periodic effect.
Definition: SDL_haptic.h:550
SDL_HapticDirection direction
Definition: SDL_haptic.h:555
A structure containing a template for a Ramp effect.
Definition: SDL_haptic.h:640
Uint16 interval
Definition: SDL_haptic.h:651
Uint16 fade_level
Definition: SDL_haptic.h:661
SDL_HapticDirection direction
Definition: SDL_haptic.h:643
Uint16 attack_level
Definition: SDL_haptic.h:659
Uint16 fade_length
Definition: SDL_haptic.h:660
Uint16 attack_length
Definition: SDL_haptic.h:658
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 int iterations
Definition: testsprite2.c:45
The generic template for any haptic effect.
Definition: SDL_haptic.h:801