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