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