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