src/haptic/SDL_haptic.c
author Edgar Simo <bobbens@gmail.com>
Sat, 21 Feb 2009 18:03:22 +0000
changeset 3080 4094b4f1c3a1
parent 2713 0906692aa6a4
child 3232 aa8de4b80772
permissions -rw-r--r--
More verbosity and error checking.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 2008 Edgar Simo
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_syshaptic.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->index = device_index;
   146     if (SDL_SYS_HapticOpen(haptic) < 0) {
   147         SDL_free(haptic);
   148         return NULL;
   149     }
   150 
   151     /* Disable autocenter and set gain to max. */
   152     if (haptic->supported & SDL_HAPTIC_GAIN)
   153         SDL_HapticSetGain(haptic, 100);
   154     if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
   155         SDL_HapticSetAutocenter(haptic, 0);
   156 
   157     /* Add haptic to list */
   158     ++haptic->ref_count;
   159     for (i = 0; SDL_haptics[i]; i++)
   160         /* Skip to next haptic */ ;
   161     SDL_haptics[i] = haptic;
   162 
   163     return haptic;
   164 }
   165 
   166 
   167 /*
   168  * Returns 1 if the device has been opened.
   169  */
   170 int
   171 SDL_HapticOpened(int device_index)
   172 {
   173     int i, opened;
   174 
   175     opened = 0;
   176     for (i = 0; SDL_haptics[i]; i++) {
   177         if (SDL_haptics[i]->index == (Uint8) device_index) {
   178             opened = 1;
   179             break;
   180         }
   181     }
   182     return opened;
   183 }
   184 
   185 
   186 /*
   187  * Returns the index to a haptic device.
   188  */
   189 int
   190 SDL_HapticIndex(SDL_Haptic * haptic)
   191 {
   192     if (!ValidHaptic(haptic)) {
   193         return -1;
   194     }
   195 
   196     return haptic->index;
   197 }
   198 
   199 
   200 /*
   201  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
   202  */
   203 int
   204 SDL_MouseIsHaptic(void)
   205 {
   206     if (SDL_SYS_HapticMouse() < 0)
   207         return SDL_FALSE;
   208     return SDL_TRUE;
   209 }
   210 
   211 
   212 /*
   213  * Returns the haptic device if mouse is haptic or NULL elsewise.
   214  */
   215 SDL_Haptic *
   216 SDL_HapticOpenFromMouse(void)
   217 {
   218     int device_index;
   219 
   220     device_index = SDL_SYS_HapticMouse();
   221 
   222     if (device_index < 0) {
   223         SDL_SetError("Haptic: Mouse isn't a haptic device.");
   224         return NULL;
   225     }
   226 
   227     return SDL_HapticOpen(device_index);
   228 }
   229 
   230 
   231 /*
   232  * Returns SDL_TRUE if joystick has haptic features.
   233  */
   234 int
   235 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   236 {
   237     int ret;
   238 
   239     /* Must be a valid joystick */
   240     if (!SDL_PrivateJoystickValid(&joystick)) {
   241         return -1;
   242     }
   243 
   244     ret = SDL_SYS_JoystickIsHaptic(joystick);
   245 
   246     if (ret > 0)
   247         return SDL_TRUE;
   248     else if (ret == 0)
   249         return SDL_FALSE;
   250     else
   251         return -1;
   252 }
   253 
   254 
   255 /*
   256  * Opens a haptic device from a joystick.
   257  */
   258 SDL_Haptic *
   259 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   260 {
   261     int i;
   262     SDL_Haptic *haptic;
   263 
   264     /* Must be a valid joystick */
   265     if (!SDL_PrivateJoystickValid(&joystick)) {
   266         return NULL;
   267     }
   268 
   269     /* Joystick must be haptic */
   270     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   271         return NULL;
   272     }
   273 
   274     /* Check to see if joystick's haptic is already open */
   275     for (i = 0; SDL_haptics[i]; i++) {
   276         if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
   277             haptic = SDL_haptics[i];
   278             ++haptic->ref_count;
   279             return haptic;
   280         }
   281     }
   282 
   283     /* Create the haptic device */
   284     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   285     if (haptic == NULL) {
   286         SDL_OutOfMemory();
   287         return NULL;
   288     }
   289 
   290     /* Initialize the haptic device */
   291     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   292     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
   293         SDL_free(haptic);
   294         return NULL;
   295     }
   296 
   297     /* Add haptic to list */
   298     ++haptic->ref_count;
   299     for (i = 0; SDL_haptics[i]; i++)
   300         /* Skip to next haptic */ ;
   301     SDL_haptics[i] = haptic;
   302 
   303     return haptic;
   304 }
   305 
   306 
   307 /*
   308  * Closes a SDL_Haptic device.
   309  */
   310 void
   311 SDL_HapticClose(SDL_Haptic * haptic)
   312 {
   313     int i;
   314 
   315     /* Must be valid */
   316     if (!ValidHaptic(haptic)) {
   317         return;
   318     }
   319 
   320     /* Check if it's still in use */
   321     if (--haptic->ref_count < 0) {
   322         return;
   323     }
   324 
   325     /* Close it, properly removing effects if needed */
   326     for (i = 0; i < haptic->neffects; i++) {
   327         if (haptic->effects[i].hweffect != NULL) {
   328             SDL_HapticDestroyEffect(haptic, i);
   329         }
   330     }
   331     SDL_SYS_HapticClose(haptic);
   332 
   333     /* Remove from the list */
   334     for (i = 0; SDL_haptics[i]; ++i) {
   335         if (haptic == SDL_haptics[i]) {
   336             SDL_haptics[i] = NULL;
   337             SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   338                        (SDL_numhaptics - i) * sizeof(haptic));
   339             break;
   340         }
   341     }
   342 
   343     /* Free */
   344     SDL_free(haptic);
   345 }
   346 
   347 /*
   348  * Cleans up after the subsystem.
   349  */
   350 void
   351 SDL_HapticQuit(void)
   352 {
   353     SDL_SYS_HapticQuit();
   354     if (SDL_haptics != NULL) {
   355         SDL_free(SDL_haptics);
   356         SDL_haptics = NULL;
   357     }
   358     SDL_numhaptics = 0;
   359 }
   360 
   361 /*
   362  * Returns the number of effects a haptic device has.
   363  */
   364 int
   365 SDL_HapticNumEffects(SDL_Haptic * haptic)
   366 {
   367     if (!ValidHaptic(haptic)) {
   368         return -1;
   369     }
   370 
   371     return haptic->neffects;
   372 }
   373 
   374 
   375 /*
   376  * Returns the number of effects a haptic device can play.
   377  */
   378 int
   379 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
   380 {
   381     if (!ValidHaptic(haptic)) {
   382         return -1;
   383     }
   384 
   385     return haptic->nplaying;
   386 }
   387 
   388 
   389 /*
   390  * Returns supported effects by the device.
   391  */
   392 unsigned int
   393 SDL_HapticQuery(SDL_Haptic * haptic)
   394 {
   395     if (!ValidHaptic(haptic)) {
   396         return -1;
   397     }
   398 
   399     return haptic->supported;
   400 }
   401 
   402 
   403 /*
   404  * Returns the number of axis on the device.
   405  */
   406 int
   407 SDL_HapticNumAxes(SDL_Haptic * haptic)
   408 {
   409     if (!ValidHaptic(haptic)) {
   410         return -1;
   411     }
   412 
   413     return haptic->naxes;
   414 }
   415 
   416 /*
   417  * Checks to see if the device can support the effect.
   418  */
   419 int
   420 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   421 {
   422     if (!ValidHaptic(haptic)) {
   423         return -1;
   424     }
   425 
   426     if ((haptic->supported & effect->type) != 0)
   427         return SDL_TRUE;
   428     return SDL_FALSE;
   429 }
   430 
   431 /*
   432  * Creates a new haptic effect.
   433  */
   434 int
   435 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   436 {
   437     int i;
   438 
   439     /* Check for device validity. */
   440     if (!ValidHaptic(haptic)) {
   441         return -1;
   442     }
   443 
   444     /* Check to see if effect is supported */
   445     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
   446         SDL_SetError("Haptic: Effect not supported by haptic device.");
   447         return -1;
   448     }
   449 
   450     /* See if there's a free slot */
   451     for (i = 0; i < haptic->neffects; i++) {
   452         if (haptic->effects[i].hweffect == NULL) {
   453 
   454             /* Now let the backend create the real effect */
   455             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
   456                 != 0) {
   457                 return -1;      /* Backend failed to create effect */
   458             }
   459 
   460             SDL_memcpy(&haptic->effects[i].effect, effect,
   461                        sizeof(SDL_HapticEffect));
   462             return i;
   463         }
   464     }
   465 
   466     SDL_SetError("Haptic: Device has no free space left.");
   467     return -1;
   468 }
   469 
   470 /*
   471  * Checks to see if an effect is valid.
   472  */
   473 static int
   474 ValidEffect(SDL_Haptic * haptic, int effect)
   475 {
   476     if ((effect < 0) || (effect >= haptic->neffects)) {
   477         SDL_SetError("Haptic: Invalid effect identifier.");
   478         return 0;
   479     }
   480     return 1;
   481 }
   482 
   483 /*
   484  * Updates an effect.
   485  */
   486 int
   487 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
   488                        SDL_HapticEffect * data)
   489 {
   490     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   491         return -1;
   492     }
   493 
   494     /* Can't change type dynamically. */
   495     if (data->type != haptic->effects[effect].effect.type) {
   496         SDL_SetError("Haptic: Updating effect type is illegal.");
   497         return -1;
   498     }
   499 
   500     /* Updates the effect */
   501     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
   502         0) {
   503         return -1;
   504     }
   505 
   506     SDL_memcpy(&haptic->effects[effect].effect, data,
   507                sizeof(SDL_HapticEffect));
   508     return 0;
   509 }
   510 
   511 
   512 /*
   513  * Runs the haptic effect on the device.
   514  */
   515 int
   516 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
   517 {
   518     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   519         return -1;
   520     }
   521 
   522     /* Run the effect */
   523     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
   524         < 0) {
   525         return -1;
   526     }
   527 
   528     return 0;
   529 }
   530 
   531 /*
   532  * Stops the haptic effect on the device.
   533  */
   534 int
   535 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   536 {
   537     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   538         return -1;
   539     }
   540 
   541     /* Stop the effect */
   542     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
   543         return -1;
   544     }
   545 
   546     return 0;
   547 }
   548 
   549 /*
   550  * Gets rid of a haptic effect.
   551  */
   552 void
   553 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   554 {
   555     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   556         return;
   557     }
   558 
   559     /* Not allocated */
   560     if (haptic->effects[effect].hweffect == NULL) {
   561         return;
   562     }
   563 
   564     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   565 }
   566 
   567 /*
   568  * Gets the status of a haptic effect.
   569  */
   570 int
   571 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
   572 {
   573     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   574         return -1;
   575     }
   576 
   577     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   578         SDL_SetError("Haptic: Device does not support status queries.");
   579         return -1;
   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         SDL_SetError("Haptic: Device does not support setting gain.");
   600         return -1;
   601     }
   602 
   603     if ((gain < 0) || (gain > 100)) {
   604         SDL_SetError("Haptic: Gain must be between 0 and 100.");
   605         return -1;
   606     }
   607 
   608     /* We use the envvar to get the maximum gain. */
   609     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   610     if (env != NULL) {
   611         max_gain = SDL_atoi(env);
   612 
   613         /* Check for sanity. */
   614         if (max_gain < 0)
   615             max_gain = 0;
   616         else if (max_gain > 100)
   617             max_gain = 100;
   618 
   619         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   620         real_gain = (gain * max_gain) / 100;
   621     } else {
   622         real_gain = gain;
   623     }
   624 
   625     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
   626         return -1;
   627     }
   628 
   629     return 0;
   630 }
   631 
   632 /*
   633  * Makes the device autocenter, 0 disables.
   634  */
   635 int
   636 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   637 {
   638     if (!ValidHaptic(haptic)) {
   639         return -1;
   640     }
   641 
   642     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   643         SDL_SetError("Haptic: Device does not support setting autocenter.");
   644         return -1;
   645     }
   646 
   647     if ((autocenter < 0) || (autocenter > 100)) {
   648         SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
   649         return -1;
   650     }
   651 
   652     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
   653         return -1;
   654     }
   655 
   656     return 0;
   657 }
   658 
   659 /*
   660  * Pauses the haptic device.
   661  */
   662 int
   663 SDL_HapticPause(SDL_Haptic * haptic)
   664 {
   665     if (!ValidHaptic(haptic)) {
   666         return -1;
   667     }
   668 
   669     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   670         SDL_SetError("Haptic: Device does not support setting pausing.");
   671         return -1;
   672     }
   673 
   674     return SDL_SYS_HapticPause(haptic);
   675 }
   676 
   677 /*
   678  * Unpauses the haptic device.
   679  */
   680 int
   681 SDL_HapticUnpause(SDL_Haptic * haptic)
   682 {
   683     if (!ValidHaptic(haptic)) {
   684         return -1;
   685     }
   686 
   687     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   688         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
   689     }
   690 
   691     return SDL_SYS_HapticUnpause(haptic);
   692 }
   693 
   694 /*
   695  * Stops all the currently playing effects.
   696  */
   697 int
   698 SDL_HapticStopAll(SDL_Haptic * haptic)
   699 {
   700     if (!ValidHaptic(haptic)) {
   701         return -1;
   702     }
   703 
   704     return SDL_SYS_HapticStopAll(haptic);
   705 }