src/haptic/SDL_haptic.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 27 Jul 2013 02:45:26 -0700
changeset 7524 6d8fd70e1477
parent 7131 70a7369c5b32
child 7530 7f26fd1df927
permissions -rw-r--r--
Improved error checking in the haptic system, preventing crashes in some cases.

Edgar Simo 2012-05-06 02:33:39 EDT

I recall that driver being buggy back in the day, but looking over the code there's a number of things being done wrong which I've fixed and it should now properly error out instead of crashing. Also make sure you initialize the haptic subsystem before using haptic commands (which I now more explicitly try to enforce).
slouken@2713
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@2713
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@2713
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@2713
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@2713
    20
*/
slouken@2713
    21
#include "SDL_config.h"
slouken@2713
    22
slouken@2713
    23
#include "SDL_syshaptic.h"
slouken@4472
    24
#include "SDL_haptic_c.h"
slouken@2713
    25
#include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
slouken@2713
    26
slouken@2713
    27
slouken@2713
    28
Uint8 SDL_numhaptics = 0;
slouken@2713
    29
SDL_Haptic **SDL_haptics = NULL;
slouken@2713
    30
slouken@2713
    31
slouken@2713
    32
/*
slouken@2713
    33
 * Initializes the Haptic devices.
slouken@2713
    34
 */
slouken@2713
    35
int
slouken@2713
    36
SDL_HapticInit(void)
slouken@2713
    37
{
slouken@2713
    38
    int arraylen;
slouken@2713
    39
    int status;
slouken@2713
    40
slouken@2713
    41
    SDL_numhaptics = 0;
slouken@2713
    42
    status = SDL_SYS_HapticInit();
slouken@2713
    43
    if (status >= 0) {
slouken@2713
    44
        arraylen = (status + 1) * sizeof(*SDL_haptics);
slouken@2713
    45
        SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
slouken@2713
    46
        if (SDL_haptics == NULL) {      /* Out of memory. */
slouken@2713
    47
            SDL_numhaptics = 0;
slouken@2713
    48
        } else {
slouken@2713
    49
            SDL_memset(SDL_haptics, 0, arraylen);
slouken@2713
    50
            SDL_numhaptics = status;
slouken@2713
    51
        }
slouken@2713
    52
        status = 0;
slouken@2713
    53
    }
slouken@2713
    54
slouken@2713
    55
    return status;
slouken@2713
    56
}
slouken@2713
    57
slouken@2713
    58
slouken@2713
    59
/*
slouken@2713
    60
 * Checks to see if the haptic device is valid
slouken@2713
    61
 */
slouken@2713
    62
static int
slouken@2713
    63
ValidHaptic(SDL_Haptic * haptic)
slouken@2713
    64
{
slouken@2713
    65
    int i;
slouken@2713
    66
    int valid;
slouken@2713
    67
slouken@2713
    68
    valid = 0;
bobbens@3080
    69
    if (haptic != NULL) {
bobbens@3080
    70
        for (i = 0; i < SDL_numhaptics; i++) {
bobbens@3080
    71
            if (SDL_haptics[i] == haptic) {
bobbens@3080
    72
                valid = 1;
bobbens@3080
    73
                break;
bobbens@3080
    74
            }
slouken@2713
    75
        }
slouken@2713
    76
    }
slouken@2713
    77
bobbens@3080
    78
    /* Create the error here. */
bobbens@3080
    79
    if (valid == 0) {
bobbens@3080
    80
        SDL_SetError("Haptic: Invalid haptic device identifier");
bobbens@3080
    81
    }
bobbens@3080
    82
slouken@2713
    83
    return valid;
slouken@2713
    84
}
slouken@2713
    85
slouken@2713
    86
slouken@2713
    87
/*
slouken@2713
    88
 * Returns the number of available devices.
slouken@2713
    89
 */
slouken@2713
    90
int
slouken@2713
    91
SDL_NumHaptics(void)
slouken@2713
    92
{
slouken@2713
    93
    return SDL_numhaptics;
slouken@2713
    94
}
slouken@2713
    95
slouken@2713
    96
slouken@2713
    97
/*
slouken@2713
    98
 * Gets the name of a Haptic device by index.
slouken@2713
    99
 */
slouken@2713
   100
const char *
slouken@2713
   101
SDL_HapticName(int device_index)
slouken@2713
   102
{
slouken@2713
   103
    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
slouken@2713
   104
        SDL_SetError("Haptic: There are %d haptic devices available",
slouken@2713
   105
                     SDL_numhaptics);
slouken@2713
   106
        return NULL;
slouken@2713
   107
    }
slouken@2713
   108
    return SDL_SYS_HapticName(device_index);
