src/haptic/windows/SDL_syshaptic.c
author Sam Lantinga
Mon, 24 Jan 2011 21:20:30 -0800
changeset 5090 327f181542f1
parent 5062 e8916fe9cfc8
child 5358 5b330ef7b8dd
permissions -rw-r--r--
Include windows.h in a single point in the source, so we can be consistent about the definition of UNICODE and have core utility functions for Windows that all modules can share.

I think this also fixes the bug relating to non-latin characters in filenames, since UNICODE wasn't defined in SDL_rwops.c
slouken@2713
     1
/*
slouken@2713
     2
    SDL - Simple DirectMedia Layer
slouken@2713
     3
    Copyright (C) 2008 Edgar Simo
slouken@2713
     4
slouken@2713
     5
    This library is free software; you can redistribute it and/or
slouken@2713
     6
    modify it under the terms of the GNU Lesser General Public
slouken@2713
     7
    License as published by the Free Software Foundation; either
slouken@2713
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@2713
     9
slouken@2713
    10
    This library is distributed in the hope that it will be useful,
slouken@2713
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@2713
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@2713
    13
    Lesser General Public License for more details.
slouken@2713
    14
slouken@2713
    15
    You should have received a copy of the GNU Lesser General Public
slouken@2713
    16
    License along with this library; if not, write to the Free Software
slouken@2713
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@2713
    18
slouken@2713
    19
    Sam Lantinga
slouken@2713
    20
    slouken@libsdl.org
slouken@2713
    21
*/
slouken@2713
    22
#include "SDL_config.h"
slouken@2713
    23
slouken@2713
    24
#ifdef SDL_HAPTIC_DINPUT
slouken@2713
    25
slouken@2713
    26
#include "SDL_haptic.h"
slouken@2713
    27
#include "../SDL_syshaptic.h"
slouken@2713
    28
#include "SDL_joystick.h"
slouken@2713
    29
#include "../../joystick/SDL_sysjoystick.h"     /* For the real SDL_Joystick */
slouken@5062
    30
#include "../../joystick/windows/SDL_dxjoystick_c.h"      /* For joystick hwdata */
slouken@2713
    31
slouken@2713
    32
slouken@2713
    33
#define MAX_HAPTICS  32
slouken@2713
    34
slouken@2713
    35
slouken@2713
    36
/*
slouken@2713
    37
 * List of available haptic devices.
slouken@2713
    38
 */
slouken@2713
    39
static struct
slouken@2713
    40
{
slouken@2713
    41
    DIDEVICEINSTANCE instance;
slouken@5090
    42
    char *name;
slouken@2713
    43
    SDL_Haptic *haptic;
slouken@2713
    44
    DIDEVCAPS capabilities;
slouken@2713
    45
} SDL_hapticlist[MAX_HAPTICS];
slouken@2713
    46
slouken@2713
    47
slouken@2713
    48
/*
slouken@2713
    49
 * Haptic system hardware data.
slouken@2713
    50
 */
slouken@2713
    51
struct haptic_hwdata
slouken@2713
    52
{
slouken@2713
    53
    LPDIRECTINPUTDEVICE2 device;
slouken@2713
    54
    DWORD axes[3];              /* Axes to use. */
slouken@2713
    55
    int is_joystick;            /* Device is loaded as joystick. */
slouken@2713
    56
};
slouken@2713
    57
slouken@2713
    58
slouken@2713
    59
/*
slouken@2713
    60
 * Haptic system effect data.
slouken@2713
    61
 */
slouken@2713
    62
struct haptic_hweffect
slouken@2713
    63
{
slouken@2713
    64
    DIEFFECT effect;
slouken@2713
    65
    LPDIRECTINPUTEFFECT ref;
slouken@2713
    66
};
slouken@2713
    67
slouken@2713
    68
slouken@2713
    69
/*
slouken@2713
    70
 * Internal stuff.
slouken@2713
    71
 */
slouken@2713
    72
static LPDIRECTINPUT dinput = NULL;
slouken@2713
    73
slouken@2713
    74
slouken@2713
    75
/*
slouken@2713
    76
 * External stuff.
slouken@2713
    77
 */
slouken@2713
    78
extern HWND SDL_HelperWindow;
slouken@2713
    79
slouken@2713
    80
slouken@2713
    81
/*
slouken@2713
    82
 * Prototypes.
slouken@2713
    83
 */
slouken@2713
    84
static void DI_SetError(const char *str, HRESULT err);
slouken@2713
    85
static int DI_GUIDIsSame(const GUID * a, const GUID * b);
slouken@2713
    86
static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic,
slouken@2713
    87
                                          DIDEVICEINSTANCE instance);
slouken@2713
    88
static int SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic,
slouken@2713
    89
                                         LPDIRECTINPUTDEVICE2 device2);
slouken@2713
    90
static DWORD DIGetTriggerButton(Uint16 button);
slouken@2713
    91
static int SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir,
slouken@2713
    92
                                int naxes);
slouken@2713
    93
static int SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
slouken@2713
    94
                              SDL_HapticEffect * src);
slouken@2713
    95
static void SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type);
slouken@2713
    96
static REFGUID SDL_SYS_HapticEffectType(SDL_HapticEffect * effect);
slouken@2713
    97
/* Callbacks. */
slouken@2713
    98
static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE *
slouken@2713
    99
                                         pdidInstance, VOID * pContext);
slouken@2713
   100
static BOOL CALLBACK DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv);
slouken@2713
   101
slouken@2713
   102
slouken@2713
   103
/* 
slouken@2713
   104
 * Like SDL_SetError but for DX error codes.
slouken@2713
   105
 */
slouken@2713
   106
static void
slouken@2713
   107
DI_SetError(const char *str, HRESULT err)
slouken@2713
   108
{
slouken@2786
   109
    /*
slouken@2786
   110
       SDL_SetError("Haptic: %s - %s: %s", str,
slouken@2786
   111
       DXGetErrorString8A(err), DXGetErrorDescription8A(err));
slouken@2786
   112
     */
slouken@2786
   113
    SDL_SetError("Haptic error %s", str);
slouken@2713
   114
}
slouken@2713
   115
slouken@2713
   116
slouken@2713
   117
/*
slouken@2713
   118
 * Checks to see if two GUID are the same.
slouken@2713
   119
 */
slouken@2713
   120
static int
slouken@2713
   121
DI_GUIDIsSame(const GUID * a, const GUID * b)
slouken@2713
   122
{
slouken@2713
   123
    if (((a)->Data1 == (b)->Data1) &&
slouken@2713
   124
        ((a)->Data2 == (b)->Data2) &&
slouken@2713
   125
        ((a)->Data3 == (b)->Data3) &&
slouken@2713
   126
        (SDL_strcmp((a)->Data4, (b)->Data4) == 0))
slouken@2713
   127
        return 1;
slouken@2713
   128
    return 0;
slouken@2713
   129
}
slouken@2713
   130
slouken@2713
   131
slouken@2713
   132
/*
slouken@2713
   133
 * Initializes the haptic subsystem.
slouken@2713
   134
 */
slouken@2713
   135
int
slouken@2713
   136
SDL_SYS_HapticInit(void)
slouken@2713
   137
{
slouken@2713
   138
    HRESULT ret;
slouken@2713
   139
    HINSTANCE instance;
slouken@2713
   140
slouken@2713
   141
    if (dinput != NULL) {       /* Already open. */
slouken@2713
   142
        SDL_SetError("Haptic: SubSystem already open.");
slouken@2713
   143
        return -1;
slouken@2713
   144
    }
slouken@2713
   145
slouken@2713
   146
    /* Clear all the memory. */
slouken@2713
   147
    SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
slouken@2713
   148
slouken@2713
   149
    SDL_numhaptics = 0;
slouken@2713
   150
slouken@2713
   151
    ret = CoInitialize(NULL);
slouken@2713
   152
    if (FAILED(ret)) {
slouken@2713
   153
        DI_SetError("Coinitialize", ret);
slouken@2713
   154
        return -1;
slouken@2713
   155
    }
slouken@2713
   156
slouken@2713
   157
    ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
slouken@2786
   158
                           &IID_IDirectInput, (LPVOID) & dinput);
slouken@2713
   159
    if (FAILED(ret)) {
slouken@2713
   160
        DI_SetError("CoCreateInstance", ret);
slouken@2713
   161
        return -1;
slouken@2713
   162
    }
slouken@2713
   163
slouken@2713
   164
    /* Because we used CoCreateInstance, we need to Initialize it, first. */
slouken@2713
   165
    instance = GetModuleHandle(NULL);
slouken@2713
   166
    if (instance == NULL) {
slouken@2713
   167
        SDL_SetError("GetModuleHandle() failed with error code %d.",
slouken@2713
   168
                     GetLastError());
slouken@2713
   169
        return -1;
slouken@2713
   170
    }
slouken@2713
   171
    ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION);
slouken@2713
   172
    if (FAILED(ret)) {
slouken@2713
   173
        DI_SetError("Initializing DirectInput device", ret);
slouken@2713
   174
        return -1;
slouken@2713
   175
    }
slouken@2713
   176
slouken@2713
   177
    /* Look for haptic devices. */
