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