slouken@2713
   109
}
slouken@2713
   110
slouken@2713
   111
slouken@2713
   112
/*
slouken@2713
   113
 * Opens a Haptic device.
slouken@2713
   114
 */
slouken@2713
   115
SDL_Haptic *
slouken@2713
   116
SDL_HapticOpen(int device_index)
slouken@2713
   117
{
slouken@2713
   118
    int i;
slouken@2713
   119
    SDL_Haptic *haptic;
slouken@2713
   120
slouken@2713
   121
    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
slouken@2713
   122
        SDL_SetError("Haptic: There are %d haptic devices available",
slouken@2713
   123
                     SDL_numhaptics);
slouken@2713
   124
        return NULL;
slouken@2713
   125
    }
slouken@2713
   126
slouken@2713
   127
    /* If the haptic is already open, return it */
slouken@2713
   128
    for (i = 0; SDL_haptics[i]; i++) {
slouken@2713
   129
        if (device_index == SDL_haptics[i]->index) {
slouken@2713
   130
            haptic = SDL_haptics[i];
slouken@2713
   131
            ++haptic->ref_count;
slouken@2713
   132
            return haptic;
slouken@2713
   133
        }
slouken@2713
   134
    }
slouken@2713
   135
slouken@2713
   136
    /* Create the haptic device */
slouken@2713
   137
    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
slouken@2713
   138
    if (haptic == NULL) {
slouken@2713
   139
        SDL_OutOfMemory();
slouken@2713
   140
        return NULL;
slouken@2713
   141
    }
slouken@2713
   142
slouken@2713
   143
    /* Initialize the haptic device */
slouken@2713
   144
    SDL_memset(haptic, 0, (sizeof *haptic));
slouken@5360
   145
    haptic->rumble_id = -1;
slouken@2713
   146
    haptic->index = device_index;
slouken@2713
   147
    if (SDL_SYS_HapticOpen(haptic) < 0) {
slouken@2713
   148
        SDL_free(haptic);
slouken@2713
   149
        return NULL;
slouken@2713
   150
    }
slouken@2713
   151
slouken@7524
   152
    /* Add haptic to list */
slouken@7524
   153
    for (i = 0; SDL_haptics[i]; i++)
slouken@7524
   154
        /* Skip to next haptic */ ;
slouken@7524
   155
    if (i >= SDL_numhaptics) {
slouken@7524
   156
        SDL_free(haptic);
slouken@7524
   157
        SDL_SetError("Haptic: Trying to add device past the number originally detected");
slouken@7524
   158
        return NULL;
slouken@7524
   159
    }
slouken@7524
   160
    SDL_haptics[i] = haptic;
slouken@7524
   161
    ++haptic->ref_count;
slouken@7524
   162
slouken@2713
   163
    /* Disable autocenter and set gain to max. */
slouken@2713
   164
    if (haptic->supported & SDL_HAPTIC_GAIN)
slouken@2713
   165
        SDL_HapticSetGain(haptic, 100);
slouken@2713
   166
    if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
slouken@2713
   167
        SDL_HapticSetAutocenter(haptic, 0);
slouken@2713
   168
slouken@2713
   169
    return haptic;
slouken@2713
   170
}
slouken@2713
   171
slouken@2713
   172
slouken@2713
   173
/*
slouken@2713
   174
 * Returns 1 if the device has been opened.
slouken@2713
   175
 */
slouken@2713
   176
int
slouken@2713
   177
SDL_HapticOpened(int device_index)
slouken@2713
   178
{
slouken@2713
   179
    int i, opened;
slouken@2713
   180
slouken@7524
   181
    /* Make sure it's valid. */
slouken@7524
   182
    if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
slouken@7524
   183
        SDL_SetError("Haptic: There are %d haptic devices available",
slouken@7524
   184
                     SDL_numhaptics);
slouken@7524
   185
        return -1;
slouken@7524
   186
    }
slouken@7524
   187
slouken@2713
   188
    opened = 0;
slouken@2713
   189
    for (i = 0; SDL_haptics[i]; i++) {
slouken@2713
   190
        if (SDL_haptics[i]->index == (Uint8) device_index) {
slouken@2713
   191
            opened = 1;
slouken@2713
   192
            break;
slouken@2713
   193
        }
slouken@2713
   194
    }
slouken@2713
   195
    return opened;
slouken@2713
   196
}
slouken@2713
   197
slouken@2713
   198
slouken@2713
   199
/*
slouken@2713
   200
 * Returns the index to a haptic device.
slouken@2713
   201
 */
slouken@2713
   202
int
slouken@2713
   203