slouken@2714
   178
    ret = IDirectInput_EnumDevices(dinput,
slouken@2714
   179
                                   0,
slouken@2713
   180
                                   EnumHapticsCallback,
slouken@2713
   181
                                   NULL,
slouken@2713
   182
                                   DIEDFL_FORCEFEEDBACK |
slouken@2713
   183
                                   DIEDFL_ATTACHEDONLY);
slouken@2713
   184
    if (FAILED(ret)) {
slouken@2713
   185
        DI_SetError("Enumerating DirectInput devices", ret);
slouken@2713
   186
        return -1;
slouken@2713
   187
    }
slouken@2713
   188
slouken@2713
   189
    return SDL_numhaptics;
slouken@2713
   190
}
slouken@2713
   191
slouken@2713
   192
/*
slouken@2713
   193
 * Callback to find the haptic devices.
slouken@2713
   194
 */
slouken@2713
   195
static BOOL CALLBACK
slouken@2713
   196
EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
slouken@2713
   197
{
slouken@2713
   198
    HRESULT ret;
slouken@2713
   199
    LPDIRECTINPUTDEVICE device;
slouken@2713
   200
slouken@2713
   201
    /* Copy the instance over, useful for creating devices. */
slouken@2713
   202
    SDL_memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance,
slouken@2713
   203
               sizeof(DIDEVICEINSTANCE));
slouken@2713
   204
slouken@2713
   205
    /* Open the device */
slouken@2713
   206
    ret = IDirectInput_CreateDevice(dinput, &pdidInstance->guidInstance,
slouken@2713
   207
                                    &device, NULL);
slouken@2713
   208
    if (FAILED(ret)) {
slouken@2713
   209
        /* DI_SetError("Creating DirectInput device",ret); */
slouken@2713
   210
        return DIENUM_CONTINUE;
slouken@2713
   211
    }
slouken@2713
   212
slouken@2713
   213
    /* Get capabilities. */
slouken@2713
   214
    SDL_hapticlist[SDL_numhaptics].capabilities.dwSize = sizeof(DIDEVCAPS);
slouken@2713
   215
    ret = IDirectInputDevice_GetCapabilities(device,
slouken@3013
   216
                                             &SDL_hapticlist[SDL_numhaptics].
slouken@3013
   217
                                             capabilities);
slouken@2713
   218
    if (FAILED(ret)) {
slouken@2713
   219
        /* DI_SetError("Getting device capabilities",ret); */
slouken@2713
   220
        IDirectInputDevice_Release(device);
slouken@2713
   221
        return DIENUM_CONTINUE;
slouken@2713
   222
    }
slouken@2713
   223
slouken@5090
   224
    /* Copy the name */
slouken@5090
   225
    SDL_hapticlist[SDL_numhaptics].name = WIN_StringToUTF8(SDL_hapticlist[SDL_numhaptics].instance.tszProductName);
slouken@5090
   226
slouken@2713
   227
    /* Close up device and count it. */
slouken@2713
   228
    IDirectInputDevice_Release(device);
slouken@2713
   229
    SDL_numhaptics++;
slouken@2713
   230
slouken@2713
   231
    /* Watch out for hard limit. */
slouken@2713
   232
    if (SDL_numhaptics >= MAX_HAPTICS)
slouken@2713
   233
        return DIENUM_STOP;
slouken@2713
   234
slouken@2713
   235
    return DIENUM_CONTINUE;
slouken@2713
   236
}
slouken@2713
   237
slouken@2713
   238
slouken@2713
   239
/*
slouken@2713
   240
 * Return the name of a haptic device, does not need to be opened.
slouken@2713
   241
 */
slouken@2713
   242
const char *
slouken@2713
   243
SDL_SYS_HapticName(int index)
slouken@2713
   244
{
slouken@5090
   245
    return SDL_hapticlist[index].name;
slouken@2713
   246
}
slouken@2713
   247
slouken@2713
   248
slouken@2713
   249
/*
slouken@2713
   250
 * Callback to get all supported effects.
slouken@2713
   251
 */
slouken@2713
   252
#define EFFECT_TEST(e,s)               \
slouken@2713
   253
if (DI_GUIDIsSame(&pei->guid, &(e)))   \
slouken@2713
   254
   haptic->supported |= (s)
slouken@2713
   255
static BOOL CALLBACK
slouken@2713
   256
DI_EffectCallback(LPCDIEFFECTINFO pei, LPVOID pv)
slouken@2713
   257
{
slouken@2713
   258
    /* Prepare the haptic device. */
slouken@2713
   259
    SDL_Haptic *haptic = (SDL_Haptic *) pv;
slouken@2713
   260
slouken@2713
   261
    /* Get supported. */
slouken@2713
   262
    EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING);
slouken@2713
   263
    EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER);
slouken@2713
   264
    EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA);
slouken@2713
   265
    EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION);
slouken@2713
   266
    EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT);
slouken@2713
   267
    EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM);
slouken@2713
   268
    EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE);
slouken@2713
   269
    EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE);
slouken@2713
   270
    EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE);
slouken@2713
   271
    EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP);
slouken@2713
   272
    EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN);
slouken@2713
   273
    EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP);
slouken@2713
   274
slouken@2713
   275
    /* Check for more. */
slouken@2713
   276
    return DIENUM_CONTINUE;
slouken@2713
   277
}
slouken@2713
   278
slouken@2713
   279
slouken@2713
   280
/*
slouken@2713
   281
 * Callback to get supported axes.
slouken@2713
   282
 */
slouken@2713
   283
static BOOL CALLBACK
slouken@2713
   284
DI_DeviceObjectCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
slouken@2713
   285
{
slouken@2713
   286
    SDL_Haptic *haptic = (SDL_Haptic *) pvRef;
slouken@2713
   287
slouken@2713
   288
    if ((dev->dwType & DIDFT_AXIS) && (dev->dwFlags & DIDOI_FFACTUATOR)) {
slouken@2713
   289
slouken@2713
   290
        haptic->hwdata->axes[haptic->naxes] = dev->dwOfs;
slouken@2713
   291
        haptic->naxes++;
slouken@2713
   292
slouken@2713
   293
        /* Currently using the artificial limit of 3 axes. */
slouken@2713
   294
        if (haptic->naxes >= 3) {
slouken@2713
   295
            return DIENUM_STOP;
slouken@2713
   296
        }
slouken@2713
   297
    }
slouken@2713
   298
slouken@2713
   299
    return DIENUM_CONTINUE;
slouken@2713
   300
}
slouken@2713
   301
slouken@2713
   302
slouken@2713
   303
/*
slouken@2713
   304
 * Opens the haptic device from the file descriptor.
slouken@2713
   305
 *
slouken@2713
   306
 *    Steps:
slouken@2713
   307
 *       - Open temporary DirectInputDevice interface.
slouken@2713
   308
 *       - Create DirectInputDevice2 interface.
slouken@2713
   309
 *       - Release DirectInputDevice interface.
slouken@2713
   310
 *       - Call SDL_SYS_HapticOpenFromDevice2
slouken@2713
   311
 */
slouken@2713
   312
static int
slouken@2713
   313
SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance)
slouken@2713
   314
{
slouken@2713
   315
    HRESULT ret;
slouken@2713
   316
    int ret2;
slouken@2713
   317
    LPDIRECTINPUTDEVICE device;
slouken@2713
   318
slouken@2713
   319
    /* Allocate the hwdata */
slouken@2713
   320
    haptic->hwdata = (struct haptic_hwdata *)
slouken@2713
   321
        SDL_malloc(sizeof(*haptic->hwdata));
slouken@2713
   322
    if (haptic->hwdata == NULL) {
slouken@2713
   323
        SDL_OutOfMemory();
slouken@2713
   324
        goto creat_err;
slouken@2713
   325
    }
slouken@2713
   326
    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
slouken@2713
   327
slouken@2713
   328
    /* Open the device */
slouken@2713
   329
    ret = IDirectInput_CreateDevice(dinput, &instance.guidInstance,
slouken@2713
   330
                                    &device, NULL);
slouken@2713
   331
    if (FAILED(ret)) {
slouken@2713
   332
        DI_SetError("Creating DirectInput device", ret);
slouken@2713
   333
        goto creat_err;
slouken@2713
   334
    }
slouken@2713
   335
slouken@2713
   336
    /* Now get the IDirectInputDevice2 interface, instead. */
slouken@2713
   337
    ret = IDirectInputDevice_QueryInterface(device,
slouken@2713
   338
                                            &IID_IDirectInputDevice2,
slouken@3013
   339
                                            (LPVOID *) & haptic->hwdata->
slouken@3013
   340
                                            device);
slouken@2713
   341
    /* Done with the temporary one now. */
slouken@2713
   342
    IDirectInputDevice_Release(device);
slouken@2713
   343
    if (FAILED(ret)) {
slouken@2713
   344
        DI_SetError("Querying DirectInput interface", ret);
slouken@2713
   345
        goto creat_err;
slouken@2713
   346
    }
slouken@2713
   347
slouken@2713
   348
    ret2 = SDL_SYS_HapticOpenFromDevice2(haptic, haptic->hwdata->device);
slouken@2713
   349
    if (ret2 < 0) {
slouken@2713
   350
        goto query_err;
slouken@2713
   351
    }
slouken@2713
   352
slouken@2713
   353
    return 0;
slouken@2713
   354
slouken@2713
   355
  query_err:
slouken@2713
   356
    IDirectInputDevice2_Release(haptic->hwdata->device);
slouken@2713
   357
  creat_err:
slouken@2713
   358
    if (haptic->hwdata != NULL) {
slouken@2713
   359
        SDL_free(haptic->hwdata);
slouken@2713
   360
        haptic->hwdata = NULL;
slouken@2713
   361
    }
slouken@2713
   362
    return -1;
slouken@2713
   363
}
slouken@2713
   364
