From bd13abc2748586a194096c347b7b00b3d9555d89 Mon Sep 17 00:00:00 2001 From: beaglejoe Date: Mon, 15 Aug 2016 05:43:59 +0000 Subject: [PATCH] Updated SDL2 to 2.0.4 with patch for FF git-svn-id: https://svn.code.sf.net/p/speed-dreams/code/trunk@6469 30fe4595-0a0c-4342-8851-515496e4dcbd Former-commit-id: d8c2e7e99b34aff043e90feb75acdbba1632745b Former-commit-id: 84fd8362c060411af6d36a6a54949c29df0a4187 --- packaging/3rdParty-devel/CMakeLists.txt | 38 +- .../patches/SDL_dinputhaptic.c.patched | 1329 +++++++++++++++++ 2 files changed, 1354 insertions(+), 13 deletions(-) create mode 100644 packaging/3rdParty-devel/patches/SDL_dinputhaptic.c.patched diff --git a/packaging/3rdParty-devel/CMakeLists.txt b/packaging/3rdParty-devel/CMakeLists.txt index d196ae30d..8daaa9882 100644 --- a/packaging/3rdParty-devel/CMakeLists.txt +++ b/packaging/3rdParty-devel/CMakeLists.txt @@ -5,7 +5,7 @@ # created : Aug 5 2015 # copyright : (C) 2015 Joe Thompson # email : beaglejoe@users.sourceforge.net -# version : $Id:$ +# version : $Id: $ # #============================================================================== # @@ -125,14 +125,26 @@ endif(OPTION_SDL_1x) # message(WARNING "TODO - need to disable SDL2 static (it is overwritten by dll's SDL2.lib)") if(OPTION_SDL_2x) -set(SDL2_ARGS ${EXTERNALS_CMAKE_ARGS} -DSDL_STATIC=Off) -message(STATUS "CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}") -ExternalProject_Add(SDL2-2.0.3 - URL https://www.libsdl.org/release/SDL2-2.0.3.tar.gz - URL_HASH SHA256=A5A69A6ABF80BCCE713FA873607735FE712F44276A7F048D60A61BB2F6B3C90C + set(SDL2_PROJECT SDL2-2.0.4) + set(SDL2_ARGS ${EXTERNALS_CMAKE_ARGS} -DSDL_STATIC=Off) + #message(STATUS "CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}") + ExternalProject_Add(${SDL2_PROJECT} + URL https://www.libsdl.org/release/SDL2-2.0.4.tar.gz + URL_HASH SHA256=DA55E540BF6331824153805D58B590A29C39D2D506C6D02FA409AEDEAB21174B CMAKE_ARGS ${SDL2_ARGS} DEPENDS OpenGL-headers ) + message(STATUS "Patching SDL 2.0.4 for DirectInput Haptics...") + message(STATUS "TODO - check if this patch is still needed with SDL2 > 2.0.4") + ExternalProject_Add_Step(${SDL2_PROJECT} sdl_2-dinput-patch + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_SOURCE_DIR}/patches/SDL_dinputhaptic.c.patched" + "/src/haptic/windows/SDL_dinputhaptic.c" + DEPENDEES update # do after update + DEPENDERS patch # do before patch + ) +else(OPTION_SDL_2x) + set(SDL2_PROJECT ) endif(OPTION_SDL_2x) if(OPTION_OPENAL) @@ -160,7 +172,7 @@ if(OPTION_PLIB) else(OPTION_PLIB_USE_HEAD) ExternalProject_Add(plib-1.8.5 - URL http://plib.sourceforge.net/dist/plib-1.8.5.tar.gz + URL https://plib.sourceforge.net/dist/plib-1.8.5.tar.gz URL_HASH SHA256=485B22BF6FDC0DA067E34EAD5E26F002B76326F6371E2AE006415DEA6A380A32 CMAKE_ARGS ${EXTERNALS_CMAKE_ARGS} DEPENDS OpenGL-headers @@ -204,7 +216,7 @@ if(OPTION_FREESOLID) #message(WARNING "TODO - need to decide between the patches for FreeSOLID-2.1.1 OR FreeSOLID-2.1.2") #ExternalProject_Add(FreeSOLID-2.1.1 # DOWNLOAD_NAME FreeSOLID-2.1.1.zip -# URL http://sourceforge.net/projects/freesolid/files/FreeSOLID/FreeSOLID-2.1.1.zip/FreeSOLID-2.1.1.zip/download +# URL https://sourceforge.net/projects/freesolid/files/FreeSOLID/FreeSOLID-2.1.1.zip/FreeSOLID-2.1.1.zip/download # URL_HASH SHA256=5A4F8576E27223F03AD0ADD76A79B06DB6CD8F15C8D2767EA35E0C540BA1BEE8 # CMAKE_ARGS ${EXTERNALS_CMAKE_ARGS} # UPDATE_COMMAND "" @@ -217,7 +229,7 @@ if(OPTION_FREESOLID) set(FreeSOLID_ARGS ${EXTERNALS_CMAKE_ARGS} -D'CMAKE_DEBUG_POSTFIX=""') ExternalProject_Add(FreeSOLID-2.1.2 DOWNLOAD_NAME FreeSOLID-2.1.2.zip - URL http://sourceforge.net/projects/freesolid/files/FreeSOLID-2.1.2.zip/download + URL https://sourceforge.net/projects/freesolid/files/FreeSOLID-2.1.2.zip/download URL_HASH SHA256=89EDC6AFDD9D60C8020B2B865B61558C86A8928DC6F1773B9F4708B5C28EB873 CMAKE_ARGS ${FreeSOLID_ARGS} ) @@ -281,7 +293,7 @@ set(EXPAT_ARGS ${EXTERNALS_CMAKE_ARGS} -DBUILD_tests=off -DBUILD_examples=off -D if(OPTION_EXPAT) ExternalProject_Add(expat-2.1.0 DOWNLOAD_NAME expat-2.1.0.tar.gz - URL http://sourceforge.net/projects/expat/files/expat/2.1.0/expat-2.1.0.tar.gz/download + URL https://sourceforge.net/projects/expat/files/expat/2.1.0/expat-2.1.0.tar.gz/download URL_HASH SHA256=823705472F816DF21C8F6AA026DD162B280806838BB55B3432B0FB1FCCA7EB86 CMAKE_ARGS ${EXPAT_ARGS} #UPDATE_COMMAND "" @@ -362,7 +374,7 @@ if(OPTION_FREETYPE) ExternalProject_Add(freetype-2.5.3 DOWNLOAD_NAME ft253.zip - URL http://sourceforge.net/projects/freetype/files/freetype2/2.5.3/ft253.zip/download + URL https://sourceforge.net/projects/freetype/files/freetype2/2.5.3/ft253.zip/download URL_HASH SHA256=CB7475E88852893B83D9C99A5FFEDEFD46398EDC8EF8410396D4D73F1A1281B9 CMAKE_ARGS ${FREETYPE_ARGS} ) @@ -379,7 +391,7 @@ if(OPTION_CURL) set(CURL_ARGS ${EXTERNALS_CMAKE_ARGS} -DBUILD_CURL_TESTS=Off) # may only be needed for Madbad's web stuff ExternalProject_Add(curl-7.43.0 - URL http://curl.haxx.se/download/curl-7.43.0.tar.bz2 + URL https://curl.haxx.se/download/curl-7.43.0.tar.bz2 URL_HASH SHA256=BAA654A1122530483CCC1C58CC112FEC3724A82C11C6A389F1E6A37DC8858DF9 CMAKE_ARGS ${CURL_ARGS} DEPENDS zlib-1.2.8 @@ -399,7 +411,7 @@ if(OPTION_OSG) URL http://trac.openscenegraph.org/downloads/developer_releases/OpenSceneGraph-3.4.0.zip URL_HASH MD5=A5E762C64373A46932E444F6F7332496 CMAKE_ARGS ${OSG_ARGS} - DEPENDS zlib-1.2.8 curl-7.43.0 freetype-2.5.3 OpenGL-headers ${JPG_PROJECT} ${PNG_PROJECT} SDL-1.2.15 SDL2-2.0.3 + DEPENDS zlib-1.2.8 curl-7.43.0 freetype-2.5.3 OpenGL-headers ${JPG_PROJECT} ${PNG_PROJECT} SDL-1.2.15 ${SDL2_PROJECT} ) ExternalProject_Add_Step(osg-OpenSceneGraph-3.4.0 sdl1x_add_cmake COMMAND ${CMAKE_COMMAND} -E copy_if_different diff --git a/packaging/3rdParty-devel/patches/SDL_dinputhaptic.c.patched b/packaging/3rdParty-devel/patches/SDL_dinputhaptic.c.patched new file mode 100644 index 000000000..2153fa4c5 --- /dev/null +++ b/packaging/3rdParty-devel/patches/SDL_dinputhaptic.c.patched @@ -0,0 +1,1329 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +/* + ALTERATION! This file has been altered. + This file has been modified by Joe Thompson + on August 15, 2016. The intent is to work around the bug 3021. + https://bugzilla.libsdl.org/show_bug.cgi?id=3021 + A proposed patch has been submitted to SDL's bugzilla, but has not yet been + reviewed or accepted. + The alterations can be found in the function: SDL_DINPUT_HapticOpenFromDevice + beginning around line 344. +*/ +#include "../../SDL_internal.h" + +#include "SDL_error.h" +#include "SDL_haptic.h" +#include "../SDL_syshaptic.h" + +#if SDL_HAPTIC_DINPUT + +#include "SDL_stdinc.h" +#include "SDL_timer.h" +#include "SDL_windowshaptic_c.h" +#include "SDL_dinputhaptic_c.h" +#include "../../joystick/windows/SDL_windowsjoystick_c.h" + +/* + * External stuff. + */ +extern HWND SDL_HelperWindow; + + +/* + * Internal stuff. + */ +static SDL_bool coinitialized = SDL_FALSE; +static LPDIRECTINPUT8 dinput = NULL; + + +/* + * Like SDL_SetError but for DX error codes. + */ +static int +DI_SetError(const char *str, HRESULT err) +{ + /* + SDL_SetError("Haptic: %s - %s: %s", str, + DXGetErrorString8A(err), DXGetErrorDescription8A(err)); + */ + return SDL_SetError("Haptic error %s", str); +} + +/* + * Checks to see if two GUID are the same. + */ +static int +DI_GUIDIsSame(const GUID * a, const GUID * b) +{ + return (SDL_memcmp(a, b, sizeof (GUID)) == 0); +} + +/* + * Callback to find the haptic devices. + */ +static BOOL CALLBACK +EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) +{ + (void) pContext; + SDL_DINPUT_MaybeAddDevice(pdidInstance); + return DIENUM_CONTINUE; /* continue enumerating */ +} + +int +SDL_DINPUT_HapticInit(void) +{ + HRESULT ret; + HINSTANCE instance; + + if (dinput != NULL) { /* Already open. */ + return SDL_SetError("Haptic: SubSystem already open."); + } + + ret = WIN_CoInitialize(); + if (FAILED(ret)) { + return DI_SetError("Coinitialize", ret); + } + + coinitialized = SDL_TRUE; + + ret = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, + &IID_IDirectInput8, (LPVOID)& dinput); + if (FAILED(ret)) { + SDL_SYS_HapticQuit(); + return DI_SetError("CoCreateInstance", ret); + } + + /* Because we used CoCreateInstance, we need to Initialize it, first. */ + instance = GetModuleHandle(NULL); + if (instance == NULL) { + SDL_SYS_HapticQuit(); + return SDL_SetError("GetModuleHandle() failed with error code %lu.", + GetLastError()); + } + ret = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); + if (FAILED(ret)) { + SDL_SYS_HapticQuit(); + return DI_SetError("Initializing DirectInput device", ret); + } + + /* Look for haptic devices. */ + ret = IDirectInput8_EnumDevices(dinput, + 0, + EnumHapticsCallback, + NULL, + DIEDFL_FORCEFEEDBACK | + DIEDFL_ATTACHEDONLY); + if (FAILED(ret)) { + SDL_SYS_HapticQuit(); + return DI_SetError("Enumerating DirectInput devices", ret); + } + return 0; +} + +int +SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance) +{ + HRESULT ret; + LPDIRECTINPUTDEVICE8 device; + const DWORD needflags = DIDC_ATTACHED | DIDC_FORCEFEEDBACK; + DIDEVCAPS capabilities; + SDL_hapticlist_item *item = NULL; + + if (dinput == NULL) { + return -1; /* not initialized. We'll pick these up on enumeration if we init later. */ + } + + /* Make sure we don't already have it */ + for (item = SDL_hapticlist; item; item = item->next) { + if ((!item->bXInputHaptic) && (SDL_memcmp(&item->instance, pdidInstance, sizeof(*pdidInstance)) == 0)) { + return -1; /* Already added */ + } + } + + /* Open the device */ + ret = IDirectInput8_CreateDevice(dinput, &pdidInstance->guidInstance, &device, NULL); + if (FAILED(ret)) { + /* DI_SetError("Creating DirectInput device",ret); */ + return -1; + } + + /* Get capabilities. */ + SDL_zero(capabilities); + capabilities.dwSize = sizeof(DIDEVCAPS); + ret = IDirectInputDevice8_GetCapabilities(device, &capabilities); + IDirectInputDevice8_Release(device); + if (FAILED(ret)) { + /* DI_SetError("Getting device capabilities",ret); */ + return -1; + } + + if ((capabilities.dwFlags & needflags) != needflags) { + return -1; /* not a device we can use. */ + } + + item = (SDL_hapticlist_item *)SDL_calloc(1, sizeof(SDL_hapticlist_item)); + if (item == NULL) { + return SDL_OutOfMemory(); + } + + item->name = WIN_StringToUTF8(pdidInstance->tszProductName); + if (!item->name) { + SDL_free(item); + return -1; + } + + /* Copy the instance over, useful for creating devices. */ + SDL_memcpy(&item->instance, pdidInstance, sizeof(DIDEVICEINSTANCE)); + SDL_memcpy(&item->capabilities, &capabilities, sizeof(capabilities)); + + return SDL_SYS_AddHapticDevice(item); +} + +int +SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance) +{ + SDL_hapticlist_item *item; + SDL_hapticlist_item *prev = NULL; + + if (dinput == NULL) { + return -1; /* not initialized, ignore this. */ + } + + for (item = SDL_hapticlist; item != NULL; item = item->next) { + if (!item->bXInputHaptic && SDL_memcmp(&item->instance, pdidInstance, sizeof(*pdidInstance)) == 0) { + /* found it, remove it. */ + return SDL_SYS_RemoveHapticDevice(prev, item); + } + prev = item; + } + return -1; +} + +/* + * Callback to get supported axes. + */ +static BOOL CALLBACK +DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef) +{ + SDL_Haptic *haptic = (SDL_Haptic *) pvRef; + + if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) { + const GUID *guid = &dev->guidType; + DWORD offset = 0; + if (DI_GUIDIsSame(guid, &GUID_XAxis)) { + offset = DIJOFS_X; + } else if (DI_GUIDIsSame(guid, &GUID_YAxis)) { + offset = DIJOFS_Y; + } else if (DI_GUIDIsSame(guid, &GUID_ZAxis)) { + offset = DIJOFS_Z; + } else if (DI_GUIDIsSame(guid, &GUID_RxAxis)) { + offset = DIJOFS_RX; + } else if (DI_GUIDIsSame(guid, &GUID_RyAxis)) { + offset = DIJOFS_RY; + } else if (DI_GUIDIsSame(guid, &GUID_RzAxis)) { + offset = DIJOFS_RZ; + } else { + return DIENUM_CONTINUE; /* can't use this, go on. */ + } + + haptic->hwdata->axes[haptic->naxes] = offset; + haptic->naxes++; + + /* Currently using the artificial limit of 3 axes. */ + if (haptic->naxes >= 3) { + return DIENUM_STOP; + } + } + + return DIENUM_CONTINUE; +} + +/* + * Callback to get all supported effects. + */ +#define EFFECT_TEST(e,s) \ +if (DI_GUIDIsSame(&pei->guid, &(e))) \ + haptic->supported |= (s) +static BOOL CALLBACK +DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv) +{ + /* Prepare the haptic device. */ + SDL_Haptic *haptic = (SDL_Haptic *) pv; + + /* Get supported. */ + EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING); + EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER); + EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA); + EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION); + EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT); + EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM); + EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE); + /* !!! FIXME: put this back when we have more bits in 2.1 */ + /* EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE); */ + EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE); + EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP); + EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN); + EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP); + + /* Check for more. */ + return DIENUM_CONTINUE; +} + +/* + * Opens the haptic device. + * + * Steps: + * - Set cooperative level. + * - Set data format. + * - Acquire exclusiveness. + * - Reset actuators. + * - Get supported features. + */ +static int +SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device8, SDL_bool is_joystick) +{ + HRESULT ret; + DIPROPDWORD dipdw; + + /* Allocate the hwdata */ + haptic->hwdata = (struct haptic_hwdata *)SDL_malloc(sizeof(*haptic->hwdata)); + if (haptic->hwdata == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); + + /* We'll use the device8 from now on. */ + haptic->hwdata->device = device8; + haptic->hwdata->is_joystick = is_joystick; + + /* !!! FIXME: opening a haptic device here first will make an attempt to + !!! FIXME: SDL_JoystickOpen() that same device fail later, since we + !!! FIXME: have it open in exclusive mode. But this will allow + !!! FIXME: SDL_JoystickOpen() followed by SDL_HapticOpenFromJoystick() + !!! FIXME: to work, and that's probably the common case. Still, + !!! FIXME: ideally, We need to unify the opening code. */ + + if (!is_joystick) { /* if is_joystick, we already set this up elsewhere. */ + /* Grab it exclusively to use force feedback stuff. */ + ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device, + SDL_HelperWindow, + DISCL_EXCLUSIVE | + DISCL_BACKGROUND); + if (FAILED(ret)) { + DI_SetError("Setting cooperative level to exclusive", ret); + goto acquire_err; + } + + /* Set data format. */ + ret = IDirectInputDevice8_SetDataFormat(haptic->hwdata->device, + &c_dfDIJoystick2); + if (FAILED(ret)) { + DI_SetError("Setting data format", ret); + goto acquire_err; + } + + /* ALTERATION! The code below was commented out and the block + inserted outside of the conditional: (!is_joystick) */ + + /* Get number of axes. */ + /* + ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device, + DI_DeviceObjectCallback, + haptic, DIDFT_AXIS); + if (FAILED(ret)) { + DI_SetError("Getting device axes", ret); + goto acquire_err; + } + */ + /* End of ALTERATION */ + + /* Acquire the device. */ + ret = IDirectInputDevice8_Acquire(haptic->hwdata->device); + if (FAILED(ret)) { + DI_SetError("Acquiring DirectInput device", ret); + goto acquire_err; + } + } + + /* ALTERATION! The code below was inserted here from the + conditional: (!is_joystick) above. See line 334 */ + + /* Get number of axes. */ + ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device, + DI_DeviceObjectCallback, + haptic, DIDFT_AXIS); + if (FAILED(ret)) { + DI_SetError("Getting device axes", ret); + goto acquire_err; + } + /* End of ALTERATION */ + + /* Reset all actuators - just in case. */ + ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, + DISFFC_RESET); + if (FAILED(ret)) { + DI_SetError("Resetting device", ret); + goto acquire_err; + } + + /* Enabling actuators. */ + ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, + DISFFC_SETACTUATORSON); + if (FAILED(ret)) { + DI_SetError("Enabling actuators", ret); + goto acquire_err; + } + + /* Get supported effects. */ + ret = IDirectInputDevice8_EnumEffects(haptic->hwdata->device, + DI_EffectCallback, haptic, + DIEFT_ALL); + if (FAILED(ret)) { + DI_SetError("Enumerating supported effects", ret); + goto acquire_err; + } + if (haptic->supported == 0) { /* Error since device supports nothing. */ + SDL_SetError("Haptic: Internal error on finding supported effects."); + goto acquire_err; + } + + /* Check autogain and autocenter. */ + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = 10000; + ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, + DIPROP_FFGAIN, &dipdw.diph); + if (!FAILED(ret)) { /* Gain is supported. */ + haptic->supported |= SDL_HAPTIC_GAIN; + } + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = DIPROPAUTOCENTER_OFF; + ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, + DIPROP_AUTOCENTER, &dipdw.diph); + if (!FAILED(ret)) { /* Autocenter is supported. */ + haptic->supported |= SDL_HAPTIC_AUTOCENTER; + } + + /* Status is always supported. */ + haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; + + /* Check maximum effects. */ + haptic->neffects = 128; /* This is not actually supported as thus under windows, + there is no way to tell the number of EFFECTS that a + device can hold, so we'll just use a "random" number + instead and put warnings in SDL_haptic.h */ + haptic->nplaying = 128; /* Even more impossible to get this then neffects. */ + + /* Prepare effects memory. */ + haptic->effects = (struct haptic_effect *) + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); + if (haptic->effects == NULL) { + SDL_OutOfMemory(); + goto acquire_err; + } + /* Clear the memory */ + SDL_memset(haptic->effects, 0, + sizeof(struct haptic_effect) * haptic->neffects); + + return 0; + + /* Error handling */ + acquire_err: + IDirectInputDevice8_Unacquire(haptic->hwdata->device); + return -1; +} + +int +SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item) +{ + HRESULT ret; + LPDIRECTINPUTDEVICE8 device; + LPDIRECTINPUTDEVICE8 device8; + + /* Open the device */ + ret = IDirectInput8_CreateDevice(dinput, &item->instance.guidInstance, + &device, NULL); + if (FAILED(ret)) { + DI_SetError("Creating DirectInput device", ret); + return -1; + } + + /* Now get the IDirectInputDevice8 interface, instead. */ + ret = IDirectInputDevice8_QueryInterface(device, + &IID_IDirectInputDevice8, + (LPVOID *)&device8); + /* Done with the temporary one now. */ + IDirectInputDevice8_Release(device); + if (FAILED(ret)) { + DI_SetError("Querying DirectInput interface", ret); + return -1; + } + + if (SDL_DINPUT_HapticOpenFromDevice(haptic, device8, SDL_FALSE) < 0) { + IDirectInputDevice8_Release(device8); + return -1; + } + return 0; +} + +int +SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + HRESULT ret; + DIDEVICEINSTANCE hap_instance, joy_instance; + + hap_instance.dwSize = sizeof(DIDEVICEINSTANCE); + joy_instance.dwSize = sizeof(DIDEVICEINSTANCE); + + /* Get the device instances. */ + ret = IDirectInputDevice8_GetDeviceInfo(haptic->hwdata->device, + &hap_instance); + if (FAILED(ret)) { + return 0; + } + ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, + &joy_instance); + if (FAILED(ret)) { + return 0; + } + + return DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance); +} + +int +SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + SDL_hapticlist_item *item; + int index = 0; + HRESULT ret; + DIDEVICEINSTANCE joy_instance; + + joy_instance.dwSize = sizeof(DIDEVICEINSTANCE); + ret = IDirectInputDevice8_GetDeviceInfo(joystick->hwdata->InputDevice, &joy_instance); + if (FAILED(ret)) { + return -1; + } + + /* Since it comes from a joystick we have to try to match it with a haptic device on our haptic list. */ + for (item = SDL_hapticlist; item != NULL; item = item->next) { + if (!item->bXInputHaptic && DI_GUIDIsSame(&item->instance.guidInstance, &joy_instance.guidInstance)) { + haptic->index = index; + return SDL_DINPUT_HapticOpenFromDevice(haptic, joystick->hwdata->InputDevice, SDL_TRUE); + } + ++index; + } + + SDL_SetError("Couldn't find joystick in haptic device list"); + return -1; +} + +void +SDL_DINPUT_HapticClose(SDL_Haptic * haptic) +{ + IDirectInputDevice8_Unacquire(haptic->hwdata->device); + + /* Only release if isn't grabbed by a joystick. */ + if (haptic->hwdata->is_joystick == 0) { + IDirectInputDevice8_Release(haptic->hwdata->device); + } +} + +void +SDL_DINPUT_HapticQuit(void) +{ + if (dinput != NULL) { + IDirectInput8_Release(dinput); + dinput = NULL; + } + + if (coinitialized) { + WIN_CoUninitialize(); + coinitialized = SDL_FALSE; + } +} + +/* + * Converts an SDL trigger button to an DIEFFECT trigger button. + */ +static DWORD +DIGetTriggerButton(Uint16 button) +{ + DWORD dwTriggerButton; + + dwTriggerButton = DIEB_NOTRIGGER; + + if (button != 0) { + dwTriggerButton = DIJOFS_BUTTON(button - 1); + } + + return dwTriggerButton; +} + + +/* + * Sets the direction. + */ +static int +SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes) +{ + LONG *rglDir; + + /* Handle no axes a part. */ + if (naxes == 0) { + effect->dwFlags |= DIEFF_SPHERICAL; /* Set as default. */ + effect->rglDirection = NULL; + return 0; + } + + /* Has axes. */ + rglDir = SDL_malloc(sizeof(LONG) * naxes); + if (rglDir == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(rglDir, 0, sizeof(LONG) * naxes); + effect->rglDirection = rglDir; + + switch (dir->type) { + case SDL_HAPTIC_POLAR: + effect->dwFlags |= DIEFF_POLAR; + rglDir[0] = dir->dir[0]; + return 0; + case SDL_HAPTIC_CARTESIAN: + effect->dwFlags |= DIEFF_CARTESIAN; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + case SDL_HAPTIC_SPHERICAL: + effect->dwFlags |= DIEFF_SPHERICAL; + rglDir[0] = dir->dir[0]; + if (naxes > 1) + rglDir[1] = dir->dir[1]; + if (naxes > 2) + rglDir[2] = dir->dir[2]; + return 0; + + default: + return SDL_SetError("Haptic: Unknown direction type."); + } +} + +/* Clamps and converts. */ +#define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF) +/* Just converts. */ +#define CONVERT(x) (((x)*10000) / 0x7FFF) +/* + * Creates the DIEFFECT from a SDL_HapticEffect. + */ +static int +SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest, + SDL_HapticEffect * src) +{ + int i; + DICONSTANTFORCE *constant; + DIPERIODIC *periodic; + DICONDITION *condition; /* Actually an array of conditions - one per axis. */ + DIRAMPFORCE *ramp; + DICUSTOMFORCE *custom; + DIENVELOPE *envelope; + SDL_HapticConstant *hap_constant; + SDL_HapticPeriodic *hap_periodic; + SDL_HapticCondition *hap_condition; + SDL_HapticRamp *hap_ramp; + SDL_HapticCustom *hap_custom; + DWORD *axes; + + /* Set global stuff. */ + SDL_memset(dest, 0, sizeof(DIEFFECT)); + dest->dwSize = sizeof(DIEFFECT); /* Set the structure size. */ + dest->dwSamplePeriod = 0; /* Not used by us. */ + dest->dwGain = 10000; /* Gain is set globally, not locally. */ + dest->dwFlags = DIEFF_OBJECTOFFSETS; /* Seems obligatory. */ + + /* Envelope. */ + envelope = SDL_malloc(sizeof(DIENVELOPE)); + if (envelope == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(envelope, 0, sizeof(DIENVELOPE)); + dest->lpEnvelope = envelope; + envelope->dwSize = sizeof(DIENVELOPE); /* Always should be this. */ + + /* Axes. */ + dest->cAxes = haptic->naxes; + if (dest->cAxes > 0) { + axes = SDL_malloc(sizeof(DWORD) * dest->cAxes); + if (axes == NULL) { + return SDL_OutOfMemory(); + } + axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */ + if (dest->cAxes > 1) { + axes[1] = haptic->hwdata->axes[1]; + } + if (dest->cAxes > 2) { + axes[2] = haptic->hwdata->axes[2]; + } + dest->rgdwAxes = axes; + } + + /* The big type handling switch, even bigger than Linux's version. */ + switch (src->type) { + case SDL_HAPTIC_CONSTANT: + hap_constant = &src->constant; + constant = SDL_malloc(sizeof(DICONSTANTFORCE)); + if (constant == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(constant, 0, sizeof(DICONSTANTFORCE)); + + /* Specifics */ + constant->lMagnitude = CONVERT(hap_constant->level); + dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + dest->lpvTypeSpecificParams = constant; + + /* Generics */ + dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button); + dest->dwTriggerRepeatInterval = hap_constant->interval; + dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_constant->attack_length == 0) + && (hap_constant->fade_length == 0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } else { + envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level); + envelope->dwAttackTime = hap_constant->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level); + envelope->dwFadeTime = hap_constant->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SINE: + /* !!! FIXME: put this back when we have more bits in 2.1 */ + /* case SDL_HAPTIC_SQUARE: */ + case SDL_HAPTIC_TRIANGLE: + case SDL_HAPTIC_SAWTOOTHUP: + case SDL_HAPTIC_SAWTOOTHDOWN: + hap_periodic = &src->periodic; + periodic = SDL_malloc(sizeof(DIPERIODIC)); + if (periodic == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(periodic, 0, sizeof(DIPERIODIC)); + + /* Specifics */ + periodic->dwMagnitude = CONVERT(SDL_abs(hap_periodic->magnitude)); + periodic->lOffset = CONVERT(hap_periodic->offset); + periodic->dwPhase = + (hap_periodic->phase + (hap_periodic->magnitude < 0 ? 18000 : 0)) % 36000; + periodic->dwPeriod = hap_periodic->period * 1000; + dest->cbTypeSpecificParams = sizeof(DIPERIODIC); + dest->lpvTypeSpecificParams = periodic; + + /* Generics */ + dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button); + dest->dwTriggerRepeatInterval = hap_periodic->interval; + dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) + < 0) { + return -1; + } + + /* Envelope */ + if ((hap_periodic->attack_length == 0) + && (hap_periodic->fade_length == 0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } else { + envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level); + envelope->dwAttackTime = hap_periodic->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level); + envelope->dwFadeTime = hap_periodic->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_SPRING: + case SDL_HAPTIC_DAMPER: + case SDL_HAPTIC_INERTIA: + case SDL_HAPTIC_FRICTION: + hap_condition = &src->condition; + condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes); + if (condition == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(condition, 0, sizeof(DICONDITION)); + + /* Specifics */ + for (i = 0; i < (int) dest->cAxes; i++) { + condition[i].lOffset = CONVERT(hap_condition->center[i]); + condition[i].lPositiveCoefficient = + CONVERT(hap_condition->right_coeff[i]); + condition[i].lNegativeCoefficient = + CONVERT(hap_condition->left_coeff[i]); + condition[i].dwPositiveSaturation = + CCONVERT(hap_condition->right_sat[i] / 2); + condition[i].dwNegativeSaturation = + CCONVERT(hap_condition->left_sat[i] / 2); + condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2); + } + dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes; + dest->lpvTypeSpecificParams = condition; + + /* Generics */ + dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button); + dest->dwTriggerRepeatInterval = hap_condition->interval; + dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) + < 0) { + return -1; + } + + /* Envelope - Not actually supported by most CONDITION implementations. */ + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + + break; + + case SDL_HAPTIC_RAMP: + hap_ramp = &src->ramp; + ramp = SDL_malloc(sizeof(DIRAMPFORCE)); + if (ramp == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(ramp, 0, sizeof(DIRAMPFORCE)); + + /* Specifics */ + ramp->lStart = CONVERT(hap_ramp->start); + ramp->lEnd = CONVERT(hap_ramp->end); + dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE); + dest->lpvTypeSpecificParams = ramp; + + /* Generics */ + dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button); + dest->dwTriggerRepeatInterval = hap_ramp->interval; + dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } else { + envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level); + envelope->dwAttackTime = hap_ramp->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level); + envelope->dwFadeTime = hap_ramp->fade_length * 1000; + } + + break; + + case SDL_HAPTIC_CUSTOM: + hap_custom = &src->custom; + custom = SDL_malloc(sizeof(DICUSTOMFORCE)); + if (custom == NULL) { + return SDL_OutOfMemory(); + } + SDL_memset(custom, 0, sizeof(DICUSTOMFORCE)); + + /* Specifics */ + custom->cChannels = hap_custom->channels; + custom->dwSamplePeriod = hap_custom->period * 1000; + custom->cSamples = hap_custom->samples; + custom->rglForceData = + SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels); + for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) { /* Copy data. */ + custom->rglForceData[i] = CCONVERT(hap_custom->data[i]); + } + dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE); + dest->lpvTypeSpecificParams = custom; + + /* Generics */ + dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */ + dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button); + dest->dwTriggerRepeatInterval = hap_custom->interval; + dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */ + + /* Direction. */ + if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) { + return -1; + } + + /* Envelope */ + if ((hap_custom->attack_length == 0) + && (hap_custom->fade_length == 0)) { + SDL_free(dest->lpEnvelope); + dest->lpEnvelope = NULL; + } else { + envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level); + envelope->dwAttackTime = hap_custom->attack_length * 1000; + envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level); + envelope->dwFadeTime = hap_custom->fade_length * 1000; + } + + break; + + default: + return SDL_SetError("Haptic: Unknown effect type."); + } + + return 0; +} + + +/* + * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT. + */ +static void +SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type) +{ + DICUSTOMFORCE *custom; + + SDL_free(effect->lpEnvelope); + effect->lpEnvelope = NULL; + SDL_free(effect->rgdwAxes); + effect->rgdwAxes = NULL; + if (effect->lpvTypeSpecificParams != NULL) { + if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */ + custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams; + SDL_free(custom->rglForceData); + custom->rglForceData = NULL; + } + SDL_free(effect->lpvTypeSpecificParams); + effect->lpvTypeSpecificParams = NULL; + } + SDL_free(effect->rglDirection); + effect->rglDirection = NULL; +} + +/* + * Gets the effect type from the generic SDL haptic effect wrapper. + */ +static REFGUID +SDL_SYS_HapticEffectType(SDL_HapticEffect * effect) +{ + switch (effect->type) { + case SDL_HAPTIC_CONSTANT: + return &GUID_ConstantForce; + + case SDL_HAPTIC_RAMP: + return &GUID_RampForce; + + /* !!! FIXME: put this back when we have more bits in 2.1 */ + /* case SDL_HAPTIC_SQUARE: + return &GUID_Square; */ + + case SDL_HAPTIC_SINE: + return &GUID_Sine; + + case SDL_HAPTIC_TRIANGLE: + return &GUID_Triangle; + + case SDL_HAPTIC_SAWTOOTHUP: + return &GUID_SawtoothUp; + + case SDL_HAPTIC_SAWTOOTHDOWN: + return &GUID_SawtoothDown; + + case SDL_HAPTIC_SPRING: + return &GUID_Spring; + + case SDL_HAPTIC_DAMPER: + return &GUID_Damper; + + case SDL_HAPTIC_INERTIA: + return &GUID_Inertia; + + case SDL_HAPTIC_FRICTION: + return &GUID_Friction; + + case SDL_HAPTIC_CUSTOM: + return &GUID_CustomForce; + + default: + return NULL; + } +} +int +SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base) +{ + HRESULT ret; + REFGUID type = SDL_SYS_HapticEffectType(base); + + if (type == NULL) { + SDL_SetError("Haptic: Unknown effect type."); + return -1; + } + + /* Get the effect. */ + if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) { + goto err_effectdone; + } + + /* Create the actual effect. */ + ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type, + &effect->hweffect->effect, + &effect->hweffect->ref, NULL); + if (FAILED(ret)) { + DI_SetError("Unable to create effect", ret); + goto err_effectdone; + } + + return 0; + +err_effectdone: + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type); + return -1; +} + +int +SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data) +{ + HRESULT ret; + DWORD flags; + DIEFFECT temp; + + /* Get the effect. */ + SDL_memset(&temp, 0, sizeof(DIEFFECT)); + if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) { + goto err_update; + } + + /* Set the flags. Might be worthwhile to diff temp with loaded effect and + * only change those parameters. */ + flags = DIEP_DIRECTION | + DIEP_DURATION | + DIEP_ENVELOPE | + DIEP_STARTDELAY | + DIEP_TRIGGERBUTTON | + DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; + + /* Create the actual effect. */ + ret = + IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); + if (FAILED(ret)) { + DI_SetError("Unable to update effect", ret); + goto err_update; + } + + /* Copy it over. */ + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type); + SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT)); + + return 0; + +err_update: + SDL_SYS_HapticFreeDIEFFECT(&temp, data->type); + return -1; +} + +int +SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations) +{ + HRESULT ret; + DWORD iter; + + /* Check if it's infinite. */ + if (iterations == SDL_HAPTIC_INFINITY) { + iter = INFINITE; + } else { + iter = iterations; + } + + /* Run the effect. */ + ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0); + if (FAILED(ret)) { + return DI_SetError("Running the effect", ret); + } + return 0; +} + +int +SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) +{ + HRESULT ret; + + ret = IDirectInputEffect_Stop(effect->hweffect->ref); + if (FAILED(ret)) { + return DI_SetError("Unable to stop effect", ret); + } + return 0; +} + +void +SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) +{ + HRESULT ret; + + ret = IDirectInputEffect_Unload(effect->hweffect->ref); + if (FAILED(ret)) { + DI_SetError("Removing effect from the device", ret); + } + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type); +} + +int +SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect) +{ + HRESULT ret; + DWORD status; + + ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status); + if (FAILED(ret)) { + return DI_SetError("Getting effect status", ret); + } + + if (status == 0) + return SDL_FALSE; + return SDL_TRUE; +} + +int +SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + HRESULT ret; + DIPROPDWORD dipdw; + + /* Create the weird structure thingy. */ + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = gain * 100; /* 0 to 10,000 */ + + /* Try to set the autocenter. */ + ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, + DIPROP_FFGAIN, &dipdw.diph); + if (FAILED(ret)) { + return DI_SetError("Setting gain", ret); + } + return 0; +} + +int +SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + HRESULT ret; + DIPROPDWORD dipdw; + + /* Create the weird structure thingy. */ + dipdw.diph.dwSize = sizeof(DIPROPDWORD); + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); + dipdw.diph.dwObj = 0; + dipdw.diph.dwHow = DIPH_DEVICE; + dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF : + DIPROPAUTOCENTER_ON; + + /* Try to set the autocenter. */ + ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, + DIPROP_AUTOCENTER, &dipdw.diph); + if (FAILED(ret)) { + return DI_SetError("Setting autocenter", ret); + } + return 0; +} + +int +SDL_DINPUT_HapticPause(SDL_Haptic * haptic) +{ + HRESULT ret; + + /* Pause the device. */ + ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, + DISFFC_PAUSE); + if (FAILED(ret)) { + return DI_SetError("Pausing the device", ret); + } + return 0; +} + +int +SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic) +{ + HRESULT ret; + + /* Unpause the device. */ + ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, + DISFFC_CONTINUE); + if (FAILED(ret)) { + return DI_SetError("Pausing the device", ret); + } + return 0; +} + +int +SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic) +{ + HRESULT ret; + + /* Try to stop the effects. */ + ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, + DISFFC_STOPALL); + if (FAILED(ret)) { + return DI_SetError("Stopping the device", ret); + } + return 0; +} + +#else /* !SDL_HAPTIC_DINPUT */ + +typedef struct DIDEVICEINSTANCE DIDEVICEINSTANCE; +typedef struct SDL_hapticlist_item SDL_hapticlist_item; + +int +SDL_DINPUT_HapticInit(void) +{ + return 0; +} + +int +SDL_DINPUT_MaybeAddDevice(const DIDEVICEINSTANCE * pdidInstance) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_MaybeRemoveDevice(const DIDEVICEINSTANCE * pdidInstance) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) +{ + return SDL_Unsupported(); +} + +void +SDL_DINPUT_HapticClose(SDL_Haptic * haptic) +{ +} + +void +SDL_DINPUT_HapticQuit(void) +{ +} + +int +SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) +{ + return SDL_Unsupported(); +} + +void +SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) +{ +} + +int +SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticPause(SDL_Haptic * haptic) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic) +{ + return SDL_Unsupported(); +} + +int +SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic) +{ + return SDL_Unsupported(); +} + +#endif /* SDL_HAPTIC_DINPUT */ + +/* vi: set ts=4 sw=4 expandtab: */