src/haptic/SDL_haptic.c
author Edgar Simo <bobbens@gmail.com>
Wed, 05 Aug 2009 16:31:49 +0000
changeset 3232 aa8de4b80772
parent 3080 4094b4f1c3a1
child 4472 791b3256fb22
permissions -rw-r--r--
Patch by Janosch Gräf <janosch.graef@gmx.net>

I just noticed that there are rarely error messages and added some.
     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         SDL_SetError("Haptic: Joystick isn't valid.");
   267         return NULL;
   268     }
   269 
   270     /* Joystick must be haptic */
   271     if (SDL_SYS_JoystickIsHaptic(joystick) <= 0) {
   272         SDL_SetError("Haptic: Joystick isn't a haptic device.");
   273         return NULL;
   274     }
   275 
   276     /* Check to see if joystick's haptic is already open */
   277     for (i = 0; SDL_haptics[i]; i++) {
   278         if (SDL_SYS_JoystickSameHaptic(SDL_haptics[i], joystick)) {
   279             haptic = SDL_haptics[i];
   280             ++haptic->ref_count;
   281             return haptic;
   282         }
   283     }
   284 
   285     /* Create the haptic device */
   286     haptic = (SDL_Haptic *) SDL_malloc((sizeof *haptic));
   287     if (haptic == NULL) {
   288         SDL_OutOfMemory();
   289         return NULL;
   290     }
   291 
   292     /* Initialize the haptic device */
   293     SDL_memset(haptic, 0, sizeof(SDL_Haptic));
   294     if (SDL_SYS_HapticOpenFromJoystick(haptic, joystick) < 0) {
   295         SDL_free(haptic);
   296         return NULL;
   297     }
   298 
   299     /* Add haptic to list */
   300     ++haptic->ref_count;
   301     for (i = 0; SDL_haptics[i]; i++)
   302         /* Skip to next haptic */ ;
   303     SDL_haptics[i] = haptic;
   304 
   305     return haptic;
   306 }
   307 
   308 
   309 /*
   310  * Closes a SDL_Haptic device.
   311  */
   312 void
   313 SDL_HapticClose(SDL_Haptic * haptic)
   314 {
   315     int i;
   316 
   317     /* Must be valid */
   318     if (!ValidHaptic(haptic)) {
   319         return;
   320     }
   321 
   322     /* Check if it's still in use */
   323     if (--haptic->ref_count < 0) {
   324         return;
   325     }
   326 
   327     /* Close it, properly removing effects if needed */
   328     for (i = 0; i < haptic->neffects; i++) {
   329         if (haptic->effects[i].hweffect != NULL) {
   330             SDL_HapticDestroyEffect(haptic, i);
   331         }
   332     }
   333     SDL_SYS_HapticClose(haptic);
   334 
   335     /* Remove from the list */
   336     for (i = 0; SDL_haptics[i]; ++i) {
   337         if (haptic == SDL_haptics[i]) {
   338             SDL_haptics[i] = NULL;
   339             SDL_memcpy(&SDL_haptics[i], &SDL_haptics[i + 1],
   340                        (SDL_numhaptics - i) * sizeof(haptic));
   341             break;
   342         }
   343     }
   344 
   345     /* Free */
   346     SDL_free(haptic);
   347 }
   348 
   349 /*
   350  * Cleans up after the subsystem.
   351  */
   352 void
   353 SDL_HapticQuit(void)
   354 {
   355     SDL_SYS_HapticQuit();
   356     if (SDL_haptics != NULL) {
   357         SDL_free(SDL_haptics);
   358         SDL_haptics = NULL;
   359     }
   360     SDL_numhaptics = 0;
   361 }
   362 
   363 /*
   364  * Returns the number of effects a haptic device has.
   365  */
   366 int
   367 SDL_HapticNumEffects(SDL_Haptic * haptic)
   368 {
   369     if (!ValidHaptic(haptic)) {
   370         return -1;
   371     }
   372 
   373     return haptic->neffects;
   374 }
   375 
   376 
   377 /*
   378  * Returns the number of effects a haptic device can play.
   379  */
   380 int
   381 SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic)
   382 {
   383     if (!ValidHaptic(haptic)) {
   384         return -1;
   385     }
   386 
   387     return haptic->nplaying;
   388 }
   389 
   390 
   391 /*
   392  * Returns supported effects by the device.
   393  */
   394 unsigned int
   395 SDL_HapticQuery(SDL_Haptic * haptic)
   396 {
   397     if (!ValidHaptic(haptic)) {
   398         return -1;
   399     }
   400 
   401     return haptic->supported;
   402 }
   403 
   404 
   405 /*
   406  * Returns the number of axis on the device.
   407  */
   408 int
   409 SDL_HapticNumAxes(SDL_Haptic * haptic)
   410 {
   411     if (!ValidHaptic(haptic)) {
   412         return -1;
   413     }
   414 
   415     return haptic->naxes;
   416 }
   417 
   418 /*
   419  * Checks to see if the device can support the effect.
   420  */
   421 int
   422 SDL_HapticEffectSupported(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   423 {
   424     if (!ValidHaptic(haptic)) {
   425         return -1;
   426     }
   427 
   428     if ((haptic->supported & effect->type) != 0)
   429         return SDL_TRUE;
   430     return SDL_FALSE;
   431 }
   432 
   433 /*
   434  * Creates a new haptic effect.
   435  */
   436 int
   437 SDL_HapticNewEffect(SDL_Haptic * haptic, SDL_HapticEffect * effect)
   438 {
   439     int i;
   440 
   441     /* Check for device validity. */
   442     if (!ValidHaptic(haptic)) {
   443         return -1;
   444     }
   445 
   446     /* Check to see if effect is supported */
   447     if (SDL_HapticEffectSupported(haptic, effect) == SDL_FALSE) {
   448         SDL_SetError("Haptic: Effect not supported by haptic device.");
   449         return -1;
   450     }
   451 
   452     /* See if there's a free slot */
   453     for (i = 0; i < haptic->neffects; i++) {
   454         if (haptic->effects[i].hweffect == NULL) {
   455 
   456             /* Now let the backend create the real effect */
   457             if (SDL_SYS_HapticNewEffect(haptic, &haptic->effects[i], effect)
   458                 != 0) {
   459                 return -1;      /* Backend failed to create effect */
   460             }
   461 
   462             SDL_memcpy(&haptic->effects[i].effect, effect,
   463                        sizeof(SDL_HapticEffect));
   464             return i;
   465         }
   466     }
   467 
   468     SDL_SetError("Haptic: Device has no free space left.");
   469     return -1;
   470 }
   471 
   472 /*
   473  * Checks to see if an effect is valid.
   474  */
   475 static int
   476 ValidEffect(SDL_Haptic * haptic, int effect)
   477 {
   478     if ((effect < 0) || (effect >= haptic->neffects)) {
   479         SDL_SetError("Haptic: Invalid effect identifier.");
   480         return 0;
   481     }
   482     return 1;
   483 }
   484 
   485 /*
   486  * Updates an effect.
   487  */
   488 int
   489 SDL_HapticUpdateEffect(SDL_Haptic * haptic, int effect,
   490                        SDL_HapticEffect * data)
   491 {
   492     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   493         return -1;
   494     }
   495 
   496     /* Can't change type dynamically. */
   497     if (data->type != haptic->effects[effect].effect.type) {
   498         SDL_SetError("Haptic: Updating effect type is illegal.");
   499         return -1;
   500     }
   501 
   502     /* Updates the effect */
   503     if (SDL_SYS_HapticUpdateEffect(haptic, &haptic->effects[effect], data) <
   504         0) {
   505         return -1;
   506     }
   507 
   508     SDL_memcpy(&haptic->effects[effect].effect, data,
   509                sizeof(SDL_HapticEffect));
   510     return 0;
   511 }
   512 
   513 
   514 /*
   515  * Runs the haptic effect on the device.
   516  */
   517 int
   518 SDL_HapticRunEffect(SDL_Haptic * haptic, int effect, Uint32 iterations)
   519 {
   520     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   521         return -1;
   522     }
   523 
   524     /* Run the effect */
   525     if (SDL_SYS_HapticRunEffect(haptic, &haptic->effects[effect], iterations)
   526         < 0) {
   527         return -1;
   528     }
   529 
   530     return 0;
   531 }
   532 
   533 /*
   534  * Stops the haptic effect on the device.
   535  */
   536 int
   537 SDL_HapticStopEffect(SDL_Haptic * haptic, int effect)
   538 {
   539     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   540         return -1;
   541     }
   542 
   543     /* Stop the effect */
   544     if (SDL_SYS_HapticStopEffect(haptic, &haptic->effects[effect]) < 0) {
   545         return -1;
   546     }
   547 
   548     return 0;
   549 }
   550 
   551 /*
   552  * Gets rid of a haptic effect.
   553  */
   554 void
   555 SDL_HapticDestroyEffect(SDL_Haptic * haptic, int effect)
   556 {
   557     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   558         return;
   559     }
   560 
   561     /* Not allocated */
   562     if (haptic->effects[effect].hweffect == NULL) {
   563         return;
   564     }
   565 
   566     SDL_SYS_HapticDestroyEffect(haptic, &haptic->effects[effect]);
   567 }
   568 
   569 /*
   570  * Gets the status of a haptic effect.
   571  */
   572 int
   573 SDL_HapticGetEffectStatus(SDL_Haptic * haptic, int effect)
   574 {
   575     if (!ValidHaptic(haptic) || !ValidEffect(haptic, effect)) {
   576         return -1;
   577     }
   578 
   579     if ((haptic->supported & SDL_HAPTIC_STATUS) == 0) {
   580         SDL_SetError("Haptic: Device does not support status queries.");
   581         return -1;
   582     }
   583 
   584     return SDL_SYS_HapticGetEffectStatus(haptic, &haptic->effects[effect]);
   585 }
   586 
   587 /*
   588  * Sets the global gain of the device.
   589  */
   590 int
   591 SDL_HapticSetGain(SDL_Haptic * haptic, int gain)
   592 {
   593     const char *env;
   594     int real_gain, max_gain;
   595 
   596     if (!ValidHaptic(haptic)) {
   597         return -1;
   598     }
   599 
   600     if ((haptic->supported & SDL_HAPTIC_GAIN) == 0) {
   601         SDL_SetError("Haptic: Device does not support setting gain.");
   602         return -1;
   603     }
   604 
   605     if ((gain < 0) || (gain > 100)) {
   606         SDL_SetError("Haptic: Gain must be between 0 and 100.");
   607         return -1;
   608     }
   609 
   610     /* We use the envvar to get the maximum gain. */
   611     env = SDL_getenv("SDL_HAPTIC_GAIN_MAX");
   612     if (env != NULL) {
   613         max_gain = SDL_atoi(env);
   614 
   615         /* Check for sanity. */
   616         if (max_gain < 0)
   617             max_gain = 0;
   618         else if (max_gain > 100)
   619             max_gain = 100;
   620 
   621         /* We'll scale it linearly with SDL_HAPTIC_GAIN_MAX */
   622         real_gain = (gain * max_gain) / 100;
   623     } else {
   624         real_gain = gain;
   625     }
   626 
   627     if (SDL_SYS_HapticSetGain(haptic, real_gain) < 0) {
   628         return -1;
   629     }
   630 
   631     return 0;
   632 }
   633 
   634 /*
   635  * Makes the device autocenter, 0 disables.
   636  */
   637 int
   638 SDL_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter)
   639 {
   640     if (!ValidHaptic(haptic)) {
   641         return -1;
   642     }
   643 
   644     if ((haptic->supported & SDL_HAPTIC_AUTOCENTER) == 0) {
   645         SDL_SetError("Haptic: Device does not support setting autocenter.");
   646         return -1;
   647     }
   648 
   649     if ((autocenter < 0) || (autocenter > 100)) {
   650         SDL_SetError("Haptic: Autocenter must be between 0 and 100.");
   651         return -1;
   652     }
   653 
   654     if (SDL_SYS_HapticSetAutocenter(haptic, autocenter) < 0) {
   655         return -1;
   656     }
   657 
   658     return 0;
   659 }
   660 
   661 /*
   662  * Pauses the haptic device.
   663  */
   664 int
   665 SDL_HapticPause(SDL_Haptic * haptic)
   666 {
   667     if (!ValidHaptic(haptic)) {
   668         return -1;
   669     }
   670 
   671     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   672         SDL_SetError("Haptic: Device does not support setting pausing.");
   673         return -1;
   674     }
   675 
   676     return SDL_SYS_HapticPause(haptic);
   677 }
   678 
   679 /*
   680  * Unpauses the haptic device.
   681  */
   682 int
   683 SDL_HapticUnpause(SDL_Haptic * haptic)
   684 {
   685     if (!ValidHaptic(haptic)) {
   686         return -1;
   687     }
   688 
   689     if ((haptic->supported & SDL_HAPTIC_PAUSE) == 0) {
   690         return 0;               /* Not going to be paused, so we pretend it's unpaused. */
   691     }
   692 
   693     return SDL_SYS_HapticUnpause(haptic);
   694 }
   695 
   696 /*
   697  * Stops all the currently playing effects.
   698  */
   699 int
   700 SDL_HapticStopAll(SDL_Haptic * haptic)
   701 {
   702     if (!ValidHaptic(haptic)) {
   703         return -1;
   704     }
   705 
   706     return SDL_SYS_HapticStopAll(haptic);
   707 }