slouken@2713
   365
slouken@2713
   366
/*
slouken@2713
   367
 * Opens the haptic device from the file descriptor.
slouken@2713
   368
 *
slouken@2713
   369
 *    Steps:
slouken@2713
   370
 *       - Set cooperative level.
slouken@2713
   371
 *       - Set data format.
slouken@2713
   372
 *       - Acquire exclusiveness.
slouken@2713
   373
 *       - Reset actuators.
slouken@2713
   374
 *       - Get supported featuers.
slouken@2713
   375
 */
slouken@2713
   376
static int
slouken@2713
   377
SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic,
slouken@2713
   378
                              LPDIRECTINPUTDEVICE2 device2)
slouken@2713
   379
{
slouken@2713
   380
    HRESULT ret;
slouken@2713
   381
    DIPROPDWORD dipdw;
slouken@2713
   382
slouken@2713
   383
    /* We'll use the device2 from now on. */
slouken@2713
   384
    haptic->hwdata->device = device2;
slouken@2713
   385
slouken@2713
   386
    /* Grab it exclusively to use force feedback stuff. */
slouken@2713
   387
    ret = IDirectInputDevice2_SetCooperativeLevel(haptic->hwdata->device,
slouken@2713
   388
                                                  SDL_HelperWindow,
slouken@2713
   389
                                                  DISCL_EXCLUSIVE |
slouken@2713
   390
                                                  DISCL_BACKGROUND);
slouken@2713
   391
    if (FAILED(ret)) {
slouken@2713
   392
        DI_SetError("Setting cooperative level to exclusive", ret);
slouken@2713
   393
        goto acquire_err;
slouken@2713
   394
    }
slouken@2713
   395
slouken@2713
   396
    /* Set data format. */
slouken@2713
   397
    ret = IDirectInputDevice2_SetDataFormat(haptic->hwdata->device,
slouken@2713
   398
                                            &c_dfDIJoystick2);
slouken@2713
   399
    if (FAILED(ret)) {
slouken@2713
   400
        DI_SetError("Setting data format", ret);
slouken@2713
   401
        goto acquire_err;
slouken@2713
   402
    }
slouken@2713
   403
slouken@2713
   404
    /* Get number of axes. */
slouken@2713
   405
    ret = IDirectInputDevice2_EnumObjects(haptic->hwdata->device,
slouken@2713
   406
                                          DI_DeviceObjectCallback,
slouken@2713
   407
                                          haptic, DIDFT_AXIS);
slouken@2713
   408
    if (FAILED(ret)) {
slouken@2713
   409
        DI_SetError("Getting device axes", ret);
slouken@2713
   410
        goto acquire_err;
slouken@2713
   411
    }
slouken@2713
   412
slouken@2713
   413
    /* Acquire the device. */
slouken@2713
   414
    ret = IDirectInputDevice2_Acquire(haptic->hwdata->device);
slouken@2713
   415
    if (FAILED(ret)) {
slouken@2713
   416
        DI_SetError("Acquiring DirectInput device", ret);
slouken@2713
   417
        goto acquire_err;
slouken@2713
   418
    }
slouken@2713
   419
slouken@2713
   420
    /* Reset all actuators - just in case. */
slouken@2713
   421
    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
slouken@2713
   422
                                                       DISFFC_RESET);
slouken@2713
   423
    if (FAILED(ret)) {
slouken@2713
   424
        DI_SetError("Resetting device", ret);
slouken@2713
   425
        goto acquire_err;
slouken@2713
   426
    }
slouken@2713
   427
slouken@2713
   428
    /* Enabling actuators. */
slouken@2713
   429
    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
slouken@2713
   430
                                                       DISFFC_SETACTUATORSON);
slouken@2713
   431
    if (FAILED(ret)) {
slouken@2713
   432
        DI_SetError("Enabling actuators", ret);
slouken@2713
   433
        goto acquire_err;
slouken@2713
   434
    }
slouken@2713
   435
slouken@2713
   436
    /* Get supported effects. */
slouken@2713
   437
    ret = IDirectInputDevice2_EnumEffects(haptic->hwdata->device,
slouken@2713
   438
                                          DI_EffectCallback, haptic,
slouken@2713
   439
                                          DIEFT_ALL);
slouken@2713
   440
    if (FAILED(ret)) {
slouken@2713
   441
        DI_SetError("Enumerating supported effects", ret);
slouken@2713
   442
        goto acquire_err;
slouken@2713
   443
    }
slouken@2713
   444
    if (haptic->supported == 0) {       /* Error since device supports nothing. */
slouken@2713
   445
        SDL_SetError("Haptic: Internal error on finding supported effects.");
slouken@2713
   446
        goto acquire_err;
slouken@2713
   447
    }
slouken@2713
   448
slouken@2713
   449
    /* Check autogain and autocenter. */
slouken@2713
   450
    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
slouken@2713
   451
    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@2713
   452
    dipdw.diph.dwObj = 0;
slouken@2713
   453
    dipdw.diph.dwHow = DIPH_DEVICE;
slouken@2713
   454
    dipdw.dwData = 10000;
slouken@2713
   455
    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
slouken@2713
   456
                                          DIPROP_FFGAIN, &dipdw.diph);
slouken@2713
   457
    if (!FAILED(ret)) {         /* Gain is supported. */
slouken@2713
   458
        haptic->supported |= SDL_HAPTIC_GAIN;
slouken@2713
   459
    }
slouken@2713
   460
    dipdw.diph.dwObj = 0;
slouken@2713
   461
    dipdw.diph.dwHow = DIPH_DEVICE;
slouken@2713
   462
    dipdw.dwData = DIPROPAUTOCENTER_OFF;
slouken@2713
   463
    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
slouken@2713
   464
                                          DIPROP_AUTOCENTER, &dipdw.diph);
slouken@2713
   465
    if (!FAILED(ret)) {         /* Autocenter is supported. */
slouken@2713
   466
        haptic->supported |= SDL_HAPTIC_AUTOCENTER;
slouken@2713
   467
    }
slouken@2713
   468
slouken@2713
   469
    /* Status is always supported. */
slouken@2713
   470
    haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE;
slouken@2713
   471
slouken@2713
   472
    /* Check maximum effects. */
slouken@2713
   473
    haptic->neffects = 128;     /* This is not actually supported as thus under windows,
slouken@2713
   474
                                   there is no way to tell the number of EFFECTS that a
slouken@2713
   475
                                   device can hold, so we'll just use a "random" number
slouken@2713
   476
                                   instead and put warnings in SDL_haptic.h */
slouken@2713
   477
    haptic->nplaying = 128;     /* Even more impossible to get this then neffects. */
slouken@2713
   478
slouken@2713
   479
    /* Prepare effects memory. */
slouken@2713
   480
    haptic->effects = (struct haptic_effect *)
slouken@2713
   481
        SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects);
slouken@2713
   482
    if (haptic->effects == NULL) {
slouken@2713
   483
        SDL_OutOfMemory();
slouken@2713
   484
        goto acquire_err;
slouken@2713
   485
    }
slouken@2713
   486
    /* Clear the memory */
slouken@2713
   487
    SDL_memset(haptic->effects, 0,
slouken@2713
   488
               sizeof(struct haptic_effect) * haptic->neffects);
slouken@2713
   489
slouken@2713
   490
    return 0;
slouken@2713
   491
slouken@2713
   492
    /* Error handling */
slouken@2713
   493
  acquire_err:
slouken@2713
   494
    IDirectInputDevice2_Unacquire(haptic->hwdata->device);
slouken@2713
   495
    return -1;
slouken@2713
   496
slouken@2713
   497
}
slouken@2713
   498
slouken@2713
   499
slouken@2713
   500
/*
slouken@2713
   501
 * Opens a haptic device for usage.
slouken@2713
   502
 */
slouken@2713
   503
int
slouken@2713
   504
SDL_SYS_HapticOpen(SDL_Haptic * haptic)
slouken@2713
   505
{
slouken@2713
   506
    return SDL_SYS_HapticOpenFromInstance(haptic,
slouken@3013
   507
                                          SDL_hapticlist[haptic->index].
slouken@3013
   508
                                          instance);
slouken@2713
   509
}
slouken@2713
   510
slouken@2713
   511
slouken@2713
   512
/*
slouken@2713
   513
 * Opens a haptic device from first mouse it finds for usage.
slouken@2713
   514
 */
slouken@2713
   515
int
slouken@2713
   516
SDL_SYS_HapticMouse(void)
slouken@2713
   517
{
slouken@2713
   518
    int i;
slouken@2713
   519
slouken@2713
   520
    /* Grab the first mouse haptic device we find. */
slouken@2713
   521
    for (i = 0; i < SDL_numhaptics; i++) {
slouken@2713
   522
        if (SDL_hapticlist[i].capabilities.dwDevType == DIDEVTYPE_MOUSE) {
slouken@2713
   523
            return i;
slouken@2713
   524
        }
slouken@2713
   525
    }
slouken@2713
   526
slouken@2713
   527
    return -1;
slouken@2713
   528
}
slouken@2713
   529