SDL_HapticIndex(SDL_Haptic * haptic)
slouken@2713
   204
{
slouken@2713
   205
    if (!ValidHaptic(haptic)) {
slouken@2713
   206
        return -1;
slouken@2713
   207
    }
slouken@2713
   208
slouken@2713
   209
    return haptic->index;
slouken@2713
   210
}
slouken@2713
   211
slouken@2713
   212
slouken@2713
   213
/*
slouken@2713
   214
 * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
slouken@2713
   215
 */
slouken@2713
   216
int
slouken@2713
   217
SDL_MouseIsHaptic(void)
slouken@2713
   218
{
slouken@2713
   219
    if (SDL_SYS_HapticMouse() < 0)
slouken@2713
   220
        return SDL_FALSE;
slouken@2713
   221
    return SDL_TRUE;
slouken@2713
   222
}
slouken@2713
   223
slouken@2713
   224
slouken@2713
   225
/*
slouken@2713
   226
 * Returns the haptic device if mouse is haptic or NULL elsewise.
slouken@2713
   227
 */
slouken@2713
   228
SDL_Haptic *
slouken@2713
   229
SDL_HapticOpenFromMouse(void)
slouken@2713
   230
{
slouken@2713
   231
    int device_index;
slouken@2713
   232
slouken@2713
   233
    device_index = SDL_SYS_HapticMouse();
slouken@2713
   234
slouken@2713
   235
    if (device_index < 0) {
slouken@2713
   236
        SDL_SetError("Haptic: Mouse isn't a haptic device.");
slouken@2713
   237
        return NULL;
slouken@2713
   238
    }
slouken@2713
   239
slouken@2713
   240
    return SDL_HapticOpen(device_index);
slouken@2713
   241
}
slouken@2713
   242
slouken@2713
   243
slouken@2713
   244
/*
slouken@2713
   245
 * Returns SDL_TRUE if joystick has haptic features.
slouken@2713
   246
 */
slouken@2713
   247
int
slouken@2713
   248
SDL_JoystickIsHaptic(SDL_Joystick * joystick)
slouken@2713
   249
{
slouken@2713
   250
    int ret;
slouken@2713
   251
slouken@2713
   252
    /* Must be a valid joystick */
slouken@6690
   253
    if (!SDL_PrivateJoystickValid(joystick)) {
slouken@2713
   254
        return -1;
slouken@2713
   255
    }
slouken@2713
   256
slouken@2713
   257
    ret = SDL_SYS_JoystickIsHaptic(joystick);
slouken@2713
   258
slouken@2713
   259
    if (ret > 0)
slouken@2713
   260
        return SDL_TRUE;
slouken@2713
   261
    else if (ret == 0)
slouken@2713
   262
        return SDL_FALSE;
slouken@2713
   263
    else
slouken@2713
   264
        return -1;
slouken@2713
   265
}
slouken@2713
   266
slouken@2713
   267
slouken@2713
   268
/*
slouken@2713
   269
 * Opens a haptic device from a joystick.
slouken@2713
   270
 */
slouken@2713
   271
SDL_Haptic *
slouken@2713
   272
SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
slouken@2713
   273
{
slouken@2713
   274
    int i;
slouken@2713
   275
    SDL_Haptic *haptic;
slouken@2713
   276
slouken@7524
   277
    /* Make sure there is room. */
slouken@7524
   278
    if (SDL_numhaptics <= 0) {
slouken@7524
   279
        SDL_SetError("Haptic: There are %d haptic devices available",
slouken@7524
   280
                     SDL_numhaptics);
slouken@7524
   281
        return NULL;
slouken@7524
   282
    }
slouken@7524
   283
slouken@2713
   284
    /* Must be a valid joystick */
slouken@6690
   285
    if (!SDL_PrivateJoystickValid(joystick)) {
bobbens@3232
   286
        SDL_SetError("Haptic: Joystick isn't valid.");
slouken@2713
   287
        return NULL;
slouken@2713
   288
    }
slouken@2713
   289
slouken@2713
   290
    /* Joystick must be haptic */
slouken@2713
   291
    if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
bobbens@3232
   292
        SDL_SetError("Haptic: Joystick isn't a haptic device.");
slouken@2713
   293
        return NULL;
slouken@2713
   294
    }
slouken@2713
   295
slouken@2713
   296
    /* Check to see if joystick's haptic is already open */
slouken@2713
   297
    for (i = 0; SDL_haptics[i]; i++) {
slouken@2713
   298
        if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
slouken@2713
   299
            haptic = SDL_haptics[i];
slouken@2713
   300
            ++haptic->ref_count;
slouken@2713
   301
            return haptic;
slouken@2713
   302
        }
slouken@2713
   303
    }
slouken@2713
   304
slouken@2713
   305
    /* Create the haptic device */
