src/joystick/SDL_joystick.c
author Sam Lantinga
Tue, 11 Dec 2012 12:16:28 -0800
changeset 6744 4ac2bb6dc80c
parent 6738 b408d5a406a3
child 6748 80a6aac67ad9
permissions -rw-r--r--
Fixed joystick GUID renaming for other platforms
     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_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         SDL_SetError("Joystick only has %d balls", joystick->nballs);
   307         retval = -1;
   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 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   456 
   457 int
   458 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   459 {
   460     int posted;
   461 
   462     /* Make sure we're not getting garbage events */
   463     if (axis >= joystick->naxes) {
   464         return 0;
   465     }
   466 
   467     /* Update internal joystick state */
   468     if (value == joystick->axes[axis]) {
   469         return 0;
   470     }
   471     joystick->axes[axis] = value;
   472 
   473     /* Post the event, if desired */
   474     posted = 0;
   475 #if !SDL_EVENTS_DISABLED
   476     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   477         SDL_Event event;
   478         event.type = SDL_JOYAXISMOTION;
   479         event.jaxis.which = joystick->instance_id;
   480         event.jaxis.axis = axis;
   481         event.jaxis.value = value;
   482         posted = SDL_PushEvent(&event) == 1;
   483     }
   484 #endif /* !SDL_EVENTS_DISABLED */
   485     return (posted);
   486 }
   487 
   488 int
   489 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   490 {
   491     int posted;
   492 
   493     /* Make sure we're not getting garbage events */
   494     if (hat >= joystick->nhats) {
   495         return 0;
   496     }
   497 
   498     /* Update internal joystick state */
   499     joystick->hats[hat] = value;
   500 
   501     /* Post the event, if desired */
   502     posted = 0;
   503 #if !SDL_EVENTS_DISABLED
   504     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   505         SDL_Event event;
   506         event.jhat.type = SDL_JOYHATMOTION;
   507         event.jhat.which = joystick->instance_id;
   508         event.jhat.hat = hat;
   509         event.jhat.value = value;
   510         posted = SDL_PushEvent(&event) == 1;
   511     }
   512 #endif /* !SDL_EVENTS_DISABLED */
   513     return (posted);
   514 }
   515 
   516 int
   517 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
   518                         Sint16 xrel, Sint16 yrel)
   519 {
   520     int posted;
   521 
   522     /* Make sure we're not getting garbage events */
   523     if (ball >= joystick->nballs) {
   524         return 0;
   525     }
   526 
   527     /* Update internal mouse state */
   528     joystick->balls[ball].dx += xrel;
   529     joystick->balls[ball].dy += yrel;
   530 
   531     /* Post the event, if desired */
   532     posted = 0;
   533 #if !SDL_EVENTS_DISABLED
   534     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   535         SDL_Event event;
   536         event.jball.type = SDL_JOYBALLMOTION;
   537         event.jball.which = joystick->instance_id;
   538         event.jball.ball = ball;
   539         event.jball.xrel = xrel;
   540         event.jball.yrel = yrel;
   541         posted = SDL_PushEvent(&event) == 1;
   542     }
   543 #endif /* !SDL_EVENTS_DISABLED */
   544     return (posted);
   545 }
   546 
   547 int
   548 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
   549 {
   550     int posted;
   551 #if !SDL_EVENTS_DISABLED
   552     SDL_Event event;
   553 
   554     switch (state) {
   555     case SDL_PRESSED:
   556         event.type = SDL_JOYBUTTONDOWN;
   557         break;
   558     case SDL_RELEASED:
   559         event.type = SDL_JOYBUTTONUP;
   560         break;
   561     default:
   562         /* Invalid state -- bail */
   563         return (0);
   564     }
   565 #endif /* !SDL_EVENTS_DISABLED */
   566 
   567     /* Make sure we're not getting garbage events */
   568     if (button >= joystick->nbuttons) {
   569         return 0;
   570     }
   571 
   572     /* Update internal joystick state */
   573     joystick->buttons[button] = state;
   574 
   575     /* Post the event, if desired */
   576     posted = 0;
   577 #if !SDL_EVENTS_DISABLED
   578     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   579         event.jbutton.which = joystick->instance_id;
   580         event.jbutton.button = button;
   581         event.jbutton.state = state;
   582         posted = SDL_PushEvent(&event) == 1;
   583     }
   584 #endif /* !SDL_EVENTS_DISABLED */
   585     return (posted);
   586 }
   587 
   588 void
   589 SDL_JoystickUpdate(void)
   590 {
   591 	SDL_Joystick *joystick;
   592 		
   593 	joystick = SDL_joysticks;
   594 	while ( joystick )
   595 	{
   596 		SDL_Joystick *joysticknext;
   597 		/* save off the next pointer, the Update call may cause a joystick removed event
   598 		 * and cause our joystick pointer to be freed
   599 		 */
   600 		joysticknext = joystick->next;
   601 
   602         SDL_updating_joystick = joystick;
   603 
   604         SDL_SYS_JoystickUpdate( joystick );
   605 
   606 		if ( joystick->closed && joystick->uncentered )
   607 		{
   608 			int i;
   609 			joystick->uncentered = 0;
   610 
   611             /* Tell the app that everything is centered/unpressed...  */
   612             for (i = 0; i < joystick->naxes; i++)
   613                 SDL_PrivateJoystickAxis(joystick, i, 0);
   614 
   615             for (i = 0; i < joystick->nbuttons; i++)
   616                 SDL_PrivateJoystickButton(joystick, i, 0);
   617 
   618             for (i = 0; i < joystick->nhats; i++)
   619                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
   620 
   621 		}
   622 
   623         SDL_updating_joystick = NULL;
   624 
   625         /* If the joystick was closed while updating, free it here */
   626         if ( joystick->ref_count <= 0 ) {
   627             SDL_JoystickClose(joystick);
   628         }
   629 
   630 		joystick = joysticknext;
   631 	}
   632 
   633 	SDL_SYS_JoystickDetect();
   634 }
   635 
   636 int
   637 SDL_JoystickEventState(int state)
   638 {
   639 #if SDL_EVENTS_DISABLED
   640     return SDL_IGNORE;
   641 #else
   642     const Uint32 event_list[] = {
   643         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   644         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
   645     };
   646     unsigned int i;
   647 
   648     switch (state) {
   649     case SDL_QUERY:
   650         state = SDL_IGNORE;
   651         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   652             state = SDL_EventState(event_list[i], SDL_QUERY);
   653             if (state == SDL_ENABLE) {
   654                 break;
   655             }
   656         }
   657         break;
   658     default:
   659         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   660             SDL_EventState(event_list[i], state);
   661         }
   662         break;
   663     }
   664     return (state);
   665 #endif /* SDL_EVENTS_DISABLED */
   666 }
   667 
   668 /* return 1 if you want to run the joystick update loop this frame, used by hotplug support */
   669 SDL_bool 
   670 SDL_PrivateJoystickNeedsPolling()
   671 {
   672 	if ( SDL_SYS_JoystickNeedsPolling() )
   673 	{
   674 		// sys layer needs us to think
   675 		return SDL_TRUE;
   676 	}
   677 	else
   678 	{
   679 		// otherwise only do it if a joystick is opened
   680 		return SDL_joysticks != NULL; 
   681 	}
   682 }
   683 
   684 
   685 /* return the guid for this index */
   686 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
   687 {
   688 	return SDL_SYS_JoystickGetDeviceGUID( device_index );
   689 }
   690 
   691 /* return the guid for this opened device */
   692 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
   693 {
   694 	return SDL_SYS_JoystickGetGUID( joystick );
   695 }
   696 
   697 /* convert the guid to a printable string */
   698 void SDL_JoystickGetGUIDString( SDL_JoystickGUID guid, char *pszGUID, int cbGUID )
   699 {
   700 	static const char k_rgchHexToASCII[] = "0123456789abcdef";
   701 	char *pchOut = NULL;
   702 	char *pchString = NULL;
   703 	int i;
   704 	
   705 	pchOut = pszGUID;
   706 
   707 	for ( i = 0; i < sizeof(guid) && i < (cbGUID-1); i++ )
   708 	{
   709 		// each input byte writes 2 ascii chars, and might write a null byte.
   710 		// If we don't have room for next input byte, stop
   711 		unsigned char c = guid.data[i];
   712 
   713 		*pchOut++ = k_rgchHexToASCII[ c >> 4 ];
   714 		*pchOut++ = k_rgchHexToASCII[ c & 0x0F ];
   715 	}
   716 	*pchOut = '\0';
   717 }
   718 
   719 
   720 //-----------------------------------------------------------------------------
   721 // Purpose: Returns the 4 bit nibble for a hex character
   722 // Input  : c - 
   723 // Output : unsigned char
   724 //-----------------------------------------------------------------------------
   725 static unsigned char nibble( char c )
   726 {
   727 	if ( ( c >= '0' ) &&
   728 		( c <= '9' ) )
   729 	{
   730 		return (unsigned char)(c - '0');
   731 	}
   732 
   733 	if ( ( c >= 'A' ) &&
   734 		( c <= 'F' ) )
   735 	{
   736 		return (unsigned char)(c - 'A' + 0x0a);
   737 	}
   738 
   739 	if ( ( c >= 'a' ) &&
   740 		( c <= 'f' ) )
   741 	{
   742 		return (unsigned char)(c - 'a' + 0x0a);
   743 	}
   744 
   745 	// received an invalid character, and no real way to return an error
   746 	// AssertMsg1( false, "Q_nibble invalid hex character '%c' ", c );
   747 	return 0;
   748 }
   749 
   750 
   751 /* convert the string version of a joystick guid to the struct */
   752 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
   753 {
   754 	SDL_JoystickGUID guid;
   755 	int maxoutputbytes= sizeof(guid);
   756 	int len = SDL_strlen( pchGUID );
   757 	Uint8 *p;
   758 	int i;
   759 
   760 	// Make sure it's even
   761 	len = ( len ) & ~0x1;
   762 
   763 	SDL_memset( &guid, 0x00, sizeof(guid) );
   764 
   765 	p = (Uint8 *)&guid;
   766 	for ( i = 0; 
   767 		( i < len ) && ( ( p - (Uint8 *)&guid ) < maxoutputbytes ); 
   768 		i+=2, p++ )
   769 	{
   770 		*p = ( nibble( pchGUID[i] ) << 4 ) | nibble( pchGUID[i+1] );		
   771 	}
   772 
   773 	return guid;
   774 }
   775 
   776 
   777 /* vi: set ts=4 sw=4 expandtab: */