1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/haptic/windows/SDL_syshaptic.c Thu Jan 20 18:04:05 2011 -0800
1.3 @@ -0,0 +1,1379 @@
1.4 +/*
1.5 + SDL - Simple DirectMedia Layer
1.6 + Copyright (C) 2008 Edgar Simo
1.7 +
1.8 + This library is free software; you can redistribute it and/or
1.9 + modify it under the terms of the GNU Lesser General Public
1.10 + License as published by the Free Software Foundation; either
1.11 + version 2.1 of the License, or (at your option) any later version.
1.12 +
1.13 + This library is distributed in the hope that it will be useful,
1.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of
1.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.16 + Lesser General Public License for more details.
1.17 +
1.18 + You should have received a copy of the GNU Lesser General Public
1.19 + License along with this library; if not, write to the Free Software
1.20 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1.21 +
1.22 + Sam Lantinga
1.23 + slouken@libsdl.org
1.24 +*/
1.25 +#include "SDL_config.h"
1.26 +
1.27 +#ifdef SDL_HAPTIC_DINPUT
1.28 +
1.29 +#include "SDL_haptic.h"
1.30 +#include "../SDL_syshaptic.h"
1.31 +#include "SDL_joystick.h"
1.32 +#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
1.33 +#include "../../joystick/windows/SDL_dxjoystick_c.h" /* For joystick hwdata */
1.34 +
1.35 +
1.36 +#define MAX_HAPTICS 32
1.37 +
1.38 +
1.39 +/*
1.40 + * List of available haptic devices.
1.41 + */
1.42 +static struct
1.43 +{
1.44 + DIDEVICEINSTANCE instance;
1.45 + SDL_Haptic *haptic;
1.46 + DIDEVCAPS capabilities;
1.47 +} SDL_hapticlist[MAX_HAPTICS];
1.48 +
1.49 +
1.50 +/*
1.51 + * Haptic system hardware data.
1.52 + */
1.53 +struct haptic_hwdata
1.54 +{
1.55 + LPDIRECTINPUTDEVICE2 device;
1.56 + DWORD axes[3]; /* Axes to use. */
1.57 + int is_joystick; /* Device is loaded as joystick. */
1.58 +};
1.59 +
1.60 +
1.61 +/*
1.62 + * Haptic system effect data.
1.63 + */
1.64 +struct haptic_hweffect
1.65 +{
1.66 + DIEFFECT effect;
1.67 + LPDIRECTINPUTEFFECT ref;
1.68 +};
1.69 +
1.70 +
1.71 +/*
1.72 + * Internal stuff.
1.73 + */
1.74 +static LPDIRECTINPUT dinput = NULL;
1.75 +
1.76 +
1.77 +/*
1.78 + * External stuff.
1.79 + */
1.80 +extern HWND SDL_HelperWindow;
1.81 +
1.82 +
1.83 +/*
1.84 + * Prototypes.
1.85 + */
1.86 +static void DI_SetError(const char *str, HRESULT err);
1.87 +static int DI_GUIDIsSame(const GUID * a, const GUID * b);
1.88 +static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic,
1.89 + DIDEVICEINSTANCE instance);
1.90 +static int SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic,
1.91 + LPDIRECTINPUTDEVICE2 device2);
1.92 +static DWORD DIGetTriggerButton(Uint16 button);
1.93 +static int SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir,
1.94 + int naxes);
1.95 +static int SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
1.96 + SDL_HapticEffect * src);
1.97 +static void SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type);
1.98 +static REFGUID SDL_SYS_HapticEffectType(SDL_HapticEffect * effect);
1.99 +/* Callbacks. */
1.100 +static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE *
1.101 + pdidInstance, VOID * pContext);
1.102 +static BOOL CALLBACK DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv);
1.103 +
1.104 +
1.105 +/*
1.106 + * Like SDL_SetError but for DX error codes.
1.107 + */
1.108 +static void
1.109 +DI_SetError(const char *str, HRESULT err)
1.110 +{
1.111 + /*
1.112 + SDL_SetError("Haptic: %s - %s: %s", str,
1.113 + DXGetErrorString8A(err), DXGetErrorDescription8A(err));
1.114 + */
1.115 + SDL_SetError("Haptic error %s", str);
1.116 +}
1.117 +
1.118 +
1.119 +/*
1.120 + * Checks to see if two GUID are the same.
1.121 + */
1.122 +static int
1.123 +DI_GUIDIsSame(const GUID * a, const GUID * b)
1.124 +{
1.125 + if (((a)->Data1 == (b)->Data1) &&
1.126 + ((a)->Data2 == (b)->Data2) &&
1.127 + ((a)->Data3 == (b)->Data3) &&
1.128 + (SDL_strcmp((a)->Data4, (b)->Data4) == 0))
1.129 + return 1;
1.130 + return 0;
1.131 +}
1.132 +
1.133 +
1.134 +/*
1.135 + * Initializes the haptic subsystem.
1.136 + */
1.137 +int
1.138 +SDL_SYS_HapticInit(void)
1.139 +{
1.140 + HRESULT ret;
1.141 + HINSTANCE instance;
1.142 +
1.143 + if (dinput != NULL) { /* Already open. */
1.144 + SDL_SetError("Haptic: SubSystem already open.");
1.145 + return -1;
1.146 + }
1.147 +
1.148 + /* Clear all the memory. */
1.149 + SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
1.150 +
1.151 + SDL_numhaptics = 0;
1.152 +
1.153 + ret = CoInitialize(NULL);
1.154 + if (FAILED(ret)) {
1.155 + DI_SetError("Coinitialize", ret);
1.156 + return -1;
1.157 + }
1.158 +
1.159 + ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
1.160 + &IID_IDirectInput, (LPVOID) & dinput);
1.161 + if (FAILED(ret)) {
1.162 + DI_SetError("CoCreateInstance", ret);
1.163 + return -1;
1.164 + }
1.165 +
1.166 + /* Because we used CoCreateInstance, we need to Initialize it, first. */
1.167 + instance = GetModuleHandle(NULL);
1.168 + if (instance == NULL) {
1.169 + SDL_SetError("GetModuleHandle() failed with error code %d.",
1.170 + GetLastError());
1.171 + return -1;
1.172 + }
1.173 + ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
1.174 + if (FAILED(ret)) {
1.175 + DI_SetError("Initializing DirectInput device", ret);
1.176 + return -1;
1.177 + }
1.178 +
1.179 + /* Look for haptic devices. */
1.180 + ret = IDirectInput_EnumDevices(dinput,
1.181 + 0,
1.182 + EnumHapticsCallback,
1.183 + NULL,
1.184 + DIEDFL_FORCEFEEDBACK |
1.185 + DIEDFL_ATTACHEDONLY);
1.186 + if (FAILED(ret)) {
1.187 + DI_SetError("Enumerating DirectInput devices", ret);
1.188 + return -1;
1.189 + }
1.190 +
1.191 + return SDL_numhaptics;
1.192 +}
1.193 +
1.194 +/*
1.195 + * Callback to find the haptic devices.
1.196 + */
1.197 +static BOOL CALLBACK
1.198 +EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
1.199 +{
1.200 + HRESULT ret;
1.201 + LPDIRECTINPUTDEVICE device;
1.202 +
1.203 + /* Copy the instance over, useful for creating devices. */
1.204 + SDL_memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance,
1.205 + sizeof(DIDEVICEINSTANCE));
1.206 +
1.207 + /* Open the device */
1.208 + ret = IDirectInput_CreateDevice(dinput, &pdidInstance->guidInstance,
1.209 + &device, NULL);
1.210 + if (FAILED(ret)) {
1.211 + /* DI_SetError("Creating DirectInput device",ret); */
1.212 + return DIENUM_CONTINUE;
1.213 + }
1.214 +
1.215 + /* Get capabilities. */
1.216 + SDL_hapticlist[SDL_numhaptics].capabilities.dwSize = sizeof(DIDEVCAPS);
1.217 + ret = IDirectInputDevice_GetCapabilities(device,
1.218 + &SDL_hapticlist[SDL_numhaptics].
1.219 + capabilities);
1.220 + if (FAILED(ret)) {
1.221 + /* DI_SetError("Getting device capabilities",ret); */
1.222 + IDirectInputDevice_Release(device);
1.223 + return DIENUM_CONTINUE;
1.224 + }
1.225 +
1.226 + /* Close up device and count it. */
1.227 + IDirectInputDevice_Release(device);
1.228 + SDL_numhaptics++;
1.229 +
1.230 + /* Watch out for hard limit. */
1.231 + if (SDL_numhaptics >= MAX_HAPTICS)
1.232 + return DIENUM_STOP;
1.233 +
1.234 + return DIENUM_CONTINUE;
1.235 +}
1.236 +
1.237 +
1.238 +/*
1.239 + * Return the name of a haptic device, does not need to be opened.
1.240 + */
1.241 +const char *
1.242 +SDL_SYS_HapticName(int index)
1.243 +{
1.244 + return SDL_hapticlist[index].instance.tszProductName;
1.245 +}
1.246 +
1.247 +
1.248 +/*
1.249 + * Callback to get all supported effects.
1.250 + */
1.251 +#define EFFECT_TEST(e,s) \
1.252 +if (DI_GUIDIsSame(&pei->guid, &(e))) \
1.253 + haptic->supported |= (s)
1.254 +static BOOL CALLBACK
1.255 +DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv)
1.256 +{
1.257 + /* Prepare the haptic device. */
1.258 + SDL_Haptic *haptic = (SDL_Haptic *) pv;
1.259 +
1.260 + /* Get supported. */
1.261 + EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING);
1.262 + EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER);
1.263 + EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA);
1.264 + EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION);
1.265 + EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT);
1.266 + EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM);
1.267 + EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE);
1.268 + EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE);
1.269 + EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE);
1.270 + EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP);
1.271 + EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN);
1.272 + EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP);
1.273 +
1.274 + /* Check for more. */
1.275 + return DIENUM_CONTINUE;
1.276 +}
1.277 +
1.278 +
1.279 +/*
1.280 + * Callback to get supported axes.
1.281 + */
1.282 +static BOOL CALLBACK
1.283 +DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
1.284 +{
1.285 + SDL_Haptic *haptic = (SDL_Haptic *) pvRef;
1.286 +
1.287 + if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) {
1.288 +
1.289 + haptic->hwdata->axes[haptic->naxes] = dev->dwOfs;
1.290 + haptic->naxes++;
1.291 +
1.292 + /* Currently using the artificial limit of 3 axes. */
1.293 + if (haptic->naxes >= 3) {
1.294 + return DIENUM_STOP;
1.295 + }
1.296 + }
1.297 +
1.298 + return DIENUM_CONTINUE;
1.299 +}
1.300 +
1.301 +
1.302 +/*
1.303 + * Opens the haptic device from the file descriptor.
1.304 + *
1.305 + * Steps:
1.306 + * - Open temporary DirectInputDevice interface.
1.307 + * - Create DirectInputDevice2 interface.
1.308 + * - Release DirectInputDevice interface.
1.309 + * - Call SDL_SYS_HapticOpenFromDevice2
1.310 + */
1.311 +static int
1.312 +SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance)
1.313 +{
1.314 + HRESULT ret;
1.315 + int ret2;
1.316 + LPDIRECTINPUTDEVICE device;
1.317 +
1.318 + /* Allocate the hwdata */
1.319 + haptic->hwdata = (struct haptic_hwdata *)
1.320 + SDL_malloc(sizeof(*haptic->hwdata));
1.321 + if (haptic->hwdata == NULL) {
1.322 + SDL_OutOfMemory();
1.323 + goto creat_err;
1.324 + }
1.325 + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
1.326 +
1.327 + /* Open the device */
1.328 + ret = IDirectInput_CreateDevice(dinput, &instance.guidInstance,
1.329 + &device, NULL);
1.330 + if (FAILED(ret)) {
1.331 + DI_SetError("Creating DirectInput device", ret);
1.332 + goto creat_err;
1.333 + }
1.334 +
1.335 + /* Now get the IDirectInputDevice2 interface, instead. */
1.336 + ret = IDirectInputDevice_QueryInterface(device,
1.337 + &IID_IDirectInputDevice2,
1.338 + (LPVOID *) & haptic->hwdata->
1.339 + device);
1.340 + /* Done with the temporary one now. */
1.341 + IDirectInputDevice_Release(device);
1.342 + if (FAILED(ret)) {
1.343 + DI_SetError("Querying DirectInput interface", ret);
1.344 + goto creat_err;
1.345 + }
1.346 +
1.347 + ret2 = SDL_SYS_HapticOpenFromDevice2(haptic, haptic->hwdata->device);
1.348 + if (ret2 < 0) {
1.349 + goto query_err;
1.350 + }
1.351 +
1.352 + return 0;
1.353 +
1.354 + query_err:
1.355 + IDirectInputDevice2_Release(haptic->hwdata->device);
1.356 + creat_err:
1.357 + if (haptic->hwdata != NULL) {
1.358 + SDL_free(haptic->hwdata);
1.359 + haptic->hwdata = NULL;
1.360 + }
1.361 + return -1;
1.362 +}
1.363 +
1.364 +
1.365 +/*
1.366 + * Opens the haptic device from the file descriptor.
1.367 + *
1.368 + * Steps:
1.369 + * - Set cooperative level.
1.370 + * - Set data format.
1.371 + * - Acquire exclusiveness.
1.372 + * - Reset actuators.
1.373 + * - Get supported featuers.
1.374 + */
1.375 +static int
1.376 +SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic,
1.377 + LPDIRECTINPUTDEVICE2 device2)
1.378 +{
1.379 + HRESULT ret;
1.380 + DIPROPDWORD dipdw;
1.381 +
1.382 + /* We'll use the device2 from now on. */
1.383 + haptic->hwdata->device = device2;
1.384 +
1.385 + /* Grab it exclusively to use force feedback stuff. */
1.386 + ret = IDirectInputDevice2_SetCooperativeLevel(haptic->hwdata->device,
1.387 + SDL_HelperWindow,
1.388 + DISCL_EXCLUSIVE |
1.389 + DISCL_BACKGROUND);
1.390 + if (FAILED(ret)) {
1.391 + DI_SetError("Setting cooperative level to exclusive", ret);
1.392 + goto acquire_err;
1.393 + }
1.394 +
1.395 + /* Set data format. */
1.396 + ret = IDirectInputDevice2_SetDataFormat(haptic->hwdata->device,
1.397 + &c_dfDIJoystick2);
1.398 + if (FAILED(ret)) {
1.399 + DI_SetError("Setting data format", ret);
1.400 + goto acquire_err;
1.401 + }
1.402 +
1.403 + /* Get number of axes. */
1.404 + ret = IDirectInputDevice2_EnumObjects(haptic->hwdata->device,
1.405 + DI_DeviceObjectCallback,
1.406 + haptic, DIDFT_AXIS);
1.407 + if (FAILED(ret)) {
1.408 + DI_SetError("Getting device axes", ret);
1.409 + goto acquire_err;
1.410 + }
1.411 +
1.412 + /* Acquire the device. */
1.413 + ret = IDirectInputDevice2_Acquire(haptic->hwdata->device);
1.414 + if (FAILED(ret)) {
1.415 + DI_SetError("Acquiring DirectInput device", ret);
1.416 + goto acquire_err;
1.417 + }
1.418 +
1.419 + /* Reset all actuators - just in case. */
1.420 + ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
1.421 + DISFFC_RESET);
1.422 + if (FAILED(ret)) {
1.423 + DI_SetError("Resetting device", ret);
1.424 + goto acquire_err;
1.425 + }
1.426 +
1.427 + /* Enabling actuators. */
1.428 + ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
1.429 + DISFFC_SETACTUATORSON);
1.430 + if (FAILED(ret)) {
1.431 + DI_SetError("Enabling actuators", ret);
1.432 + goto acquire_err;
1.433 + }
1.434 +
1.435 + /* Get supported effects. */
1.436 + ret = IDirectInputDevice2_EnumEffects(haptic->hwdata->device,
1.437 + DI_EffectCallback, haptic,
1.438 + DIEFT_ALL);
1.439 + if (FAILED(ret)) {
1.440 + DI_SetError("Enumerating supported effects", ret);
1.441 + goto acquire_err;
1.442 + }
1.443 + if (haptic->supported == 0) { /* Error since device supports nothing. */
1.444 + SDL_SetError("Haptic: Internal error on finding supported effects.");
1.445 + goto acquire_err;
1.446 + }
1.447 +
1.448 + /* Check autogain and autocenter. */
1.449 + dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1.450 + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1.451 + dipdw.diph.dwObj = 0;
1.452 + dipdw.diph.dwHow = DIPH_DEVICE;
1.453 + dipdw.dwData = 10000;
1.454 + ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
1.455 + DIPROP_FFGAIN, &dipdw.diph);
1.456 + if (!FAILED(ret)) { /* Gain is supported. */
1.457 + haptic->supported |= SDL_HAPTIC_GAIN;
1.458 + }
1.459 + dipdw.diph.dwObj = 0;
1.460 + dipdw.diph.dwHow = DIPH_DEVICE;
1.461 + dipdw.dwData = DIPROPAUTOCENTER_OFF;
1.462 + ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
1.463 + DIPROP_AUTOCENTER, &dipdw.diph);
1.464 + if (!FAILED(ret)) { /* Autocenter is supported. */
1.465 + haptic->supported |= SDL_HAPTIC_AUTOCENTER;
1.466 + }
1.467 +
1.468 + /* Status is always supported. */
1.469 + haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
1.470 +
1.471 + /* Check maximum effects. */
1.472 + haptic->neffects = 128; /* This is not actually supported as thus under windows,
1.473 + there is no way to tell the number of EFFECTS that a
1.474 + device can hold, so we'll just use a "random" number
1.475 + instead and put warnings in SDL_haptic.h */
1.476 + haptic->nplaying = 128; /* Even more impossible to get this then neffects. */
1.477 +
1.478 + /* Prepare effects memory. */
1.479 + haptic->effects = (struct haptic_effect *)
1.480 + SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
1.481 + if (haptic->effects == NULL) {
1.482 + SDL_OutOfMemory();
1.483 + goto acquire_err;
1.484 + }
1.485 + /* Clear the memory */
1.486 + SDL_memset(haptic->effects, 0,
1.487 + sizeof(struct haptic_effect) * haptic->neffects);
1.488 +
1.489 + return 0;
1.490 +
1.491 + /* Error handling */
1.492 + acquire_err:
1.493 + IDirectInputDevice2_Unacquire(haptic->hwdata->device);
1.494 + return -1;
1.495 +
1.496 +}
1.497 +
1.498 +
1.499 +/*
1.500 + * Opens a haptic device for usage.
1.501 + */
1.502 +int
1.503 +SDL_SYS_HapticOpen(SDL_Haptic * haptic)
1.504 +{
1.505 + return SDL_SYS_HapticOpenFromInstance(haptic,
1.506 + SDL_hapticlist[haptic->index].
1.507 + instance);
1.508 +}
1.509 +
1.510 +
1.511 +/*
1.512 + * Opens a haptic device from first mouse it finds for usage.
1.513 + */
1.514 +int
1.515 +SDL_SYS_HapticMouse(void)
1.516 +{
1.517 + int i;
1.518 +
1.519 + /* Grab the first mouse haptic device we find. */
1.520 + for (i = 0; i < SDL_numhaptics; i++) {
1.521 + if (SDL_hapticlist[i].capabilities.dwDevType == DIDEVTYPE_MOUSE) {
1.522 + return i;
1.523 + }
1.524 + }
1.525 +
1.526 + return -1;
1.527 +}
1.528 +
1.529 +
1.530 +/*
1.531 + * Checks to see if a joystick has haptic features.
1.532 + */
1.533 +int
1.534 +SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
1.535 +{
1.536 + if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
1.537 + return SDL_TRUE;
1.538 + }
1.539 +
1.540 + return SDL_FALSE;
1.541 +}
1.542 +
1.543 +
1.544 +/*
1.545 + * Checks to see if the haptic device and joystick and in reality the same.
1.546 + */
1.547 +int
1.548 +SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
1.549 +{
1.550 + HRESULT ret;
1.551 + DIDEVICEINSTANCE hap_instance, joy_instance;
1.552 +
1.553 + /* Get the device instances. */
1.554 + ret = IDirectInputDevice2_GetDeviceInfo(haptic->hwdata->device,
1.555 + &hap_instance);
1.556 + if (FAILED(ret)) {
1.557 + return 0;
1.558 + }
1.559 + ret = IDirectInputDevice2_GetDeviceInfo(joystick->hwdata->InputDevice,
1.560 + &joy_instance);
1.561 + if (FAILED(ret)) {
1.562 + return 0;
1.563 + }
1.564 +
1.565 + if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance))
1.566 + return 1;
1.567 +
1.568 + return 0;
1.569 +}
1.570 +
1.571 +
1.572 +/*
1.573 + * Opens a SDL_Haptic from a SDL_Joystick.
1.574 + */
1.575 +int
1.576 +SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
1.577 +{
1.578 + int ret;
1.579 +
1.580 + /* Allocate the hwdata */
1.581 + haptic->hwdata = (struct haptic_hwdata *)
1.582 + SDL_malloc(sizeof(*haptic->hwdata));
1.583 + if (haptic->hwdata == NULL) {
1.584 + SDL_OutOfMemory();
1.585 + return -1;
1.586 + }
1.587 + SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
1.588 +
1.589 + /* Now open the device. */
1.590 + ret =
1.591 + SDL_SYS_HapticOpenFromDevice2(haptic, joystick->hwdata->InputDevice);
1.592 + if (ret < 0) {
1.593 + return -1;
1.594 + }
1.595 +
1.596 + /* It's using the joystick device. */
1.597 + haptic->hwdata->is_joystick = 1;
1.598 +
1.599 + return 0;
1.600 +}
1.601 +
1.602 +
1.603 +/*
1.604 + * Closes the haptic device.
1.605 + */
1.606 +void
1.607 +SDL_SYS_HapticClose(SDL_Haptic * haptic)
1.608 +{
1.609 + if (haptic->hwdata) {
1.610 +
1.611 + /* Free effects. */
1.612 + SDL_free(haptic->effects);
1.613 + haptic->effects = NULL;
1.614 + haptic->neffects = 0;
1.615 +
1.616 + /* Clean up */
1.617 + IDirectInputDevice2_Unacquire(haptic->hwdata->device);
1.618 + /* Only release if isn't grabbed by a joystick. */
1.619 + if (haptic->hwdata->is_joystick == 0) {
1.620 + IDirectInputDevice2_Release(haptic->hwdata->device);
1.621 + }
1.622 +
1.623 + /* Free */
1.624 + SDL_free(haptic->hwdata);
1.625 + haptic->hwdata = NULL;
1.626 + }
1.627 +}
1.628 +
1.629 +
1.630 +/*
1.631 + * Clean up after system specific haptic stuff
1.632 + */
1.633 +void
1.634 +SDL_SYS_HapticQuit(void)
1.635 +{
1.636 + IDirectInput_Release(dinput);
1.637 + dinput = NULL;
1.638 +}
1.639 +
1.640 +
1.641 +/*
1.642 + * Converts an SDL trigger button to an DIEFFECT trigger button.
1.643 + */
1.644 +static DWORD
1.645 +DIGetTriggerButton(Uint16 button)
1.646 +{
1.647 + DWORD dwTriggerButton;
1.648 +
1.649 + dwTriggerButton = DIEB_NOTRIGGER;
1.650 +
1.651 + if (button != 0) {
1.652 + dwTriggerButton = DIJOFS_BUTTON(button - 1);
1.653 + }
1.654 +
1.655 + return dwTriggerButton;
1.656 +}
1.657 +
1.658 +
1.659 +/*
1.660 + * Sets the direction.
1.661 + */
1.662 +static int
1.663 +SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
1.664 +{
1.665 + LONG *rglDir;
1.666 +
1.667 + /* Handle no axes a part. */
1.668 + if (naxes == 0) {
1.669 + effect->dwFlags |= DIEFF_SPHERICAL; /* Set as default. */
1.670 + effect->rglDirection = NULL;
1.671 + return 0;
1.672 + }
1.673 +
1.674 + /* Has axes. */
1.675 + rglDir = SDL_malloc(sizeof(LONG) * naxes);
1.676 + if (rglDir == NULL) {
1.677 + SDL_OutOfMemory();
1.678 + return -1;
1.679 + }
1.680 + SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
1.681 + effect->rglDirection = rglDir;
1.682 +
1.683 + switch (dir->type) {
1.684 + case SDL_HAPTIC_POLAR:
1.685 + effect->dwFlags |= DIEFF_POLAR;
1.686 + rglDir[0] = dir->dir[0];
1.687 + return 0;
1.688 + case SDL_HAPTIC_CARTESIAN:
1.689 + effect->dwFlags |= DIEFF_CARTESIAN;
1.690 + rglDir[0] = dir->dir[0];
1.691 + if (naxes > 1)
1.692 + rglDir[1] = dir->dir[1];
1.693 + if (naxes > 2)
1.694 + rglDir[2] = dir->dir[2];
1.695 + return 0;
1.696 + case SDL_HAPTIC_SPHERICAL:
1.697 + effect->dwFlags |= DIEFF_SPHERICAL;
1.698 + rglDir[0] = dir->dir[0];
1.699 + if (naxes > 1)
1.700 + rglDir[1] = dir->dir[1];
1.701 + if (naxes > 2)
1.702 + rglDir[2] = dir->dir[2];
1.703 + return 0;
1.704 +
1.705 + default:
1.706 + SDL_SetError("Haptic: Unknown direction type.");
1.707 + return -1;
1.708 + }
1.709 +}
1.710 +
1.711 +#define CONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
1.712 +/*
1.713 + * Creates the DIEFFECT from a SDL_HapticEffect.
1.714 + */
1.715 +static int
1.716 +SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
1.717 + SDL_HapticEffect * src)
1.718 +{
1.719 + int i;
1.720 + DICONSTANTFORCE *constant;
1.721 + DIPERIODIC *periodic;
1.722 + DICONDITION *condition; /* Actually an array of conditions - one per axis. */
1.723 + DIRAMPFORCE *ramp;
1.724 + DICUSTOMFORCE *custom;
1.725 + DIENVELOPE *envelope;
1.726 + SDL_HapticConstant *hap_constant;
1.727 + SDL_HapticPeriodic *hap_periodic;
1.728 + SDL_HapticCondition *hap_condition;
1.729 + SDL_HapticRamp *hap_ramp;
1.730 + SDL_HapticCustom *hap_custom;
1.731 + DWORD *axes;
1.732 +
1.733 + /* Set global stuff. */
1.734 + SDL_memset(dest, 0, sizeof(DIEFFECT));
1.735 + dest->dwSize = sizeof(DIEFFECT); /* Set the structure size. */
1.736 + dest->dwSamplePeriod = 0; /* Not used by us. */
1.737 + dest->dwGain = 10000; /* Gain is set globally, not locally. */
1.738 + dest->dwFlags = DIEFF_OBJECTOFFSETS; /* Seems obligatory. */
1.739 +
1.740 + /* Envelope. */
1.741 + envelope = SDL_malloc(sizeof(DIENVELOPE));
1.742 + if (envelope == NULL) {
1.743 + SDL_OutOfMemory();
1.744 + return -1;
1.745 + }
1.746 + SDL_memset(envelope, 0, sizeof(DIENVELOPE));
1.747 + dest->lpEnvelope = envelope;
1.748 + envelope->dwSize = sizeof(DIENVELOPE); /* Always should be this. */
1.749 +
1.750 + /* Axes. */
1.751 + dest->cAxes = haptic->naxes;
1.752 + if (dest->cAxes > 0) {
1.753 + axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
1.754 + if (axes == NULL) {
1.755 + SDL_OutOfMemory();
1.756 + return -1;
1.757 + }
1.758 + axes[0] = haptic->hwdata->axes[0]; /* Always at least one axis. */
1.759 + if (dest->cAxes > 1) {
1.760 + axes[1] = haptic->hwdata->axes[1];
1.761 + }
1.762 + if (dest->cAxes > 2) {
1.763 + axes[2] = haptic->hwdata->axes[2];
1.764 + }
1.765 + dest->rgdwAxes = axes;
1.766 + }
1.767 +
1.768 +
1.769 + /* The big type handling switch, even bigger then linux's version. */
1.770 + switch (src->type) {
1.771 + case SDL_HAPTIC_CONSTANT:
1.772 + hap_constant = &src->constant;
1.773 + constant = SDL_malloc(sizeof(DICONSTANTFORCE));
1.774 + if (constant == NULL) {
1.775 + SDL_OutOfMemory();
1.776 + return -1;
1.777 + }
1.778 + SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
1.779 +
1.780 + /* Specifics */
1.781 + constant->lMagnitude = CONVERT(hap_constant->level);
1.782 + dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
1.783 + dest->lpvTypeSpecificParams = constant;
1.784 +
1.785 + /* Generics */
1.786 + dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
1.787 + dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
1.788 + dest->dwTriggerRepeatInterval = hap_constant->interval;
1.789 + dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */
1.790 +
1.791 + /* Direction. */
1.792 + if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes)
1.793 + < 0) {
1.794 + return -1;
1.795 + }
1.796 +
1.797 + /* Envelope */
1.798 + if ((hap_constant->attack_length == 0)
1.799 + && (hap_constant->fade_length == 0)) {
1.800 + SDL_free(dest->lpEnvelope);
1.801 + dest->lpEnvelope = NULL;
1.802 + } else {
1.803 + envelope->dwAttackLevel = CONVERT(hap_constant->attack_level);
1.804 + envelope->dwAttackTime = hap_constant->attack_length * 1000;
1.805 + envelope->dwFadeLevel = CONVERT(hap_constant->fade_level);
1.806 + envelope->dwFadeTime = hap_constant->fade_length * 1000;
1.807 + }
1.808 +
1.809 + break;
1.810 +
1.811 + case SDL_HAPTIC_SINE:
1.812 + case SDL_HAPTIC_SQUARE:
1.813 + case SDL_HAPTIC_TRIANGLE:
1.814 + case SDL_HAPTIC_SAWTOOTHUP:
1.815 + case SDL_HAPTIC_SAWTOOTHDOWN:
1.816 + hap_periodic = &src->periodic;
1.817 + periodic = SDL_malloc(sizeof(DIPERIODIC));
1.818 + if (periodic == NULL) {
1.819 + SDL_OutOfMemory();
1.820 + return -1;
1.821 + }
1.822 + SDL_memset(periodic, 0, sizeof(DIPERIODIC));
1.823 +
1.824 + /* Specifics */
1.825 + periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
1.826 + periodic->lOffset = CONVERT(hap_periodic->offset);
1.827 + periodic->dwPhase = hap_periodic->phase;
1.828 + periodic->dwPeriod = hap_periodic->period * 1000;
1.829 + dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
1.830 + dest->lpvTypeSpecificParams = periodic;
1.831 +
1.832 + /* Generics */
1.833 + dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
1.834 + dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
1.835 + dest->dwTriggerRepeatInterval = hap_periodic->interval;
1.836 + dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */
1.837 +
1.838 + /* Direction. */
1.839 + if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
1.840 + < 0) {
1.841 + return -1;
1.842 + }
1.843 +
1.844 + /* Envelope */
1.845 + if ((hap_periodic->attack_length == 0)
1.846 + && (hap_periodic->fade_length == 0)) {
1.847 + SDL_free(dest->lpEnvelope);
1.848 + dest->lpEnvelope = NULL;
1.849 + } else {
1.850 + envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level);
1.851 + envelope->dwAttackTime = hap_periodic->attack_length * 1000;
1.852 + envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level);
1.853 + envelope->dwFadeTime = hap_periodic->fade_length * 1000;
1.854 + }
1.855 +
1.856 + break;
1.857 +
1.858 + case SDL_HAPTIC_SPRING:
1.859 + case SDL_HAPTIC_DAMPER:
1.860 + case SDL_HAPTIC_INERTIA:
1.861 + case SDL_HAPTIC_FRICTION:
1.862 + hap_condition = &src->condition;
1.863 + condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
1.864 + if (condition == NULL) {
1.865 + SDL_OutOfMemory();
1.866 + return -1;
1.867 + }
1.868 + SDL_memset(condition, 0, sizeof(DICONDITION));
1.869 +
1.870 + /* Specifics */
1.871 + for (i = 0; i < (int) dest->cAxes; i++) {
1.872 + condition[i].lOffset = CONVERT(hap_condition->center[i]);
1.873 + condition[i].lPositiveCoefficient =
1.874 + CONVERT(hap_condition->right_coeff[i]);
1.875 + condition[i].lNegativeCoefficient =
1.876 + CONVERT(hap_condition->left_coeff[i]);
1.877 + condition[i].dwPositiveSaturation =
1.878 + CONVERT(hap_condition->right_sat[i]);
1.879 + condition[i].dwNegativeSaturation =
1.880 + CONVERT(hap_condition->left_sat[i]);
1.881 + condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
1.882 + }
1.883 + dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
1.884 + dest->lpvTypeSpecificParams = condition;
1.885 +
1.886 + /* Generics */
1.887 + dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */
1.888 + dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
1.889 + dest->dwTriggerRepeatInterval = hap_condition->interval;
1.890 + dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */
1.891 +
1.892 + /* Direction. */
1.893 + if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
1.894 + < 0) {
1.895 + return -1;
1.896 + }
1.897 +
1.898 + /* Envelope - Not actually supported by most CONDITION implementations. */
1.899 + SDL_free(dest->lpEnvelope);
1.900 + dest->lpEnvelope = NULL;
1.901 +
1.902 + break;
1.903 +
1.904 + case SDL_HAPTIC_RAMP:
1.905 + hap_ramp = &src->ramp;
1.906 + ramp = SDL_malloc(sizeof(DIRAMPFORCE));
1.907 + if (ramp == NULL) {
1.908 + SDL_OutOfMemory();
1.909 + return -1;
1.910 + }
1.911 + SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
1.912 +
1.913 + /* Specifics */
1.914 + ramp->lStart = CONVERT(hap_ramp->start);
1.915 + ramp->lEnd = CONVERT(hap_ramp->end);
1.916 + dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
1.917 + dest->lpvTypeSpecificParams = ramp;
1.918 +
1.919 + /* Generics */
1.920 + dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */
1.921 + dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
1.922 + dest->dwTriggerRepeatInterval = hap_ramp->interval;
1.923 + dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */
1.924 +
1.925 + /* Direction. */
1.926 + if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
1.927 + return -1;
1.928 + }
1.929 +
1.930 + /* Envelope */
1.931 + if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
1.932 + SDL_free(dest->lpEnvelope);
1.933 + dest->lpEnvelope = NULL;
1.934 + } else {
1.935 + envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level);
1.936 + envelope->dwAttackTime = hap_ramp->attack_length * 1000;
1.937 + envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level);
1.938 + envelope->dwFadeTime = hap_ramp->fade_length * 1000;
1.939 + }
1.940 +
1.941 + break;
1.942 +
1.943 + case SDL_HAPTIC_CUSTOM:
1.944 + hap_custom = &src->custom;
1.945 + custom = SDL_malloc(sizeof(DICUSTOMFORCE));
1.946 + if (custom == NULL) {
1.947 + SDL_OutOfMemory();
1.948 + return -1;
1.949 + }
1.950 + SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
1.951 +
1.952 + /* Specifics */
1.953 + custom->cChannels = hap_custom->channels;
1.954 + custom->dwSamplePeriod = hap_custom->period * 1000;
1.955 + custom->cSamples = hap_custom->samples;
1.956 + custom->rglForceData =
1.957 + SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
1.958 + for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) { /* Copy data. */
1.959 + custom->rglForceData[i] = CONVERT(hap_custom->data[i]);
1.960 + }
1.961 + dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
1.962 + dest->lpvTypeSpecificParams = custom;
1.963 +
1.964 + /* Generics */
1.965 + dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */
1.966 + dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
1.967 + dest->dwTriggerRepeatInterval = hap_custom->interval;
1.968 + dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */
1.969 +
1.970 + /* Direction. */
1.971 + if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) <
1.972 + 0) {
1.973 + return -1;
1.974 + }
1.975 +
1.976 + /* Envelope */
1.977 + if ((hap_custom->attack_length == 0)
1.978 + && (hap_custom->fade_length == 0)) {
1.979 + SDL_free(dest->lpEnvelope);
1.980 + dest->lpEnvelope = NULL;
1.981 + } else {
1.982 + envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
1.983 + envelope->dwAttackTime = hap_custom->attack_length * 1000;
1.984 + envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
1.985 + envelope->dwFadeTime = hap_custom->fade_length * 1000;
1.986 + }
1.987 +
1.988 + break;
1.989 +
1.990 +
1.991 + default:
1.992 + SDL_SetError("Haptic: Unknown effect type.");
1.993 + return -1;
1.994 + }
1.995 +
1.996 + return 0;
1.997 +}
1.998 +
1.999 +
1.1000 +/*
1.1001 + * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
1.1002 + */
1.1003 +static void
1.1004 +SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
1.1005 +{
1.1006 + DICUSTOMFORCE *custom;
1.1007 +
1.1008 + if (effect->lpEnvelope != NULL) {
1.1009 + SDL_free(effect->lpEnvelope);
1.1010 + effect->lpEnvelope = NULL;
1.1011 + }
1.1012 + if (effect->rgdwAxes != NULL) {
1.1013 + SDL_free(effect->rgdwAxes);
1.1014 + effect->rgdwAxes = NULL;
1.1015 + }
1.1016 + if (effect->lpvTypeSpecificParams != NULL) {
1.1017 + if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */
1.1018 + custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
1.1019 + SDL_free(custom->rglForceData);
1.1020 + custom->rglForceData = NULL;
1.1021 + }
1.1022 + SDL_free(effect->lpvTypeSpecificParams);
1.1023 + effect->lpvTypeSpecificParams = NULL;
1.1024 + }
1.1025 + if (effect->rglDirection != NULL) {
1.1026 + SDL_free(effect->rglDirection);
1.1027 + effect->rglDirection = NULL;
1.1028 + }
1.1029 +}
1.1030 +
1.1031 +
1.1032 +/*
1.1033 + * Gets the effect type from the generic SDL haptic effect wrapper.
1.1034 + */
1.1035 +static REFGUID
1.1036 +SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
1.1037 +{
1.1038 + switch (effect->type) {
1.1039 + case SDL_HAPTIC_CONSTANT:
1.1040 + return &GUID_ConstantForce;
1.1041 +
1.1042 + case SDL_HAPTIC_RAMP:
1.1043 + return &GUID_RampForce;
1.1044 +
1.1045 + case SDL_HAPTIC_SQUARE:
1.1046 + return &GUID_Square;
1.1047 +
1.1048 + case SDL_HAPTIC_SINE:
1.1049 + return &GUID_Sine;
1.1050 +
1.1051 + case SDL_HAPTIC_TRIANGLE:
1.1052 + return &GUID_Triangle;
1.1053 +
1.1054 + case SDL_HAPTIC_SAWTOOTHUP:
1.1055 + return &GUID_SawtoothUp;
1.1056 +
1.1057 + case SDL_HAPTIC_SAWTOOTHDOWN:
1.1058 + return &GUID_SawtoothDown;
1.1059 +
1.1060 + case SDL_HAPTIC_SPRING:
1.1061 + return &GUID_Spring;
1.1062 +
1.1063 + case SDL_HAPTIC_DAMPER:
1.1064 + return &GUID_Damper;
1.1065 +
1.1066 + case SDL_HAPTIC_INERTIA:
1.1067 + return &GUID_Inertia;
1.1068 +
1.1069 + case SDL_HAPTIC_FRICTION:
1.1070 + return &GUID_Friction;
1.1071 +
1.1072 + case SDL_HAPTIC_CUSTOM:
1.1073 + return &GUID_CustomForce;
1.1074 +
1.1075 + default:
1.1076 + SDL_SetError("Haptic: Unknown effect type.");
1.1077 + return NULL;
1.1078 + }
1.1079 +}
1.1080 +
1.1081 +
1.1082 +/*
1.1083 + * Creates a new haptic effect.
1.1084 + */
1.1085 +int
1.1086 +SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
1.1087 + SDL_HapticEffect * base)
1.1088 +{
1.1089 + HRESULT ret;
1.1090 +
1.1091 + /* Get the type. */
1.1092 + REFGUID type = SDL_SYS_HapticEffectType(base);
1.1093 + if (type == NULL) {
1.1094 + goto err_hweffect;
1.1095 + }
1.1096 +
1.1097 + /* Alloc the effect. */
1.1098 + effect->hweffect = (struct haptic_hweffect *)
1.1099 + SDL_malloc(sizeof(struct haptic_hweffect));
1.1100 + if (effect->hweffect == NULL) {
1.1101 + SDL_OutOfMemory();
1.1102 + goto err_hweffect;
1.1103 + }
1.1104 +
1.1105 + /* Get the effect. */
1.1106 + if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
1.1107 + goto err_effectdone;
1.1108 + }
1.1109 +
1.1110 + /* Create the actual effect. */
1.1111 + ret = IDirectInputDevice2_CreateEffect(haptic->hwdata->device, type,
1.1112 + &effect->hweffect->effect,
1.1113 + &effect->hweffect->ref, NULL);
1.1114 + if (FAILED(ret)) {
1.1115 + DI_SetError("Unable to create effect", ret);
1.1116 + goto err_effectdone;
1.1117 + }
1.1118 +
1.1119 + return 0;
1.1120 +
1.1121 + err_effectdone:
1.1122 + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
1.1123 + err_hweffect:
1.1124 + if (effect->hweffect != NULL) {
1.1125 + SDL_free(effect->hweffect);
1.1126 + effect->hweffect = NULL;
1.1127 + }
1.1128 + return -1;
1.1129 +}
1.1130 +
1.1131 +
1.1132 +/*
1.1133 + * Updates an effect.
1.1134 + */
1.1135 +int
1.1136 +SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
1.1137 + struct haptic_effect *effect,
1.1138 + SDL_HapticEffect * data)
1.1139 +{
1.1140 + HRESULT ret;
1.1141 + DWORD flags;
1.1142 + DIEFFECT temp;
1.1143 +
1.1144 + /* Get the effect. */
1.1145 + SDL_memset(&temp, 0, sizeof(DIEFFECT));
1.1146 + if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
1.1147 + goto err_update;
1.1148 + }
1.1149 +
1.1150 + /* Set the flags. Might be worthwhile to diff temp with loaded effect and
1.1151 + * only change those parameters. */
1.1152 + flags = DIEP_DIRECTION |
1.1153 + DIEP_DURATION |
1.1154 + DIEP_ENVELOPE |
1.1155 + DIEP_STARTDELAY |
1.1156 + DIEP_TRIGGERBUTTON |
1.1157 + DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
1.1158 +
1.1159 + /* Create the actual effect. */
1.1160 + ret =
1.1161 + IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
1.1162 + if (FAILED(ret)) {
1.1163 + DI_SetError("Unable to update effect", ret);
1.1164 + goto err_update;
1.1165 + }
1.1166 +
1.1167 + /* Copy it over. */
1.1168 + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
1.1169 + SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
1.1170 +
1.1171 + return 0;
1.1172 +
1.1173 + err_update:
1.1174 + SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
1.1175 + return -1;
1.1176 +}
1.1177 +
1.1178 +
1.1179 +/*
1.1180 + * Runs an effect.
1.1181 + */
1.1182 +int
1.1183 +SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
1.1184 + Uint32 iterations)
1.1185 +{
1.1186 + HRESULT ret;
1.1187 + DWORD iter;
1.1188 +
1.1189 + /* Check if it's infinite. */
1.1190 + if (iterations == SDL_HAPTIC_INFINITY) {
1.1191 + iter = INFINITE;
1.1192 + } else
1.1193 + iter = iterations;
1.1194 +
1.1195 + /* Run the effect. */
1.1196 + ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
1.1197 + if (FAILED(ret)) {
1.1198 + DI_SetError("Running the effect", ret);
1.1199 + return -1;
1.1200 + }
1.1201 +
1.1202 + return 0;
1.1203 +}
1.1204 +
1.1205 +
1.1206 +/*
1.1207 + * Stops an effect.
1.1208 + */
1.1209 +int
1.1210 +SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1.1211 +{
1.1212 + HRESULT ret;
1.1213 +
1.1214 + ret = IDirectInputEffect_Stop(effect->hweffect->ref);
1.1215 + if (FAILED(ret)) {
1.1216 + DI_SetError("Unable to stop effect", ret);
1.1217 + return -1;
1.1218 + }
1.1219 +
1.1220 + return 0;
1.1221 +}
1.1222 +
1.1223 +
1.1224 +/*
1.1225 + * Frees the effect.
1.1226 + */
1.1227 +void
1.1228 +SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
1.1229 +{
1.1230 + HRESULT ret;
1.1231 +
1.1232 + ret = IDirectInputEffect_Unload(effect->hweffect->ref);
1.1233 + if (FAILED(ret)) {
1.1234 + DI_SetError("Removing effect from the device", ret);
1.1235 + }
1.1236 + SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect,
1.1237 + effect->effect.type);
1.1238 + SDL_free(effect->hweffect);
1.1239 + effect->hweffect = NULL;
1.1240 +}
1.1241 +
1.1242 +
1.1243 +/*
1.1244 + * Gets the status of a haptic effect.
1.1245 + */
1.1246 +int
1.1247 +SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
1.1248 + struct haptic_effect *effect)
1.1249 +{
1.1250 + HRESULT ret;
1.1251 + DWORD status;
1.1252 +
1.1253 + ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
1.1254 + if (FAILED(ret)) {
1.1255 + DI_SetError("Getting effect status", ret);
1.1256 + return -1;
1.1257 + }
1.1258 +
1.1259 + if (status == 0)
1.1260 + return SDL_FALSE;
1.1261 + return SDL_TRUE;
1.1262 +}
1.1263 +
1.1264 +
1.1265 +/*
1.1266 + * Sets the gain.
1.1267 + */
1.1268 +int
1.1269 +SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
1.1270 +{
1.1271 + HRESULT ret;
1.1272 + DIPROPDWORD dipdw;
1.1273 +
1.1274 + /* Create the weird structure thingy. */
1.1275 + dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1.1276 + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1.1277 + dipdw.diph.dwObj = 0;
1.1278 + dipdw.diph.dwHow = DIPH_DEVICE;
1.1279 + dipdw.dwData = gain * 100; /* 0 to 10,000 */
1.1280 +
1.1281 + /* Try to set the autocenter. */
1.1282 + ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
1.1283 + DIPROP_FFGAIN, &dipdw.diph);
1.1284 + if (FAILED(ret)) {
1.1285 + DI_SetError("Setting gain", ret);
1.1286 + return -1;
1.1287 + }
1.1288 +
1.1289 + return 0;
1.1290 +}
1.1291 +
1.1292 +
1.1293 +/*
1.1294 + * Sets the autocentering.
1.1295 + */
1.1296 +int
1.1297 +SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
1.1298 +{
1.1299 + HRESULT ret;
1.1300 + DIPROPDWORD dipdw;
1.1301 +
1.1302 + /* Create the weird structure thingy. */
1.1303 + dipdw.diph.dwSize = sizeof(DIPROPDWORD);
1.1304 + dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
1.1305 + dipdw.diph.dwObj = 0;
1.1306 + dipdw.diph.dwHow = DIPH_DEVICE;
1.1307 + dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
1.1308 + DIPROPAUTOCENTER_ON;
1.1309 +
1.1310 + /* Try to set the autocenter. */
1.1311 + ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
1.1312 + DIPROP_AUTOCENTER, &dipdw.diph);
1.1313 + if (FAILED(ret)) {
1.1314 + DI_SetError("Setting autocenter", ret);
1.1315 + return -1;
1.1316 + }
1.1317 +
1.1318 + return 0;
1.1319 +}
1.1320 +
1.1321 +
1.1322 +/*
1.1323 + * Pauses the device.
1.1324 + */
1.1325 +int
1.1326 +SDL_SYS_HapticPause(SDL_Haptic * haptic)
1.1327 +{
1.1328 + HRESULT ret;
1.1329 +
1.1330 + /* Pause the device. */
1.1331 + ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
1.1332 + DISFFC_PAUSE);
1.1333 + if (FAILED(ret)) {
1.1334 + DI_SetError("Pausing the device", ret);
1.1335 + return -1;
1.1336 + }
1.1337 +
1.1338 + return 0;
1.1339 +}
1.1340 +
1.1341 +
1.1342 +/*
1.1343 + * Pauses the device.
1.1344 + */
1.1345 +int
1.1346 +SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
1.1347 +{
1.1348 + HRESULT ret;
1.1349 +
1.1350 + /* Unpause the device. */
1.1351 + ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
1.1352 + DISFFC_CONTINUE);
1.1353 + if (FAILED(ret)) {
1.1354 + DI_SetError("Pausing the device", ret);
1.1355 + return -1;
1.1356 + }
1.1357 +
1.1358 + return 0;
1.1359 +}
1.1360 +
1.1361 +
1.1362 +/*
1.1363 + * Stops all the playing effects on the device.
1.1364 + */
1.1365 +int
1.1366 +SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
1.1367 +{
1.1368 + HRESULT ret;
1.1369 +
1.1370 + /* Try to stop the effects. */
1.1371 + ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
1.1372 + DISFFC_STOPALL);
1.1373 + if (FAILED(ret)) {
1.1374 + DI_SetError("Stopping the device", ret);
1.1375 + return -1;
1.1376 + }
1.1377 +
1.1378 + return 0;
1.1379 +}
1.1380 +
1.1381 +
1.1382 +#endif /* SDL_HAPTIC_DINPUT */