slouken@2713
   306
    haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
slouken@2713
   307
    if (haptic == NULL) {
slouken@2713
   308
        SDL_OutOfMemory();
slouken@2713
   309
        return NULL;
slouken@2713
   310
    }
slouken@2713
   311
slouken@2713
   312
    /* Initialize the haptic device */
slouken@2713
   313
    SDL_memset(haptic, 0, sizeof(SDL_Haptic));
slouken@5360
   314
    haptic->rumble_id = -1;
slouken@2713
   315
    if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
slouken@2713
   316
        SDL_free(haptic);
slouken@2713
   317
        return NULL;
slouken@2713
   318
    }
slouken@2713
   319
slouken@2713
   320
    /* Add haptic to list */
slouken@2713
   321
    for (i = 0; SDL_haptics[i]; i++)
slouken@2713
   322
        /* Skip to next haptic */ ;
slouken@7524
   323
    if (i >= SDL_numhaptics) {
slouken@7524
   324
        SDL_free(haptic);
slouken@7524
   325
        SDL_SetError("Haptic: Trying to add device past the number originally detected");
slouken@7524
   326
        return NULL;
slouken@7524
   327
    }
slouken@2713
   328
    SDL_haptics[i] = haptic;
slouken@7524
   329
    ++haptic->ref_count;
slouken@2713
   330
slouken@2713
   331
    return haptic;
slouken@2713
   332
}
slouken@2713
   333
slouken@2713
   334
slouken@2713
   335
/*
slouken@2713
   336
 * Closes a SDL_Haptic device.
slouken@2713
   337
 */
slouken@2713
   338
void
slouken@2713
   339
SDL_HapticClose(SDL_Haptic * haptic)
slouken@2713
   340
{
slouken@2713
   341
    int i;
slouken@2713
   342
slouken@2713
   343
    /* Must be valid */
slouken@2713
   344
    if (!ValidHaptic(haptic)) {
slouken@2713
   345
        return;
slouken@2713
   346
    }
slouken@2713
   347
slouken@2713
   348
    /* Check if it's still in use */
slouken@2713
   349
    if (--haptic->ref_count < 0) {
slouken@2713
   350
        return;
slouken@2713
   351
    }
slouken@2713
   352
slouken@2713
   353
    /* Close it, properly removing effects if needed */
slouken@2713
   354
    for (i = 0; i < haptic->neffects; i++) {
slouken@2713
   355
        if (haptic->effects[i].hweffect != NULL) {
slouken@2713
   356
            SDL_HapticDestroyEffect(haptic, i);
slouken@2713
   357
        }
slouken@2713
   358
    }
slouken@2713
   359
    SDL_SYS_HapticClose(haptic);
slouken@2713
   360
slouken@2713
   361
    /* Remove from the list */
slouken@2713
   362
    for (i = 0; SDL_haptics[i]; ++i) {
slouken@2713
   363
        if (haptic == SDL_haptics[i]) {
slouken@2713
   364
            SDL_haptics[i] = NULL;
slouken@2713
   365
            SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
slouken@2713
   366
                       (SDL_numhaptics - i) * sizeof(haptic));
slouken@2713
   367
            break;
slouken@2713
   368
        }
slouken@2713
   369
    }
slouken@2713
   370
slouken@2713
   371
    /* Free */
slouken@2713
   372
    SDL_free(haptic);
slouken@2713
   373
}
slouken@2713
   374
slouken@2713
   375
/*
slouken@2713
   376
 * Cleans up after the subsystem.
slouken@2713
   377
 */
slouken@2713
   378
void
slouken@2713
   379
SDL_HapticQuit(void)
slouken@2713
   380
{
slouken@2713
   381
    SDL_SYS_HapticQuit();
slouken@2713
   382
    if (SDL_haptics != NULL) {
slouken@2713
   383
        SDL_free(SDL_haptics);
slouken@2713
   384
        SDL_haptics = NULL;
slouken@2713
   385
    }
slouken@2713
   386
    SDL_numhaptics = 0;
slouken@2713
   387
}
slouken@2713
   388
slouken@2713
   389
/*
slouken@2713
   390
 * Returns the number of effects a haptic device has.
slouken@2713
   391
 */
slouken@2713
   392
int
slouken@2713
   393
SDL_HapticNumEffects(SDL_Haptic * haptic)
slouken@2713
   394
{
slouken@2713
   395
    if (!ValidHaptic(haptic)) {
slouken@2713
   396
        return -1;
slouken@2713
   397
    }
slouken@2713
   398
slouken@2713
   399
    return haptic->neffects;
slouken@2713
   400
}
slouken@2713
   401
slouken@2713
   402
slouken@2713
   403
