src/haptic/SDL_haptic.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 01 May 2013 11:32:05 +0200
changeset 7131 70a7369c5b32
parent 7037 3fedf1f25b94
child 7524 6d8fd70e1477
permissions -rw-r--r--
Fixed SDL_HapticQuery() returning -1 as unsigned int if device is not valid.

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