Atlas - SDL_dinputhaptic.c

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