src/haptic/SDL_haptic.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 27 Jul 2013 13:39:43 +0200
changeset 7530 7f26fd1df927
parent 7524 6d8fd70e1477
child 7531 a117b90a3a12
permissions -rw-r--r--
Corrected SDL_HapticUpdateEffect() returning 0 instead of index of effect.
According to documentation in header and wiki the index should be returned.
This change may break existing programs which assume only 0 means a success.
     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     /* Add haptic to list */
   153     for (i = 0; SDL_haptics[i]; i++)
   154         /* Skip to next haptic */ ;
   155     if (i >= SDL_numhaptics) {
   156         SDL_free(haptic);
   157         SDL_SetError("Haptic: Trying to add device past the number originally detected");
   158         return NULL;
   159     }
   160     SDL_haptics[i] = haptic;
   161     ++haptic->ref_count;
   162 
   163     /* Disable autocenter and set gain to max. */
   164     if (haptic->supported & SDL_HAPTIC_GAIN)
   165         SDL_HapticSetGain(haptic, 100);
   166     if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
   167         SDL_HapticSetAutocenter(haptic, 0);
   168 
   169     return haptic;
   170 }
   171 
   172 
   173 /*
   174  * Returns 1 if the device has been opened.
   175  */
   176 int
   177 SDL_HapticOpened(int device_index)
   178 {
   179     int i, opened;
   180 
   181     /* Make sure it's valid. */
   182     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   183         SDL_SetError("Haptic: There are %d haptic devices available",
   184                      SDL_numhaptics);
   185         return -1;
   186     }
   187 
   188     opened = 0;
   189     for (i = 0; SDL_haptics[i]; i++) {
   190         if (SDL_haptics[i]->index == (Uint8) device_index) {
   191             opened = 1;
   192             break;
   193         }
   194     }
   195     return opened;
   196 }
   197 
   198 
   199 /*
   200  * Returns the index to a haptic device.
   201  */
   202 int
   203 SDL_HapticIndex(SDL_Haptic * haptic)
   204 {
   205     if (!ValidHaptic(haptic)) {
   206         return -1;
   207     }
   208 
   209     return haptic->index;
   210 }
   211 
   212 
   213 /*
   214  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
   215  */
   216 int
   217 SDL_MouseIsHaptic(void)
   218 {
   219     if (SDL_SYS_HapticMouse() < 0)
   220         return SDL_FALSE;
   221     return SDL_TRUE;
   222 }
   223 
   224 
   225 /*
   226  * Returns the haptic device if mouse is haptic or NULL elsewise.
   227  */
   228 SDL_Haptic *
   229 SDL_HapticOpenFromMouse(void)
   230 {
   231     int device_index;
   232 
   233     device_index = SDL_SYS_HapticMouse();
   234 
   235     if (device_index < 0) {
   236         SDL_SetError("Haptic: Mouse isn't a haptic device.");
   237         return NULL;
   238     }
   239 
   240     return SDL_HapticOpen(device_index);
   241 }
   242 
   243 
   244 /*
   245  * Returns SDL_TRUE if joystick has haptic features.
   246  */
   247 int
   248 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   249 {
   250     int ret;
   251 
   252     /* Must be a valid joystick */
   253     if (!SDL_PrivateJoystickValid(joystick)) {
   254         return -1;
   255     }
   256 
   257     ret = SDL_SYS_JoystickIsHaptic(joystick);
   258 
   259     if (ret > 0)
   260         return SDL_TRUE;
   261     else if (ret == 0)
   262         return SDL_FALSE;
   263     else
   264         return -1;
   265 }
   266 
   267 
   268 /*
   269  * Opens a haptic device from a joystick.
   270  */
   271 SDL_Haptic *
   272 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   273 {
   274     int i;
   275     SDL_Haptic *haptic;
   276 
   277     /* Make sure there is room. */
   278     if (SDL_numhaptics <= 0) {
   279         SDL_SetError("Haptic: There are %d haptic devices available",
   280                      SDL_numhaptics);
   281         return NULL;
   282     }
   283 
   284     /* Must be a valid joystick */
   285     if (!SDL_PrivateJoystickValid(joystick)) {
   286         SDL_SetError("Haptic: Joystick isn't valid.");
   287         return NULL;
   288     }
   289 
   290     /* Joystick must be haptic */
   291     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   292         SDL_SetError("Haptic: Joystick isn't a haptic device.");
   293         return NULL;
   294     }
   295 
   296     /* Check to see if joystick's haptic is already open */
   297     for (i = 0; SDL_haptics[i]; i++) {
   298         if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
   299             haptic = SDL_haptics[i];
   300             ++haptic->ref_count;
   301             return haptic;
   302         }
   303     }
   304 
   305     /* Create the haptic device */
   306     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   307     if (haptic == NULL) {
   308         SDL_OutOfMemory();
   309         return NULL;
   310     }
   311 
   312     /* Initialize the haptic device */
   313     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   314     haptic->rumble_id = -1;
   315     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
   316         SDL_free(haptic);
   317         return NULL;
   318     }
   319 
   320     /* Add haptic to list */
   321     for (i = 0; SDL_haptics[i]; i++)
   322         /* Skip to next haptic */ ;
   323     if (i >= SDL_numhaptics) {
   324         SDL_free(haptic);
   325         SDL_SetError("Haptic: Trying to add device past the number originally detected");
   326         return NULL;
   327     }
   328     SDL_haptics[i] = haptic;
   329     ++haptic->ref_count;
   330 
   331     return haptic;
   332 }
   333 
   334 
   335 /*
   336  * Closes a SDL_Haptic device.
   337  */
   338 void
   339 SDL_HapticClose(SDL_Haptic * haptic)
   340 {
   341     int i;
   342 
   343     /* Must be valid */
   344     if (!ValidHaptic(haptic)) {
   345         return;
   346     }
   347 
   348     /* Check if it's still in use */
   349     if (--haptic->ref_count < 0) {
   350         return;
   351     }
   352 
   353     /* Close it, properly removing effects if needed */
   354     for (i = 0; i < haptic->neffects; i++) {
   355         if (haptic->effects[i].hweffect != NULL) {
   356             SDL_HapticDestroyEffect(haptic, i);
   357         }
   358     }
   359     SDL_SYS_HapticClose(haptic);
   360 
   361     /* Remove from the list */
   362     for (i = 0; SDL_haptics[i]; ++i) {
   363         if (haptic == SDL_haptics[i]) {
   364             SDL_haptics[i] = NULL;
   365             SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   366                        (SDL_numhaptics - i) * sizeof(haptic));
   367             break;
   368         }
   369     }
   370 
   371     /* Free */
   372     SDL_free(haptic);
   373 }
   374 
   375 /*
   376  * Cleans up after the subsystem.
   377  */
   378 void
   379 SDL_HapticQuit(void)
   380 {
   381     SDL_SYS_HapticQuit();
   382     if (SDL_haptics != NULL) {
   383         SDL_free(SDL_haptics);
   384         SDL_haptics = NULL;
   385     }
   386     SDL_numhaptics = 0;
   387 }
   388 
   389 /*
   390  * Returns the number of effects a haptic device has.
   391  */
   392 int
   393 SDL_HapticNumEffects(SDL_Haptic * haptic)
   394 {
   395     if (!ValidHaptic(haptic)) {
   396         return -1;
   397     }
   398 
   399     return haptic->neffects;
   400 }
   401 
   402 
   403 /*
   404  * Returns the number of effects a haptic device can play.
   405  */
   406 int
   407 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
   408 {
   409     if (!ValidHaptic(haptic)) {
   410         return -1;
   411     }
   412 
   413     return haptic->nplaying;
   414 }
   415 
   416 
   417 /*
   418  * Returns supported effects by the device.
   419  */
   420 unsigned int
   421 SDL_HapticQuery(SDL_Haptic * haptic)
   422 {
   423     if (!ValidHaptic(haptic)) {
   424         return 0; /* same as if no effects were supported */
   425     }
   426 
   427     return haptic->supported;
   428 }
   429 
   430 
   431 /*
   432  * Returns the number of axis on the device.
   433  */
   434 int
   435 SDL_HapticNumAxes(SDL_Haptic * haptic)
   436 {
   437     if (!ValidHaptic(haptic)) {
   438         return -1;
   439     }
   440 
   441     return haptic->naxes;
   442 }
   443 
   444 /*
   445  * Checks to see if the device can support the effect.
   446  */
   447 int
   448 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   449 {
   450     if (!ValidHaptic(haptic)) {
   451         return -1;
   452     }
   453 
   454     if ((haptic->supported & effect->type) != 0)
   455         return SDL_TRUE;
   456     return SDL_FALSE;
   457 }
   458 
   459 /*
   460  * Creates a new haptic effect.
   461  */
   462 int
   463 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   464 {
   465     int i;
   466 
   467     /* Check for device validity. */
   468     if (!ValidHaptic(haptic)) {
   469         return -1;
   470     }
   471 
   472     /* Check to see if effect is supported */
   473     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
   474         return SDL_SetError("Haptic: Effect not supported by haptic device.");
   475     }
   476 
   477     /* See if there's a free slot */
   478     for (i = 0; i < haptic->neffects; i++) {
   479         if (haptic->effects[i].hweffect == NULL) {
   480 
   481             /* Now let the backend create the real effect */
   482             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
   483                 != 0) {
   484                 return -1;      /* Backend failed to create effect */
   485             }
   486 
   487             SDL_memcpy(&haptic->effects[i].effect, effect,
   488                        sizeof(SDL_HapticEffect));
   489             return i;
   490         }
   491     }
   492 
   493     return SDL_SetError("Haptic: Device has no free space left.");
   494 }
   495 
   496 /*
   497  * Checks to see if an effect is valid.
   498  */
   499 static int
   500 ValidEffect(SDL_Haptic * haptic, int effect)
   501 {
   502     if ((effect < 0) || (effect >= haptic->neffects)) {
   503         SDL_SetError("Haptic: Invalid effect identifier.");
   504         return 0;
   505     }
   506     return 1;
   507 }
   508 
   509 /*
   510  * Updates an effect.
   511  */
   512 int
   513 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
   514                        SDL_HapticEffect * data)
   515 {
   516     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   517         return -1;
   518     }
   519 
   520     /* Can't change type dynamically. */
   521     if (data->type != haptic->effects[effect].effect.type) {
   522         return SDL_SetError("Haptic: Updating effect type is illegal.");
   523     }
   524 
   525     /* Updates the effect */
   526     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
   527         0) {
   528         return -1;
   529     }
   530 
   531     SDL_memcpy(&haptic->effects[effect].effect, data,
   532                sizeof(SDL_HapticEffect));
   533     return effect;
   534 }
   535 
   536 
   537 /*
   538  * Runs the haptic effect on the device.
   539  */
   540 int
   541 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
   542 {
   543     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   544         return -1;
   545     }
   546 
   547     /* Run the effect */
   548     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
   549         < 0) {
   550         return -1;
   551     }
   552 
   553     return 0;
   554 }
   555 
   556 /*
   557  * Stops the haptic effect on the device.
   558  */
   559 int
   560 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   561 {
   562     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   563         return -1;
   564     }
   565 
   566     /* Stop the effect */
   567     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
   568         return -1;
   569     }
   570 
   571     return 0;
   572 }
   573 
   574 /*
   575  * Gets rid of a haptic effect.
   576  */
   577 void
   578 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   579 {
   580     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   581         return;
   582     }
   583 
   584     /* Not allocated */
   585     if (haptic->effects[effect].hweffect == NULL) {
   586         return;
   587     }
   588 
   589     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   590 }
   591 
   592 /*
   593  * Gets the status of a haptic effect.
   594  */
   595 int
   596 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
   597 {
   598     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   599         return -1;
   600     }
   601 
   602     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   603         return SDL_SetError("Haptic: Device does not support status queries.");
   604     }
   605 
   606     return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   607 }
   608 
   609 /*
   610  * Sets the global gain of the device.
   611  */
   612 int
   613 SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
   614 {
   615     const char *env;
   616     int real_gain, max_gain;
   617 
   618     if (!ValidHaptic(haptic)) {
   619         return -1;
   620     }
   621 
   622     if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   623         return SDL_SetError("Haptic: Device does not support setting gain.");
   624     }
   625 
   626     if ((gain < 0) || (gain > 100)) {
   627         return SDL_SetError("Haptic: Gain must be between 0 and 100.");
   628     }
   629 
   630     /* We use the envvar to get the maximum gain. */
   631     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   632     if (env != NULL) {
   633         max_gain = SDL_atoi(env);
   634 
   635         /* Check for sanity. */
   636         if (max_gain < 0)
   637             max_gain = 0;
   638         else if (max_gain > 100)
   639             max_gain = 100;
   640 
   641         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   642         real_gain = (gain * max_gain) / 100;
   643     } else {
   644         real_gain = gain;
   645     }
   646 
   647     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
   648         return -1;
   649     }
   650 
   651     return 0;
   652 }
   653 
   654 /*
   655  * Makes the device autocenter, 0 disables.
   656  */
   657 int
   658 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   659 {
   660     if (!ValidHaptic(haptic)) {
   661         return -1;
   662     }
   663 
   664     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   665         return SDL_SetError("Haptic: Device does not support setting autocenter.");
   666     }
   667 
   668     if ((autocenter < 0) || (autocenter > 100)) {
   669         return SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
   670     }
   671 
   672     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
   673         return -1;
   674     }
   675 
   676     return 0;
   677 }
   678 
   679 /*
   680  * Pauses the haptic device.
   681  */
   682 int
   683 SDL_HapticPause(SDL_Haptic * haptic)
   684 {
   685     if (!ValidHaptic(haptic)) {
   686         return -1;
   687     }
   688 
   689     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   690         return SDL_SetError("Haptic: Device does not support setting pausing.");
   691     }
   692 
   693     return SDL_SYS_HapticPause(haptic);
   694 }
   695 
   696 /*
   697  * Unpauses the haptic device.
   698  */
   699 int
   700 SDL_HapticUnpause(SDL_Haptic * haptic)
   701 {
   702     if (!ValidHaptic(haptic)) {
   703         return -1;
   704     }
   705 
   706     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   707         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
   708     }
   709 
   710     return SDL_SYS_HapticUnpause(haptic);
   711 }
   712 
   713 /*
   714  * Stops all the currently playing effects.
   715  */
   716 int
   717 SDL_HapticStopAll(SDL_Haptic * haptic)
   718 {
   719     if (!ValidHaptic(haptic)) {
   720         return -1;
   721     }
   722 
   723     return SDL_SYS_HapticStopAll(haptic);
   724 }
   725 
   726 static void
   727 SDL_HapticRumbleCreate(SDL_HapticEffect * efx)
   728 {
   729    SDL_memset(efx, 0, sizeof(SDL_HapticEffect));
   730    efx->type = SDL_HAPTIC_SINE;
   731    efx->periodic.period = 1000;
   732    efx->periodic.magnitude = 0x4000;
   733    efx->periodic.length = 5000;
   734    efx->periodic.attack_length = 0;
   735    efx->periodic.fade_length = 0;
   736 }
   737 
   738 /*
   739  * Checks to see if rumble is supported.
   740  */
   741 int
   742 SDL_HapticRumbleSupported(SDL_Haptic * haptic)
   743 {
   744     SDL_HapticEffect efx;
   745 
   746     if (!ValidHaptic(haptic)) {
   747         return -1;
   748     }
   749 
   750     SDL_HapticRumbleCreate(&efx);
   751     return SDL_HapticEffectSupported(haptic, &efx);
   752 }
   753 
   754 /*
   755  * Initializes the haptic device for simple rumble playback.
   756  */
   757 int
   758 SDL_HapticRumbleInit(SDL_Haptic * haptic)
   759 {
   760     if (!ValidHaptic(haptic)) {
   761         return -1;
   762     }
   763 
   764     /* Already allocated. */
   765     if (haptic->rumble_id >= 0) {
   766         return 0;
   767     }
   768 
   769     /* Copy over. */
   770     SDL_HapticRumbleCreate(&haptic->rumble_effect);
   771     haptic->rumble_id = SDL_HapticNewEffect(haptic, &haptic->rumble_effect);
   772     if (haptic->rumble_id >= 0) {
   773         return 0;
   774     }
   775     return -1;
   776 }
   777 
   778 /*
   779  * Runs simple rumble on a haptic device
   780  */
   781 int
   782 SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length)
   783 {
   784     int ret;
   785     SDL_HapticPeriodic *efx;
   786 
   787     if (!ValidHaptic(haptic)) {
   788         return -1;
   789     }
   790 
   791     if (haptic->rumble_id < 0) {
   792         return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
   793     }
   794 
   795     /* Clamp strength. */
   796     if (strength > 1.0f) {
   797         strength = 1.0f;
   798     }
   799     else if (strength < 0.0f) {
   800         strength = 0.0f;
   801     }
   802 
   803     /* New effect. */
   804     efx = &haptic->rumble_effect.periodic;
   805     efx->magnitude = (Sint16)(32767.0f*strength);
   806     efx->length = length;
   807     ret = SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect);
   808     if (ret) {
   809         return ret;
   810     }
   811 
   812     return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1);
   813 }
   814 
   815 /*
   816  * Stops the simple rumble on a haptic device.
   817  */
   818 int
   819 SDL_HapticRumbleStop(SDL_Haptic * haptic)
   820 {
   821     if (!ValidHaptic(haptic)) {
   822         return -1;
   823     }
   824 
   825     if (haptic->rumble_id < 0) {
   826         return SDL_SetError("Haptic: Rumble effect not initialized on haptic device");
   827     }
   828 
   829     return SDL_HapticStopEffect(haptic, haptic->rumble_id);
   830 }
   831 
   832