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
DI_SetError(const char * str,HRESULT err)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
DI_GUIDIsSame(const GUID * a,const GUID * b)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
EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance,VOID * pContext)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
SDL_DINPUT_HapticInit(void)82 SDL_DINPUT_HapticInit(void)
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)) {
101 SDL_SYS_HapticQuit();
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) {
108 SDL_SYS_HapticQuit();
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)) {
114 SDL_SYS_HapticQuit();
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)) {
126 SDL_SYS_HapticQuit();
127 return DI_SetError("Enumerating DirectInput devices", ret);
128 }
129 return 0;
130 }
131
132 int
SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)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
SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)192 SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
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
DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev,LPVOID pvRef)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
DI_EffectCallback(LPCDIEFFECTINFO pei,LPVOID pv)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
SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic,LPDIRECTINPUTDEVICE8 device8,SDL_bool is_joystick)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 &SDL_c_dfDIJoystick2);
329 if (FAILED(ret)) {
330 DI_SetError("Setting data format", ret);
331 goto acquire_err;
332 }
333
334
335 /* Acquire the device. */
336 ret = IDirectInputDevice8_Acquire(haptic->hwdata->device);
337 if (FAILED(ret)) {
338 DI_SetError("Acquiring DirectInput device", ret);
339 goto acquire_err;
340 }
341 }
342
343 /* Get number of axes. */
344 ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device,
345 DI_DeviceObjectCallback,
346 haptic, DIDFT_AXIS);
347 if (FAILED(ret)) {
348 DI_SetError("Getting device axes", ret);
349 goto acquire_err;
350 }
351
352 /* Reset all actuators - just in case. */
353 ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
354 DISFFC_RESET);
355 if (FAILED(ret)) {
356 DI_SetError("Resetting device", ret);
357 goto acquire_err;
358 }
359
360 /* Enabling actuators. */
361 ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
362 DISFFC_SETACTUATORSON);
363 if (FAILED(ret)) {
364 DI_SetError("Enabling actuators", ret);
365 goto acquire_err;
366 }
367
368 /* Get supported effects. */
369 ret = IDirectInputDevice8_EnumEffects(haptic->hwdata->device,
370 DI_EffectCallback, haptic,
371 DIEFT_ALL);
372 if (FAILED(ret)) {
373 DI_SetError("Enumerating supported effects", ret);
374 goto acquire_err;
375 }
376 if (haptic->supported == 0) { /* Error since device supports nothing. */
377 SDL_SetError("Haptic: Internal error on finding supported effects.");
378 goto acquire_err;
379 }
380
381 /* Check autogain and autocenter. */
382 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
383 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
384 dipdw.diph.dwObj = 0;
385 dipdw.diph.dwHow = DIPH_DEVICE;
386 dipdw.dwData = 10000;
387 ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
388 DIPROP_FFGAIN, &dipdw.diph);
389 if (!FAILED(ret)) { /* Gain is supported. */
390 haptic->supported |= SDL_HAPTIC_GAIN;
391 }
392 dipdw.diph.dwObj = 0;
393 dipdw.diph.dwHow = DIPH_DEVICE;
394 dipdw.dwData = DIPROPAUTOCENTER_OFF;
395 ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
396 DIPROP_AUTOCENTER, &dipdw.diph);
397 if (!FAILED(ret)) { /* Autocenter is supported. */
398 haptic->supported |= SDL_HAPTIC_AUTOCENTER;
399 }
400
401 /* Status is always supported. */
402 haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
403
404 /* Check maximum effects. */
405 haptic->neffects = 128; /* This is not actually supported as thus under windows,
406 there is no way to tell the number of EFFECTS that a
407 device can hold, so we'll just use a "random" number
408 instead and put warnings in SDL_haptic.h */
409 haptic->nplaying = 128; /* Even more impossible to get this then neffects. */
410
411 /* Prepare effects memory. */
412 haptic->effects = (struct haptic_effect *)
413 SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
414 if (haptic->effects == NULL) {
415 SDL_OutOfMemory();
416 goto acquire_err;
417 }
418 /* Clear the memory */
419 SDL_memset(haptic->effects, 0,
420 sizeof(struct haptic_effect) * haptic->neffects);
421
422 return 0;
423
424 /* Error handling */
425 acquire_err:
426 IDirectInputDevice8_Unacquire(haptic->hwdata->device);
427 return -1;
428 }
429
430 int
SDL_DINPUT_HapticOpen(SDL_Haptic * haptic,SDL_hapticlist_item * item)431 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
432 {
433 HRESULT ret;
434 LPDIRECTINPUTDEVICE8 device;
435 LPDIRECTINPUTDEVICE8 device8;
436
437 /* Open the device */
438 ret = IDirectInput8_CreateDevice(dinput, &item->instance.guidInstance,
439 &device, NULL);
440 if (FAILED(ret)) {
441 DI_SetError("Creating DirectInput device", ret);
442 return -1;
443 }
444
445 /* Now get the IDirectInputDevice8 interface, instead. */
446 ret = IDirectInputDevice8_QueryInterface(device,
447 &IID_IDirectInputDevice8,
448 (LPVOID *)&device8);
449 /* Done with the temporary one now. */
450 IDirectInputDevice8_Release(device);
451 if (FAILED(ret)) {
452 DI_SetError("Querying DirectInput interface", ret);
453 return -1;
454 }
455
456 if (SDL_DINPUT_HapticOpenFromDevice(haptic, device8, SDL_FALSE) < 0) {
457 IDirectInputDevice8_Release(device8);
458 return -1;
459 }
460 return 0;
461 }
462
463 int
SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic,SDL_Joystick * joystick)464 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
465 {
466 HRESULT ret;
467 DIDEVICEINSTANCE hap_instance, joy_instance;
468
469 hap_instance.dwSize = sizeof(DIDEVICEINSTANCE);
470 joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
471
472 /* Get the device instances. */
473 ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device,
474 &hap_instance);
475 if (FAILED(ret)) {
476 return 0;
477 }
478 ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice,
479 &joy_instance);
480 if (FAILED(ret)) {
481 return 0;
482 }
483
484 return DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance);
485 }
486
487 int
SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic,SDL_Joystick * joystick)488 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
489 {
490 SDL_hapticlist_item *item;
491 int index = 0;
492 HRESULT ret;
493 DIDEVICEINSTANCE joy_instance;
494
495 joy_instance.dwSize = sizeof(DIDEVICEINSTANCE);
496 ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance);
497 if (FAILED(ret)) {
498 return -1;
499 }
500
501 /* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */
502 for (item = SDL_hapticlist; item != NULL; item = item->next) {
503 if (!item->bXInputHaptic && DI_GUIDIsSame(&item->instance.guidInstance, &joy_instance.guidInstance)) {
504 haptic->index = index;
505 return SDL_DINPUT_HapticOpenFromDevice(haptic, joystick->hwdata->InputDevice, SDL_TRUE);
506 }
507 ++index;
508 }
509
510 SDL_SetError("Couldn't find joystick in haptic device list");
511 return -1;
512 }
513
514 void
SDL_DINPUT_HapticClose(SDL_Haptic * haptic)515 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
516 {
517 IDirectInputDevice8_Unacquire(haptic->hwdata->device);
518
519 /* Only release if isn't grabbed by a joystick. */
520 if (haptic->hwdata->is_joystick == 0) {
521 IDirectInputDevice8_Release(haptic->hwdata->device);
522 }
523 }
524
525 void
SDL_DINPUT_HapticQuit(void)526 SDL_DINPUT_HapticQuit(void)
527 {
528 if (dinput != NULL) {
529 IDirectInput8_Release(dinput);
530 dinput = NULL;
531 }
532
533 if (coinitialized) {
534 WIN_CoUninitialize();
535 coinitialized = SDL_FALSE;
536 }
537 }
538
539 /*
540 * Converts an SDL trigger button to an DIEFFECT trigger button.
541 */
542 static DWORD
DIGetTriggerButton(Uint16 button)543 DIGetTriggerButton(Uint16 button)
544 {
545 DWORD dwTriggerButton;
546
547 dwTriggerButton = DIEB_NOTRIGGER;
548
549 if (button != 0) {
550 dwTriggerButton = DIJOFS_BUTTON(button - 1);
551 }
552
553 return dwTriggerButton;
554 }
555
556
557 /*
558 * Sets the direction.
559 */
560 static int
SDL_SYS_SetDirection(DIEFFECT * effect,SDL_HapticDirection * dir,int naxes)561 SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
562 {
563 LONG *rglDir;
564
565 /* Handle no axes a part. */
566 if (naxes == 0) {
567 effect->dwFlags |= DIEFF_SPHERICAL; /* Set as default. */
568 effect->rglDirection = NULL;
569 return 0;
570 }
571
572 /* Has axes. */
573 rglDir = SDL_malloc(sizeof(LONG) * naxes);
574 if (rglDir == NULL) {
575 return SDL_OutOfMemory();
576 }
577 SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
578 effect->rglDirection = rglDir;
579
580 switch (dir->type) {
581 case SDL_HAPTIC_POLAR:
582 effect->dwFlags |= DIEFF_POLAR;
583 rglDir[0] = dir->dir[0];
584 return 0;
585 case SDL_HAPTIC_CARTESIAN:
586 effect->dwFlags |= DIEFF_CARTESIAN;
587 rglDir[0] = dir->dir[0];
588 if (naxes > 1)
589 rglDir[1] = dir->dir[1];
590 if (naxes > 2)
591 rglDir[2] = dir->dir[2];
592 return 0;
593 case SDL_HAPTIC_SPHERICAL:
594 effect->dwFlags |= DIEFF_SPHERICAL;
595 rglDir[0] = dir->dir[0];
596 if (naxes > 1)
597 rglDir[1] = dir->dir[1];
598 if (naxes > 2)
599 rglDir[2] = dir->dir[2];
600 return 0;
601
602 default:
603 return SDL_SetError("Haptic: Unknown direction type.");
604 }
605 }
606
607 /* Clamps and converts. */
608 #define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
609 /* Just converts. */
610 #define CONVERT(x) (((x)*10000) / 0x7FFF)
611 /*
612 * Creates the DIEFFECT from a SDL_HapticEffect.
613 */
614 static int
SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,DIEFFECT * dest,SDL_HapticEffect * src)615 SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
616 SDL_HapticEffect * src)
617 {
618 int i;
619 DICONSTANTFORCE *constant;
620 DIPERIODIC *periodic;
621 DICONDITION *condition; /* Actually an array of conditions - one per axis. */
622 DIRAMPFORCE *ramp;
623 DICUSTOMFORCE *custom;
624 DIENVELOPE *envelope;
625 SDL_HapticConstant *hap_constant;
626 SDL_HapticPeriodic *hap_periodic;
627 SDL_HapticCondition *hap_condition;
628 SDL_HapticRamp *hap_ramp;
629 SDL_HapticCustom *hap_custom;
630 DWORD *axes;
631
632 /* Set global stuff. */
633 SDL_memset(dest, 0, sizeof(DIEFFECT));
634 dest->dwSize = sizeof(DIEFFECT); /* Set the structure size. */
635 dest->dwSamplePeriod = 0; /* Not used by us. */
636 dest->dwGain = 10000; /* Gain is set globally, not locally. */
637 dest->dwFlags = DIEFF_OBJECTOFFSETS; /* Seems obligatory. */
638
639 /* Envelope. */
640 envelope = SDL_malloc(sizeof(DIENVELOPE));
641 if (envelope == NULL) {
642 return SDL_OutOfMemory();
643 }
644 SDL_memset(envelope, 0, sizeof(DIENVELOPE));
645 dest->lpEnvelope = envelope;
646 envelope->dwSize = sizeof(DIENVELOPE); /* Always should be this. */
647
648 /* Axes. */
649 dest->cAxes = haptic->naxes;
650 if (dest->cAxes > 0) {
651 axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
652 if (axes == NULL) {
653 return SDL_OutOfMemory();
654 }
655 axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */
656 if (dest->cAxes > 1) {
657 axes[1] = haptic->hwdata->axes[1];
658 }
659 if (dest->cAxes > 2) {
660 axes[2] = haptic->hwdata->axes[2];
661 }
662 dest->rgdwAxes = axes;
663 }
664
665 /* The big type handling switch, even bigger than Linux's version. */
666 switch (src->type) {
667 case SDL_HAPTIC_CONSTANT:
668 hap_constant = &src->constant;
669 constant = SDL_malloc(sizeof(DICONSTANTFORCE));
670 if (constant == NULL) {
671 return SDL_OutOfMemory();
672 }
673 SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
674
675 /* Specifics */
676 constant->lMagnitude = CONVERT(hap_constant->level);
677 dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
678 dest->lpvTypeSpecificParams = constant;
679
680 /* Generics */
681 dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
682 dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
683 dest->dwTriggerRepeatInterval = hap_constant->interval;
684 dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */
685
686 /* Direction. */
687 if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) {
688 return -1;
689 }
690
691 /* Envelope */
692 if ((hap_constant->attack_length == 0)
693 && (hap_constant->fade_length == 0)) {
694 SDL_free(dest->lpEnvelope);
695 dest->lpEnvelope = NULL;
696 } else {
697 envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
698 envelope->dwAttackTime = hap_constant->attack_length * 1000;
699 envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
700 envelope->dwFadeTime = hap_constant->fade_length * 1000;
701 }
702
703 break;
704
705 case SDL_HAPTIC_SINE:
706 /* !!! FIXME: put this back when we have more bits in 2.1 */
707 /* case SDL_HAPTIC_SQUARE: */
708 case SDL_HAPTIC_TRIANGLE:
709 case SDL_HAPTIC_SAWTOOTHUP:
710 case SDL_HAPTIC_SAWTOOTHDOWN:
711 hap_periodic = &src->periodic;
712 periodic = SDL_malloc(sizeof(DIPERIODIC));
713 if (periodic == NULL) {
714 return SDL_OutOfMemory();
715 }
716 SDL_memset(periodic, 0, sizeof(DIPERIODIC));
717
718 /* Specifics */
719 periodic->dwMagnitude = CONVERT(SDL_abs(hap_periodic->magnitude));
720 periodic->lOffset = CONVERT(hap_periodic->offset);
721 periodic->dwPhase =
722 (hap_periodic->phase + (hap_periodic->magnitude < 0 ? 18000 : 0)) % 36000;
723 periodic->dwPeriod = hap_periodic->period * 1000;
724 dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
725 dest->lpvTypeSpecificParams = periodic;
726
727 /* Generics */
728 dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
729 dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
730 dest->dwTriggerRepeatInterval = hap_periodic->interval;
731 dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */
732
733 /* Direction. */
734 if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
735 < 0) {
736 return -1;
737 }
738
739 /* Envelope */
740 if ((hap_periodic->attack_length == 0)
741 && (hap_periodic->fade_length == 0)) {
742 SDL_free(dest->lpEnvelope);
743 dest->lpEnvelope = NULL;
744 } else {
745 envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
746 envelope->dwAttackTime = hap_periodic->attack_length * 1000;
747 envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
748 envelope->dwFadeTime = hap_periodic->fade_length * 1000;
749 }
750
751 break;
752
753 case SDL_HAPTIC_SPRING:
754 case SDL_HAPTIC_DAMPER:
755 case SDL_HAPTIC_INERTIA:
756 case SDL_HAPTIC_FRICTION:
757 hap_condition = &src->condition;
758 condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
759 if (condition == NULL) {
760 return SDL_OutOfMemory();
761 }
762 SDL_memset(condition, 0, sizeof(DICONDITION));
763
764 /* Specifics */
765 for (i = 0; i < (int) dest->cAxes; i++) {
766 condition[i].lOffset = CONVERT(hap_condition->center[i]);
767 condition[i].lPositiveCoefficient =
768 CONVERT(hap_condition->right_coeff[i]);
769 condition[i].lNegativeCoefficient =
770 CONVERT(hap_condition->left_coeff[i]);
771 condition[i].dwPositiveSaturation =
772 CCONVERT(hap_condition->right_sat[i] / 2);
773 condition[i].dwNegativeSaturation =
774 CCONVERT(hap_condition->left_sat[i] / 2);
775 condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
776 }
777 dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
778 dest->lpvTypeSpecificParams = condition;
779
780 /* Generics */
781 dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */
782 dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
783 dest->dwTriggerRepeatInterval = hap_condition->interval;
784 dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */
785
786 /* Direction. */
787 if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
788 < 0) {
789 return -1;
790 }
791
792 /* Envelope - Not actually supported by most CONDITION implementations. */
793 SDL_free(dest->lpEnvelope);
794 dest->lpEnvelope = NULL;
795
796 break;
797
798 case SDL_HAPTIC_RAMP:
799 hap_ramp = &src->ramp;
800 ramp = SDL_malloc(sizeof(DIRAMPFORCE));
801 if (ramp == NULL) {
802 return SDL_OutOfMemory();
803 }
804 SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
805
806 /* Specifics */
807 ramp->lStart = CONVERT(hap_ramp->start);
808 ramp->lEnd = CONVERT(hap_ramp->end);
809 dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
810 dest->lpvTypeSpecificParams = ramp;
811
812 /* Generics */
813 dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */
814 dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
815 dest->dwTriggerRepeatInterval = hap_ramp->interval;
816 dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */
817
818 /* Direction. */
819 if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
820 return -1;
821 }
822
823 /* Envelope */
824 if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
825 SDL_free(dest->lpEnvelope);
826 dest->lpEnvelope = NULL;
827 } else {
828 envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
829 envelope->dwAttackTime = hap_ramp->attack_length * 1000;
830 envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
831 envelope->dwFadeTime = hap_ramp->fade_length * 1000;
832 }
833
834 break;
835
836 case SDL_HAPTIC_CUSTOM:
837 hap_custom = &src->custom;
838 custom = SDL_malloc(sizeof(DICUSTOMFORCE));
839 if (custom == NULL) {
840 return SDL_OutOfMemory();
841 }
842 SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
843
844 /* Specifics */
845 custom->cChannels = hap_custom->channels;
846 custom->dwSamplePeriod = hap_custom->period * 1000;
847 custom->cSamples = hap_custom->samples;
848 custom->rglForceData =
849 SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
850 for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) { /* Copy data. */
851 custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
852 }
853 dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
854 dest->lpvTypeSpecificParams = custom;
855
856 /* Generics */
857 dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */
858 dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
859 dest->dwTriggerRepeatInterval = hap_custom->interval;
860 dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */
861
862 /* Direction. */
863 if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
864 return -1;
865 }
866
867 /* Envelope */
868 if ((hap_custom->attack_length == 0)
869 && (hap_custom->fade_length == 0)) {
870 SDL_free(dest->lpEnvelope);
871 dest->lpEnvelope = NULL;
872 } else {
873 envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
874 envelope->dwAttackTime = hap_custom->attack_length * 1000;
875 envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
876 envelope->dwFadeTime = hap_custom->fade_length * 1000;
877 }
878
879 break;
880
881 default:
882 return SDL_SetError("Haptic: Unknown effect type.");
883 }
884
885 return 0;
886 }
887
888
889 /*
890 * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
891 */
892 static void
SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect,int type)893 SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
894 {
895 DICUSTOMFORCE *custom;
896
897 SDL_free(effect->lpEnvelope);
898 effect->lpEnvelope = NULL;
899 SDL_free(effect->rgdwAxes);
900 effect->rgdwAxes = NULL;
901 if (effect->lpvTypeSpecificParams != NULL) {
902 if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */
903 custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
904 SDL_free(custom->rglForceData);
905 custom->rglForceData = NULL;
906 }
907 SDL_free(effect->lpvTypeSpecificParams);
908 effect->lpvTypeSpecificParams = NULL;
909 }
910 SDL_free(effect->rglDirection);
911 effect->rglDirection = NULL;
912 }
913
914 /*
915 * Gets the effect type from the generic SDL haptic effect wrapper.
916 */
917 static REFGUID
SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)918 SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
919 {
920 switch (effect->type) {
921 case SDL_HAPTIC_CONSTANT:
922 return &GUID_ConstantForce;
923
924 case SDL_HAPTIC_RAMP:
925 return &GUID_RampForce;
926
927 /* !!! FIXME: put this back when we have more bits in 2.1 */
928 /* case SDL_HAPTIC_SQUARE:
929 return &GUID_Square; */
930
931 case SDL_HAPTIC_SINE:
932 return &GUID_Sine;
933
934 case SDL_HAPTIC_TRIANGLE:
935 return &GUID_Triangle;
936
937 case SDL_HAPTIC_SAWTOOTHUP:
938 return &GUID_SawtoothUp;
939
940 case SDL_HAPTIC_SAWTOOTHDOWN:
941 return &GUID_SawtoothDown;
942
943 case SDL_HAPTIC_SPRING:
944 return &GUID_Spring;
945
946 case SDL_HAPTIC_DAMPER:
947 return &GUID_Damper;
948
949 case SDL_HAPTIC_INERTIA:
950 return &GUID_Inertia;
951
952 case SDL_HAPTIC_FRICTION:
953 return &GUID_Friction;
954
955 case SDL_HAPTIC_CUSTOM:
956 return &GUID_CustomForce;
957
958 default:
959 return NULL;
960 }
961 }
962 int
SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic,struct haptic_effect * effect,SDL_HapticEffect * base)963 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
964 {
965 HRESULT ret;
966 REFGUID type = SDL_SYS_HapticEffectType(base);
967
968 if (type == NULL) {
969 SDL_SetError("Haptic: Unknown effect type.");
970 return -1;
971 }
972
973 /* Get the effect. */
974 if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
975 goto err_effectdone;
976 }
977
978 /* Create the actual effect. */
979 ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type,
980 &effect->hweffect->effect,
981 &effect->hweffect->ref, NULL);
982 if (FAILED(ret)) {
983 DI_SetError("Unable to create effect", ret);
984 goto err_effectdone;
985 }
986
987 return 0;
988
989 err_effectdone:
990 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
991 return -1;
992 }
993
994 int
SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic,struct haptic_effect * effect,SDL_HapticEffect * data)995 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
996 {
997 HRESULT ret;
998 DWORD flags;
999 DIEFFECT temp;
1000
1001 /* Get the effect. */
1002 SDL_memset(&temp, 0, sizeof(DIEFFECT));
1003 if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
1004 goto err_update;
1005 }
1006
1007 /* Set the flags. Might be worthwhile to diff temp with loaded effect and
1008 * only change those parameters. */
1009 flags = DIEP_DIRECTION |
1010 DIEP_DURATION |
1011 DIEP_ENVELOPE |
1012 DIEP_STARTDELAY |
1013 DIEP_TRIGGERBUTTON |
1014 DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
1015
1016 /* Create the actual effect. */
1017 ret =
1018 IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
1019 if (FAILED(ret)) {
1020 DI_SetError("Unable to update effect", ret);
1021 goto err_update;
1022 }
1023
1024 /* Copy it over. */
1025 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
1026 SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
1027
1028 return 0;
1029
1030 err_update:
1031 SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
1032 return -1;
1033 }
1034
1035 int
SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic,struct haptic_effect * effect,Uint32 iterations)1036 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
1037 {
1038 HRESULT ret;
1039 DWORD iter;
1040
1041 /* Check if it's infinite. */
1042 if (iterations == SDL_HAPTIC_INFINITY) {
1043 iter = INFINITE;
1044 } else {
1045 iter = iterations;
1046 }
1047
1048 /* Run the effect. */
1049 ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
1050 if (FAILED(ret)) {
1051 return DI_SetError("Running the effect", ret);
1052 }
1053 return 0;
1054 }
1055
1056 int
SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic,struct haptic_effect * effect)1057 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1058 {
1059 HRESULT ret;
1060
1061 ret = IDirectInputEffect_Stop(effect->hweffect->ref);
1062 if (FAILED(ret)) {
1063 return DI_SetError("Unable to stop effect", ret);
1064 }
1065 return 0;
1066 }
1067
1068 void
SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic,struct haptic_effect * effect)1069 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1070 {
1071 HRESULT ret;
1072
1073 ret = IDirectInputEffect_Unload(effect->hweffect->ref);
1074 if (FAILED(ret)) {
1075 DI_SetError("Removing effect from the device", ret);
1076 }
1077 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type);
1078 }
1079
1080 int
SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic,struct haptic_effect * effect)1081 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
1082 {
1083 HRESULT ret;
1084 DWORD status;
1085
1086 ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
1087 if (FAILED(ret)) {
1088 return DI_SetError("Getting effect status", ret);
1089 }
1090
1091 if (status == 0)
1092 return SDL_FALSE;
1093 return SDL_TRUE;
1094 }
1095
1096 int
SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic,int gain)1097 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
1098 {
1099 HRESULT ret;
1100 DIPROPDWORD dipdw;
1101
1102 /* Create the weird structure thingy. */
1103 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1104 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1105 dipdw.diph.dwObj = 0;
1106 dipdw.diph.dwHow = DIPH_DEVICE;
1107 dipdw.dwData = gain * 100; /* 0 to 10,000 */
1108
1109 /* Try to set the autocenter. */
1110 ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
1111 DIPROP_FFGAIN, &dipdw.diph);
1112 if (FAILED(ret)) {
1113 return DI_SetError("Setting gain", ret);
1114 }
1115 return 0;
1116 }
1117
1118 int
SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic,int autocenter)1119 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1120 {
1121 HRESULT ret;
1122 DIPROPDWORD dipdw;
1123
1124 /* Create the weird structure thingy. */
1125 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1126 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1127 dipdw.diph.dwObj = 0;
1128 dipdw.diph.dwHow = DIPH_DEVICE;
1129 dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
1130 DIPROPAUTOCENTER_ON;
1131
1132 /* Try to set the autocenter. */
1133 ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device,
1134 DIPROP_AUTOCENTER, &dipdw.diph);
1135 if (FAILED(ret)) {
1136 return DI_SetError("Setting autocenter", ret);
1137 }
1138 return 0;
1139 }
1140
1141 int
SDL_DINPUT_HapticPause(SDL_Haptic * haptic)1142 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
1143 {
1144 HRESULT ret;
1145
1146 /* Pause the device. */
1147 ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
1148 DISFFC_PAUSE);
1149 if (FAILED(ret)) {
1150 return DI_SetError("Pausing the device", ret);
1151 }
1152 return 0;
1153 }
1154
1155 int
SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)1156 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
1157 {
1158 HRESULT ret;
1159
1160 /* Unpause the device. */
1161 ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
1162 DISFFC_CONTINUE);
1163 if (FAILED(ret)) {
1164 return DI_SetError("Pausing the device", ret);
1165 }
1166 return 0;
1167 }
1168
1169 int
SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)1170 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
1171 {
1172 HRESULT ret;
1173
1174 /* Try to stop the effects. */
1175 ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device,
1176 DISFFC_STOPALL);
1177 if (FAILED(ret)) {
1178 return DI_SetError("Stopping the device", ret);
1179 }
1180 return 0;
1181 }
1182
1183 #else /* !SDL_HAPTIC_DINPUT */
1184
1185 typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE;
1186 typedef struct SDL_hapticlist_item SDL_hapticlist_item;
1187
1188 int
SDL_DINPUT_HapticInit(void)1189 SDL_DINPUT_HapticInit(void)
1190 {
1191 return 0;
1192 }
1193
1194 int
SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)1195 SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance)
1196 {
1197 return SDL_Unsupported();
1198 }
1199
1200 int
SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)1201 SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance)
1202 {
1203 return SDL_Unsupported();
1204 }
1205
1206 int
SDL_DINPUT_HapticOpen(SDL_Haptic * haptic,SDL_hapticlist_item * item)1207 SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item)
1208 {
1209 return SDL_Unsupported();
1210 }
1211
1212 int
SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic,SDL_Joystick * joystick)1213 SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
1214 {
1215 return SDL_Unsupported();
1216 }
1217
1218 int
SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic,SDL_Joystick * joystick)1219 SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
1220 {
1221 return SDL_Unsupported();
1222 }
1223
1224 void
SDL_DINPUT_HapticClose(SDL_Haptic * haptic)1225 SDL_DINPUT_HapticClose(SDL_Haptic * haptic)
1226 {
1227 }
1228
1229 void
SDL_DINPUT_HapticQuit(void)1230 SDL_DINPUT_HapticQuit(void)
1231 {
1232 }
1233
1234 int
SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic,struct haptic_effect * effect,SDL_HapticEffect * base)1235 SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base)
1236 {
1237 return SDL_Unsupported();
1238 }
1239
1240 int
SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic,struct haptic_effect * effect,SDL_HapticEffect * data)1241 SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data)
1242 {
1243 return SDL_Unsupported();
1244 }
1245
1246 int
SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic,struct haptic_effect * effect,Uint32 iterations)1247 SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations)
1248 {
1249 return SDL_Unsupported();
1250 }
1251
1252 int
SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic,struct haptic_effect * effect)1253 SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1254 {
1255 return SDL_Unsupported();
1256 }
1257
1258 void
SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic,struct haptic_effect * effect)1259 SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1260 {
1261 }
1262
1263 int
SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic,struct haptic_effect * effect)1264 SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect)
1265 {
1266 return SDL_Unsupported();
1267 }
1268
1269 int
SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic,int gain)1270 SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain)
1271 {
1272 return SDL_Unsupported();
1273 }
1274
1275 int
SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic,int autocenter)1276 SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1277 {
1278 return SDL_Unsupported();
1279 }
1280
1281 int
SDL_DINPUT_HapticPause(SDL_Haptic * haptic)1282 SDL_DINPUT_HapticPause(SDL_Haptic * haptic)
1283 {
1284 return SDL_Unsupported();
1285 }
1286
1287 int
SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)1288 SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic)
1289 {
1290 return SDL_Unsupported();
1291 }
1292
1293 int
SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)1294 SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic)
1295 {
1296 return SDL_Unsupported();
1297 }
1298
1299 #endif /* SDL_HAPTIC_DINPUT */
1300
1301 /* vi: set ts=4 sw=4 expandtab: */
1302