/*
slouken@2713
   404
 * Returns the number of effects a haptic device can play.
slouken@2713
   405
 */
slouken@2713
   406
int
slouken@2713
   407
SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
slouken@2713
   408
{
slouken@2713
   409
    if (!ValidHaptic(haptic)) {
slouken@2713
   410
        return -1;
slouken@2713
   411
    }
slouken@2713
   412
slouken@2713
   413
    return haptic->nplaying;
slouken@2713
   414
}
slouken@2713
   415
slouken@2713
   416
slouken@2713
   417
/*
slouken@2713
   418
 * Returns supported effects by the device.
slouken@2713
   419
 */
slouken@2713
   420
unsigned int
slouken@2713
   421
SDL_HapticQuery(SDL_Haptic * haptic)
slouken@2713
   422
{
slouken@2713
   423
    if (!ValidHaptic(haptic)) {
philipp@7131
   424
        return 0; /* same as if no effects were supported */
slouken@2713
   425
    }
slouken@2713
   426
slouken@2713
   427
    return haptic->supported;
slouken@2713
   428
}
slouken@2713
   429
slouken@2713
   430
slouken@2713
   431
/*
slouken@2713
   432
 * Returns the number of axis on the device.
slouken@2713
   433
 */
slouken@2713
   434
int
slouken@2713
   435
SDL_HapticNumAxes(SDL_Haptic * haptic)
slouken@2713
   436
{
slouken@2713
   437
    if (!ValidHaptic(haptic)) {
slouken@2713
   438
        return -1;
slouken@2713
   439
    }
slouken@2713
   440
slouken@2713
   441
    return haptic->naxes;
slouken@2713
   442
}
slouken@2713
   443
slouken@2713
   444
/*
slouken@2713
   445
 * Checks to see if the device can support the effect.
slouken@2713
   446
 */
slouken@2713
   447
int
slouken@2713
   448
SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
slouken@2713
   449
{
slouken@2713
   450
    if (!ValidHaptic(haptic)) {
slouken@2713
   451
        return -1;
slouken@2713
   452
    }
slouken@2713
   453
slouken@2713
   454
    if ((haptic->supported & effect->type) != 0)
slouken@2713
   455
        return SDL_TRUE;
slouken@2713
   456
    return SDL_FALSE;
slouken@2713
   457
}
slouken@2713
   458
slouken@2713
   459
/*
slouken@2713
   460
 * Creates a new haptic effect.
slouken@2713
   461
 */
slouken@2713
   462
int
slouken@2713
   463
SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
slouken@2713
   464
{
slouken@2713
   465
    int i;
slouken@2713
   466
slouken@2713
   467
    /* Check for device validity. */
slouken@2713
   468
    if (!ValidHaptic(haptic)) {
slouken@2713
   469
        return -1;
slouken@2713
   470
    }
slouken@2713
   471
slouken@2713
   472
    /* Check to see if effect is supported */
slouken@2713
   473
    if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
icculus@7037
   474
        return SDL_SetError("Haptic: Effect not supported by haptic device.");
slouken@2713
   475
    }
slouken@2713
   476
slouken@2713
   477
    /* See if there's a free slot */
slouken@2713
   478
    for (i = 0; i < haptic->neffects; i++) {
slouken@2713
   479
        if (haptic->effects[i].hweffect == NULL) {
slouken@2713
   480
slouken@2713
   481
            /* Now let the backend create the real effect */
slouken@2713
   482
            if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
slouken@2713
   483
                != 0) {
slouken@2713
   484
                return -1;      /* Backend failed to create effect */
slouken@2713
   485
            }
slouken@2713
   486
slouken@2713
   487
            SDL_memcpy(&haptic->effects[i].effect, effect,
slouken@2713
   488
                       sizeof(SDL_HapticEffect));
slouken@2713
   489
            return i;
slouken@2713
   490
        }
slouken@2713
   491
    }
slouken@2713
   492
icculus@7037
   493
    return SDL_SetError("Haptic: Device has no free space left.");
slouken@2713
   494
}
slouken@2713
   495
slouken@2713
   496
/*
slouken@2713
   497
 * Checks to see if an effect is valid.
slouken@2713
   498
 */
slouken@2713
   499
static int
slouken@2713
   500
ValidEffect(SDL_Haptic * haptic, int effect)
slouken@2713
   501
{
slouken@2713
   502
    if ((effect < 0) || (effect >= haptic->neffects)) {
slouken@2713
   503
        SDL_SetError("Haptic: Invalid effect identifier.");
slouken@2713
   504
        return 0;
slouken@2713
   505
    }
slouken@2713
   506
    return 1;
slouken@2713
   507
}
slouken@2713
   508
slouken@2713
   509