slouken@2713
   530
slouken@2713
   531
/*
slouken@2713
   532
 * Checks to see if a joystick has haptic features.
slouken@2713
   533
 */
slouken@2713
   534
int
slouken@2713
   535
SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick)
slouken@2713
   536
{
slouken@2713
   537
    if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
slouken@2713
   538
        return SDL_TRUE;
slouken@2713
   539
    }
slouken@2713
   540
slouken@2713
   541
    return SDL_FALSE;
slouken@2713
   542
}
slouken@2713
   543
slouken@2713
   544
slouken@2713
   545
/*
slouken@2713
   546
 * Checks to see if the haptic device and joystick and in reality the same.
slouken@2713
   547
 */
slouken@2713
   548
int
slouken@2713
   549
SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
slouken@2713
   550
{
slouken@2713
   551
    HRESULT ret;
slouken@2713
   552
    DIDEVICEINSTANCE hap_instance, joy_instance;
slouken@2713
   553
slouken@2713
   554
    /* Get the device instances. */
slouken@2713
   555
    ret = IDirectInputDevice2_GetDeviceInfo(haptic->hwdata->device,
slouken@2713
   556
                                            &hap_instance);
slouken@2713
   557
    if (FAILED(ret)) {
slouken@2713
   558
        return 0;
slouken@2713
   559
    }
slouken@2713
   560
    ret = IDirectInputDevice2_GetDeviceInfo(joystick->hwdata->InputDevice,
slouken@2713
   561
                                            &joy_instance);
slouken@2713
   562
    if (FAILED(ret)) {
slouken@2713
   563
        return 0;
slouken@2713
   564
    }
slouken@2713
   565
slouken@2713
   566
    if (DI_GUIDIsSame(&hap_instance.guidInstance, &joy_instance.guidInstance))
slouken@2713
   567
        return 1;
slouken@2713
   568
slouken@2713
   569
    return 0;
slouken@2713
   570
}
slouken@2713
   571
slouken@2713
   572
slouken@2713
   573
/*
slouken@2713
   574
 * Opens a SDL_Haptic from a SDL_Joystick.
slouken@2713
   575
 */
slouken@2713
   576
int
slouken@2713
   577
SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
slouken@2713
   578
{
slouken@2713
   579
    int ret;
slouken@2713
   580
slouken@2713
   581
    /* Allocate the hwdata */
slouken@2713
   582
    haptic->hwdata = (struct haptic_hwdata *)
slouken@2713
   583
        SDL_malloc(sizeof(*haptic->hwdata));
slouken@2713
   584
    if (haptic->hwdata == NULL) {
slouken@2713
   585
        SDL_OutOfMemory();
slouken@2713
   586
        return -1;
slouken@2713
   587
    }
slouken@2713
   588
    SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata));
slouken@2713
   589
slouken@2713
   590
    /* Now open the device. */
slouken@2713
   591
    ret =
slouken@2713
   592
        SDL_SYS_HapticOpenFromDevice2(haptic, joystick->hwdata->InputDevice);
slouken@2713
   593
    if (ret < 0) {
slouken@2713
   594
        return -1;
slouken@2713
   595
    }
slouken@2713
   596
slouken@2713
   597
    /* It's using the joystick device. */
slouken@2713
   598
    haptic->hwdata->is_joystick = 1;
slouken@2713
   599
slouken@2713
   600
    return 0;
slouken@2713
   601
}
slouken@2713
   602
slouken@2713
   603
slouken@2713
   604
/*
slouken@2713
   605
 * Closes the haptic device.
slouken@2713
   606
 */
slouken@2713
   607
void
slouken@2713
   608
SDL_SYS_HapticClose(SDL_Haptic * haptic)
slouken@2713
   609
{
slouken@2713
   610
    if (haptic->hwdata) {
slouken@2713
   611
slouken@2713
   612
        /* Free effects. */
slouken@2713
   613
        SDL_free(haptic->effects);
slouken@2713
   614
        haptic->effects = NULL;
slouken@2713
   615
        haptic->neffects = 0;
slouken@2713
   616
slouken@2713
   617
        /* Clean up */
slouken@2713
   618
        IDirectInputDevice2_Unacquire(haptic->hwdata->device);
slouken@2713
   619
        /* Only release if isn't grabbed by a joystick. */
slouken@2713
   620
        if (haptic->hwdata->is_joystick == 0) {
slouken@2713
   621
            IDirectInputDevice2_Release(haptic->hwdata->device);
slouken@2713
   622
        }
slouken@2713
   623
slouken@2713
   624
        /* Free */
slouken@2713
   625
        SDL_free(haptic->hwdata);
slouken@2713
   626
        haptic->hwdata = NULL;
slouken@2713
   627
    }
slouken@2713
   628
}
slouken@2713
   629
slouken@2713
   630
slouken@2713
   631
/* 
slouken@2713
   632
 * Clean up after system specific haptic stuff
slouken@2713
   633
 */
slouken@2713
   634
void
slouken@2713
   635
SDL_SYS_HapticQuit(void)
slouken@2713
   636
{
slouken@5090
   637
    int i;
slouken@5090
   638
slouken@5090
   639
    for (i = 0; i < SDL_arraysize(SDL_hapticlist); ++i) {
slouken@5090
   640
        if (SDL_hapticlist[i].name) {
slouken@5090
   641
            SDL_free(SDL_hapticlist[i].name);
slouken@5090
   642
            SDL_hapticlist[i].name = NULL;
slouken@5090
   643
        }
slouken@5090
   644
    }
slouken@5090
   645
slouken@2713
   646
    IDirectInput_Release(dinput);
slouken@2713
   647
    dinput = NULL;
slouken@2713
   648
}
slouken@2713
   649
slouken@2713
   650
slouken@2713
   651
/*
slouken@2713
   652
 * Converts an SDL trigger button to an DIEFFECT trigger button.
slouken@2713
   653
 */
slouken@2713
   654
static DWORD
slouken@2713
   655
DIGetTriggerButton(Uint16 button)
slouken@2713
   656
{
slouken@2713
   657
    DWORD dwTriggerButton;
slouken@2713
   658
slouken@2713
   659
    dwTriggerButton = DIEB_NOTRIGGER;
slouken@2713
   660
slouken@2713
   661
    if (button != 0) {
slouken@2713
   662
        dwTriggerButton = DIJOFS_BUTTON(button - 1);
slouken@2713
   663
    }
slouken@2713
   664
slouken@2713
   665
    return dwTriggerButton;
slouken@2713
   666
}
slouken@2713
   667
slouken@2713
   668
slouken@2713
   669
/*
slouken@2713
   670
 * Sets the direction.
slouken@2713
   671
 */
slouken@2713
   672
static int
slouken@2713
   673
SDL_SYS_SetDirection(DIEFFECT * effect, SDL_HapticDirection * dir, int naxes)
slouken@2713
   674
{
slouken@2713
   675
    LONG *rglDir;
slouken@2713
   676
slouken@2713
   677
    /* Handle no axes a part. */
slouken@2713
   678
    if (naxes == 0) {
slouken@2713
   679
        effect->dwFlags |= DIEFF_SPHERICAL;     /* Set as default. */
slouken@2713
   680
        effect->rglDirection = NULL;
slouken@2713
   681
        return 0;
slouken@2713
   682
    }
slouken@2713
   683
slouken@2713
   684
    /* Has axes. */
slouken@2713
   685
    rglDir = SDL_malloc(sizeof(LONG) * naxes);
slouken@2713
   686
    if (rglDir == NULL) {
slouken@2713
   687
        SDL_OutOfMemory();
slouken@2713
   688
        return -1;
slouken@2713
   689
    }
slouken@2713
   690
    SDL_memset(rglDir, 0, sizeof(LONG) * naxes);
slouken@2713
   691
    effect->rglDirection = rglDir;
slouken@2713
   692
slouken@2713
   693
    switch (dir->type) {
slouken@2713
   694
    case SDL_HAPTIC_POLAR:
slouken@2713
   695
        effect->dwFlags |= DIEFF_POLAR;
slouken@2713
   696
        rglDir[0] = dir->dir[0];
slouken@2713
   697
        return 0;
slouken@2713
   698
    case SDL_HAPTIC_CARTESIAN:
slouken@2713
   699
        effect->dwFlags |= DIEFF_CARTESIAN;
slouken@2713
   700
        rglDir[0] = dir->dir[0];
slouken@2713
   701
        if (naxes > 1)
slouken@2713
   702
            rglDir[1] = dir->dir[1];
slouken@2713
   703
        if (naxes > 2)
slouken@2713
   704
            rglDir[2] = dir->dir[2];
slouken@2713
   705
        return 0;
slouken@2713
   706
    case SDL_HAPTIC_SPHERICAL:
slouken@2713
   707
        effect->dwFlags |= DIEFF_SPHERICAL;
slouken@2713
   708
        rglDir[0] = dir->dir[0];
slouken@2713
   709
        if (naxes > 1)
slouken@2713
   710
            rglDir[1] = dir->dir[1];
slouken@2713
   711
        if (naxes > 2)
slouken@2713
   712
            rglDir[2] = dir->dir[2];
slouken@2713
   713
        return 0;
slouken@2713
   714
slouken@2713
   715
    default:
slouken@2713
   716
        SDL_SetError("Haptic: Unknown direction type.");
slouken@2713
   717
        return -1;
slouken@2713
   718
    }
slouken@2713
   719
}
slouken@2713
   720
