src/joystick/SDL_joystick.c
author Sam Lantinga
Sat, 06 Oct 2012 12:16:32 -0700
changeset 6566 dd7e57847ea9
parent 6145 964d13f789e2
child 6690 9548c8a58103
permissions -rw-r--r--
Add flags to the vidmode debug output
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 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     for (i = numsticks; i--; ) {
   407         SDL_Joystick *stick = SDL_joysticks[i];
   408         if (stick && (stick->ref_count >= 1)) {
   409             stick->ref_count = 1;
   410             SDL_JoystickClose(stick);
   411         }
   412     }
   413 
   414     /* Quit the joystick setup */
   415     SDL_SYS_JoystickQuit();
   416     if (SDL_joysticks) {
   417         SDL_free(SDL_joysticks);
   418         SDL_joysticks = NULL;
   419     }
   420 }
   421 
   422 
   423 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   424 
   425 int
   426 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   427 {
   428     int posted;
   429 
   430     /* Make sure we're not getting garbage events */
   431     if (axis >= joystick->naxes) {
   432         return 0;
   433     }
   434 
   435     /* Update internal joystick state */
   436     joystick->axes[axis] = value;
   437 
   438     /* Post the event, if desired */
   439     posted = 0;
   440 #if !SDL_EVENTS_DISABLED
   441     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   442         SDL_Event event;
   443         event.type = SDL_JOYAXISMOTION;
   444         event.jaxis.which = joystick->index;
   445         event.jaxis.axis = axis;
   446         event.jaxis.value = value;
   447         if ((SDL_EventOK == NULL)
   448             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   449             posted = 1;
   450             SDL_PushEvent(&event);
   451         }
   452     }
   453 #endif /* !SDL_EVENTS_DISABLED */
   454     return (posted);
   455 }
   456 
   457 int
   458 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   459 {
   460     int posted;
   461 
   462     /* Make sure we're not getting garbage events */
   463     if (hat >= joystick->nhats) {
   464         return 0;
   465     }
   466 
   467     /* Update internal joystick state */
   468     joystick->hats[hat] = value;
   469 
   470     /* Post the event, if desired */
   471     posted = 0;
   472 #if !SDL_EVENTS_DISABLED
   473     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   474         SDL_Event event;
   475         event.jhat.type = SDL_JOYHATMOTION;
   476         event.jhat.which = joystick->index;
   477         event.jhat.hat = hat;
   478         event.jhat.value = value;
   479         if ((SDL_EventOK == NULL)
   480             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   481             posted = 1;
   482             SDL_PushEvent(&event);
   483         }
   484     }
   485 #endif /* !SDL_EVENTS_DISABLED */
   486     return (posted);
   487 }
   488 
   489 int
   490 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
   491                         Sint16 xrel, Sint16 yrel)
   492 {
   493     int posted;
   494 
   495     /* Make sure we're not getting garbage events */
   496     if (ball >= joystick->nballs) {
   497         return 0;
   498     }
   499 
   500     /* Update internal mouse state */
   501     joystick->balls[ball].dx += xrel;
   502     joystick->balls[ball].dy += yrel;
   503 
   504     /* Post the event, if desired */
   505     posted = 0;
   506 #if !SDL_EVENTS_DISABLED
   507     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   508         SDL_Event event;
   509         event.jball.type = SDL_JOYBALLMOTION;
   510         event.jball.which = joystick->index;
   511         event.jball.ball = ball;
   512         event.jball.xrel = xrel;
   513         event.jball.yrel = yrel;
   514         if ((SDL_EventOK == NULL)
   515             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   516             posted = 1;
   517             SDL_PushEvent(&event);
   518         }
   519     }
   520 #endif /* !SDL_EVENTS_DISABLED */
   521     return (posted);
   522 }
   523 
   524 int
   525 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
   526 {
   527     int posted;
   528 #if !SDL_EVENTS_DISABLED
   529     SDL_Event event;
   530 
   531     switch (state) {
   532     case SDL_PRESSED:
   533         event.type = SDL_JOYBUTTONDOWN;
   534         break;
   535     case SDL_RELEASED:
   536         event.type = SDL_JOYBUTTONUP;
   537         break;
   538     default:
   539         /* Invalid state -- bail */
   540         return (0);
   541     }
   542 #endif /* !SDL_EVENTS_DISABLED */
   543 
   544     /* Make sure we're not getting garbage events */
   545     if (button >= joystick->nbuttons) {
   546         return 0;
   547     }
   548 
   549     /* Update internal joystick state */
   550     joystick->buttons[button] = state;
   551 
   552     /* Post the event, if desired */
   553     posted = 0;
   554 #if !SDL_EVENTS_DISABLED
   555     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   556         event.jbutton.which = joystick->index;
   557         event.jbutton.button = button;
   558         event.jbutton.state = state;
   559         if ((SDL_EventOK == NULL)
   560             || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   561             posted = 1;
   562             SDL_PushEvent(&event);
   563         }
   564     }
   565 #endif /* !SDL_EVENTS_DISABLED */
   566     return (posted);
   567 }
   568 
   569 void
   570 SDL_JoystickUpdate(void)
   571 {
   572     int i;
   573 
   574     for (i = 0; SDL_joysticks[i]; ++i) {
   575         SDL_SYS_JoystickUpdate(SDL_joysticks[i]);
   576     }
   577 }
   578 
   579 int
   580 SDL_JoystickEventState(int state)
   581 {
   582 #if SDL_EVENTS_DISABLED
   583     return SDL_IGNORE;
   584 #else
   585     const Uint32 event_list[] = {
   586         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   587         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP,
   588     };
   589     unsigned int i;
   590 
   591     switch (state) {
   592     case SDL_QUERY:
   593         state = SDL_IGNORE;
   594         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   595             state = SDL_EventState(event_list[i], SDL_QUERY);
   596             if (state == SDL_ENABLE) {
   597                 break;
   598             }
   599         }
   600         break;
   601     default:
   602         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   603             SDL_EventState(event_list[i], state);
   604         }
   605         break;
   606     }
   607     return (state);
   608 #endif /* SDL_EVENTS_DISABLED */
   609 }
   610 
   611 /* vi: set ts=4 sw=4 expandtab: */