src/haptic/SDL_haptic.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 12 Aug 2017 08:15:09 -0700
changeset 11238 c728c661cec7
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Fixed bug 3191 - haptic system on android?

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