slouken@2713
   721
#define CONVERT(x)   (((x) > 0x7FFF) ? 10000 : ((x)*10000) / 0x7FFF)
slouken@2713
   722
/*
slouken@2713
   723
 * Creates the DIEFFECT from a SDL_HapticEffect.
slouken@2713
   724
 */
slouken@2713
   725
static int
slouken@2713
   726
SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic, DIEFFECT * dest,
slouken@2713
   727
                   SDL_HapticEffect * src)
slouken@2713
   728
{
slouken@2713
   729
    int i;
slouken@2713
   730
    DICONSTANTFORCE *constant;
slouken@2713
   731
    DIPERIODIC *periodic;
slouken@2713
   732
    DICONDITION *condition;     /* Actually an array of conditions - one per axis. */
slouken@2713
   733
    DIRAMPFORCE *ramp;
slouken@2713
   734
    DICUSTOMFORCE *custom;
slouken@2713
   735
    DIENVELOPE *envelope;
slouken@2713
   736
    SDL_HapticConstant *hap_constant;
slouken@2713
   737
    SDL_HapticPeriodic *hap_periodic;
slouken@2713
   738
    SDL_HapticCondition *hap_condition;
slouken@2713
   739
    SDL_HapticRamp *hap_ramp;
slouken@2713
   740
    SDL_HapticCustom *hap_custom;
slouken@2713
   741
    DWORD *axes;
slouken@2713
   742
slouken@2713
   743
    /* Set global stuff. */
slouken@2713
   744
    SDL_memset(dest, 0, sizeof(DIEFFECT));
slouken@2713
   745
    dest->dwSize = sizeof(DIEFFECT);    /* Set the structure size. */
slouken@2713
   746
    dest->dwSamplePeriod = 0;   /* Not used by us. */
slouken@2713
   747
    dest->dwGain = 10000;       /* Gain is set globally, not locally. */
slouken@2713
   748
    dest->dwFlags = DIEFF_OBJECTOFFSETS;        /* Seems obligatory. */
slouken@2713
   749
slouken@2713
   750
    /* Envelope. */
slouken@2713
   751
    envelope = SDL_malloc(sizeof(DIENVELOPE));
slouken@2713
   752
    if (envelope == NULL) {
slouken@2713
   753
        SDL_OutOfMemory();
slouken@2713
   754
        return -1;
slouken@2713
   755
    }
slouken@2713
   756
    SDL_memset(envelope, 0, sizeof(DIENVELOPE));
slouken@2713
   757
    dest->lpEnvelope = envelope;
slouken@2713
   758
    envelope->dwSize = sizeof(DIENVELOPE);      /* Always should be this. */
slouken@2713
   759
slouken@2713
   760
    /* Axes. */
slouken@2713
   761
    dest->cAxes = haptic->naxes;
slouken@2713
   762
    if (dest->cAxes > 0) {
slouken@2713
   763
        axes = SDL_malloc(sizeof(DWORD) * dest->cAxes);
slouken@2713
   764
        if (axes == NULL) {
slouken@2713
   765
            SDL_OutOfMemory();
slouken@2713
   766
            return -1;
slouken@2713
   767
        }
slouken@2713
   768
        axes[0] = haptic->hwdata->axes[0];      /* Always at least one axis. */
slouken@2713
   769
        if (dest->cAxes > 1) {
slouken@2713
   770
            axes[1] = haptic->hwdata->axes[1];
slouken@2713
   771
        }
slouken@2713
   772
        if (dest->cAxes > 2) {
slouken@2713
   773
            axes[2] = haptic->hwdata->axes[2];
slouken@2713
   774
        }
slouken@2713
   775
        dest->rgdwAxes = axes;
slouken@2713
   776
    }
slouken@2713
   777
slouken@2713
   778
slouken@2713
   779
    /* The big type handling switch, even bigger then linux's version. */
slouken@2713
   780
    switch (src->type) {
slouken@2713
   781
    case SDL_HAPTIC_CONSTANT:
slouken@2713
   782
        hap_constant = &src->constant;
slouken@2713
   783
        constant = SDL_malloc(sizeof(DICONSTANTFORCE));
slouken@2713
   784
        if (constant == NULL) {
slouken@2713
   785
            SDL_OutOfMemory();
slouken@2713
   786
            return -1;
slouken@2713
   787
        }
slouken@2713
   788
        SDL_memset(constant, 0, sizeof(DICONSTANTFORCE));
slouken@2713
   789
slouken@2713
   790
        /* Specifics */
slouken@2713
   791
        constant->lMagnitude = CONVERT(hap_constant->level);
slouken@2713
   792
        dest->cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
slouken@2713
   793
        dest->lpvTypeSpecificParams = constant;
slouken@2713
   794
slouken@2713
   795
        /* Generics */
slouken@2713
   796
        dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */
slouken@2713
   797
        dest->dwTriggerButton = DIGetTriggerButton(hap_constant->button);
slouken@2713
   798
        dest->dwTriggerRepeatInterval = hap_constant->interval;
slouken@2713
   799
        dest->dwStartDelay = hap_constant->delay * 1000;        /* In microseconds. */
slouken@2713
   800
slouken@2713
   801
        /* Direction. */
slouken@2713
   802
        if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes)
slouken@2713
   803
            < 0) {
slouken@2713
   804
            return -1;
slouken@2713
   805
        }
slouken@2713
   806
slouken@2713
   807
        /* Envelope */
slouken@2713
   808
        if ((hap_constant->attack_length == 0)
slouken@2713
   809
            && (hap_constant->fade_length == 0)) {
slouken@2713
   810
            SDL_free(dest->lpEnvelope);
slouken@2713
   811
            dest->lpEnvelope = NULL;
slouken@2713
   812
        } else {
slouken@2713
   813
            envelope->dwAttackLevel = CONVERT(hap_constant->attack_level);
slouken@2713
   814
            envelope->dwAttackTime = hap_constant->attack_length * 1000;
slouken@2713
   815
            envelope->dwFadeLevel = CONVERT(hap_constant->fade_level);
slouken@2713
   816
            envelope->dwFadeTime = hap_constant->fade_length * 1000;
slouken@2713
   817
        }
slouken@2713
   818
slouken@2713
   819
        break;
slouken@2713
   820
slouken@2713
   821
    case SDL_HAPTIC_SINE:
slouken@2713
   822
    case SDL_HAPTIC_SQUARE:
slouken@2713
   823
    case SDL_HAPTIC_TRIANGLE:
slouken@2713
   824
    case SDL_HAPTIC_SAWTOOTHUP:
slouken@2713
   825
    case SDL_HAPTIC_SAWTOOTHDOWN:
slouken@2713
   826
        hap_periodic = &src->periodic;
slouken@2713
   827
        periodic = SDL_malloc(sizeof(DIPERIODIC));
slouken@2713
   828
        if (periodic == NULL) {
slouken@2713
   829
            SDL_OutOfMemory();
slouken@2713
   830
            return -1;
slouken@2713
   831
        }
slouken@2713
   832
        SDL_memset(periodic, 0, sizeof(DIPERIODIC));
slouken@2713
   833
slouken@2713
   834
        /* Specifics */
slouken@2713
   835
        periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
slouken@2713
   836
        periodic->lOffset = CONVERT(hap_periodic->offset);
slouken@2713
   837
        periodic->dwPhase = hap_periodic->phase;
slouken@2713
   838
        periodic->dwPeriod = hap_periodic->period * 1000;
slouken@2713
   839
        dest->cbTypeSpecificParams = sizeof(DIPERIODIC);
slouken@2713
   840
        dest->lpvTypeSpecificParams = periodic;
slouken@2713
   841
slouken@2713
   842
        /* Generics */
slouken@2713
   843
        dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */
slouken@2713
   844
        dest->dwTriggerButton = DIGetTriggerButton(hap_periodic->button);
slouken@2713
   845
        dest->dwTriggerRepeatInterval = hap_periodic->interval;
slouken@2713
   846
        dest->dwStartDelay = hap_periodic->delay * 1000;        /* In microseconds. */
slouken@2713
   847
slouken@2713
   848
        /* Direction. */
slouken@2713
   849
        if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes)
slouken@2713
   850
            < 0) {
slouken@2713
   851
            return -1;
slouken@2713
   852
        }
slouken@2713
   853
slouken@2713
   854
        /* Envelope */
slouken@2713
   855
        if ((hap_periodic->attack_length == 0)
slouken@2713
   856
            && (hap_periodic->fade_length == 0)) {
slouken@2713
   857
            SDL_free(dest->lpEnvelope);
slouken@2713
   858
            dest->lpEnvelope = NULL;
slouken@2713
   859
        } else {
slouken@2713
   860
            envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level);
slouken@2713
   861
            envelope->dwAttackTime = hap_periodic->attack_length * 1000;
