src/joystick/SDL_joystick.c
author David Ludwig <dludwig@pobox.com>
Tue, 24 Dec 2013 21:28:31 -0500
changeset 8552 abd934eac415
parent 7922 6ebd3a9aee8c
child 8093 b43765095a6f
permissions -rw-r--r--
WinRT: moved ill-performing XInput device-detection calls to a separate thread
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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.h"
    26 #include "SDL_events.h"
    27 #include "SDL_sysjoystick.h"
    28 #include "SDL_assert.h"
    29 #include "SDL_hints.h"
    30 
    31 #if !SDL_EVENTS_DISABLED
    32 #include "../events/SDL_events_c.h"
    33 #endif
    34 
    35 static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
    36 static SDL_Joystick *SDL_joysticks = NULL;
    37 static SDL_Joystick *SDL_updating_joystick = NULL;
    38 
    39 static void
    40 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
    41 {
    42     if (hint && *hint == '1') {
    43         SDL_joystick_allows_background_events = SDL_TRUE;
    44     } else {
    45         SDL_joystick_allows_background_events = SDL_FALSE;
    46     }
    47 }
    48 
    49 int
    50 SDL_JoystickInit(void)
    51 {
    52     int status;
    53 
    54     /* See if we should allow joystick events while in the background */
    55     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
    56                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
    57 
    58 #if !SDL_EVENTS_DISABLED
    59     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
    60         return -1;
    61     }
    62 #endif /* !SDL_EVENTS_DISABLED */
    63 
    64     status = SDL_SYS_JoystickInit();
    65     if (status >= 0) {
    66         status = 0;
    67     }
    68     return (status);
    69 }
    70 
    71 /*
    72  * Count the number of joysticks attached to the system
    73  */
    74 int
    75 SDL_NumJoysticks(void)
    76 {
    77     return SDL_SYS_NumJoysticks();
    78 }
    79 
    80 /*
    81  * Get the implementation dependent name of a joystick
    82  */
    83 const char *
    84 SDL_JoystickNameForIndex(int device_index)
    85 {
    86     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
    87         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
    88         return (NULL);
    89     }
    90     return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
    91 }
    92 
    93 /*
    94  * Open a joystick for use - the index passed as an argument refers to
    95  * the N'th joystick on the system.  This index is the value which will
    96  * identify this joystick in future joystick events.
    97  *
    98  * This function returns a joystick identifier, or NULL if an error occurred.
    99  */
   100 SDL_Joystick *
   101 SDL_JoystickOpen(int device_index)
   102 {
   103     SDL_Joystick *joystick;
   104     SDL_Joystick *joysticklist;
   105     const char *joystickname = NULL;
   106 
   107     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   108         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   109         return (NULL);
   110     }
   111 
   112     joysticklist = SDL_joysticks;
   113     /* If the joystick is already open, return it
   114     * it is important that we have a single joystick * for each instance id
   115     */
   116     while ( joysticklist )
   117     {
   118         if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == joysticklist->instance_id ) {
   119                 joystick = joysticklist;
   120                 ++joystick->ref_count;
   121                 return (joystick);
   122         }
   123         joysticklist = joysticklist->next;
   124     }
   125 
   126     /* Create and initialize the joystick */
   127     joystick = (SDL_Joystick *) SDL_malloc((sizeof *joystick));
   128     if (joystick == NULL) {
   129         SDL_OutOfMemory();
   130         return NULL;
   131     }
   132 
   133     SDL_memset(joystick, 0, (sizeof *joystick));
   134     if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
   135         SDL_free(joystick);
   136         return NULL;
   137     }
   138 
   139     joystickname = SDL_SYS_JoystickNameForDeviceIndex( device_index );
   140     if ( joystickname )
   141         joystick->name = SDL_strdup( joystickname );
   142     else
   143         joystick->name = NULL;
   144 
   145     if (joystick->naxes > 0) {
   146         joystick->axes = (Sint16 *) SDL_malloc
   147             (joystick->naxes * sizeof(Sint16));
   148     }
   149     if (joystick->nhats > 0) {
   150         joystick->hats = (Uint8 *) SDL_malloc
   151             (joystick->nhats * sizeof(Uint8));
   152     }
   153     if (joystick->nballs > 0) {
   154         joystick->balls = (struct balldelta *) SDL_malloc
   155             (joystick->nballs * sizeof(*joystick->balls));
   156     }
   157     if (joystick->nbuttons > 0) {
   158         joystick->buttons = (Uint8 *) SDL_malloc
   159             (joystick->nbuttons * sizeof(Uint8));
   160     }
   161     if (((joystick->naxes > 0) && !joystick->axes)
   162         || ((joystick->nhats > 0) && !joystick->hats)
   163         || ((joystick->nballs > 0) && !joystick->balls)
   164         || ((joystick->nbuttons > 0) && !joystick->buttons)) {
   165         SDL_OutOfMemory();
   166         SDL_JoystickClose(joystick);
   167         return NULL;
   168     }
   169     if (joystick->axes) {
   170         SDL_memset(joystick->axes, 0, joystick->naxes * sizeof(Sint16));
   171     }
   172     if (joystick->hats) {
   173         SDL_memset(joystick->hats, 0, joystick->nhats * sizeof(Uint8));
   174     }
   175     if (joystick->balls) {
   176         SDL_memset(joystick->balls, 0,
   177             joystick->nballs * sizeof(*joystick->balls));
   178     }
   179     if (joystick->buttons) {
   180         SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8));
   181     }
   182 
   183     /* Add joystick to list */
   184     ++joystick->ref_count;
   185     /* Link the joystick in the list */
   186     joystick->next = SDL_joysticks;
   187     SDL_joysticks = joystick;
   188 
   189     SDL_SYS_JoystickUpdate( joystick );
   190 
   191     return (joystick);
   192 }
   193 
   194 
   195 /*
   196  * Checks to make sure the joystick is valid.
   197  */
   198 int
   199 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
   200 {
   201     int valid;
   202 
   203     if ( joystick == NULL ) {
   204         SDL_SetError("Joystick hasn't been opened yet");
   205         valid = 0;
   206     } else {
   207         valid = 1;
   208     }
   209 
   210     if ( joystick && joystick->closed )
   211     {
   212         valid = 0;
   213     }
   214 
   215     return valid;
   216 }
   217 
   218 /*
   219  * Get the number of multi-dimensional axis controls on a joystick
   220  */
   221 int
   222 SDL_JoystickNumAxes(SDL_Joystick * joystick)
   223 {
   224     if (!SDL_PrivateJoystickValid(joystick)) {
   225         return (-1);
   226     }
   227     return (joystick->naxes);
   228 }
   229 
   230 /*
   231  * Get the number of hats on a joystick
   232  */
   233 int
   234 SDL_JoystickNumHats(SDL_Joystick * joystick)
   235 {
   236     if (!SDL_PrivateJoystickValid(joystick)) {
   237         return (-1);
   238     }
   239     return (joystick->nhats);
   240 }
   241 
   242 /*
   243  * Get the number of trackballs on a joystick
   244  */
   245 int
   246 SDL_JoystickNumBalls(SDL_Joystick * joystick)
   247 {
   248     if (!SDL_PrivateJoystickValid(joystick)) {
   249         return (-1);
   250     }
   251     return (joystick->nballs);
   252 }
   253 
   254 /*
   255  * Get the number of buttons on a joystick
   256  */
   257 int
   258 SDL_JoystickNumButtons(SDL_Joystick * joystick)
   259 {
   260     if (!SDL_PrivateJoystickValid(joystick)) {
   261         return (-1);
   262     }
   263     return (joystick->nbuttons);
   264 }
   265 
   266 /*
   267  * Get the current state of an axis control on a joystick
   268  */
   269 Sint16
   270 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
   271 {
   272     Sint16 state;
   273 
   274     if (!SDL_PrivateJoystickValid(joystick)) {
   275         return (0);
   276     }
   277     if (axis < joystick->naxes) {
   278         state = joystick->axes[axis];
   279     } else {
   280         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   281         state = 0;
   282     }
   283     return (state);
   284 }
   285 
   286 /*
   287  * Get the current state of a hat on a joystick
   288  */
   289 Uint8
   290 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
   291 {
   292     Uint8 state;
   293 
   294     if (!SDL_PrivateJoystickValid(joystick)) {
   295         return (0);
   296     }
   297     if (hat < joystick->nhats) {
   298         state = joystick->hats[hat];
   299     } else {
   300         SDL_SetError("Joystick only has %d hats", joystick->nhats);
   301         state = 0;
   302     }
   303     return (state);
   304 }
   305 
   306 /*
   307  * Get the ball axis change since the last poll
   308  */
   309 int
   310 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
   311 {
   312     int retval;
   313 
   314     if (!SDL_PrivateJoystickValid(joystick)) {
   315         return (-1);
   316     }
   317 
   318     retval = 0;
   319     if (ball < joystick->nballs) {
   320         if (dx) {
   321             *dx = joystick->balls[ball].dx;
   322         }
   323         if (dy) {
   324             *dy = joystick->balls[ball].dy;
   325         }
   326         joystick->balls[ball].dx = 0;
   327         joystick->balls[ball].dy = 0;
   328     } else {
   329         return SDL_SetError("Joystick only has %d balls", joystick->nballs);
   330     }
   331     return (retval);
   332 }
   333 
   334 /*
   335  * Get the current state of a button on a joystick
   336  */
   337 Uint8
   338 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
   339 {
   340     Uint8 state;
   341 
   342     if (!SDL_PrivateJoystickValid(joystick)) {
   343         return (0);
   344     }
   345     if (button < joystick->nbuttons) {
   346         state = joystick->buttons[button];
   347     } else {
   348         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
   349         state = 0;
   350     }
   351     return (state);
   352 }
   353 
   354 /*
   355  * Return if the joystick in question is currently attached to the system,
   356  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
   357  */
   358 SDL_bool
   359 SDL_JoystickGetAttached(SDL_Joystick * joystick)
   360 {
   361     if (!SDL_PrivateJoystickValid(joystick)) {
   362         return SDL_FALSE;
   363     }
   364 
   365     return SDL_SYS_JoystickAttached(joystick);
   366 }
   367 
   368 /*
   369  * Get the instance id for this opened joystick
   370  */
   371 SDL_JoystickID
   372 SDL_JoystickInstanceID(SDL_Joystick * joystick)
   373 {
   374     if (!SDL_PrivateJoystickValid(joystick)) {
   375         return (-1);
   376     }
   377 
   378     return (joystick->instance_id);
   379 }
   380 
   381 /*
   382  * Get the friendly name of this joystick
   383  */
   384 const char *
   385 SDL_JoystickName(SDL_Joystick * joystick)
   386 {
   387     if (!SDL_PrivateJoystickValid(joystick)) {
   388         return (NULL);
   389     }
   390 
   391     return (joystick->name);
   392 }
   393 
   394 /*
   395  * Close a joystick previously opened with SDL_JoystickOpen()
   396  */
   397 void
   398 SDL_JoystickClose(SDL_Joystick * joystick)
   399 {
   400     SDL_Joystick *joysticklist;
   401     SDL_Joystick *joysticklistprev;
   402 
   403     if (!joystick) {
   404         return;
   405     }
   406 
   407     /* First decrement ref count */
   408     if (--joystick->ref_count > 0) {
   409         return;
   410     }
   411 
   412     if (joystick == SDL_updating_joystick) {
   413         return;
   414     }
   415 
   416     SDL_SYS_JoystickClose(joystick);
   417 
   418     joysticklist = SDL_joysticks;
   419     joysticklistprev = NULL;
   420     while ( joysticklist )
   421     {
   422         if (joystick == joysticklist)
   423         {
   424             if ( joysticklistprev )
   425             {
   426                 /* unlink this entry */
   427                 joysticklistprev->next = joysticklist->next;
   428             }
   429             else
   430             {
   431                 SDL_joysticks = joystick->next;
   432             }
   433 
   434             break;
   435         }
   436         joysticklistprev = joysticklist;
   437         joysticklist = joysticklist->next;
   438     }
   439 
   440     SDL_free(joystick->name);
   441 
   442     /* Free the data associated with this joystick */
   443     SDL_free(joystick->axes);
   444     SDL_free(joystick->hats);
   445     SDL_free(joystick->balls);
   446     SDL_free(joystick->buttons);
   447     SDL_free(joystick);
   448 }
   449 
   450 void
   451 SDL_JoystickQuit(void)
   452 {
   453     /* Make sure we're not getting called in the middle of updating joysticks */
   454     SDL_assert(!SDL_updating_joystick);
   455 
   456     /* Stop the event polling */
   457     while ( SDL_joysticks )
   458     {
   459         SDL_joysticks->ref_count = 1;
   460         SDL_JoystickClose(SDL_joysticks);
   461     }
   462 
   463     /* Quit the joystick setup */
   464     SDL_SYS_JoystickQuit();
   465 
   466 #if !SDL_EVENTS_DISABLED
   467     SDL_QuitSubSystem(SDL_INIT_EVENTS);
   468 #endif
   469 }
   470 
   471 
   472 static SDL_bool
   473 SDL_PrivateJoystickShouldIgnoreEvent()
   474 {
   475     if (SDL_joystick_allows_background_events)
   476     {
   477         return SDL_FALSE;
   478     }
   479 
   480     if (SDL_WasInit(SDL_INIT_VIDEO)) {
   481         if (SDL_GetKeyboardFocus() == NULL) {
   482             /* Video is initialized and we don't have focus, ignore the event. */
   483             return SDL_TRUE;
   484         } else {
   485             return SDL_FALSE;
   486         }
   487     }
   488 
   489     /* Video subsystem wasn't initialized, always allow the event */
   490     return SDL_FALSE;
   491 }
   492 
   493 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   494 
   495 int
   496 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   497 {
   498     int posted;
   499 
   500     /* Make sure we're not getting garbage events */
   501     if (axis >= joystick->naxes) {
   502         return 0;
   503     }
   504 
   505     /* Update internal joystick state */
   506     if (value == joystick->axes[axis]) {
   507         return 0;
   508     }
   509     joystick->axes[axis] = value;
   510 
   511     /* We ignore events if we don't have keyboard focus, except for centering
   512      * events.
   513      */
   514     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   515         if (!(joystick->closed && joystick->uncentered)) {
   516             return 0;
   517         }
   518     }
   519 
   520     /* Post the event, if desired */
   521     posted = 0;
   522 #if !SDL_EVENTS_DISABLED
   523     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   524         SDL_Event event;
   525         event.type = SDL_JOYAXISMOTION;
   526         event.jaxis.which = joystick->instance_id;
   527         event.jaxis.axis = axis;
   528         event.jaxis.value = value;
   529         posted = SDL_PushEvent(&event) == 1;
   530     }
   531 #endif /* !SDL_EVENTS_DISABLED */
   532     return (posted);
   533 }
   534 
   535 int
   536 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   537 {
   538     int posted;
   539 
   540     /* Make sure we're not getting garbage events */
   541     if (hat >= joystick->nhats) {
   542         return 0;
   543     }
   544 
   545     /* Update internal joystick state */
   546     joystick->hats[hat] = value;
   547 
   548     /* We ignore events if we don't have keyboard focus, except for centering
   549      * events.
   550      */
   551     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   552         if (!(joystick->closed && joystick->uncentered)) {
   553             return 0;
   554         }
   555     }
   556 
   557 
   558     /* Post the event, if desired */
   559     posted = 0;
   560 #if !SDL_EVENTS_DISABLED
   561     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   562         SDL_Event event;
   563         event.jhat.type = SDL_JOYHATMOTION;
   564         event.jhat.which = joystick->instance_id;
   565         event.jhat.hat = hat;
   566         event.jhat.value = value;
   567         posted = SDL_PushEvent(&event) == 1;
   568     }
   569 #endif /* !SDL_EVENTS_DISABLED */
   570     return (posted);
   571 }
   572 
   573 int
   574 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
   575                         Sint16 xrel, Sint16 yrel)
   576 {
   577     int posted;
   578 
   579     /* Make sure we're not getting garbage events */
   580     if (ball >= joystick->nballs) {
   581         return 0;
   582     }
   583 
   584     /* We ignore events if we don't have keyboard focus. */
   585     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   586         return 0;
   587     }
   588 
   589     /* Update internal mouse state */
   590     joystick->balls[ball].dx += xrel;
   591     joystick->balls[ball].dy += yrel;
   592 
   593     /* Post the event, if desired */
   594     posted = 0;
   595 #if !SDL_EVENTS_DISABLED
   596     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   597         SDL_Event event;
   598         event.jball.type = SDL_JOYBALLMOTION;
   599         event.jball.which = joystick->instance_id;
   600         event.jball.ball = ball;
   601         event.jball.xrel = xrel;
   602         event.jball.yrel = yrel;
   603         posted = SDL_PushEvent(&event) == 1;
   604     }
   605 #endif /* !SDL_EVENTS_DISABLED */
   606     return (posted);
   607 }
   608 
   609 int
   610 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
   611 {
   612     int posted;
   613 #if !SDL_EVENTS_DISABLED
   614     SDL_Event event;
   615 
   616     switch (state) {
   617     case SDL_PRESSED:
   618         event.type = SDL_JOYBUTTONDOWN;
   619         break;
   620     case SDL_RELEASED:
   621         event.type = SDL_JOYBUTTONUP;
   622         break;
   623     default:
   624         /* Invalid state -- bail */
   625         return (0);
   626     }
   627 #endif /* !SDL_EVENTS_DISABLED */
   628 
   629     /* Make sure we're not getting garbage events */
   630     if (button >= joystick->nbuttons) {
   631         return 0;
   632     }
   633 
   634     /* We ignore events if we don't have keyboard focus, except for button
   635      * release. */
   636     if (state == SDL_PRESSED && SDL_PrivateJoystickShouldIgnoreEvent()) {
   637         return 0;
   638     }
   639 
   640     /* Update internal joystick state */
   641     joystick->buttons[button] = state;
   642 
   643     /* Post the event, if desired */
   644     posted = 0;
   645 #if !SDL_EVENTS_DISABLED
   646     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   647         event.jbutton.which = joystick->instance_id;
   648         event.jbutton.button = button;
   649         event.jbutton.state = state;
   650         posted = SDL_PushEvent(&event) == 1;
   651     }
   652 #endif /* !SDL_EVENTS_DISABLED */
   653     return (posted);
   654 }
   655 
   656 void
   657 SDL_JoystickUpdate(void)
   658 {
   659     SDL_Joystick *joystick;
   660 
   661     joystick = SDL_joysticks;
   662     while ( joystick )
   663     {
   664         SDL_Joystick *joysticknext;
   665         /* save off the next pointer, the Update call may cause a joystick removed event
   666          * and cause our joystick pointer to be freed
   667          */
   668         joysticknext = joystick->next;
   669 
   670         SDL_updating_joystick = joystick;
   671 
   672         SDL_SYS_JoystickUpdate( joystick );
   673 
   674         if ( joystick->closed && joystick->uncentered )
   675         {
   676             int i;
   677 
   678             /* Tell the app that everything is centered/unpressed...  */
   679             for (i = 0; i < joystick->naxes; i++)
   680                 SDL_PrivateJoystickAxis(joystick, i, 0);
   681 
   682             for (i = 0; i < joystick->nbuttons; i++)
   683                 SDL_PrivateJoystickButton(joystick, i, 0);
   684 
   685             for (i = 0; i < joystick->nhats; i++)
   686                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
   687 
   688             joystick->uncentered = 0;
   689         }
   690 
   691         SDL_updating_joystick = NULL;
   692 
   693         /* If the joystick was closed while updating, free it here */
   694         if ( joystick->ref_count <= 0 ) {
   695             SDL_JoystickClose(joystick);
   696         }
   697 
   698         joystick = joysticknext;
   699     }
   700 
   701     /* this needs to happen AFTER walking the joystick list above, so that any
   702        dangling hardware data from removed devices can be free'd
   703      */
   704     SDL_SYS_JoystickDetect();
   705 }
   706 
   707 int
   708 SDL_JoystickEventState(int state)
   709 {
   710 #if SDL_EVENTS_DISABLED
   711     return SDL_DISABLE;
   712 #else
   713     const Uint32 event_list[] = {
   714         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   715         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
   716     };
   717     unsigned int i;
   718 
   719     switch (state) {
   720     case SDL_QUERY:
   721         state = SDL_DISABLE;
   722         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   723             state = SDL_EventState(event_list[i], SDL_QUERY);
   724             if (state == SDL_ENABLE) {
   725                 break;
   726             }
   727         }
   728         break;
   729     default:
   730         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   731             SDL_EventState(event_list[i], state);
   732         }
   733         break;
   734     }
   735     return (state);
   736 #endif /* SDL_EVENTS_DISABLED */
   737 }
   738 
   739 /* return 1 if you want to run the joystick update loop this frame, used by hotplug support */
   740 SDL_bool
   741 SDL_PrivateJoystickNeedsPolling()
   742 {
   743     if (SDL_joysticks != NULL) {
   744         return SDL_TRUE;
   745     } else {
   746         return SDL_SYS_JoystickNeedsPolling();
   747     }
   748 }
   749 
   750 
   751 /* return the guid for this index */
   752 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
   753 {
   754     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   755         SDL_JoystickGUID emptyGUID;
   756         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   757         SDL_zero( emptyGUID );
   758         return emptyGUID;
   759     }
   760     return SDL_SYS_JoystickGetDeviceGUID( device_index );
   761 }
   762 
   763 /* return the guid for this opened device */
   764 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
   765 {
   766     if (!SDL_PrivateJoystickValid(joystick)) {
   767         SDL_JoystickGUID emptyGUID;
   768         SDL_zero( emptyGUID );
   769         return emptyGUID;
   770     }
   771     return SDL_SYS_JoystickGetGUID( joystick );
   772 }
   773 
   774 /* convert the guid to a printable string */
   775 void SDL_JoystickGetGUIDString( SDL_JoystickGUID guid, char *pszGUID, int cbGUID )
   776 {
   777     static const char k_rgchHexToASCII[] = "0123456789abcdef";
   778     int i;
   779 
   780     if ((pszGUID == NULL) || (cbGUID <= 0)) {
   781         return;
   782     }
   783 
   784     for ( i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++ )
   785     {
   786         /* each input byte writes 2 ascii chars, and might write a null byte. */
   787         /* If we don't have room for next input byte, stop */
   788         unsigned char c = guid.data[i];
   789 
   790         *pszGUID++ = k_rgchHexToASCII[ c >> 4 ];
   791         *pszGUID++ = k_rgchHexToASCII[ c & 0x0F ];
   792     }
   793     *pszGUID = '\0';
   794 }
   795 
   796 
   797 /*-----------------------------------------------------------------------------
   798  * Purpose: Returns the 4 bit nibble for a hex character
   799  * Input  : c -
   800  * Output : unsigned char
   801  *-----------------------------------------------------------------------------*/
   802 static unsigned char nibble( char c )
   803 {
   804     if ( ( c >= '0' ) &&
   805         ( c <= '9' ) )
   806     {
   807         return (unsigned char)(c - '0');
   808     }
   809 
   810     if ( ( c >= 'A' ) &&
   811         ( c <= 'F' ) )
   812     {
   813         return (unsigned char)(c - 'A' + 0x0a);
   814     }
   815 
   816     if ( ( c >= 'a' ) &&
   817         ( c <= 'f' ) )
   818     {
   819         return (unsigned char)(c - 'a' + 0x0a);
   820     }
   821 
   822     /* received an invalid character, and no real way to return an error */
   823     /* AssertMsg1( false, "Q_nibble invalid hex character '%c' ", c ); */
   824     return 0;
   825 }
   826 
   827 
   828 /* convert the string version of a joystick guid to the struct */
   829 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
   830 {
   831     SDL_JoystickGUID guid;
   832     int maxoutputbytes= sizeof(guid);
   833     size_t len = SDL_strlen( pchGUID );
   834     Uint8 *p;
   835     size_t i;
   836 
   837     /* Make sure it's even */
   838     len = ( len ) & ~0x1;
   839 
   840     SDL_memset( &guid, 0x00, sizeof(guid) );
   841 
   842     p = (Uint8 *)&guid;
   843     for ( i = 0;
   844         ( i < len ) && ( ( p - (Uint8 *)&guid ) < maxoutputbytes );
   845         i+=2, p++ )
   846     {
   847         *p = ( nibble( pchGUID[i] ) << 4 ) | nibble( pchGUID[i+1] );
   848     }
   849 
   850     return guid;
   851 }
   852 
   853 
   854 /* vi: set ts=4 sw=4 expandtab: */