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