src/haptic/SDL_haptic.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 26 Jun 2010 08:56:48 -0700
changeset 4472 791b3256fb22
parent 3232 aa8de4b80772
child 5360 220d3af9121f
permissions -rw-r--r--
Mostly cleaned up warnings with -Wmissing-prototypes
     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 "SDL_haptic_c.h"
    26 #include "../joystick/SDL_joystick_c.h" /* For SDL_PrivateJoystickValid */
    27 
    28 
    29 Uint8 SDL_numhaptics = 0;
    30 SDL_Haptic **SDL_haptics = NULL;
    31 
    32 
    33 /*
    34  * Initializes the Haptic devices.
    35  */
    36 int
    37 SDL_HapticInit(void)
    38 {
    39     int arraylen;
    40     int status;
    41 
    42     SDL_numhaptics = 0;
    43     status = SDL_SYS_HapticInit();
    44     if (status >= 0) {
    45         arraylen = (status + 1) * sizeof(*SDL_haptics);
    46         SDL_haptics = (SDL_Haptic **) SDL_malloc(arraylen);
    47         if (SDL_haptics == NULL) {      /* Out of memory. */
    48             SDL_numhaptics = 0;
    49         } else {
    50             SDL_memset(SDL_haptics, 0, arraylen);
    51             SDL_numhaptics = status;
    52         }
    53         status = 0;
    54     }
    55 
    56     return status;
    57 }
    58 
    59 
    60 /*
    61  * Checks to see if the haptic device is valid
    62  */
    63 static int
    64 ValidHaptic(SDL_Haptic * haptic)
    65 {
    66     int i;
    67     int valid;
    68 
    69     valid = 0;
    70     if (haptic != NULL) {
    71         for (i = 0; i < SDL_numhaptics; i++) {
    72             if (SDL_haptics[i] == haptic) {
    73                 valid = 1;
    74                 break;
    75             }
    76         }
    77     }
    78 
    79     /* Create the error here. */
    80     if (valid == 0) {
    81         SDL_SetError("Haptic: Invalid haptic device identifier");
    82     }
    83 
    84     return valid;
    85 }
    86 
    87 
    88 /*
    89  * Returns the number of available devices.
    90  */
    91 int
    92 SDL_NumHaptics(void)
    93 {
    94     return SDL_numhaptics;
    95 }
    96 
    97 
    98 /*
    99  * Gets the name of a Haptic device by index.
   100  */
   101 const char *
   102 SDL_HapticName(int device_index)
   103 {
   104     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   105         SDL_SetError("Haptic: There are %d haptic devices available",
   106                      SDL_numhaptics);
   107         return NULL;
   108     }
   109     return SDL_SYS_HapticName(device_index);
   110 }
   111 
   112 
   113 /*
   114  * Opens a Haptic device.
   115  */
   116 SDL_Haptic *
   117 SDL_HapticOpen(int device_index)
   118 {
   119     int i;
   120     SDL_Haptic *haptic;
   121 
   122     if ((device_index < 0) || (device_index >= SDL_numhaptics)) {
   123         SDL_SetError("Haptic: There are %d haptic devices available",
   124                      SDL_numhaptics);
   125         return NULL;
   126     }
   127 
   128     /* If the haptic is already open, return it */
   129     for (i = 0; SDL_haptics[i]; i++) {
   130         if (device_index == SDL_haptics[i]->index) {
   131             haptic = SDL_haptics[i];
   132             ++haptic->ref_count;
   133             return haptic;
   134         }
   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->index = device_index;
   147     if (SDL_SYS_HapticOpen(haptic) < 0) {
   148         SDL_free(haptic);
   149         return NULL;
   150     }
   151 
   152     /* Disable autocenter and set gain to max. */
   153     if (haptic->supported & SDL_HAPTIC_GAIN)
   154         SDL_HapticSetGain(haptic, 100);
   155     if (haptic->supported & SDL_HAPTIC_AUTOCENTER)
   156         SDL_HapticSetAutocenter(haptic, 0);
   157 
   158     /* Add haptic to list */
   159     ++haptic->ref_count;
   160     for (i = 0; SDL_haptics[i]; i++)
   161         /* Skip to next haptic */ ;
   162     SDL_haptics[i] = haptic;
   163 
   164     return haptic;
   165 }
   166 
   167 
   168 /*
   169  * Returns 1 if the device has been opened.
   170  */
   171 int
   172 SDL_HapticOpened(int device_index)
   173 {
   174     int i, opened;
   175 
   176     opened = 0;
   177     for (i = 0; SDL_haptics[i]; i++) {
   178         if (SDL_haptics[i]->index == (Uint8) device_index) {
   179             opened = 1;
   180             break;
   181         }
   182     }
   183     return opened;
   184 }
   185 
   186 
   187 /*
   188  * Returns the index to a haptic device.
   189  */
   190 int
   191 SDL_HapticIndex(SDL_Haptic * haptic)
   192 {
   193     if (!ValidHaptic(haptic)) {
   194         return -1;
   195     }
   196 
   197     return haptic->index;
   198 }
   199 
   200 
   201 /*
   202  * Returns SDL_TRUE if mouse is haptic, SDL_FALSE if it isn't.
   203  */
   204 int
   205 SDL_MouseIsHaptic(void)
   206 {
   207     if (SDL_SYS_HapticMouse() < 0)
   208         return SDL_FALSE;
   209     return SDL_TRUE;
   210 }
   211 
   212 
   213 /*
   214  * Returns the haptic device if mouse is haptic or NULL elsewise.
   215  */
   216 SDL_Haptic *
   217 SDL_HapticOpenFromMouse(void)
   218 {
   219     int device_index;
   220 
   221     device_index = SDL_SYS_HapticMouse();
   222 
   223     if (device_index < 0) {
   224         SDL_SetError("Haptic: Mouse isn't a haptic device.");
   225         return NULL;
   226     }
   227 
   228     return SDL_HapticOpen(device_index);
   229 }
   230 
   231 
   232 /*
   233  * Returns SDL_TRUE if joystick has haptic features.
   234  */
   235 int
   236 SDL_JoystickIsHaptic(SDL_Joystick * joystick)
   237 {
   238     int ret;
   239 
   240     /* Must be a valid joystick */
   241     if (!SDL_PrivateJoystickValid(&joystick)) {
   242         return -1;
   243     }
   244 
   245     ret = SDL_SYS_JoystickIsHaptic(joystick);
   246 
   247     if (ret > 0)
   248         return SDL_TRUE;
   249     else if (ret == 0)
   250         return SDL_FALSE;
   251     else
   252         return -1;
   253 }
   254 
   255 
   256 /*
   257  * Opens a haptic device from a joystick.
   258  */
   259 SDL_Haptic *
   260 SDL_HapticOpenFromJoystick(SDL_Joystick * joystick)
   261 {
   262     int i;
   263     SDL_Haptic *haptic;
   264 
   265     /* Must be a valid joystick */
   266     if (!SDL_PrivateJoystickValid(&joystick)) {
   267         SDL_SetError("Haptic: Joystick isn't valid.");
   268         return NULL;
   269     }
   270 
   271     /* Joystick must be haptic */
   272     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   273         SDL_SetError("Haptic: Joystick isn't a haptic device.");
   274         return NULL;
   275     }
   276 
   277     /* Check to see if joystick's haptic is already open */
   278     for (i = 0; SDL_haptics[i]; i++) {
   279         if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
   280             haptic = SDL_haptics[i];
   281             ++haptic->ref_count;
   282             return haptic;
   283         }
   284     }
   285 
   286     /* Create the haptic device */
   287     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   288     if (haptic == NULL) {
   289         SDL_OutOfMemory();
   290         return NULL;
   291     }
   292 
   293     /* Initialize the haptic device */
   294     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   295     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
   296         SDL_free(haptic);
   297         return NULL;
   298     }
   299 
   300     /* Add haptic to list */
   301     ++haptic->ref_count;
   302     for (i = 0; SDL_haptics[i]; i++)
   303         /* Skip to next haptic */ ;
   304     SDL_haptics[i] = haptic;
   305 
   306     return haptic;
   307 }
   308 
   309 
   310 /*
   311  * Closes a SDL_Haptic device.
   312  */
   313 void
   314 SDL_HapticClose(SDL_Haptic * haptic)
   315 {
   316     int i;
   317 
   318     /* Must be valid */
   319     if (!ValidHaptic(haptic)) {
   320         return;
   321     }
   322 
   323     /* Check if it's still in use */
   324     if (--haptic->ref_count < 0) {
   325         return;
   326     }
   327 
   328     /* Close it, properly removing effects if needed */
   329     for (i = 0; i < haptic->neffects; i++) {
   330         if (haptic->effects[i].hweffect != NULL) {
   331             SDL_HapticDestroyEffect(haptic, i);
   332         }
   333     }
   334     SDL_SYS_HapticClose(haptic);
   335 
   336     /* Remove from the list */
   337     for (i = 0; SDL_haptics[i]; ++i) {
   338         if (haptic == SDL_haptics[i]) {
   339             SDL_haptics[i] = NULL;
   340             SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   341                        (SDL_numhaptics - i) * sizeof(haptic));
   342             break;
   343         }
   344     }
   345 
   346     /* Free */
   347     SDL_free(haptic);
   348 }
   349 
   350 /*
   351  * Cleans up after the subsystem.
   352  */
   353 void
   354 SDL_HapticQuit(void)
   355 {
   356     SDL_SYS_HapticQuit();
   357     if (SDL_haptics != NULL) {
   358         SDL_free(SDL_haptics);
   359         SDL_haptics = NULL;
   360     }
   361     SDL_numhaptics = 0;
   362 }
   363 
   364 /*
   365  * Returns the number of effects a haptic device has.
   366  */
   367 int
   368 SDL_HapticNumEffects(SDL_Haptic * haptic)
   369 {
   370     if (!ValidHaptic(haptic)) {
   371         return -1;
   372     }
   373 
   374     return haptic->neffects;
   375 }
   376 
   377 
   378 /*
   379  * Returns the number of effects a haptic device can play.
   380  */
   381 int
   382 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
   383 {
   384     if (!ValidHaptic(haptic)) {
   385         return -1;
   386     }
   387 
   388     return haptic->nplaying;
   389 }
   390 
   391 
   392 /*
   393  * Returns supported effects by the device.
   394  */
   395 unsigned int
   396 SDL_HapticQuery(SDL_Haptic * haptic)
   397 {
   398     if (!ValidHaptic(haptic)) {
   399         return -1;
   400     }
   401 
   402     return haptic->supported;
   403 }
   404 
   405 
   406 /*
   407  * Returns the number of axis on the device.
   408  */
   409 int
   410 SDL_HapticNumAxes(SDL_Haptic * haptic)
   411 {
   412     if (!ValidHaptic(haptic)) {
   413         return -1;
   414     }
   415 
   416     return haptic->naxes;
   417 }
   418 
   419 /*
   420  * Checks to see if the device can support the effect.
   421  */
   422 int
   423 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   424 {
   425     if (!ValidHaptic(haptic)) {
   426         return -1;
   427     }
   428 
   429     if ((haptic->supported & effect->type) != 0)
   430         return SDL_TRUE;
   431     return SDL_FALSE;
   432 }
   433 
   434 /*
   435  * Creates a new haptic effect.
   436  */
   437 int
   438 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   439 {
   440     int i;
   441 
   442     /* Check for device validity. */
   443     if (!ValidHaptic(haptic)) {
   444         return -1;
   445     }
   446 
   447     /* Check to see if effect is supported */
   448     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
   449         SDL_SetError("Haptic: Effect not supported by haptic device.");
   450         return -1;
   451     }
   452 
   453     /* See if there's a free slot */
   454     for (i = 0; i < haptic->neffects; i++) {
   455         if (haptic->effects[i].hweffect == NULL) {
   456 
   457             /* Now let the backend create the real effect */
   458             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
   459                 != 0) {
   460                 return -1;      /* Backend failed to create effect */
   461             }
   462 
   463             SDL_memcpy(&haptic->effects[i].effect, effect,
   464                        sizeof(SDL_HapticEffect));
   465             return i;
   466         }
   467     }
   468 
   469     SDL_SetError("Haptic: Device has no free space left.");
   470     return -1;
   471 }
   472 
   473 /*
   474  * Checks to see if an effect is valid.
   475  */
   476 static int
   477 ValidEffect(SDL_Haptic * haptic, int effect)
   478 {
   479     if ((effect < 0) || (effect >= haptic->neffects)) {
   480         SDL_SetError("Haptic: Invalid effect identifier.");
   481         return 0;
   482     }
   483     return 1;
   484 }
   485 
   486 /*
   487  * Updates an effect.
   488  */
   489 int
   490 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
   491                        SDL_HapticEffect * data)
   492 {
   493     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   494         return -1;
   495     }
   496 
   497     /* Can't change type dynamically. */
   498     if (data->type != haptic->effects[effect].effect.type) {
   499         SDL_SetError("Haptic: Updating effect type is illegal.");
   500         return -1;
   501     }
   502 
   503     /* Updates the effect */
   504     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
   505         0) {
   506         return -1;
   507     }
   508 
   509     SDL_memcpy(&haptic->effects[effect].effect, data,
   510                sizeof(SDL_HapticEffect));
   511     return 0;
   512 }
   513 
   514 
   515 /*
   516  * Runs the haptic effect on the device.
   517  */
   518 int
   519 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
   520 {
   521     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   522         return -1;
   523     }
   524 
   525     /* Run the effect */
   526     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
   527         < 0) {
   528         return -1;
   529     }
   530 
   531     return 0;
   532 }
   533 
   534 /*
   535  * Stops the haptic effect on the device.
   536  */
   537 int
   538 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   539 {
   540     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   541         return -1;
   542     }
   543 
   544     /* Stop the effect */
   545     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
   546         return -1;
   547     }
   548 
   549     return 0;
   550 }
   551 
   552 /*
   553  * Gets rid of a haptic effect.
   554  */
   555 void
   556 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   557 {
   558     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   559         return;
   560     }
   561 
   562     /* Not allocated */
   563     if (haptic->effects[effect].hweffect == NULL) {
   564         return;
   565     }
   566 
   567     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   568 }
   569 
   570 /*
   571  * Gets the status of a haptic effect.
   572  */
   573 int
   574 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
   575 {
   576     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   577         return -1;
   578     }
   579 
   580     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   581         SDL_SetError("Haptic: Device does not support status queries.");
   582         return -1;
   583     }
   584 
   585     return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   586 }
   587 
   588 /*
   589  * Sets the global gain of the device.
   590  */
   591 int
   592 SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
   593 {
   594     const char *env;
   595     int real_gain, max_gain;
   596 
   597     if (!ValidHaptic(haptic)) {
   598         return -1;
   599     }
   600 
   601     if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   602         SDL_SetError("Haptic: Device does not support setting gain.");
   603         return -1;
   604     }
   605 
   606     if ((gain < 0) || (gain > 100)) {
   607         SDL_SetError("Haptic: Gain must be between 0 and 100.");
   608         return -1;
   609     }
   610 
   611     /* We use the envvar to get the maximum gain. */
   612     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   613     if (env != NULL) {
   614         max_gain = SDL_atoi(env);
   615 
   616         /* Check for sanity. */
   617         if (max_gain < 0)
   618             max_gain = 0;
   619         else if (max_gain > 100)
   620             max_gain = 100;
   621 
   622         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   623         real_gain = (gain * max_gain) / 100;
   624     } else {
   625         real_gain = gain;
   626     }
   627 
   628     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
   629         return -1;
   630     }
   631 
   632     return 0;
   633 }
   634 
   635 /*
   636  * Makes the device autocenter, 0 disables.
   637  */
   638 int
   639 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   640 {
   641     if (!ValidHaptic(haptic)) {
   642         return -1;
   643     }
   644 
   645     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   646         SDL_SetError("Haptic: Device does not support setting autocenter.");
   647         return -1;
   648     }
   649 
   650     if ((autocenter < 0) || (autocenter > 100)) {
   651         SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
   652         return -1;
   653     }
   654 
   655     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
   656         return -1;
   657     }
   658 
   659     return 0;
   660 }
   661 
   662 /*
   663  * Pauses the haptic device.
   664  */
   665 int
   666 SDL_HapticPause(SDL_Haptic * haptic)
   667 {
   668     if (!ValidHaptic(haptic)) {
   669         return -1;
   670     }
   671 
   672     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   673         SDL_SetError("Haptic: Device does not support setting pausing.");
   674         return -1;
   675     }
   676 
   677     return SDL_SYS_HapticPause(haptic);
   678 }
   679 
   680 /*
   681  * Unpauses the haptic device.
   682  */
   683 int
   684 SDL_HapticUnpause(SDL_Haptic * haptic)
   685 {
   686     if (!ValidHaptic(haptic)) {
   687         return -1;
   688     }
   689 
   690     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   691         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
   692     }
   693 
   694     return SDL_SYS_HapticUnpause(haptic);
   695 }
   696 
   697 /*
   698  * Stops all the currently playing effects.
   699  */
   700 int
   701 SDL_HapticStopAll(SDL_Haptic * haptic)
   702 {
   703     if (!ValidHaptic(haptic)) {
   704         return -1;
   705     }
   706 
   707     return SDL_SYS_HapticStopAll(haptic);
   708 }