slouken@2713
   862
            envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level);
slouken@2713
   863
            envelope->dwFadeTime = hap_periodic->fade_length * 1000;
slouken@2713
   864
        }
slouken@2713
   865
slouken@2713
   866
        break;
slouken@2713
   867
slouken@2713
   868
    case SDL_HAPTIC_SPRING:
slouken@2713
   869
    case SDL_HAPTIC_DAMPER:
slouken@2713
   870
    case SDL_HAPTIC_INERTIA:
slouken@2713
   871
    case SDL_HAPTIC_FRICTION:
slouken@2713
   872
        hap_condition = &src->condition;
slouken@2713
   873
        condition = SDL_malloc(sizeof(DICONDITION) * dest->cAxes);
slouken@2713
   874
        if (condition == NULL) {
slouken@2713
   875
            SDL_OutOfMemory();
slouken@2713
   876
            return -1;
slouken@2713
   877
        }
slouken@2713
   878
        SDL_memset(condition, 0, sizeof(DICONDITION));
slouken@2713
   879
slouken@2713
   880
        /* Specifics */
slouken@2713
   881
        for (i = 0; i < (int) dest->cAxes; i++) {
slouken@2713
   882
            condition[i].lOffset = CONVERT(hap_condition->center[i]);
slouken@2713
   883
            condition[i].lPositiveCoefficient =
slouken@2713
   884
                CONVERT(hap_condition->right_coeff[i]);
slouken@2713
   885
            condition[i].lNegativeCoefficient =
slouken@2713
   886
                CONVERT(hap_condition->left_coeff[i]);
slouken@2713
   887
            condition[i].dwPositiveSaturation =
slouken@2713
   888
                CONVERT(hap_condition->right_sat[i]);
slouken@2713
   889
            condition[i].dwNegativeSaturation =
slouken@2713
   890
                CONVERT(hap_condition->left_sat[i]);
slouken@2713
   891
            condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
slouken@2713
   892
        }
slouken@2713
   893
        dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
slouken@2713
   894
        dest->lpvTypeSpecificParams = condition;
slouken@2713
   895
slouken@2713
   896
        /* Generics */
slouken@2713
   897
        dest->dwDuration = hap_condition->length * 1000;        /* In microseconds. */
slouken@2713
   898
        dest->dwTriggerButton = DIGetTriggerButton(hap_condition->button);
slouken@2713
   899
        dest->dwTriggerRepeatInterval = hap_condition->interval;
slouken@2713
   900
        dest->dwStartDelay = hap_condition->delay * 1000;       /* In microseconds. */
slouken@2713
   901
slouken@2713
   902
        /* Direction. */
slouken@2713
   903
        if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes)
slouken@2713
   904
            < 0) {
slouken@2713
   905
            return -1;
slouken@2713
   906
        }
slouken@2713
   907
slouken@2713
   908
        /* Envelope - Not actually supported by most CONDITION implementations. */
slouken@2713
   909
        SDL_free(dest->lpEnvelope);
slouken@2713
   910
        dest->lpEnvelope = NULL;
slouken@2713
   911
slouken@2713
   912
        break;
slouken@2713
   913
slouken@2713
   914
    case SDL_HAPTIC_RAMP:
slouken@2713
   915
        hap_ramp = &src->ramp;
slouken@2713
   916
        ramp = SDL_malloc(sizeof(DIRAMPFORCE));
slouken@2713
   917
        if (ramp == NULL) {
slouken@2713
   918
            SDL_OutOfMemory();
slouken@2713
   919
            return -1;
slouken@2713
   920
        }
slouken@2713
   921
        SDL_memset(ramp, 0, sizeof(DIRAMPFORCE));
slouken@2713
   922
slouken@2713
   923
        /* Specifics */
slouken@2713
   924
        ramp->lStart = CONVERT(hap_ramp->start);
slouken@2713
   925
        ramp->lEnd = CONVERT(hap_ramp->end);
slouken@2713
   926
        dest->cbTypeSpecificParams = sizeof(DIRAMPFORCE);
slouken@2713
   927
        dest->lpvTypeSpecificParams = ramp;
slouken@2713
   928
slouken@2713
   929
        /* Generics */
slouken@2713
   930
        dest->dwDuration = hap_ramp->length * 1000;     /* In microseconds. */
slouken@2713
   931
        dest->dwTriggerButton = DIGetTriggerButton(hap_ramp->button);
slouken@2713
   932
        dest->dwTriggerRepeatInterval = hap_ramp->interval;
slouken@2713
   933
        dest->dwStartDelay = hap_ramp->delay * 1000;    /* In microseconds. */
slouken@2713
   934
slouken@2713
   935
        /* Direction. */
slouken@2713
   936
        if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) {
slouken@2713
   937
            return -1;
slouken@2713
   938
        }
slouken@2713
   939
slouken@2713
   940
        /* Envelope */
slouken@2713
   941
        if ((hap_ramp->attack_length == 0) && (hap_ramp->fade_length == 0)) {
slouken@2713
   942
            SDL_free(dest->lpEnvelope);
slouken@2713
   943
            dest->lpEnvelope = NULL;
slouken@2713
   944
        } else {
slouken@2713
   945
            envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level);
slouken@2713
   946
            envelope->dwAttackTime = hap_ramp->attack_length * 1000;
slouken@2713
   947
            envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level);
slouken@2713
   948
            envelope->dwFadeTime = hap_ramp->fade_length * 1000;
slouken@2713
   949
        }
slouken@2713
   950
slouken@2713
   951
        break;
slouken@2713
   952
slouken@2713
   953
    case SDL_HAPTIC_CUSTOM:
slouken@2713
   954
        hap_custom = &src->custom;
slouken@2713
   955
        custom = SDL_malloc(sizeof(DICUSTOMFORCE));
slouken@2713
   956
        if (custom == NULL) {
slouken@2713
   957
            SDL_OutOfMemory();
slouken@2713
   958
            return -1;
slouken@2713
   959
        }
slouken@2713
   960
        SDL_memset(custom, 0, sizeof(DICUSTOMFORCE));
slouken@2713
   961
slouken@2713
   962
        /* Specifics */
slouken@2713
   963
        custom->cChannels = hap_custom->channels;
slouken@2713
   964
        custom->dwSamplePeriod = hap_custom->period * 1000;
slouken@2713
   965
        custom->cSamples = hap_custom->samples;
slouken@2713
   966
        custom->rglForceData =
slouken@2713
   967
            SDL_malloc(sizeof(LONG) * custom->cSamples * custom->cChannels);
slouken@2713
   968
        for (i = 0; i < hap_custom->samples * hap_custom->channels; i++) {      /* Copy data. */
slouken@2713
   969
            custom->rglForceData[i] = CONVERT(hap_custom->data[i]);
slouken@2713
   970
        }
slouken@2713
   971
        dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
slouken@2713
   972
        dest->lpvTypeSpecificParams = custom;
slouken@2713
   973
slouken@2713
   974
        /* Generics */
slouken@2713
   975
        dest->dwDuration = hap_custom->length * 1000;   /* In microseconds. */
slouken@2713
   976
        dest->dwTriggerButton = DIGetTriggerButton(hap_custom->button);
slouken@2713
   977
        dest->dwTriggerRepeatInterval = hap_custom->interval;
slouken@2713
   978
        dest->dwStartDelay = hap_custom->delay * 1000;  /* In microseconds. */
slouken@2713
   979
slouken@2713
   980
        /* Direction. */
slouken@2713
   981
        if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) <
slouken@2713
   982
            0) {
slouken@2713
   983
            return -1;
slouken@2713
   984
        }
slouken@2713
   985
slouken@2713
   986
        /* Envelope */
slouken@2713
   987
        if ((hap_custom->attack_length == 0)
slouken@2713
   988
            && (hap_custom->fade_length == 0)) {
slouken@2713
   989
            SDL_free(dest->lpEnvelope);
slouken@2713
   990
            dest->lpEnvelope = NULL;
slouken@2713
   991
        } else {
slouken@2713
   992
            envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
slouken@2713
   993
            envelope->dwAttackTime = hap_custom->attack_length * 1000;
slouken@2713
   994
            envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
slouken@2713
   995
            envelope->dwFadeTime = hap_custom->fade_length * 1000;
slouken@2713
   996
        }
slouken@2713
   997
slouken@2713
   998
        break;
slouken@2713
   999
slouken@2713
  1000
slouken@2713
  1001
    default:
slouken@2713
  1002
        SDL_SetError("Haptic: Unknown effect type.");
slouken@2713
  1003
        return -1;
slouken@2713
  1004
    }
slouken@2713
  1005
slouken@2713
  1006
    return 0;
slouken@2713
  1007
}
slouken@2713
  1008
slouken@2713
  1009
slouken@2713
  1010
/*
slouken@2713
  1011
 * Frees an DIEFFECT allocated by SDL_SYS_ToDIEFFECT.
slouken@2713
  1012
 */
slouken@2713
  1013
static void
slouken@2713
  1014
