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