Mercurial > sdl-ios-xcode
comparison src/haptic/win32/SDL_syshaptic.c @ 2713:0906692aa6a4
Final merge of Google Summer of Code 2008 work...
Force Feedback for SDL
by Edgar Simo, mentored by Ryan C. Gordon
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 25 Aug 2008 09:55:03 +0000 |
parents | |
children | 1d1be6137875 |
comparison
equal
deleted
inserted
replaced
2712:c4e697245676 | 2713:0906692aa6a4 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 2008 Edgar Simo | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Lesser General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2.1 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with this library; if not, write to the Free Software | |
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@libsdl.org | |
21 */ | |
22 #include "SDL_config.h" | |
23 | |
24 #ifdef SDL_HAPTIC_DINPUT | |
25 | |
26 #include "SDL_haptic.h" | |
27 #include "../SDL_syshaptic.h" | |
28 #include "SDL_joystick.h" | |
29 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ | |
30 #include "../../joystick/win32/SDL_dxjoystick_c.h" /* For joystick hwdata */ | |
31 | |
32 #define WIN32_LEAN_AND_MEAN | |
33 #include <windows.h> | |
34 | |
35 #define DIRECTINPUT_VERSION 0x0700 /* Need at least DirectX 7 for dwStartDelay */ | |
36 #include <dinput.h> | |
37 #include <dxerr.h> | |
38 #ifdef _MSC_VER | |
39 # pragma comment (lib, "dinput8.lib") | |
40 # pragma comment (lib, "dxguid.lib") | |
41 # pragma comment (lib, "dxerr.lib") | |
42 #endif /* _MSC_VER */ | |
43 | |
44 /* an ISO hack for VisualC++ */ | |
45 #ifdef _MSC_VER | |
46 #define snprintf _snprintf | |
47 #endif /* _MSC_VER */ | |
48 | |
49 | |
50 #define MAX_HAPTICS 32 | |
51 | |
52 | |
53 /* | |
54 * List of available haptic devices. | |
55 */ | |
56 static struct | |
57 { | |
58 DIDEVICEINSTANCE instance; | |
59 SDL_Haptic *haptic; | |
60 DIDEVCAPS capabilities; | |
61 } SDL_hapticlist[MAX_HAPTICS]; | |
62 | |
63 | |
64 /* | |
65 * Haptic system hardware data. | |
66 */ | |
67 struct haptic_hwdata | |
68 { | |
69 LPDIRECTINPUTDEVICE2 device; | |
70 DWORD axes[3]; /* Axes to use. */ | |
71 int is_joystick; /* Device is loaded as joystick. */ | |
72 }; | |
73 | |
74 | |
75 /* | |
76 * Haptic system effect data. | |
77 */ | |
78 struct haptic_hweffect | |
79 { | |
80 DIEFFECT effect; | |
81 LPDIRECTINPUTEFFECT ref; | |
82 }; | |
83 | |
84 | |
85 /* | |
86 * Internal stuff. | |
87 */ | |
88 static LPDIRECTINPUT dinput = NULL; | |
89 | |
90 | |
91 /* | |
92 * External stuff. | |
93 */ | |
94 extern HWND SDL_HelperWindow; | |
95 | |
96 | |
97 /* | |
98 * Prototypes. | |
99 */ | |
100 static void DI_SetError(const char *str, HRESULT err); | |
101 static int DI_GUIDIsSame(const GUID * a, const GUID * b); | |
102 static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, | |
103 DIDEVICEINSTANCE instance); | |
104 static int SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic, | |
105 LPDIRECTINPUTDEVICE2 device2); | |
106 static DWORD DIGetTriggerButton(Uint16 button); | |
107 static int SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, | |
108 int naxes); | |
109 static int SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest, | |
110 SDL_HapticEffect * src); | |
111 static void SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type); | |
112 static REFGUID SDL_SYS_HapticEffectType(SDL_HapticEffect * effect); | |
113 /* Callbacks. */ | |
114 static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE * | |
115 pdidInstance, VOID * pContext); | |
116 static BOOL CALLBACK DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv); | |
117 | |
118 | |
119 /* | |
120 * Like SDL_SetError but for DX error codes. | |
121 */ | |
122 static void | |
123 DI_SetError(const char *str, HRESULT err) | |
124 { | |
125 SDL_SetError("Haptic: %s - %s: %s", str, | |
126 DXGetErrorString(err), DXGetErrorDescription(err)); | |
127 } | |
128 | |
129 | |
130 /* | |
131 * Checks to see if two GUID are the same. | |
132 */ | |
133 static int | |
134 DI_GUIDIsSame(const GUID * a, const GUID * b) | |
135 { | |
136 if (((a)->Data1 == (b)->Data1) && | |
137 ((a)->Data2 == (b)->Data2) && | |
138 ((a)->Data3 == (b)->Data3) && | |
139 (SDL_strcmp((a)->Data4, (b)->Data4) == 0)) | |
140 return 1; | |
141 return 0; | |
142 } | |
143 | |
144 | |
145 /* | |
146 * Initializes the haptic subsystem. | |
147 */ | |
148 int | |
149 SDL_SYS_HapticInit(void) | |
150 { | |
151 HRESULT ret; | |
152 HINSTANCE instance; | |
153 | |
154 if (dinput != NULL) { /* Already open. */ | |
155 SDL_SetError("Haptic: SubSystem already open."); | |
156 return -1; | |
157 } | |
158 | |
159 /* Clear all the memory. */ | |
160 SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); | |
161 | |
162 SDL_numhaptics = 0; | |
163 | |
164 ret = CoInitialize(NULL); | |
165 if (FAILED(ret)) { | |
166 DI_SetError("Coinitialize", ret); | |
167 return -1; | |
168 } | |
169 | |
170 ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER, | |
171 &IID_IDirectInput, &dinput); | |
172 if (FAILED(ret)) { | |
173 DI_SetError("CoCreateInstance", ret); | |
174 return -1; | |
175 } | |
176 | |
177 /* Because we used CoCreateInstance, we need to Initialize it, first. */ | |
178 instance = GetModuleHandle(NULL); | |
179 if (instance == NULL) { | |
180 SDL_SetError("GetModuleHandle() failed with error code %d.", | |
181 GetLastError()); | |
182 return -1; | |
183 } | |
184 ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION); | |
185 if (FAILED(ret)) { | |
186 DI_SetError("Initializing DirectInput device", ret); | |
187 return -1; | |
188 } | |
189 | |
190 /* Look for haptic devices. */ | |
191 ret = IDirectInput_EnumDevices(dinput, 0, /* Not sure if this is legal, but gets all devices. */ | |
192 EnumHapticsCallback, | |
193 NULL, | |
194 DIEDFL_FORCEFEEDBACK | | |
195 DIEDFL_ATTACHEDONLY); | |
196 if (FAILED(ret)) { | |
197 DI_SetError("Enumerating DirectInput devices", ret); | |
198 return -1; | |
199 } | |
200 | |
201 return SDL_numhaptics; | |
202 } | |
203 | |
204 /* | |
205 * Callback to find the haptic devices. | |
206 */ | |
207 static BOOL CALLBACK | |
208 EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) | |
209 { | |
210 HRESULT ret; | |
211 LPDIRECTINPUTDEVICE device; | |
212 | |
213 /* Copy the instance over, useful for creating devices. */ | |
214 SDL_memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance, | |
215 sizeof(DIDEVICEINSTANCE)); | |
216 | |
217 /* Open the device */ | |
218 ret = IDirectInput_CreateDevice(dinput, &pdidInstance->guidInstance, | |
219 &device, NULL); | |
220 if (FAILED(ret)) { | |
221 /* DI_SetError("Creating DirectInput device",ret); */ | |
222 return DIENUM_CONTINUE; | |
223 } | |
224 | |
225 /* Get capabilities. */ | |
226 SDL_hapticlist[SDL_numhaptics].capabilities.dwSize = sizeof(DIDEVCAPS); | |
227 ret = IDirectInputDevice_GetCapabilities(device, | |
228 &SDL_hapticlist[SDL_numhaptics]. | |
229 capabilities); | |
230 if (FAILED(ret)) { | |
231 /* DI_SetError("Getting device capabilities",ret); */ | |
232 IDirectInputDevice_Release(device); | |
233 return DIENUM_CONTINUE; | |
234 } | |
235 | |
236 /* Close up device and count it. */ | |
237 IDirectInputDevice_Release(device); | |
238 SDL_numhaptics++; | |
239 | |
240 /* Watch out for hard limit. */ | |
241 if (SDL_numhaptics >= MAX_HAPTICS) | |
242 return DIENUM_STOP; | |
243 | |
244 return DIENUM_CONTINUE; | |
245 } | |
246 | |
247 | |
248 /* | |
249 * Return the name of a haptic device, does not need to be opened. | |
250 */ | |
251 const char * | |
252 SDL_SYS_HapticName(int index) | |
253 { | |
254 return SDL_hapticlist[index].instance.tszProductName; | |
255 } | |
256 | |
257 | |
258 /* | |
259 * Callback to get all supported effects. | |
260 */ | |
261 #define EFFECT_TEST(e,s) \ | |
262 if (DI_GUIDIsSame(&pei->guid, &(e))) \ | |
263 haptic->supported |= (s) | |
264 static BOOL CALLBACK | |
265 DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv) | |
266 { | |
267 /* Prepare the haptic device. */ | |
268 SDL_Haptic *haptic = (SDL_Haptic *) pv; | |
269 | |
270 /* Get supported. */ | |
271 EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING); | |
272 EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER); | |
273 EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA); | |
274 EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION); | |
275 EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT); | |
276 EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM); | |
277 EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE); | |
278 EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE); | |
279 EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE); | |
280 EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP); | |
281 EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN); | |
282 EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP); | |
283 | |
284 /* Check for more. */ | |
285 return DIENUM_CONTINUE; | |
286 } | |
287 | |
288 | |
289 /* | |
290 * Callback to get supported axes. | |
291 */ | |
292 static BOOL CALLBACK | |
293 DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef) | |
294 { | |
295 SDL_Haptic *haptic = (SDL_Haptic *) pvRef; | |
296 | |
297 if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) { | |
298 | |
299 haptic->hwdata->axes[haptic->naxes] = dev->dwOfs; | |
300 haptic->naxes++; | |
301 | |
302 /* Currently using the artificial limit of 3 axes. */ | |
303 if (haptic->naxes >= 3) { | |
304 return DIENUM_STOP; | |
305 } | |
306 } | |
307 | |
308 return DIENUM_CONTINUE; | |
309 } | |
310 | |
311 | |
312 /* | |
313 * Opens the haptic device from the file descriptor. | |
314 * | |
315 * Steps: | |
316 * - Open temporary DirectInputDevice interface. | |
317 * - Create DirectInputDevice2 interface. | |
318 * - Release DirectInputDevice interface. | |
319 * - Call SDL_SYS_HapticOpenFromDevice2 | |
320 */ | |
321 static int | |
322 SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance) | |
323 { | |
324 HRESULT ret; | |
325 int ret2; | |
326 LPDIRECTINPUTDEVICE device; | |
327 | |
328 /* Allocate the hwdata */ | |
329 haptic->hwdata = (struct haptic_hwdata *) | |
330 SDL_malloc(sizeof(*haptic->hwdata)); | |
331 if (haptic->hwdata == NULL) { | |
332 SDL_OutOfMemory(); | |
333 goto creat_err; | |
334 } | |
335 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); | |
336 | |
337 /* Open the device */ | |
338 ret = IDirectInput_CreateDevice(dinput, &instance.guidInstance, | |
339 &device, NULL); | |
340 if (FAILED(ret)) { | |
341 DI_SetError("Creating DirectInput device", ret); | |
342 goto creat_err; | |
343 } | |
344 | |
345 /* Now get the IDirectInputDevice2 interface, instead. */ | |
346 ret = IDirectInputDevice_QueryInterface(device, | |
347 &IID_IDirectInputDevice2, | |
348 (LPVOID *) & haptic->hwdata-> | |
349 device); | |
350 /* Done with the temporary one now. */ | |
351 IDirectInputDevice_Release(device); | |
352 if (FAILED(ret)) { | |
353 DI_SetError("Querying DirectInput interface", ret); | |
354 goto creat_err; | |
355 } | |
356 | |
357 ret2 = SDL_SYS_HapticOpenFromDevice2(haptic, haptic->hwdata->device); | |
358 if (ret2 < 0) { | |
359 goto query_err; | |
360 } | |
361 | |
362 return 0; | |
363 | |
364 query_err: | |
365 IDirectInputDevice2_Release(haptic->hwdata->device); | |
366 creat_err: | |
367 if (haptic->hwdata != NULL) { | |
368 SDL_free(haptic->hwdata); | |
369 haptic->hwdata = NULL; | |
370 } | |
371 return -1; | |
372 } | |
373 | |
374 | |
375 /* | |
376 * Opens the haptic device from the file descriptor. | |
377 * | |
378 * Steps: | |
379 * - Set cooperative level. | |
380 * - Set data format. | |
381 * - Acquire exclusiveness. | |
382 * - Reset actuators. | |
383 * - Get supported featuers. | |
384 */ | |
385 static int | |
386 SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic, | |
387 LPDIRECTINPUTDEVICE2 device2) | |
388 { | |
389 HRESULT ret; | |
390 DIPROPDWORD dipdw; | |
391 | |
392 /* We'll use the device2 from now on. */ | |
393 haptic->hwdata->device = device2; | |
394 | |
395 /* Grab it exclusively to use force feedback stuff. */ | |
396 ret = IDirectInputDevice2_SetCooperativeLevel(haptic->hwdata->device, | |
397 SDL_HelperWindow, | |
398 DISCL_EXCLUSIVE | | |
399 DISCL_BACKGROUND); | |
400 if (FAILED(ret)) { | |
401 DI_SetError("Setting cooperative level to exclusive", ret); | |
402 goto acquire_err; | |
403 } | |
404 | |
405 /* Set data format. */ | |
406 ret = IDirectInputDevice2_SetDataFormat(haptic->hwdata->device, | |
407 &c_dfDIJoystick2); | |
408 if (FAILED(ret)) { | |
409 DI_SetError("Setting data format", ret); | |
410 goto acquire_err; | |
411 } | |
412 | |
413 /* Get number of axes. */ | |
414 ret = IDirectInputDevice2_EnumObjects(haptic->hwdata->device, | |
415 DI_DeviceObjectCallback, | |
416 haptic, DIDFT_AXIS); | |
417 if (FAILED(ret)) { | |
418 DI_SetError("Getting device axes", ret); | |
419 goto acquire_err; | |
420 } | |
421 | |
422 /* Acquire the device. */ | |
423 ret = IDirectInputDevice2_Acquire(haptic->hwdata->device); | |
424 if (FAILED(ret)) { | |
425 DI_SetError("Acquiring DirectInput device", ret); | |
426 goto acquire_err; | |
427 } | |
428 | |
429 /* Reset all actuators - just in case. */ | |
430 ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, | |
431 DISFFC_RESET); | |
432 if (FAILED(ret)) { | |
433 DI_SetError("Resetting device", ret); | |
434 goto acquire_err; | |
435 } | |
436 | |
437 /* Enabling actuators. */ | |
438 ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, | |
439 DISFFC_SETACTUATORSON); | |
440 if (FAILED(ret)) { | |
441 DI_SetError("Enabling actuators", ret); | |
442 goto acquire_err; | |
443 } | |
444 | |
445 /* Get supported effects. */ | |
446 ret = IDirectInputDevice2_EnumEffects(haptic->hwdata->device, | |
447 DI_EffectCallback, haptic, | |
448 DIEFT_ALL); | |
449 if (FAILED(ret)) { | |
450 DI_SetError("Enumerating supported effects", ret); | |
451 goto acquire_err; | |
452 } | |
453 if (haptic->supported == 0) { /* Error since device supports nothing. */ | |
454 SDL_SetError("Haptic: Internal error on finding supported effects."); | |
455 goto acquire_err; | |
456 } | |
457 | |
458 /* Check autogain and autocenter. */ | |
459 dipdw.diph.dwSize = sizeof(DIPROPDWORD); | |
460 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
461 dipdw.diph.dwObj = 0; | |
462 dipdw.diph.dwHow = DIPH_DEVICE; | |
463 dipdw.dwData = 10000; | |
464 ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device, | |
465 DIPROP_FFGAIN, &dipdw.diph); | |
466 if (!FAILED(ret)) { /* Gain is supported. */ | |
467 haptic->supported |= SDL_HAPTIC_GAIN; | |
468 } | |
469 dipdw.diph.dwObj = 0; | |
470 dipdw.diph.dwHow = DIPH_DEVICE; | |
471 dipdw.dwData = DIPROPAUTOCENTER_OFF; | |
472 ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device, | |
473 DIPROP_AUTOCENTER, &dipdw.diph); | |
474 if (!FAILED(ret)) { /* Autocenter is supported. */ | |
475 haptic->supported |= SDL_HAPTIC_AUTOCENTER; | |
476 } | |
477 | |
478 /* Status is always supported. */ | |
479 haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; | |
480 | |
481 /* Check maximum effects. */ | |
482 haptic->neffects = 128; /* This is not actually supported as thus under windows, | |
483 there is no way to tell the number of EFFECTS that a | |
484 device can hold, so we'll just use a "random" number | |
485 instead and put warnings in SDL_haptic.h */ | |
486 haptic->nplaying = 128; /* Even more impossible to get this then neffects. */ | |
487 | |
488 /* Prepare effects memory. */ | |
489 haptic->effects = (struct haptic_effect *) | |
490 SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); | |
491 if (haptic->effects == NULL) { | |
492 SDL_OutOfMemory(); | |
493 goto acquire_err; | |
494 } | |
495 /* Clear the memory */ | |
496 SDL_memset(haptic->effects, 0, | |
497 sizeof(struct haptic_effect) * haptic->neffects); | |
498 | |
499 return 0; | |
500 | |
501 /* Error handling */ | |
502 acquire_err: | |
503 IDirectInputDevice2_Unacquire(haptic->hwdata->device); | |
504 return -1; | |
505 | |
506 } | |
507 | |
508 | |
509 /* | |
510 * Opens a haptic device for usage. | |
511 */ | |
512 int | |
513 SDL_SYS_HapticOpen(SDL_Haptic * haptic) | |
514 { | |
515 return SDL_SYS_HapticOpenFromInstance(haptic, | |
516 SDL_hapticlist[haptic->index]. | |
517 instance); | |
518 } | |
519 | |
520 | |
521 /* | |
522 * Opens a haptic device from first mouse it finds for usage. | |
523 */ | |
524 int | |
525 SDL_SYS_HapticMouse(void) | |
526 { | |
527 int i; | |
528 | |
529 /* Grab the first mouse haptic device we find. */ | |
530 for (i = 0; i < SDL_numhaptics; i++) { | |
531 if (SDL_hapticlist[i].capabilities.dwDevType == DIDEVTYPE_MOUSE) { | |
532 return i; | |
533 } | |
534 } | |
535 | |
536 return -1; | |
537 } | |
538 | |
539 | |
540 /* | |
541 * Checks to see if a joystick has haptic features. | |
542 */ | |
543 int | |
544 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick) | |
545 { | |
546 if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) { | |
547 return SDL_TRUE; | |
548 } | |
549 | |
550 return SDL_FALSE; | |
551 } | |
552 | |
553 | |
554 /* | |
555 * Checks to see if the haptic device and joystick and in reality the same. | |
556 */ | |
557 int | |
558 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) | |
559 { | |
560 HRESULT ret; | |
561 DIDEVICEINSTANCE hap_instance, joy_instance; | |
562 | |
563 /* Get the device instances. */ | |
564 ret = IDirectInputDevice2_GetDeviceInfo(haptic->hwdata->device, | |
565 &hap_instance); | |
566 if (FAILED(ret)) { | |
567 return 0; | |
568 } | |
569 ret = IDirectInputDevice2_GetDeviceInfo(joystick->hwdata->InputDevice, | |
570 &joy_instance); | |
571 if (FAILED(ret)) { | |
572 return 0; | |
573 } | |
574 | |
575 if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance)) | |
576 return 1; | |
577 | |
578 return 0; | |
579 } | |
580 | |
581 | |
582 /* | |
583 * Opens a SDL_Haptic from a SDL_Joystick. | |
584 */ | |
585 int | |
586 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) | |
587 { | |
588 int ret; | |
589 | |
590 /* Allocate the hwdata */ | |
591 haptic->hwdata = (struct haptic_hwdata *) | |
592 SDL_malloc(sizeof(*haptic->hwdata)); | |
593 if (haptic->hwdata == NULL) { | |
594 SDL_OutOfMemory(); | |
595 return -1; | |
596 } | |
597 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); | |
598 | |
599 /* Now open the device. */ | |
600 ret = | |
601 SDL_SYS_HapticOpenFromDevice2(haptic, joystick->hwdata->InputDevice); | |
602 if (ret < 0) { | |
603 return -1; | |
604 } | |
605 | |
606 /* It's using the joystick device. */ | |
607 haptic->hwdata->is_joystick = 1; | |
608 | |
609 return 0; | |
610 } | |
611 | |
612 | |
613 /* | |
614 * Closes the haptic device. | |
615 */ | |
616 void | |
617 SDL_SYS_HapticClose(SDL_Haptic * haptic) | |
618 { | |
619 if (haptic->hwdata) { | |
620 | |
621 /* Free effects. */ | |
622 SDL_free(haptic->effects); | |
623 haptic->effects = NULL; | |
624 haptic->neffects = 0; | |
625 | |
626 /* Clean up */ | |
627 IDirectInputDevice2_Unacquire(haptic->hwdata->device); | |
628 /* Only release if isn't grabbed by a joystick. */ | |
629 if (haptic->hwdata->is_joystick == 0) { | |
630 IDirectInputDevice2_Release(haptic->hwdata->device); | |
631 } | |
632 | |
633 /* Free */ | |
634 SDL_free(haptic->hwdata); | |
635 haptic->hwdata = NULL; | |
636 } | |
637 } | |
638 | |
639 | |
640 /* | |
641 * Clean up after system specific haptic stuff | |
642 */ | |
643 void | |
644 SDL_SYS_HapticQuit(void) | |
645 { | |
646 IDirectInput_Release(dinput); | |
647 dinput = NULL; | |
648 } | |
649 | |
650 | |
651 /* | |
652 * Converts an SDL trigger button to an DIEFFECT trigger button. | |
653 */ | |
654 static DWORD | |
655 DIGetTriggerButton(Uint16 button) | |
656 { | |
657 DWORD dwTriggerButton; | |
658 | |
659 dwTriggerButton = DIEB_NOTRIGGER; | |
660 | |
661 if (button != 0) { | |
662 dwTriggerButton = DIJOFS_BUTTON(button - 1); | |
663 } | |
664 | |
665 return dwTriggerButton; | |
666 } | |
667 | |
668 | |
669 /* | |
670 * Sets the direction. | |
671 */ | |
672 static int | |
673 SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes) | |
674 { | |
675 LONG *rglDir; | |
676 | |
677 /* Handle no axes a part. */ | |
678 if (naxes == 0) { | |
679 effect->dwFlags |= DIEFF_SPHERICAL; /* Set as default. */ | |
680 effect->rglDirection = NULL; | |
681 return 0; | |
682 } | |
683 | |
684 /* Has axes. */ | |
685 rglDir = SDL_malloc(sizeof(LONG) * naxes); | |
686 if (rglDir == NULL) { | |
687 SDL_OutOfMemory(); | |
688 return -1; | |
689 } | |
690 SDL_memset(rglDir, 0, sizeof(LONG) * naxes); | |
691 effect->rglDirection = rglDir; | |
692 | |
693 switch (dir->type) { | |
694 case SDL_HAPTIC_POLAR: | |
695 effect->dwFlags |= DIEFF_POLAR; | |
696 rglDir[0] = dir->dir[0]; | |
697 return 0; | |
698 case SDL_HAPTIC_CARTESIAN: | |
699 effect->dwFlags |= DIEFF_CARTESIAN; | |
700 rglDir[0] = dir->dir[0]; | |
701 if (naxes > 1) | |
702 rglDir[1] = dir->dir[1]; | |
703 if (naxes > 2) | |
704 rglDir[2] = dir->dir[2]; | |
705 return 0; | |
706 case SDL_HAPTIC_SPHERICAL: | |
707 effect->dwFlags |= DIEFF_SPHERICAL; | |
708 rglDir[0] = dir->dir[0]; | |
709 if (naxes > 1) | |
710 rglDir[1] = dir->dir[1]; | |
711 if (naxes > 2) | |
712 rglDir[2] = dir->dir[2]; | |
713 return 0; | |
714 | |
715 default: | |
716 SDL_SetError("Haptic: Unknown direction type."); | |
717 return -1; | |
718 } | |
719 } | |
720 | |
721 #define CONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF) | |
722 /* | |
723 * Creates the DIEFFECT from a SDL_HapticEffect. | |
724 */ | |
725 static int | |
726 SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest, | |
727 SDL_HapticEffect * src) | |
728 { | |
729 int i; | |
730 DICONSTANTFORCE *constant; | |
731 DIPERIODIC *periodic; | |
732 DICONDITION *condition; /* Actually an array of conditions - one per axis. */ | |
733 DIRAMPFORCE *ramp; | |
734 DICUSTOMFORCE *custom; | |
735 DIENVELOPE *envelope; | |
736 SDL_HapticConstant *hap_constant; | |
737 SDL_HapticPeriodic *hap_periodic; | |
738 SDL_HapticCondition *hap_condition; | |
739 SDL_HapticRamp *hap_ramp; | |
740 SDL_HapticCustom *hap_custom; | |
741 DWORD *axes; | |
742 | |
743 /* Set global stuff. */ | |
744 SDL_memset(dest, 0, sizeof(DIEFFECT)); | |
745 dest->dwSize = sizeof(DIEFFECT); /* Set the structure size. */ | |
746 dest->dwSamplePeriod = 0; /* Not used by us. */ | |
747 dest->dwGain = 10000; /* Gain is set globally, not locally. */ | |
748 dest->dwFlags = DIEFF_OBJECTOFFSETS; /* Seems obligatory. */ | |
749 | |
750 /* Envelope. */ | |
751 envelope = SDL_malloc(sizeof(DIENVELOPE)); | |
752 if (envelope == NULL) { | |
753 SDL_OutOfMemory(); | |
754 return -1; | |
755 } | |
756 SDL_memset(envelope, 0, sizeof(DIENVELOPE)); | |
757 dest->lpEnvelope = envelope; | |
758 envelope->dwSize = sizeof(DIENVELOPE); /* Always should be this. */ | |
759 | |
760 /* Axes. */ | |
761 dest->cAxes = haptic->naxes; | |
762 if (dest->cAxes > 0) { | |
763 axes = SDL_malloc(sizeof(DWORD) * dest->cAxes); | |
764 if (axes == NULL) { | |
765 SDL_OutOfMemory(); | |
766 return -1; | |
767 } | |
768 axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */ | |
769 if (dest->cAxes > 1) { | |
770 axes[1] = haptic->hwdata->axes[1]; | |
771 } | |
772 if (dest->cAxes > 2) { | |
773 axes[2] = haptic->hwdata->axes[2]; | |
774 } | |
775 dest->rgdwAxes = axes; | |
776 } | |
777 | |
778 | |
779 /* The big type handling switch, even bigger then linux's version. */ | |
780 switch (src->type) { | |
781 case SDL_HAPTIC_CONSTANT: | |
782 hap_constant = &src->constant; | |
783 constant = SDL_malloc(sizeof(DICONSTANTFORCE)); | |
784 if (constant == NULL) { | |
785 SDL_OutOfMemory(); | |
786 return -1; | |
787 } | |
788 SDL_memset(constant, 0, sizeof(DICONSTANTFORCE)); | |
789 | |
790 /* Specifics */ | |
791 constant->lMagnitude = CONVERT(hap_constant->level); | |
792 dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE); | |
793 dest->lpvTypeSpecificParams = constant; | |
794 | |
795 /* Generics */ | |
796 dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */ | |
797 dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button); | |
798 dest->dwTriggerRepeatInterval = hap_constant->interval; | |
799 dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */ | |
800 | |
801 /* Direction. */ | |
802 if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) | |
803 < 0) { | |
804 return -1; | |
805 } | |
806 | |
807 /* Envelope */ | |
808 if ((hap_constant->attack_length == 0) | |
809 && (hap_constant->fade_length == 0)) { | |
810 SDL_free(dest->lpEnvelope); | |
811 dest->lpEnvelope = NULL; | |
812 } else { | |
813 envelope->dwAttackLevel = CONVERT(hap_constant->attack_level); | |
814 envelope->dwAttackTime = hap_constant->attack_length * 1000; | |
815 envelope->dwFadeLevel = CONVERT(hap_constant->fade_level); | |
816 envelope->dwFadeTime = hap_constant->fade_length * 1000; | |
817 } | |
818 | |
819 break; | |
820 | |
821 case SDL_HAPTIC_SINE: | |
822 case SDL_HAPTIC_SQUARE: | |
823 case SDL_HAPTIC_TRIANGLE: | |
824 case SDL_HAPTIC_SAWTOOTHUP: | |
825 case SDL_HAPTIC_SAWTOOTHDOWN: | |
826 hap_periodic = &src->periodic; | |
827 periodic = SDL_malloc(sizeof(DIPERIODIC)); | |
828 if (periodic == NULL) { | |
829 SDL_OutOfMemory(); | |
830 return -1; | |
831 } | |
832 SDL_memset(periodic, 0, sizeof(DIPERIODIC)); | |
833 | |
834 /* Specifics */ | |
835 periodic->dwMagnitude = CONVERT(hap_periodic->magnitude); | |
836 periodic->lOffset = CONVERT(hap_periodic->offset); | |
837 periodic->dwPhase = hap_periodic->phase; | |
838 periodic->dwPeriod = hap_periodic->period * 1000; | |
839 dest->cbTypeSpecificParams = sizeof(DIPERIODIC); | |
840 dest->lpvTypeSpecificParams = periodic; | |
841 | |
842 /* Generics */ | |
843 dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */ | |
844 dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button); | |
845 dest->dwTriggerRepeatInterval = hap_periodic->interval; | |
846 dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */ | |
847 | |
848 /* Direction. */ | |
849 if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) | |
850 < 0) { | |
851 return -1; | |
852 } | |
853 | |
854 /* Envelope */ | |
855 if ((hap_periodic->attack_length == 0) | |
856 && (hap_periodic->fade_length == 0)) { | |
857 SDL_free(dest->lpEnvelope); | |
858 dest->lpEnvelope = NULL; | |
859 } else { | |
860 envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level); | |
861 envelope->dwAttackTime = hap_periodic->attack_length * 1000; | |
862 envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level); | |
863 envelope->dwFadeTime = hap_periodic->fade_length * 1000; | |
864 } | |
865 | |
866 break; | |
867 | |
868 case SDL_HAPTIC_SPRING: | |
869 case SDL_HAPTIC_DAMPER: | |
870 case SDL_HAPTIC_INERTIA: | |
871 case SDL_HAPTIC_FRICTION: | |
872 hap_condition = &src->condition; | |
873 condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes); | |
874 if (condition == NULL) { | |
875 SDL_OutOfMemory(); | |
876 return -1; | |
877 } | |
878 SDL_memset(condition, 0, sizeof(DICONDITION)); | |
879 | |
880 /* Specifics */ | |
881 for (i = 0; i < (int) dest->cAxes; i++) { | |
882 condition[i].lOffset = CONVERT(hap_condition->center[i]); | |
883 condition[i].lPositiveCoefficient = | |
884 CONVERT(hap_condition->right_coeff[i]); | |
885 condition[i].lNegativeCoefficient = | |
886 CONVERT(hap_condition->left_coeff[i]); | |
887 condition[i].dwPositiveSaturation = | |
888 CONVERT(hap_condition->right_sat[i]); | |
889 condition[i].dwNegativeSaturation = | |
890 CONVERT(hap_condition->left_sat[i]); | |
891 condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]); | |
892 } | |
893 dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes; | |
894 dest->lpvTypeSpecificParams = condition; | |
895 | |
896 /* Generics */ | |
897 dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */ | |
898 dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button); | |
899 dest->dwTriggerRepeatInterval = hap_condition->interval; | |
900 dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */ | |
901 | |
902 /* Direction. */ | |
903 if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) | |
904 < 0) { | |
905 return -1; | |
906 } | |
907 | |
908 /* Envelope - Not actually supported by most CONDITION implementations. */ | |
909 SDL_free(dest->lpEnvelope); | |
910 dest->lpEnvelope = NULL; | |
911 | |
912 break; | |
913 | |
914 case SDL_HAPTIC_RAMP: | |
915 hap_ramp = &src->ramp; | |
916 ramp = SDL_malloc(sizeof(DIRAMPFORCE)); | |
917 if (ramp == NULL) { | |
918 SDL_OutOfMemory(); | |
919 return -1; | |
920 } | |
921 SDL_memset(ramp, 0, sizeof(DIRAMPFORCE)); | |
922 | |
923 /* Specifics */ | |
924 ramp->lStart = CONVERT(hap_ramp->start); | |
925 ramp->lEnd = CONVERT(hap_ramp->end); | |
926 dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE); | |
927 dest->lpvTypeSpecificParams = ramp; | |
928 | |
929 /* Generics */ | |
930 dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */ | |
931 dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button); | |
932 dest->dwTriggerRepeatInterval = hap_ramp->interval; | |
933 dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */ | |
934 | |
935 /* Direction. */ | |
936 if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) { | |
937 return -1; | |
938 } | |
939 | |
940 /* Envelope */ | |
941 if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) { | |
942 SDL_free(dest->lpEnvelope); | |
943 dest->lpEnvelope = NULL; | |
944 } else { | |
945 envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level); | |
946 envelope->dwAttackTime = hap_ramp->attack_length * 1000; | |
947 envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level); | |
948 envelope->dwFadeTime = hap_ramp->fade_length * 1000; | |
949 } | |
950 | |
951 break; | |
952 | |
953 case SDL_HAPTIC_CUSTOM: | |
954 hap_custom = &src->custom; | |
955 custom = SDL_malloc(sizeof(DICUSTOMFORCE)); | |
956 if (custom == NULL) { | |
957 SDL_OutOfMemory(); | |
958 return -1; | |
959 } | |
960 SDL_memset(custom, 0, sizeof(DICUSTOMFORCE)); | |
961 | |
962 /* Specifics */ | |
963 custom->cChannels = hap_custom->channels; | |
964 custom->dwSamplePeriod = hap_custom->period * 1000; | |
965 custom->cSamples = hap_custom->samples; | |
966 custom->rglForceData = | |
967 SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels); | |
968 for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) { /* Copy data. */ | |
969 custom->rglForceData[i] = CONVERT(hap_custom->data[i]); | |
970 } | |
971 dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE); | |
972 dest->lpvTypeSpecificParams = custom; | |
973 | |
974 /* Generics */ | |
975 dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */ | |
976 dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button); | |
977 dest->dwTriggerRepeatInterval = hap_custom->interval; | |
978 dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */ | |
979 | |
980 /* Direction. */ | |
981 if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < | |
982 0) { | |
983 return -1; | |
984 } | |
985 | |
986 /* Envelope */ | |
987 if ((hap_custom->attack_length == 0) | |
988 && (hap_custom->fade_length == 0)) { | |
989 SDL_free(dest->lpEnvelope); | |
990 dest->lpEnvelope = NULL; | |
991 } else { | |
992 envelope->dwAttackLevel = CONVERT(hap_custom->attack_level); | |
993 envelope->dwAttackTime = hap_custom->attack_length * 1000; | |
994 envelope->dwFadeLevel = CONVERT(hap_custom->fade_level); | |
995 envelope->dwFadeTime = hap_custom->fade_length * 1000; | |
996 } | |
997 | |
998 break; | |
999 | |
1000 | |
1001 default: | |
1002 SDL_SetError("Haptic: Unknown effect type."); | |
1003 return -1; | |
1004 } | |
1005 | |
1006 return 0; | |
1007 } | |
1008 | |
1009 | |
1010 /* | |
1011 * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT. | |
1012 */ | |
1013 static void | |
1014 SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type) | |
1015 { | |
1016 DICUSTOMFORCE *custom; | |
1017 | |
1018 if (effect->lpEnvelope != NULL) { | |
1019 SDL_free(effect->lpEnvelope); | |
1020 effect->lpEnvelope = NULL; | |
1021 } | |
1022 if (effect->rgdwAxes != NULL) { | |
1023 SDL_free(effect->rgdwAxes); | |
1024 effect->rgdwAxes = NULL; | |
1025 } | |
1026 if (effect->lpvTypeSpecificParams != NULL) { | |
1027 if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */ | |
1028 custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams; | |
1029 SDL_free(custom->rglForceData); | |
1030 custom->rglForceData = NULL; | |
1031 } | |
1032 SDL_free(effect->lpvTypeSpecificParams); | |
1033 effect->lpvTypeSpecificParams = NULL; | |
1034 } | |
1035 if (effect->rglDirection != NULL) { | |
1036 SDL_free(effect->rglDirection); | |
1037 effect->rglDirection = NULL; | |
1038 } | |
1039 } | |
1040 | |
1041 | |
1042 /* | |
1043 * Gets the effect type from the generic SDL haptic effect wrapper. | |
1044 */ | |
1045 static REFGUID | |
1046 SDL_SYS_HapticEffectType(SDL_HapticEffect * effect) | |
1047 { | |
1048 switch (effect->type) { | |
1049 case SDL_HAPTIC_CONSTANT: | |
1050 return &GUID_ConstantForce; | |
1051 | |
1052 case SDL_HAPTIC_RAMP: | |
1053 return &GUID_RampForce; | |
1054 | |
1055 case SDL_HAPTIC_SQUARE: | |
1056 return &GUID_Square; | |
1057 | |
1058 case SDL_HAPTIC_SINE: | |
1059 return &GUID_Sine; | |
1060 | |
1061 case SDL_HAPTIC_TRIANGLE: | |
1062 return &GUID_Triangle; | |
1063 | |
1064 case SDL_HAPTIC_SAWTOOTHUP: | |
1065 return &GUID_SawtoothUp; | |
1066 | |
1067 case SDL_HAPTIC_SAWTOOTHDOWN: | |
1068 return &GUID_SawtoothDown; | |
1069 | |
1070 case SDL_HAPTIC_SPRING: | |
1071 return &GUID_Spring; | |
1072 | |
1073 case SDL_HAPTIC_DAMPER: | |
1074 return &GUID_Damper; | |
1075 | |
1076 case SDL_HAPTIC_INERTIA: | |
1077 return &GUID_Inertia; | |
1078 | |
1079 case SDL_HAPTIC_FRICTION: | |
1080 return &GUID_Friction; | |
1081 | |
1082 case SDL_HAPTIC_CUSTOM: | |
1083 return &GUID_CustomForce; | |
1084 | |
1085 default: | |
1086 SDL_SetError("Haptic: Unknown effect type."); | |
1087 return NULL; | |
1088 } | |
1089 } | |
1090 | |
1091 | |
1092 /* | |
1093 * Creates a new haptic effect. | |
1094 */ | |
1095 int | |
1096 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, | |
1097 SDL_HapticEffect * base) | |
1098 { | |
1099 HRESULT ret; | |
1100 | |
1101 /* Get the type. */ | |
1102 REFGUID type = SDL_SYS_HapticEffectType(base); | |
1103 if (type == NULL) { | |
1104 goto err_hweffect; | |
1105 } | |
1106 | |
1107 /* Alloc the effect. */ | |
1108 effect->hweffect = (struct haptic_hweffect *) | |
1109 SDL_malloc(sizeof(struct haptic_hweffect)); | |
1110 if (effect->hweffect == NULL) { | |
1111 SDL_OutOfMemory(); | |
1112 goto err_hweffect; | |
1113 } | |
1114 | |
1115 /* Get the effect. */ | |
1116 if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) { | |
1117 goto err_effectdone; | |
1118 } | |
1119 | |
1120 /* Create the actual effect. */ | |
1121 ret = IDirectInputDevice2_CreateEffect(haptic->hwdata->device, type, | |
1122 &effect->hweffect->effect, | |
1123 &effect->hweffect->ref, NULL); | |
1124 if (FAILED(ret)) { | |
1125 DI_SetError("Unable to create effect", ret); | |
1126 goto err_effectdone; | |
1127 } | |
1128 | |
1129 return 0; | |
1130 | |
1131 err_effectdone: | |
1132 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type); | |
1133 err_hweffect: | |
1134 if (effect->hweffect != NULL) { | |
1135 SDL_free(effect->hweffect); | |
1136 effect->hweffect = NULL; | |
1137 } | |
1138 return -1; | |
1139 } | |
1140 | |
1141 | |
1142 /* | |
1143 * Updates an effect. | |
1144 */ | |
1145 int | |
1146 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, | |
1147 struct haptic_effect *effect, | |
1148 SDL_HapticEffect * data) | |
1149 { | |
1150 HRESULT ret; | |
1151 DWORD flags; | |
1152 DIEFFECT temp; | |
1153 | |
1154 /* Get the effect. */ | |
1155 SDL_memset(&temp, 0, sizeof(DIEFFECT)); | |
1156 if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) { | |
1157 goto err_update; | |
1158 } | |
1159 | |
1160 /* Set the flags. Might be worthwhile to diff temp with loaded effect and | |
1161 * only change those parameters. */ | |
1162 flags = DIEP_DIRECTION | | |
1163 DIEP_DURATION | | |
1164 DIEP_ENVELOPE | | |
1165 DIEP_STARTDELAY | | |
1166 DIEP_TRIGGERBUTTON | | |
1167 DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; | |
1168 | |
1169 /* Create the actual effect. */ | |
1170 ret = | |
1171 IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); | |
1172 if (FAILED(ret)) { | |
1173 DI_SetError("Unable to update effect", ret); | |
1174 goto err_update; | |
1175 } | |
1176 | |
1177 /* Copy it over. */ | |
1178 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type); | |
1179 SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT)); | |
1180 | |
1181 return 0; | |
1182 | |
1183 err_update: | |
1184 SDL_SYS_HapticFreeDIEFFECT(&temp, data->type); | |
1185 return -1; | |
1186 } | |
1187 | |
1188 | |
1189 /* | |
1190 * Runs an effect. | |
1191 */ | |
1192 int | |
1193 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, | |
1194 Uint32 iterations) | |
1195 { | |
1196 HRESULT ret; | |
1197 DWORD iter; | |
1198 | |
1199 /* Check if it's infinite. */ | |
1200 if (iterations == SDL_HAPTIC_INFINITY) { | |
1201 iter = INFINITE; | |
1202 } else | |
1203 iter = iterations; | |
1204 | |
1205 /* Run the effect. */ | |
1206 ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0); | |
1207 if (FAILED(ret)) { | |
1208 DI_SetError("Running the effect", ret); | |
1209 return -1; | |
1210 } | |
1211 | |
1212 return 0; | |
1213 } | |
1214 | |
1215 | |
1216 /* | |
1217 * Stops an effect. | |
1218 */ | |
1219 int | |
1220 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) | |
1221 { | |
1222 HRESULT ret; | |
1223 | |
1224 ret = IDirectInputEffect_Stop(effect->hweffect->ref); | |
1225 if (FAILED(ret)) { | |
1226 DI_SetError("Unable to stop effect", ret); | |
1227 return -1; | |
1228 } | |
1229 | |
1230 return 0; | |
1231 } | |
1232 | |
1233 | |
1234 /* | |
1235 * Frees the effect. | |
1236 */ | |
1237 void | |
1238 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) | |
1239 { | |
1240 HRESULT ret; | |
1241 | |
1242 ret = IDirectInputEffect_Unload(effect->hweffect->ref); | |
1243 if (FAILED(ret)) { | |
1244 DI_SetError("Removing effect from the device", ret); | |
1245 } | |
1246 SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, | |
1247 effect->effect.type); | |
1248 SDL_free(effect->hweffect); | |
1249 effect->hweffect = NULL; | |
1250 } | |
1251 | |
1252 | |
1253 /* | |
1254 * Gets the status of a haptic effect. | |
1255 */ | |
1256 int | |
1257 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, | |
1258 struct haptic_effect *effect) | |
1259 { | |
1260 HRESULT ret; | |
1261 DWORD status; | |
1262 | |
1263 ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status); | |
1264 if (FAILED(ret)) { | |
1265 DI_SetError("Getting effect status", ret); | |
1266 return -1; | |
1267 } | |
1268 | |
1269 if (status == 0) | |
1270 return SDL_FALSE; | |
1271 return SDL_TRUE; | |
1272 } | |
1273 | |
1274 | |
1275 /* | |
1276 * Sets the gain. | |
1277 */ | |
1278 int | |
1279 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) | |
1280 { | |
1281 HRESULT ret; | |
1282 DIPROPDWORD dipdw; | |
1283 | |
1284 /* Create the weird structure thingy. */ | |
1285 dipdw.diph.dwSize = sizeof(DIPROPDWORD); | |
1286 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
1287 dipdw.diph.dwObj = 0; | |
1288 dipdw.diph.dwHow = DIPH_DEVICE; | |
1289 dipdw.dwData = gain * 100; /* 0 to 10,000 */ | |
1290 | |
1291 /* Try to set the autocenter. */ | |
1292 ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device, | |
1293 DIPROP_FFGAIN, &dipdw.diph); | |
1294 if (FAILED(ret)) { | |
1295 DI_SetError("Setting gain", ret); | |
1296 return -1; | |
1297 } | |
1298 | |
1299 return 0; | |
1300 } | |
1301 | |
1302 | |
1303 /* | |
1304 * Sets the autocentering. | |
1305 */ | |
1306 int | |
1307 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) | |
1308 { | |
1309 HRESULT ret; | |
1310 DIPROPDWORD dipdw; | |
1311 | |
1312 /* Create the weird structure thingy. */ | |
1313 dipdw.diph.dwSize = sizeof(DIPROPDWORD); | |
1314 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
1315 dipdw.diph.dwObj = 0; | |
1316 dipdw.diph.dwHow = DIPH_DEVICE; | |
1317 dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF : | |
1318 DIPROPAUTOCENTER_ON; | |
1319 | |
1320 /* Try to set the autocenter. */ | |
1321 ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device, | |
1322 DIPROP_AUTOCENTER, &dipdw.diph); | |
1323 if (FAILED(ret)) { | |
1324 DI_SetError("Setting autocenter", ret); | |
1325 return -1; | |
1326 } | |
1327 | |
1328 return 0; | |
1329 } | |
1330 | |
1331 | |
1332 /* | |
1333 * Pauses the device. | |
1334 */ | |
1335 int | |
1336 SDL_SYS_HapticPause(SDL_Haptic * haptic) | |
1337 { | |
1338 HRESULT ret; | |
1339 | |
1340 /* Pause the device. */ | |
1341 ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, | |
1342 DISFFC_PAUSE); | |
1343 if (FAILED(ret)) { | |
1344 DI_SetError("Pausing the device", ret); | |
1345 return -1; | |
1346 } | |
1347 | |
1348 return 0; | |
1349 } | |
1350 | |
1351 | |
1352 /* | |
1353 * Pauses the device. | |
1354 */ | |
1355 int | |
1356 SDL_SYS_HapticUnpause(SDL_Haptic * haptic) | |
1357 { | |
1358 HRESULT ret; | |
1359 | |
1360 /* Unpause the device. */ | |
1361 ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, | |
1362 DISFFC_CONTINUE); | |
1363 if (FAILED(ret)) { | |
1364 DI_SetError("Pausing the device", ret); | |
1365 return -1; | |
1366 } | |
1367 | |
1368 return 0; | |
1369 } | |
1370 | |
1371 | |
1372 /* | |
1373 * Stops all the playing effects on the device. | |
1374 */ | |
1375 int | |
1376 SDL_SYS_HapticUnpause(SDL_Haptic * haptic) | |
1377 { | |
1378 HRESULT ret; | |
1379 | |
1380 /* Try to stop the effects. */ | |
1381 ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, | |
1382 DISFFC_STOPALL); | |
1383 if (FAILED(ret)) { | |
1384 DI_SetError("Stopping the device", ret); | |
1385 return -1; | |
1386 } | |
1387 | |
1388 return 0; | |
1389 } | |
1390 | |
1391 | |
1392 #endif /* SDL_HAPTIC_DINPUT */ |