SDL_SYS_HapticFreeDIEFFECT(DIEFFECT * effect, int type)
slouken@2713
  1015
{
slouken@2713
  1016
    DICUSTOMFORCE *custom;
slouken@2713
  1017
slouken@2713
  1018
    if (effect->lpEnvelope != NULL) {
slouken@2713
  1019
        SDL_free(effect->lpEnvelope);
slouken@2713
  1020
        effect->lpEnvelope = NULL;
slouken@2713
  1021
    }
slouken@2713
  1022
    if (effect->rgdwAxes != NULL) {
slouken@2713
  1023
        SDL_free(effect->rgdwAxes);
slouken@2713
  1024
        effect->rgdwAxes = NULL;
slouken@2713
  1025
    }
slouken@2713
  1026
    if (effect->lpvTypeSpecificParams != NULL) {
slouken@2713
  1027
        if (type == SDL_HAPTIC_CUSTOM) {        /* Must free the custom data. */
slouken@2713
  1028
            custom = (DICUSTOMFORCE *) effect->lpvTypeSpecificParams;
slouken@2713
  1029
            SDL_free(custom->rglForceData);
slouken@2713
  1030
            custom->rglForceData = NULL;
slouken@2713
  1031
        }
slouken@2713
  1032
        SDL_free(effect->lpvTypeSpecificParams);
slouken@2713
  1033
        effect->lpvTypeSpecificParams = NULL;
slouken@2713
  1034
    }
slouken@2713
  1035
    if (effect->rglDirection != NULL) {
slouken@2713
  1036
        SDL_free(effect->rglDirection);
slouken@2713
  1037
        effect->rglDirection = NULL;
slouken@2713
  1038
    }
slouken@2713
  1039
}
slouken@2713
  1040
slouken@2713
  1041
slouken@2713
  1042
/*
slouken@2713
  1043
 * Gets the effect type from the generic SDL haptic effect wrapper.
slouken@2713
  1044
 */
slouken@2713
  1045
static REFGUID
slouken@2713
  1046
SDL_SYS_HapticEffectType(SDL_HapticEffect * effect)
slouken@2713
  1047
{
slouken@2713
  1048
    switch (effect->type) {
slouken@2713
  1049
    case SDL_HAPTIC_CONSTANT:
slouken@2713
  1050
        return &GUID_ConstantForce;
slouken@2713
  1051
slouken@2713
  1052
    case SDL_HAPTIC_RAMP:
slouken@2713
  1053
        return &GUID_RampForce;
slouken@2713
  1054
slouken@2713
  1055
    case SDL_HAPTIC_SQUARE:
slouken@2713
  1056
        return &GUID_Square;
slouken@2713
  1057
slouken@2713
  1058
    case SDL_HAPTIC_SINE:
slouken@2713
  1059
        return &GUID_Sine;
slouken@2713
  1060
slouken@2713
  1061
    case SDL_HAPTIC_TRIANGLE:
slouken@2713
  1062
        return &GUID_Triangle;
slouken@2713
  1063
slouken@2713
  1064
    case SDL_HAPTIC_SAWTOOTHUP:
slouken@2713
  1065
        return &GUID_SawtoothUp;
slouken@2713
  1066
slouken@2713
  1067
    case SDL_HAPTIC_SAWTOOTHDOWN:
slouken@2713
  1068
        return &GUID_SawtoothDown;
slouken@2713
  1069
slouken@2713
  1070
    case SDL_HAPTIC_SPRING:
slouken@2713
  1071
        return &GUID_Spring;
slouken@2713
  1072
slouken@2713
  1073
    case SDL_HAPTIC_DAMPER:
slouken@2713
  1074
        return &GUID_Damper;
slouken@2713
  1075
slouken@2713
  1076
    case SDL_HAPTIC_INERTIA:
slouken@2713
  1077
        return &GUID_Inertia;
slouken@2713
  1078
slouken@2713
  1079
    case SDL_HAPTIC_FRICTION:
slouken@2713
  1080
        return &GUID_Friction;
slouken@2713
  1081
slouken@2713
  1082
    case SDL_HAPTIC_CUSTOM:
slouken@2713
  1083
        return &GUID_CustomForce;
slouken@2713
  1084
slouken@2713
  1085
    default:
slouken@2713
  1086
        SDL_SetError("Haptic: Unknown effect type.");
slouken@2713
  1087
        return NULL;
slouken@2713
  1088
    }
slouken@2713
  1089
}
slouken@2713
  1090
slouken@2713
  1091
slouken@2713
  1092
/*
slouken@2713
  1093
 * Creates a new haptic effect.
slouken@2713
  1094
 */
slouken@2713
  1095
int
slouken@2713
  1096
SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
slouken@2713
  1097
                        SDL_HapticEffect * base)
slouken@2713
  1098
{
slouken@2713
  1099
    HRESULT ret;
slouken@2713
  1100
slouken@2713
  1101
    /* Get the type. */
slouken@2713
  1102
    REFGUID type = SDL_SYS_HapticEffectType(base);
slouken@2713
  1103
    if (type == NULL) {
slouken@2713
  1104
        goto err_hweffect;
slouken@2713
  1105
    }
slouken@2713
  1106
slouken@2713
  1107
    /* Alloc the effect. */
slouken@2713
  1108
    effect->hweffect = (struct haptic_hweffect *)
slouken@2713
  1109
        SDL_malloc(sizeof(struct haptic_hweffect));
slouken@2713
  1110
    if (effect->hweffect == NULL) {
slouken@2713
  1111
        SDL_OutOfMemory();
slouken@2713
  1112
        goto err_hweffect;
slouken@2713
  1113
    }
slouken@2713
  1114
slouken@2713
  1115
    /* Get the effect. */
slouken@2713
  1116
    if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) {
slouken@2713
  1117
        goto err_effectdone;
slouken@2713
  1118
    }
slouken@2713
  1119
slouken@2713
  1120
    /* Create the actual effect. */
slouken@2713
  1121
    ret = IDirectInputDevice2_CreateEffect(haptic->hwdata->device, type,
slouken@2713
  1122
                                           &effect->hweffect->effect,
slouken@2713
  1123
                                           &effect->hweffect->ref, NULL);
slouken@2713
  1124
    if (FAILED(ret)) {
slouken@2713
  1125
        DI_SetError("Unable to create effect", ret);
slouken@2713
  1126
        goto err_effectdone;
slouken@2713
  1127
    }
slouken@2713
  1128
slouken@2713
  1129
    return 0;
slouken@2713
  1130
slouken@2713
  1131
  err_effectdone:
slouken@2713
  1132
    SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type);
slouken@2713
  1133
  err_hweffect:
slouken@2713
  1134
    if (effect->hweffect != NULL) {
slouken@2713
  1135
        SDL_free(effect->hweffect);
slouken@2713
  1136
        effect->hweffect = NULL;
slouken@2713
  1137
    }
slouken@2713
  1138
    return -1;
slouken@2713
  1139
}
slouken@2713
  1140
slouken@2713
  1141
slouken@2713
  1142
/*
slouken@2713
  1143
 * Updates an effect.
slouken@2713
  1144
 */
slouken@2713
  1145
int
slouken@2713
  1146
SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic,
slouken@2713
  1147
                           struct haptic_effect *effect,
slouken@2713
  1148
                           SDL_HapticEffect * data)
slouken@2713
  1149
{
slouken@2713
  1150
    HRESULT ret;
slouken@2713
  1151
    DWORD flags;
slouken@2713
  1152
    DIEFFECT temp;
slouken@2713
  1153
slouken@2713
  1154
    /* Get the effect. */
slouken@2713
  1155
    SDL_memset(&temp, 0, sizeof(DIEFFECT));
slouken@2713
  1156
    if (SDL_SYS_ToDIEFFECT(haptic, &temp, data) < 0) {
slouken@2713
  1157
        goto err_update;
slouken@2713
  1158
    }
slouken@2713
  1159
slouken@2713
  1160
    /* Set the flags.  Might be worthwhile to diff temp with loaded effect and
slouken@2713
  1161
     *  only change those parameters. */
slouken@2713
  1162
    flags = DIEP_DIRECTION |
slouken@2713
  1163
        DIEP_DURATION |
slouken@2713
  1164
        DIEP_ENVELOPE |
slouken@2713
  1165
        DIEP_STARTDELAY |
slouken@2713
  1166
        DIEP_TRIGGERBUTTON |
slouken@2713
  1167
        DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS;
slouken@2713
  1168
slouken@2713
  1169
    /* Create the actual effect. */
slouken@2713
  1170
    ret =
slouken@2713
  1171
        IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags);
slouken@2713
  1172
    if (FAILED(ret)) {
slouken@2713
  1173
        DI_SetError("Unable to update effect", ret);
slouken@2713
  1174
        goto err_update;
slouken@2713
  1175
    }
slouken@2713
  1176
slouken@2713
  1177
    /* Copy it over. */
slouken@2713
  1178
    SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type);
slouken@2713
  1179
    SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT));
slouken@2713
  1180
slouken@2713
  1181
    return 0;
slouken@2713
  1182
slouken@2713
  1183
  err_update:
slouken@2713
  1184
    SDL_SYS_HapticFreeDIEFFECT(&temp, data->type);
slouken@2713
  1185
    return -1;
slouken@2713
  1186
}
slouken@2713
  1187
slouken@2713
  1188
slouken@2713
  1189
/*
slouken@2713
  1190
 * Runs an effect.
slouken@2713
  1191
 */
slouken@2713
  1192