/*
slouken@2713
   510
 * Updates an effect.
slouken@2713
   511
 */
slouken@2713
   512
int
slouken@2713
   513
SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
slouken@2713
   514
                       SDL_HapticEffect * data)
slouken@2713
   515
{
slouken@2713
   516
    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
slouken@2713
   517
        return -1;
slouken@2713
   518
    }
slouken@2713
   519
slouken@2713
   520
    /* Can't change type dynamically. */
slouken@2713
   521
    if (data->type != haptic->effects[effect].effect.type) {
icculus@7037
   522
        return SDL_SetError("Haptic: Updating effect type is illegal.");
slouken@2713
   523
    }
slouken@2713
   524
slouken@2713
   525
    /* Updates the effect */
slouken@2713
   526
    if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
slouken@2713
   527
        0) {
slouken@2713
   528
        return -1;
slouken@2713
   529
    }
slouken@2713
   530
slouken@2713
   531
    SDL_memcpy(&haptic->effects[effect].effect, data,
slouken@2713
   532
               sizeof(SDL_HapticEffect));
slouken@2713
   533
    return 0;
slouken@2713
   534
}
slouken@2713
   535
slouken@2713
   536
slouken@2713
   537
/*
slouken@2713
   538
 * Runs the haptic effect on the device.
slouken@2713
   539
 */
slouken@2713
   540
int
slouken@2713
   541
SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
slouken@2713
   542
{
slouken@2713
   543
    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
slouken@2713
   544
        return -1;
slouken@2713
   545
    }
slouken@2713
   546
slouken@2713
   547
    /* Run the effect */
slouken@2713
   548
    if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
slouken@2713
   549
        < 0) {
slouken@2713
   550
        return -1;
slouken@2713
   551
    }
slouken@2713
   552
slouken@2713
   553
    return 0;
slouken@2713
   554
}
slouken@2713
   555
slouken@2713
   556
/*
slouken@2713
   557
 * Stops the haptic effect on the device.
slouken@2713
   558
 */
slouken@2713
   559
int
slouken@2713
   560
SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
slouken@2713
   561
{
slouken@2713
   562
    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
slouken@2713
   563
        return -1;
slouken@2713
   564
    }
slouken@2713
   565
slouken@2713
   566
    /* Stop the effect */
slouken@2713
   567
    if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
slouken@2713
   568
        return -1;
slouken@2713
   569
    }
slouken@2713
   570
slouken@2713
   571
    return 0;
slouken@2713
   572
}
slouken@2713
   573
slouken@2713
   574
/*
slouken@2713
   575
 * Gets rid of a haptic effect.
slouken@2713
   576
 */
slouken@2713
   577
void
slouken@2713
   578
SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
slouken@2713
   579
{
slouken@2713
   580
    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
slouken@2713
   581
        return;
slouken@2713
   582
    }
slouken@2713
   583
slouken@2713
   584
    /* Not allocated */
slouken@2713
   585
    if (haptic->effects[effect].hweffect == NULL) {
slouken@2713
   586
        return;
slouken@2713
   587
    }
slouken@2713
   588
slouken@2713
   589
    SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
slouken@2713
   590
}
slouken@2713
   591
slouken@2713
   592
/*
slouken@2713
   593
 * Gets the status of a haptic effect.
slouken@2713
   594
 */
slouken@2713
   595
int
slouken@2713
   596
SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
slouken@2713
   597
{
slouken@2713
   598
    if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
slouken@2713
   599
        return -1;
slouken@2713
   600
    }
slouken@2713
   601
slouken@2713
   602
    if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
icculus@7037
   603
        return SDL_SetError("Haptic: Device does not support status queries.");
slouken@2713
   604
    }
slouken@2713
   605
slouken@2713
   606
    return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
slouken@2713
   607
}
slouken@2713
   608
slouken@2713
   609
/*
slouken@2713
   610
 * Sets the global gain of the device.
slouken@2713
   611
 */
slouken@2713
   612
int
slouken@2713
   613
SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
slouken@2713
   614
{
slouken@2713
   615
    const char *env;
slouken@2713
   616
    int real_gain, max_gain;
slouken@2713
   617
slouken@2713
   618
    if (!ValidHaptic(haptic)) {
slouken@2713
   619
        return -1;
slouken@2713
   620
    }
slouken@2713
   621
slouken@2713
   622
    if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
icculus@7037
   623
        return SDL_SetError("Haptic: Device does not support setting gain.");
slouken@2713
   624
    }
slouken@2713
   625
slouken@2713
   626
    if ((gain < 0) || (gain > 100)) {
icculus@7037
   627
        return SDL_SetError("Haptic: Gain must be between 0 and 100.");
slouken@2713
   628
    }
