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