src/joystick/SDL_joystick.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Oct 2011 05:56:58 -0400
changeset 6044 35448a5ea044
parent 5861 b781fa6468aa
child 6095 32d8fad8d7ad
permissions -rw-r--r--
Lots of fixes importing SDL source wholesale into a new iOS project
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* This is the joystick API for Simple DirectMedia Layer */
    24 
    25 #include "SDL_events.h"
    26 #include "SDL_sysjoystick.h"
    27 #include "SDL_joystick_c.h"
    28 #include "SDL_assert.h"
    29 
    30 #if !SDL_EVENTS_DISABLED
    31 #include "../events/SDL_events_c.h"
    32 #endif
    33 
    34 Uint8 SDL_numjoysticks = 0;
    35 SDL_Joystick **SDL_joysticks = NULL;
    36 
    37 int
    38 SDL_JoystickInit(void)
    39 {
    40     int arraylen;
    41     int status;
    42 
    43     SDL_numjoysticks = 0;
    44     status = SDL_SYS_JoystickInit();
    45     if (status >= 0) {
    46         arraylen = (status + 1) * sizeof(*SDL_joysticks);
    47         SDL_joysticks = (SDL_Joystick **) SDL_malloc(arraylen);
    48         if (SDL_joysticks == NULL) {
    49             SDL_numjoysticks = 0;
    50         } else {
    51             SDL_memset(SDL_joysticks, 0, arraylen);
    52             SDL_numjoysticks = status;
    53         }
    54         status = 0;
    55     }
    56     return (status);
    57 }
    58 
    59 /*
    60  * Count the number of joysticks attached to the system
    61  */
    62 int
    63 SDL_NumJoysticks(void)
    64 {
    65     return SDL_numjoysticks;
    66 }
    67 
    68 /*
    69  * Get the implementation dependent name of a joystick
    70  */
    71 const char *
    72 SDL_JoystickName(int device_index)
    73 {
    74     if ((device_index < 0) || (device_index >= SDL_numjoysticks)) {
    75         SDL_SetError("There are %d joysticks available", SDL_numjoysticks);
    76         return (NULL);
    77     }
    78     return (SDL_SYS_JoystickName(device_index));
    79 }
    80 
    81 /*
    82  * Open a joystick for use - the index passed as an argument refers to
    83  * the N'th joystick on the system.  This index is the value which will
    84  * identify this joystick in future joystick events.
    85  *
    86  * This function returns a joystick identifier, or NULL if an error occurred.
    87  */
    88 SDL_Joystick *
    89 SDL_JoystickOpen(int device_index)
    90 {
    91     int i;
    92     SDL_Joystick *joystick;
    93 
    94     if ((device_index < 0) || (device_index >= SDL_numjoysticks)) {
    95         SDL_SetError("There are %d joysticks available", SDL_numjoysticks);
    96         return (NULL);
    97     }
    98 
    99     /* If the joystick is already open, return it */
   100     for (i = 0; SDL_joysticks[i]; ++i) {
   101         if (device_index == SDL_joysticks[i]->index) {
   102             joystick = SDL_joysticks[i];
   103             ++joystick->ref_count;
   104             return (joystick);
   105         }
   106     }
   107 
   108     /* Create and initialize the joystick */
   109     joystick = (SDL_Joystick *) SDL_malloc((sizeof *joystick));
   110     if (joystick == NULL) {
   111         SDL_OutOfMemory();
   112         return NULL;
   113     }
   114 
   115     SDL_memset(joystick, 0, (sizeof *joystick));
   116     joystick->index = device_index;
   117     if (SDL_SYS_JoystickOpen(joystick) < 0) {
   118         SDL_free(joystick);
   119         return NULL;
   120     }
   121     if (joystick->naxes > 0) {
   122         joystick->axes = (Sint16 *) SDL_malloc
   123             (joystick->naxes * sizeof(Sint16));
   124     }
   125     if (joystick->nhats > 0) {
   126         joystick->hats = (Uint8 *) SDL_malloc
   127             (joystick->nhats * sizeof(Uint8));
   128     }
   129     if (joystick->nballs > 0) {
   130         joystick->balls = (struct balldelta *) SDL_malloc
   131             (joystick->nballs * sizeof(*joystick->balls));
   132     }
   133     if (joystick->nbuttons > 0) {
   134         joystick->buttons = (Uint8 *) SDL_malloc
   135             (joystick->nbuttons * sizeof(Uint8));
   136     }
   137     if (((joystick->naxes > 0) && !joystick->axes)
   138         || ((joystick->nhats > 0) && !joystick->hats)
   139         || ((joystick->nballs > 0) && !joystick->balls)
   140         || ((joystick->nbuttons > 0) && !joystick->buttons)) {
   141         SDL_OutOfMemory();
   142         SDL_JoystickClose(joystick);
   143         return NULL;
   144     }
   145     if (joystick->axes) {
   146         SDL_memset(joystick->axes, 0, joystick->naxes * sizeof(Sint16));
   147     }
   148     if (joystick->hats) {
   149         SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8));
   150     }
   151     if (joystick->balls) {
   152         SDL_memset(joystick->balls, 0,
   153             joystick->nballs * sizeof(*joystick->balls));
   154     }
   155     if (joystick->buttons) {
   156         SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8));
   157     }
   158 
   159     /* Add joystick to list */
   160     ++joystick->ref_count;
   161     for (i = 0; SDL_joysticks[i]; ++i)
   162         /* Skip to next joystick */ ;
   163     SDL_joysticks[i] = joystick;
   164 
   165     return (joystick);
   166 }
   167 
   168 /*
   169  * Returns 1 if the joystick has been opened, or 0 if it has not.
   170  */
   171 int
   172 SDL_JoystickOpened(int device_index)
   173 {
   174     int i, opened;
   175 
   176     opened = 0;
   177     for (i = 0; SDL_joysticks[i]; ++i) {
   178         if (SDL_joysticks[i]->index == (Uint8) device_index) {
   179             opened = 1;
   180             break;
   181         }
   182     }
   183     return (opened);
   184 }
   185 
   186 
   187 /*
   188  * Checks to make sure the joystick is valid.
   189  */
   190 int
   191 SDL_PrivateJoystickValid(SDL_Joystick ** joystick)
   192 {
   193     int valid;
   194 
   195     if (*joystick == NULL) {
   196         SDL_SetError("Joystick hasn't been opened yet");
   197         valid = 0;
   198     } else {
   199         valid = 1;
   200     }
   201     return valid;
   202 }
   203 
   204 /*
   205  * Get the device index of an opened joystick.
   206  */
   207 int
   208 SDL_JoystickIndex(SDL_Joystick * joystick)
   209 {
   210     if (!SDL_PrivateJoystickValid(&joystick)) {
   211         return (-1);
   212     }
   213     return (joystick->index);
   214 }
   215 
   216 /*
   217  * Get the number of multi-dimensional axis controls on a joystick
   218  */
   219 int
   220 SDL_JoystickNumAxes(SDL_Joystick * joystick)
   221 {
   222     if (!SDL_PrivateJoystickValid(&joystick)) {
   223         return (-1);
   224     }
   225     return (joystick->naxes);
   226 }
   227 
   228 /*
   229  * Get the number of hats on a joystick
   230  */
   231 int
   232 SDL_JoystickNumHats(SDL_Joystick * joystick)
   233 {
   234     if (!SDL_PrivateJoystickValid(&joystick)) {
   235         return (-1);
   236     }
   237     return (joystick->nhats);
   238 }
   239 
   240 /*
   241  * Get the number of trackballs on a joystick
   242  */
   243 int
   244 SDL_JoystickNumBalls(SDL_Joystick * joystick)
   245 {
   246     if (!SDL_PrivateJoystickValid(&joystick)) {
   247         return (-1);
   248     }
   249     return (joystick->nballs);
   250 }
   251 
   252 /*
   253  * Get the number of buttons on a joystick
   254  */
   255 int
   256 SDL_JoystickNumButtons(SDL_Joystick * joystick)
   257 {
   258     if (!SDL_PrivateJoystickValid(&joystick)) {
   259         return (-1);
   260     }
   261     return (joystick->nbuttons);
   262 }
   263 
   264 /*
   265  * Get the current state of an axis control on a joystick
   266  */
   267 Sint16
   268 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
   269 {
   270     Sint16 state;
   271 
   272     if (!SDL_PrivateJoystickValid(&joystick)) {
   273         return (0);
   274     }
   275     if (axis < joystick->naxes) {
   276         state = joystick->axes[axis];
   277     } else {
   278         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   279         state = 0;
   280     }
   281     return (state);
   282 }
   283 
   284 /*
   285  * Get the current state of a hat on a joystick
   286  */
   287 Uint8
   288 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
   289 {
   290     Uint8 state;
   291 
   292     if (!SDL_PrivateJoystickValid(&joystick)) {
   293         return (0);
   294     }
   295     if (hat < joystick->nhats) {
   296         state = joystick->hats[hat];
   297     } else {
   298         SDL_SetError("Joystick only has %d hats", joystick->nhats);
   299         state = 0;
   300     }
   301     return (state);
   302 }
   303 
   304 /*
   305  * Get the ball axis change since the last poll
   306  */
   307 int
   308 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
   309 {
   310     int retval;
   311 
   312     if (!SDL_PrivateJoystickValid(&joystick)) {
   313         return (-1);
   314     }
   315 
   316     retval = 0;
   317     if (ball < joystick->nballs) {
   318         if (dx) {
   319             *dx = joystick->balls[ball].dx;
   320         }
   321         if (dy) {
   322             *dy = joystick->balls[ball].dy;
   323         }
   324         joystick->balls[ball].dx = 0;
   325         joystick->balls[ball].dy = 0;
   326     } else {
   327         SDL_SetError("Joystick only has %d balls", joystick->nballs);
   328         retval = -1;
   329     }
   330     return (retval);
   331 }
   332 
   333 /*
   334  * Get the current state of a button on a joystick
   335  */
   336 Uint8
   337 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
   338 {
   339     Uint8 state;
   340 
   341     if (!SDL_PrivateJoystickValid(&joystick)) {
   342         return (0);
   343     }
   344     if (button < joystick->nbuttons) {
   345         state = joystick->buttons[button];
   346     } else {
   347         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
   348         state = 0;
   349     }
   350     return (state);
   351 }
   352 
   353 /*
   354  * Close a joystick previously opened with SDL_JoystickOpen()
   355  */
   356 void
   357 SDL_JoystickClose(SDL_Joystick * joystick)
   358 {
   359     int i;
   360 
   361     if (!SDL_PrivateJoystickValid(&joystick)) {
   362         return;
   363     }
   364 
   365     /* First decrement ref count */
   366     if (--joystick->ref_count > 0) {
   367         return;
   368     }
   369 
   370     SDL_SYS_JoystickClose(joystick);
   371 
   372     /* Remove joystick from list */
   373     for (i = 0; SDL_joysticks[i]; ++i) {
   374         if (joystick == SDL_joysticks[i]) {
   375             SDL_memmove(&SDL_joysticks[i], &SDL_joysticks[i + 1],
   376                         (SDL_numjoysticks - i) * sizeof(joystick));
   377             break;
   378         }
   379     }
   380 
   381     /* Free the data associated with this joystick */
   382     if (joystick->axes) {
   383         SDL_free(joystick->axes);
   384     }
   385     if (joystick->hats) {
   386         SDL_free(joystick->hats);
   387     }
   388     if (joystick->balls) {
   389         SDL_free(joystick->balls);
   390     }
   391     if (joystick->buttons) {
   392         SDL_free(joystick->buttons);
   393     }
   394     SDL_free(joystick);
   395 }
   396 
   397 void
   398 SDL_JoystickQuit(void)
   399 {
   400     const int numsticks = SDL_numjoysticks;
   401     int i;
   402 
   403     /* Stop the event polling */
   404     SDL_numjoysticks = 0;
   405 
   406     SDL_assert( (SDL_joysticks == NULL) == (numsticks == 0) );
   407 
   408     for (i = 0; i < numsticks; i++) {
   409         SDL_Joystick *stick = SDL_joysticks[i];
   410         if (stick && (stick->ref_count >= 1)) {
   411             stick->ref_count = 1;
   412             SDL_JoystickClose(stick);
   413         }
   414     }
   415 
   416     /* Quit the joystick setup */
   417     SDL_SYS_JoystickQuit();
   418     if (SDL_joysticks) {
   419         SDL_free(SDL_joysticks);
   420         SDL_joysticks = NULL;
   421     }
   422 }
   423 
   424 
   425 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   426 
   427 int
   428 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   429 {
   430     int posted;
   431 
   432     /* Update internal joystick state */
   433     joystick->axes[axis] = value;
   434 
   435     /* Post the event, if desired */
   436     posted = 0;
   437 #if !SDL_EVENTS_DISABLED
   438     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   439         SDL_Event event;
   440         event.type = SDL_JOYAXISMOTION;
   441         event.jaxis.which = joystick->index;
   442         event.jaxis.axis = axis;
   443         event.jaxis.value = value;
   444         if ((SDL_EventOK == NULL)
   445             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   446             posted = 1;
   447             SDL_PushEvent(&event);
   448         }
   449     }
   450 #endif /* !SDL_EVENTS_DISABLED */
   451     return (posted);
   452 }
   453 
   454 int
   455 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   456 {
   457     int posted;
   458 
   459     /* Update internal joystick state */
   460     joystick->hats[hat] = value;
   461 
   462     /* Post the event, if desired */
   463     posted = 0;
   464 #if !SDL_EVENTS_DISABLED
   465     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   466         SDL_Event event;
   467         event.jhat.type = SDL_JOYHATMOTION;
   468         event.jhat.which = joystick->index;
   469         event.jhat.hat = hat;
   470         event.jhat.value = value;
   471         if ((SDL_EventOK == NULL)
   472             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   473             posted = 1;
   474             SDL_PushEvent(&event);
   475         }
   476     }
   477 #endif /* !SDL_EVENTS_DISABLED */
   478     return (posted);
   479 }
   480 
   481 int
   482 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
   483                         Sint16 xrel, Sint16 yrel)
   484 {
   485     int posted;
   486 
   487     /* Update internal mouse state */
   488     joystick->balls[ball].dx += xrel;
   489     joystick->balls[ball].dy += yrel;
   490 
   491     /* Post the event, if desired */
   492     posted = 0;
   493 #if !SDL_EVENTS_DISABLED
   494     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   495         SDL_Event event;
   496         event.jball.type = SDL_JOYBALLMOTION;
   497         event.jball.which = joystick->index;
   498         event.jball.ball = ball;
   499         event.jball.xrel = xrel;
   500         event.jball.yrel = yrel;
   501         if ((SDL_EventOK == NULL)
   502             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   503             posted = 1;
   504             SDL_PushEvent(&event);
   505         }
   506     }
   507 #endif /* !SDL_EVENTS_DISABLED */
   508     return (posted);
   509 }
   510 
   511 int
   512 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
   513 {
   514     int posted;
   515 #if !SDL_EVENTS_DISABLED
   516     SDL_Event event;
   517 
   518     switch (state) {
   519     case SDL_PRESSED:
   520         event.type = SDL_JOYBUTTONDOWN;
   521         break;
   522     case SDL_RELEASED:
   523         event.type = SDL_JOYBUTTONUP;
   524         break;
   525     default:
   526         /* Invalid state -- bail */
   527         return (0);
   528     }
   529 #endif /* !SDL_EVENTS_DISABLED */
   530 
   531     /* Update internal joystick state */
   532     joystick->buttons[button] = state;
   533 
   534     /* Post the event, if desired */
   535     posted = 0;
   536 #if !SDL_EVENTS_DISABLED
   537     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   538         event.jbutton.which = joystick->index;
   539         event.jbutton.button = button;
   540         event.jbutton.state = state;
   541         if ((SDL_EventOK == NULL)
   542             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   543             posted = 1;
   544             SDL_PushEvent(&event);
   545         }
   546     }
   547 #endif /* !SDL_EVENTS_DISABLED */
   548     return (posted);
   549 }
   550 
   551 void
   552 SDL_JoystickUpdate(void)
   553 {
   554     int i;
   555 
   556     for (i = 0; SDL_joysticks[i]; ++i) {
   557         SDL_SYS_JoystickUpdate(SDL_joysticks[i]);
   558     }
   559 }
   560 
   561 int
   562 SDL_JoystickEventState(int state)
   563 {
   564 #if SDL_EVENTS_DISABLED
   565     return SDL_IGNORE;
   566 #else
   567     const Uint32 event_list[] = {
   568         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   569         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP,
   570     };
   571     unsigned int i;
   572 
   573     switch (state) {
   574     case SDL_QUERY:
   575         state = SDL_IGNORE;
   576         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   577             state = SDL_EventState(event_list[i], SDL_QUERY);
   578             if (state == SDL_ENABLE) {
   579                 break;
   580             }
   581         }
   582         break;
   583     default:
   584         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   585             SDL_EventState(event_list[i], state);
   586         }
   587         break;
   588     }
   589     return (state);
   590 #endif /* SDL_EVENTS_DISABLED */
   591 }
   592 
   593 /* vi: set ts=4 sw=4 expandtab: */