slouken@2713
   629
slouken@2713
   630
    /* We use the envvar to get the maximum gain. */
slouken@2713
   631
    env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
slouken@2713
   632
    if (env != NULL) {
slouken@2713
   633
        max_gain = SDL_atoi(env);
slouken@2713
   634
slouken@2713
   635
        /* Check for sanity. */
slouken@2713
   636
        if (max_gain < 0)
slouken@2713
   637
            max_gain = 0;
slouken@2713
   638
        else if (max_gain > 100)
slouken@2713
   639
            max_gain = 100;
slouken@2713
   640
slouken@2713
   641
        /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
slouken@2713
   642
        real_gain = (gain * max_gain) / 100;
slouken@2713
   643
    } else {
slouken@2713
   644
        real_gain = gain;
slouken@2713
   645
    }
slouken@2713
   646
slouken@2713
   647
    if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
slouken@2713
   648
        return -1;
slouken@2713
   649
    }
slouken@2713
   650
slouken@2713
   651
    return 0;
slouken@2713
   652
}
slouken@2713
   653
slouken@2713
   654
/*
slouken@2713
   655
 * Makes the device autocenter, 0 disables.
slouken@2713
   656
 */
slouken@2713
   657
int
slouken@2713
   658
SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
slouken@2713
   659
{
slouken@2713
   660
    if (!ValidHaptic(haptic)) {
slouken@2713
   661
        return -1;
slouken@2713
   662
    }
slouken@2713
   663
slouken@2713
   664
    if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
icculus@7037
   665
        return SDL_SetError("Haptic: Device does not support setting autocenter.");
slouken@2713
   666
    }
slouken@2713
   667
slouken@2713
   668
    if ((autocenter < 0) || (autocenter > 100)) {
icculus@7037
   669
        return SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
slouken@2713
   670
    }
slouken@2713
   671
slouken@2713
   672
    if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
slouken@2713
   673
        return -1;
slouken@2713
   674
    }
slouken@2713
   675
slouken@2713
   676
    return 0;
slouken@2713
   677
}
slouken@2713
   678
slouken@2713
   679
/*
slouken@2713
   680
 * Pauses the haptic device.
slouken@2713
   681
 */
slouken@2713
   682
int
slouken@2713
   683
SDL_HapticPause(SDL_Haptic * haptic)
slouken@2713
   684
{
slouken@2713
   685
    if (!ValidHaptic(haptic)) {
slouken@2713
   686
        return -1;
slouken@2713
   687
    }
slouken@2713
   688
slouken@2713
   689
    if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
icculus@7037
   690
        return SDL_SetError("Haptic: Device does not support setting pausing.");
slouken@2713
   691
    }
slouken@2713
   692
slouken@2713
   693
    return SDL_SYS_HapticPause(haptic);
slouken@2713
   694
}
slouken@2713
   695
slouken@2713
   696
/*
slouken@2713
   697
 * Unpauses the haptic device.
slouken@2713
   698
 */
slouken@2713
   699
int
slouken@2713
   700
SDL_HapticUnpause(SDL_Haptic * haptic)
slouken@2713
   701
{
slouken@2713
   702
    if (!ValidHaptic(haptic)) {
slouken@2713
   703
        return -1;
slouken@2713
   704
    }
slouken@2713
   705
slouken@2713
   706
    if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
slouken@2713
   707
        return 0;               /* Not going to be paused, so we pretend it's unpaused. */
slouken@2713
   708
    }
slouken@2713
   709
slouken@2713
   710
    return SDL_SYS_HapticUnpause(haptic);
slouken@2713
   711
}
slouken@2713
   712
slouken@2713
   713
/*
slouken@2713
   714
 * Stops all the currently playing effects.
slouken@2713
   715
 */
slouken@2713
   716
int
slouken@2713
   717
SDL_HapticStopAll(SDL_Haptic * haptic)
slouken@2713
   718
{
slouken@2713
   719
    if (!ValidHaptic(haptic)) {
slouken@2713
   720
        return -1;
slouken@2713
   721
    }
slouken@2713
   722
slouken@2713
   723
    return SDL_SYS_HapticStopAll(haptic);
slouken@2713
   724
}
slouken@5360
   725
slouken@5362
   726
static void
slouken@5360
   727
SDL_HapticRumbleCreate(SDL_HapticEffect * efx)
slouken@5360
   728
{
slouken@5360
   729
   SDL_memset(efx, 0, sizeof(SDL_HapticEffect));
slouken@5360
   730
   efx->type = SDL_HAPTIC_SINE;
slouken@5360
   731
   efx->periodic.period = 1000;
slouken@5360
   732
   efx->periodic.magnitude = 0x4000;
slouken@5360
   733
   efx->periodic.length = 5000;
slouken@5360
   734
   efx->periodic.attack_length = 0;
slouken@5360
   735
   efx->periodic.fade_length = 0;
slouken@5360
   736
}
slouken@5360
   737
