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