src/haptic/windows/SDL_dinputhaptic.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 16 Mar 2020 13:28:38 -0700
changeset 13635 701fe6486077
parent 13422 fd6a12de91c7
child 13789 a359f4f93439
permissions -rw-r--r--
Fixed bug 3446 - The haptic API does not allow to select the direction axes

Mathieu Laurendeau

Consider a device supporting effects on multiple axes.
There's currently no way to play effects against a single-axis direction.


A device supporting effects against X and Y may not allow to play effects with a two-axis direction coordinate, even if one of the coordinates is null.

My current (ugly) work around for this is to add a direction type SDL_HAPTIC_X_FORCE to play effects against a X-axis only direction (patch attached).

This issue impacted two GIMX users using the following wheels:
- Leo Bodnar SimSteering force feedback wheel
- Accuforce direct drive wheel

Playing constant/spring/damper effects against a X-axis direction worked well for the first wheel, but not for the second one.

A better strategy seems to play the effects against the first axis reported by the DirectInput enumeration.

This strategy also works with Logitech wheels (at least the DFGT).

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