slouken@5360
   738
/*
slouken@5360
   739
 * Checks to see if rumble is supported.
slouken@5360
   740
 */
slouken@5360
   741
int
slouken@5360
   742
SDL_HapticRumbleSupported(SDL_Haptic * haptic)
slouken@5360
   743
{
slouken@5360
   744
    SDL_HapticEffect efx;
slouken@5360
   745
slouken@5360
   746
    if (!ValidHaptic(haptic)) {
slouken@5360
   747
        return -1;
slouken@5360
   748
    }
slouken@5360
   749
slouken@5360
   750
    SDL_HapticRumbleCreate(&efx);
slouken@5360
   751
    return SDL_HapticEffectSupported(haptic, &efx);
slouken@5360
   752
}
slouken@5360
   753
slouken@5360
   754
/*
slouken@5360
   755
 * Initializes the haptic device for simple rumble playback.
slouken@5360
   756
 */
slouken@5360
   757
int
slouken@5360
   758
SDL_HapticRumbleInit(SDL_Haptic * haptic)
slouken@5360
   759
{
slouken@5360
   760
    if (!ValidHaptic(haptic)) {
slouken@5360
   761
        return -1;
slouken@5360
   762
    }
slouken@5360
   763
slouken@5360
   764
    /* Already allocated. */
slouken@5360
   765
    if (haptic->rumble_id >= 0) {
slouken@5360
   766
        return 0;
slouken@5360
   767
    }
slouken@5360
   768
slouken@5360
   769
    /* Copy over. */
slouken@5360
   770
    SDL_HapticRumbleCreate(&haptic->rumble_effect);
slouken@5360
   771
    haptic->rumble_id = SDL_HapticNewEffect(haptic, &haptic->rumble_effect);
slouken@5360
   772
    if (haptic->rumble_id >= 0) {
slouken@5360
   773
        return 0;
slouken@5360
   774
    }
slouken@5360
   775
    return -1;
slouken@5360
   776
}
slouken@5360
   777
slouken@5360
   778
/*
slouken@5360
   779
 * Runs simple rumble on a haptic device
slouken@5360
   780
 */
slouken@5360
   781
int
slouken@5360
   782
SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length)
slouken@5360
   783
{
slouken@7524
   784
    int ret;
slouken@5360
   785
    SDL_HapticPeriodic *efx;
slouken@5360
   786
slouken@5360
   787
    if (!ValidHaptic(haptic)) {
slouken@5360
   788
        return -1;
slouken@5360
   789
    }
slouken@5360
   790
slouken@5360
   791
    if (haptic->rumble_id < 0) {
icculus@7037
   792
        return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
slouken@5360
   793
    }
slouken@5360
   794
slouken@5360
   795
    /* Clamp strength. */
slouken@5360
   796
    if (strength > 1.0f) {
slouken@5360
   797
        strength = 1.0f;
slouken@5360
   798
    }
slouken@5360
   799
    else if (strength < 0.0f) {
slouken@5360
   800
        strength = 0.0f;
slouken@5360
   801
    }
slouken@5360
   802
slouken@5360
   803
    /* New effect. */
slouken@5360
   804
    efx = &haptic->rumble_effect.periodic;
slouken@5360
   805
    efx->magnitude = (Sint16)(32767.0f*strength);
slouken@5360
   806
    efx->length = length;
slouken@7524
   807
    ret = SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect);
slouken@7524
   808
    if (ret) {
slouken@7524
   809
        return ret;
slouken@7524
   810
    }
slouken@5360
   811
slouken@5360
   812
    return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1);
slouken@5360
   813
}
slouken@5360
   814
slouken@5360
   815
/*
slouken@5360
   816
 * Stops the simple rumble on a haptic device.
slouken@5360
   817
 */
slouken@5360
   818
int
slouken@5360
   819
SDL_HapticRumbleStop(SDL_Haptic * haptic)
slouken@5360
   820
{
slouken@5360
   821
    if (!ValidHaptic(haptic)) {
slouken@5360
   822
        return -1;
slouken@5360
   823
    }
slouken@5360
   824
slouken@5360
   825
    if (haptic->rumble_id < 0) {
icculus@7037
   826
        return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
slouken@5360
   827
    }
slouken@5360
   828
slouken@5360
   829
    return SDL_HapticStopEffect(haptic, haptic->rumble_id);
slouken@5360
   830
}
slouken@5360
   831
slouken@5360
   832