int
slouken@2713
  1193
SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect,
slouken@2713
  1194
                        Uint32 iterations)
slouken@2713
  1195
{
slouken@2713
  1196
    HRESULT ret;
slouken@2713
  1197
    DWORD iter;
slouken@2713
  1198
slouken@2713
  1199
    /* Check if it's infinite. */
slouken@2713
  1200
    if (iterations == SDL_HAPTIC_INFINITY) {
slouken@2713
  1201
        iter = INFINITE;
slouken@2713
  1202
    } else
slouken@2713
  1203
        iter = iterations;
slouken@2713
  1204
slouken@2713
  1205
    /* Run the effect. */
slouken@2713
  1206
    ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0);
slouken@2713
  1207
    if (FAILED(ret)) {
slouken@2713
  1208
        DI_SetError("Running the effect", ret);
slouken@2713
  1209
        return -1;
slouken@2713
  1210
    }
slouken@2713
  1211
slouken@2713
  1212
    return 0;
slouken@2713
  1213
}
slouken@2713
  1214
slouken@2713
  1215
slouken@2713
  1216
/*
slouken@2713
  1217
 * Stops an effect.
slouken@2713
  1218
 */
slouken@2713
  1219
int
slouken@2713
  1220
SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
slouken@2713
  1221
{
slouken@2713
  1222
    HRESULT ret;
slouken@2713
  1223
slouken@2713
  1224
    ret = IDirectInputEffect_Stop(effect->hweffect->ref);
slouken@2713
  1225
    if (FAILED(ret)) {
slouken@2713
  1226
        DI_SetError("Unable to stop effect", ret);
slouken@2713
  1227
        return -1;
slouken@2713
  1228
    }
slouken@2713
  1229
slouken@2713
  1230
    return 0;
slouken@2713
  1231
}
slouken@2713
  1232
slouken@2713
  1233
slouken@2713
  1234
/*
slouken@2713
  1235
 * Frees the effect.
slouken@2713
  1236
 */
slouken@2713
  1237
void
slouken@2713
  1238
SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect)
slouken@2713
  1239
{
slouken@2713
  1240
    HRESULT ret;
slouken@2713
  1241
slouken@2713
  1242
    ret = IDirectInputEffect_Unload(effect->hweffect->ref);
slouken@2713
  1243
    if (FAILED(ret)) {
slouken@2713
  1244
        DI_SetError("Removing effect from the device", ret);
slouken@2713
  1245
    }
slouken@2713
  1246
    SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect,
slouken@2713
  1247
                               effect->effect.type);
slouken@2713
  1248
    SDL_free(effect->hweffect);
slouken@2713
  1249
    effect->hweffect = NULL;
slouken@2713
  1250
}
slouken@2713
  1251
slouken@2713
  1252
slouken@2713
  1253
/*
slouken@2713
  1254
 * Gets the status of a haptic effect.
slouken@2713
  1255
 */
slouken@2713
  1256
int
slouken@2713
  1257
SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic,
slouken@2713
  1258
                              struct haptic_effect *effect)
slouken@2713
  1259
{
slouken@2713
  1260
    HRESULT ret;
slouken@2713
  1261
    DWORD status;
slouken@2713
  1262
slouken@2713
  1263
    ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status);
slouken@2713
  1264
    if (FAILED(ret)) {
slouken@2713
  1265
        DI_SetError("Getting effect status", ret);
slouken@2713
  1266
        return -1;
slouken@2713
  1267
    }
slouken@2713
  1268
slouken@2713
  1269
    if (status == 0)
slouken@2713
  1270
        return SDL_FALSE;
slouken@2713
  1271
    return SDL_TRUE;
slouken@2713
  1272
}
slouken@2713
  1273
slouken@2713
  1274
slouken@2713
  1275
/*
slouken@2713
  1276
 * Sets the gain.
slouken@2713
  1277
 */
slouken@2713
  1278
int
slouken@2713
  1279
SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain)
slouken@2713
  1280
{
slouken@2713
  1281
    HRESULT ret;
slouken@2713
  1282
    DIPROPDWORD dipdw;
slouken@2713
  1283
slouken@2713
  1284
    /* Create the weird structure thingy. */
slouken@2713
  1285
    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
slouken@2713
  1286
    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@2713
  1287
    dipdw.diph.dwObj = 0;
slouken@2713
  1288
    dipdw.diph.dwHow = DIPH_DEVICE;
slouken@2713
  1289
    dipdw.dwData = gain * 100;  /* 0 to 10,000 */
slouken@2713
  1290
slouken@2713
  1291
    /* Try to set the autocenter. */
slouken@2713
  1292
    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
slouken@2713
  1293
                                          DIPROP_FFGAIN, &dipdw.diph);
slouken@2713
  1294
    if (FAILED(ret)) {
slouken@2713
  1295
        DI_SetError("Setting gain", ret);
slouken@2713
  1296
        return -1;
slouken@2713
  1297
    }
slouken@2713
  1298
slouken@2713
  1299
    return 0;
slouken@2713
  1300
}
slouken@2713
  1301
slouken@2713
  1302
slouken@2713
  1303
/*
slouken@2713
  1304
 * Sets the autocentering.
slouken@2713
  1305
 */
slouken@2713
  1306
int
slouken@2713
  1307
SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
slouken@2713
  1308
{
slouken@2713
  1309
    HRESULT ret;
slouken@2713
  1310
    DIPROPDWORD dipdw;
slouken@2713
  1311
slouken@2713
  1312
    /* Create the weird structure thingy. */
slouken@2713
  1313
    dipdw.diph.dwSize = sizeof(DIPROPDWORD);
slouken@2713
  1314
    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
slouken@2713
  1315
    dipdw.diph.dwObj = 0;
slouken@2713
  1316
    dipdw.diph.dwHow = DIPH_DEVICE;
slouken@2713
  1317
    dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF :
slouken@2713
  1318
        DIPROPAUTOCENTER_ON;
slouken@2713
  1319
slouken@2713
  1320
    /* Try to set the autocenter. */
slouken@2713
  1321
    ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device,
slouken@2713
  1322
                                          DIPROP_AUTOCENTER, &dipdw.diph);
slouken@2713
  1323
    if (FAILED(ret)) {
slouken@2713
  1324
        DI_SetError("Setting autocenter", ret);
slouken@2713
  1325
        return -1;
slouken@2713
  1326
    }
slouken@2713
  1327
slouken@2713
  1328
    return 0;
slouken@2713
  1329
}
slouken@2713
  1330
slouken@2713
  1331
slouken@2713
  1332
/*
slouken@2713
  1333
 * Pauses the device.
slouken@2713
  1334
 */
slouken@2713
  1335
int
slouken@2713
  1336
SDL_SYS_HapticPause(SDL_Haptic * haptic)
slouken@2713
  1337
{
slouken@2713
  1338
    HRESULT ret;
slouken@2713
  1339
slouken@2713
  1340
    /* Pause the device. */
slouken@2713
  1341
    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
slouken@2713
  1342
                                                       DISFFC_PAUSE);
slouken@2713
  1343
    if (FAILED(ret)) {
slouken@2713
  1344
        DI_SetError("Pausing the device", ret);
slouken@2713
  1345
        return -1;
slouken@2713
  1346
    }
slouken@2713
  1347
slouken@2713
  1348
    return 0;
slouken@2713
  1349
}
slouken@2713
  1350
slouken@2713
  1351
slouken@2713
  1352
/*
slouken@2713
  1353
 * Pauses the device.
slouken@2713
  1354
 */
slouken@2713
  1355
int
slouken@2713
  1356
SDL_SYS_HapticUnpause(SDL_Haptic * haptic)
slouken@2713
  1357
{
slouken@2713
  1358
    HRESULT ret;
slouken@2713
  1359
slouken@2713
  1360
    /* Unpause the device. */
slouken@2713
  1361
    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
slouken@2713
  1362
                                                       DISFFC_CONTINUE);
slouken@2713
  1363
    if (FAILED(ret)) {
slouken@2713
  1364
        DI_SetError("Pausing the device", ret);
slouken@2713
  1365
        return -1;
slouken@2713
  1366
    }
slouken@2713
  1367
slouken@2713
  1368
    return 0;
slouken@2713
  1369
}
slouken@2713
  1370
slouken@2713
  1371
slouken@2713
  1372
/*
slouken@2713
  1373
 * Stops all the playing effects on the device.
slouken@2713
  1374
 */
slouken@2713
  1375
int
bobbens@2715
  1376
SDL_SYS_HapticStopAll(SDL_Haptic * haptic)
slouken@2713
  1377
{
slouken@2713
  1378
    HRESULT ret;
slouken@2713
  1379
slouken@2713
  1380
    /* Try to stop the effects. */
slouken@2713
  1381
    ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device,
slouken@2713
  1382
                                                       DISFFC_STOPALL);
slouken@2713
  1383
    if (FAILED(ret)) {
slouken@2713
  1384
        DI_SetError("Stopping the device", ret);
slouken@2713
  1385
        return -1;
slouken@2713
  1386
    }
slouken@2713
  1387
slouken@2713
  1388
    return 0;
slouken@2713
  1389
}
slouken@2713
  1390
slouken@2713
  1391
slouken@2713
  1392
#endif /* SDL_HAPTIC_DINPUT */