src/joystick/SDL_joystick.c
author Ryan C. Gordon
Mon, 23 Jan 2017 12:06:10 -0500
changeset 10837 c2f241c2f6ad
parent 10823 77ef0962ea62
child 10855 fc18eb831c08
permissions -rw-r--r--
audio: Fix same bug as last commit, but for _mm_bslli_si128 vs _mm_slli_si128.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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_internal.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_bool SDL_updating_joystick = SDL_FALSE;
    38 static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
    39 
    40 void
    41 SDL_LockJoystickList(void)
    42 {
    43     if (SDL_joystick_lock) {
    44         SDL_LockMutex(SDL_joystick_lock);
    45     }
    46 }
    47 
    48 void
    49 SDL_UnlockJoystickList(void)
    50 {
    51     if (SDL_joystick_lock) {
    52         SDL_UnlockMutex(SDL_joystick_lock);
    53     }
    54 }
    55 
    56 
    57 static void
    58 SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
    59 {
    60     if (hint && *hint == '1') {
    61         SDL_joystick_allows_background_events = SDL_TRUE;
    62     } else {
    63         SDL_joystick_allows_background_events = SDL_FALSE;
    64     }
    65 }
    66 
    67 int
    68 SDL_JoystickInit(void)
    69 {
    70     int status;
    71 
    72     /* Create the joystick list lock */
    73     if (!SDL_joystick_lock) {
    74         SDL_joystick_lock = SDL_CreateMutex();
    75     }
    76 
    77     /* See if we should allow joystick events while in the background */
    78     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
    79                         SDL_JoystickAllowBackgroundEventsChanged, NULL);
    80 
    81 #if !SDL_EVENTS_DISABLED
    82     if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) {
    83         return -1;
    84     }
    85 #endif /* !SDL_EVENTS_DISABLED */
    86 
    87     status = SDL_SYS_JoystickInit();
    88     if (status >= 0) {
    89         status = 0;
    90     }
    91     return (status);
    92 }
    93 
    94 /*
    95  * Count the number of joysticks attached to the system
    96  */
    97 int
    98 SDL_NumJoysticks(void)
    99 {
   100     return SDL_SYS_NumJoysticks();
   101 }
   102 
   103 /*
   104  * Get the implementation dependent name of a joystick
   105  */
   106 const char *
   107 SDL_JoystickNameForIndex(int device_index)
   108 {
   109     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   110         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   111         return (NULL);
   112     }
   113     return (SDL_SYS_JoystickNameForDeviceIndex(device_index));
   114 }
   115 
   116 /*
   117  * Return true if this joystick is known to have all axes centered at zero
   118  * This isn't generally needed unless the joystick never generates an initial axis value near zero,
   119  * e.g. it's emulating axes with digital buttons
   120  */
   121 static SDL_bool
   122 SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
   123 {
   124     struct {
   125         Uint16 vendor;
   126         Uint16 product;
   127     } zero_centered_joysticks[] = {
   128         { 0x0e8f, 0x3013 }, /* HuiJia SNES USB adapter */
   129         { 0x05a0, 0x3232 }, /* 8Bitdo Zero Gamepad */
   130     };
   131 
   132     int i;
   133     Uint16 vendor = SDL_JoystickGetVendor(joystick);
   134     Uint16 product = SDL_JoystickGetProduct(joystick);
   135 
   136 /*printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);*/
   137 
   138     if (joystick->naxes == 2) {
   139         /* Assume D-pad or thumbstick style axes are centered at 0 */
   140         return SDL_TRUE;
   141     }
   142 
   143     for (i = 0; i < SDL_arraysize(zero_centered_joysticks); ++i) {
   144         if (vendor == zero_centered_joysticks[i].vendor &&
   145             product == zero_centered_joysticks[i].product) {
   146             return SDL_TRUE;
   147         }
   148     }
   149     return SDL_FALSE;
   150 }
   151 
   152 /*
   153  * Open a joystick for use - the index passed as an argument refers to
   154  * the N'th joystick on the system.  This index is the value which will
   155  * identify this joystick in future joystick events.
   156  *
   157  * This function returns a joystick identifier, or NULL if an error occurred.
   158  */
   159 SDL_Joystick *
   160 SDL_JoystickOpen(int device_index)
   161 {
   162     SDL_Joystick *joystick;
   163     SDL_Joystick *joysticklist;
   164     const char *joystickname = NULL;
   165 
   166     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   167         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   168         return (NULL);
   169     }
   170 
   171     SDL_LockJoystickList();
   172 
   173     joysticklist = SDL_joysticks;
   174     /* If the joystick is already open, return it
   175     * it is important that we have a single joystick * for each instance id
   176     */
   177     while (joysticklist) {
   178         if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == joysticklist->instance_id) {
   179                 joystick = joysticklist;
   180                 ++joystick->ref_count;
   181                 SDL_UnlockJoystickList();
   182                 return (joystick);
   183         }
   184         joysticklist = joysticklist->next;
   185     }
   186 
   187     /* Create and initialize the joystick */
   188     joystick = (SDL_Joystick *) SDL_malloc((sizeof *joystick));
   189     if (joystick == NULL) {
   190         SDL_OutOfMemory();
   191         SDL_UnlockJoystickList();
   192         return NULL;
   193     }
   194 
   195     SDL_memset(joystick, 0, (sizeof *joystick));
   196     if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
   197         SDL_free(joystick);
   198         SDL_UnlockJoystickList();
   199         return NULL;
   200     }
   201 
   202     joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
   203     if (joystickname)
   204         joystick->name = SDL_strdup(joystickname);
   205     else
   206         joystick->name = NULL;
   207 
   208     if (joystick->naxes > 0) {
   209         joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
   210     }
   211     if (joystick->nhats > 0) {
   212         joystick->hats = (Uint8 *) SDL_calloc(joystick->nhats, sizeof(Uint8));
   213     }
   214     if (joystick->nballs > 0) {
   215         joystick->balls = (struct balldelta *) SDL_calloc(joystick->nballs, sizeof(*joystick->balls));
   216     }
   217     if (joystick->nbuttons > 0) {
   218         joystick->buttons = (Uint8 *) SDL_calloc(joystick->nbuttons, sizeof(Uint8));
   219     }
   220     if (((joystick->naxes > 0) && !joystick->axes)
   221         || ((joystick->nhats > 0) && !joystick->hats)
   222         || ((joystick->nballs > 0) && !joystick->balls)
   223         || ((joystick->nbuttons > 0) && !joystick->buttons)) {
   224         SDL_OutOfMemory();
   225         SDL_JoystickClose(joystick);
   226         SDL_UnlockJoystickList();
   227         return NULL;
   228     }
   229     joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
   230 
   231     /* If this joystick is known to have all zero centered axes, skip the auto-centering code */
   232     if (SDL_JoystickAxesCenteredAtZero(joystick)) {
   233         int i;
   234 
   235         for (i = 0; i < joystick->naxes; ++i) {
   236             joystick->axes[i].has_initial_value = SDL_TRUE;
   237         }
   238     }
   239 
   240     /* Add joystick to list */
   241     ++joystick->ref_count;
   242     /* Link the joystick in the list */
   243     joystick->next = SDL_joysticks;
   244     SDL_joysticks = joystick;
   245 
   246     SDL_UnlockJoystickList();
   247 
   248     SDL_SYS_JoystickUpdate(joystick);
   249 
   250     return (joystick);
   251 }
   252 
   253 
   254 /*
   255  * Checks to make sure the joystick is valid.
   256  */
   257 int
   258 SDL_PrivateJoystickValid(SDL_Joystick * joystick)
   259 {
   260     int valid;
   261 
   262     if (joystick == NULL) {
   263         SDL_SetError("Joystick hasn't been opened yet");
   264         valid = 0;
   265     } else {
   266         valid = 1;
   267     }
   268 
   269     return valid;
   270 }
   271 
   272 /*
   273  * Get the number of multi-dimensional axis controls on a joystick
   274  */
   275 int
   276 SDL_JoystickNumAxes(SDL_Joystick * joystick)
   277 {
   278     if (!SDL_PrivateJoystickValid(joystick)) {
   279         return (-1);
   280     }
   281     return (joystick->naxes);
   282 }
   283 
   284 /*
   285  * Get the number of hats on a joystick
   286  */
   287 int
   288 SDL_JoystickNumHats(SDL_Joystick * joystick)
   289 {
   290     if (!SDL_PrivateJoystickValid(joystick)) {
   291         return (-1);
   292     }
   293     return (joystick->nhats);
   294 }
   295 
   296 /*
   297  * Get the number of trackballs on a joystick
   298  */
   299 int
   300 SDL_JoystickNumBalls(SDL_Joystick * joystick)
   301 {
   302     if (!SDL_PrivateJoystickValid(joystick)) {
   303         return (-1);
   304     }
   305     return (joystick->nballs);
   306 }
   307 
   308 /*
   309  * Get the number of buttons on a joystick
   310  */
   311 int
   312 SDL_JoystickNumButtons(SDL_Joystick * joystick)
   313 {
   314     if (!SDL_PrivateJoystickValid(joystick)) {
   315         return (-1);
   316     }
   317     return (joystick->nbuttons);
   318 }
   319 
   320 /*
   321  * Get the current state of an axis control on a joystick
   322  */
   323 Sint16
   324 SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
   325 {
   326     Sint16 state;
   327 
   328     if (!SDL_PrivateJoystickValid(joystick)) {
   329         return (0);
   330     }
   331     if (axis < joystick->naxes) {
   332         state = joystick->axes[axis].value;
   333     } else {
   334         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   335         state = 0;
   336     }
   337     return (state);
   338 }
   339 
   340 /*
   341  * Get the initial state of an axis control on a joystick
   342  */
   343 SDL_bool
   344 SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
   345 {
   346     if (!SDL_PrivateJoystickValid(joystick)) {
   347         return SDL_FALSE;
   348     }
   349     if (axis >= joystick->naxes) {
   350         SDL_SetError("Joystick only has %d axes", joystick->naxes);
   351         return SDL_FALSE;
   352     }
   353     if (state) {
   354         *state = joystick->axes[axis].initial_value;
   355     }
   356     return joystick->axes[axis].has_initial_value;
   357 }
   358 
   359 /*
   360  * Get the current state of a hat on a joystick
   361  */
   362 Uint8
   363 SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
   364 {
   365     Uint8 state;
   366 
   367     if (!SDL_PrivateJoystickValid(joystick)) {
   368         return (0);
   369     }
   370     if (hat < joystick->nhats) {
   371         state = joystick->hats[hat];
   372     } else {
   373         SDL_SetError("Joystick only has %d hats", joystick->nhats);
   374         state = 0;
   375     }
   376     return (state);
   377 }
   378 
   379 /*
   380  * Get the ball axis change since the last poll
   381  */
   382 int
   383 SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
   384 {
   385     int retval;
   386 
   387     if (!SDL_PrivateJoystickValid(joystick)) {
   388         return (-1);
   389     }
   390 
   391     retval = 0;
   392     if (ball < joystick->nballs) {
   393         if (dx) {
   394             *dx = joystick->balls[ball].dx;
   395         }
   396         if (dy) {
   397             *dy = joystick->balls[ball].dy;
   398         }
   399         joystick->balls[ball].dx = 0;
   400         joystick->balls[ball].dy = 0;
   401     } else {
   402         return SDL_SetError("Joystick only has %d balls", joystick->nballs);
   403     }
   404     return (retval);
   405 }
   406 
   407 /*
   408  * Get the current state of a button on a joystick
   409  */
   410 Uint8
   411 SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
   412 {
   413     Uint8 state;
   414 
   415     if (!SDL_PrivateJoystickValid(joystick)) {
   416         return (0);
   417     }
   418     if (button < joystick->nbuttons) {
   419         state = joystick->buttons[button];
   420     } else {
   421         SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
   422         state = 0;
   423     }
   424     return (state);
   425 }
   426 
   427 /*
   428  * Return if the joystick in question is currently attached to the system,
   429  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
   430  */
   431 SDL_bool
   432 SDL_JoystickGetAttached(SDL_Joystick * joystick)
   433 {
   434     if (!SDL_PrivateJoystickValid(joystick)) {
   435         return SDL_FALSE;
   436     }
   437 
   438     return SDL_SYS_JoystickAttached(joystick);
   439 }
   440 
   441 /*
   442  * Get the instance id for this opened joystick
   443  */
   444 SDL_JoystickID
   445 SDL_JoystickInstanceID(SDL_Joystick * joystick)
   446 {
   447     if (!SDL_PrivateJoystickValid(joystick)) {
   448         return (-1);
   449     }
   450 
   451     return (joystick->instance_id);
   452 }
   453 
   454 /*
   455  * Find the SDL_Joystick that owns this instance id
   456  */
   457 SDL_Joystick *
   458 SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
   459 {
   460     SDL_Joystick *joystick;
   461 
   462     SDL_LockJoystickList();
   463     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   464         if (joystick->instance_id == joyid) {
   465             SDL_UnlockJoystickList();
   466             return joystick;
   467         }
   468     }
   469     SDL_UnlockJoystickList();
   470     return NULL;
   471 }
   472 
   473 /*
   474  * Get the friendly name of this joystick
   475  */
   476 const char *
   477 SDL_JoystickName(SDL_Joystick * joystick)
   478 {
   479     if (!SDL_PrivateJoystickValid(joystick)) {
   480         return (NULL);
   481     }
   482 
   483     return (joystick->name);
   484 }
   485 
   486 /*
   487  * Close a joystick previously opened with SDL_JoystickOpen()
   488  */
   489 void
   490 SDL_JoystickClose(SDL_Joystick * joystick)
   491 {
   492     SDL_Joystick *joysticklist;
   493     SDL_Joystick *joysticklistprev;
   494 
   495     if (!joystick) {
   496         return;
   497     }
   498 
   499     SDL_LockJoystickList();
   500 
   501     /* First decrement ref count */
   502     if (--joystick->ref_count > 0) {
   503         SDL_UnlockJoystickList();
   504         return;
   505     }
   506 
   507     if (SDL_updating_joystick) {
   508         SDL_UnlockJoystickList();
   509         return;
   510     }
   511 
   512     SDL_SYS_JoystickClose(joystick);
   513     joystick->hwdata = NULL;
   514 
   515     joysticklist = SDL_joysticks;
   516     joysticklistprev = NULL;
   517     while (joysticklist) {
   518         if (joystick == joysticklist) {
   519             if (joysticklistprev) {
   520                 /* unlink this entry */
   521                 joysticklistprev->next = joysticklist->next;
   522             } else {
   523                 SDL_joysticks = joystick->next;
   524             }
   525             break;
   526         }
   527         joysticklistprev = joysticklist;
   528         joysticklist = joysticklist->next;
   529     }
   530 
   531     SDL_free(joystick->name);
   532 
   533     /* Free the data associated with this joystick */
   534     SDL_free(joystick->axes);
   535     SDL_free(joystick->hats);
   536     SDL_free(joystick->balls);
   537     SDL_free(joystick->buttons);
   538     SDL_free(joystick);
   539 
   540     SDL_UnlockJoystickList();
   541 }
   542 
   543 void
   544 SDL_JoystickQuit(void)
   545 {
   546     /* Make sure we're not getting called in the middle of updating joysticks */
   547     SDL_assert(!SDL_updating_joystick);
   548 
   549     SDL_LockJoystickList();
   550 
   551     /* Stop the event polling */
   552     while (SDL_joysticks) {
   553         SDL_joysticks->ref_count = 1;
   554         SDL_JoystickClose(SDL_joysticks);
   555     }
   556 
   557     /* Quit the joystick setup */
   558     SDL_SYS_JoystickQuit();
   559 
   560     SDL_UnlockJoystickList();
   561 
   562 #if !SDL_EVENTS_DISABLED
   563     SDL_QuitSubSystem(SDL_INIT_EVENTS);
   564 #endif
   565 
   566     if (SDL_joystick_lock) {
   567         SDL_DestroyMutex(SDL_joystick_lock);
   568         SDL_joystick_lock = NULL;
   569     }
   570 }
   571 
   572 
   573 static SDL_bool
   574 SDL_PrivateJoystickShouldIgnoreEvent()
   575 {
   576     if (SDL_joystick_allows_background_events) {
   577         return SDL_FALSE;
   578     }
   579 
   580     if (SDL_WasInit(SDL_INIT_VIDEO)) {
   581         if (SDL_GetKeyboardFocus() == NULL) {
   582             /* Video is initialized and we don't have focus, ignore the event. */
   583             return SDL_TRUE;
   584         } else {
   585             return SDL_FALSE;
   586         }
   587     }
   588 
   589     /* Video subsystem wasn't initialized, always allow the event */
   590     return SDL_FALSE;
   591 }
   592 
   593 /* These are global for SDL_sysjoystick.c and SDL_events.c */
   594 
   595 void SDL_PrivateJoystickAdded(int device_index)
   596 {
   597 #if !SDL_EVENTS_DISABLED
   598     SDL_Event event;
   599 
   600     event.type = SDL_JOYDEVICEADDED;
   601 
   602     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   603         event.jdevice.which = device_index;
   604         if ((SDL_EventOK == NULL) ||
   605              (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   606             SDL_PushEvent(&event);
   607         }
   608     }
   609 #endif /* !SDL_EVENTS_DISABLED */
   610 }
   611 
   612 /*
   613  * If there is an existing add event in the queue, it needs to be modified
   614  * to have the right value for which, because the number of controllers in
   615  * the system is now one less.
   616  */
   617 static void UpdateEventsForDeviceRemoval()
   618 {
   619     int i, num_events;
   620     SDL_Event *events;
   621 
   622     num_events = SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   623     if (num_events <= 0) {
   624         return;
   625     }
   626 
   627     events = SDL_stack_alloc(SDL_Event, num_events);
   628     if (!events) {
   629         return;
   630     }
   631 
   632     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
   633     for (i = 0; i < num_events; ++i) {
   634         --events[i].jdevice.which;
   635     }
   636     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
   637 
   638     SDL_stack_free(events);
   639 }
   640 
   641 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
   642 {
   643 #if !SDL_EVENTS_DISABLED
   644     SDL_Event event;
   645 
   646     event.type = SDL_JOYDEVICEREMOVED;
   647 
   648     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   649         event.jdevice.which = device_instance;
   650         if ((SDL_EventOK == NULL) ||
   651              (*SDL_EventOK) (SDL_EventOKParam, &event)) {
   652             SDL_PushEvent(&event);
   653         }
   654     }
   655 
   656     UpdateEventsForDeviceRemoval();
   657 #endif /* !SDL_EVENTS_DISABLED */
   658 }
   659 
   660 int
   661 SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   662 {
   663     int posted;
   664     const int MAX_ALLOWED_JITTER = SDL_JOYSTICK_AXIS_MAX / 80;  /* ShanWan PS3 controller needed 96 */
   665 
   666     /* Make sure we're not getting garbage or duplicate events */
   667     if (axis >= joystick->naxes) {
   668         return 0;
   669     }
   670     if (!joystick->axes[axis].has_initial_value) {
   671         joystick->axes[axis].initial_value = value;
   672         joystick->axes[axis].value = value;
   673         joystick->axes[axis].zero = value;
   674         joystick->axes[axis].has_initial_value = SDL_TRUE;
   675     }
   676     if (SDL_abs(value - joystick->axes[axis].value) <= MAX_ALLOWED_JITTER) {
   677         return 0;
   678     }
   679     if (!joystick->axes[axis].sent_initial_value) {
   680         joystick->axes[axis].sent_initial_value = SDL_TRUE;
   681         joystick->axes[axis].value = value; /* Just so we pass the check above */
   682         SDL_PrivateJoystickAxis(joystick, axis, joystick->axes[axis].initial_value);
   683     }
   684 
   685     /* We ignore events if we don't have keyboard focus, except for centering
   686      * events.
   687      */
   688     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   689         if ((value > joystick->axes[axis].zero && value >= joystick->axes[axis].value) ||
   690             (value < joystick->axes[axis].zero && value <= joystick->axes[axis].value)) {
   691             return 0;
   692         }
   693     }
   694 
   695     /* Update internal joystick state */
   696     joystick->axes[axis].value = value;
   697 
   698     /* Post the event, if desired */
   699     posted = 0;
   700 #if !SDL_EVENTS_DISABLED
   701     if (SDL_GetEventState(SDL_JOYAXISMOTION) == SDL_ENABLE) {
   702         SDL_Event event;
   703         event.type = SDL_JOYAXISMOTION;
   704         event.jaxis.which = joystick->instance_id;
   705         event.jaxis.axis = axis;
   706         event.jaxis.value = value;
   707         posted = SDL_PushEvent(&event) == 1;
   708     }
   709 #endif /* !SDL_EVENTS_DISABLED */
   710     return (posted);
   711 }
   712 
   713 int
   714 SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   715 {
   716     int posted;
   717 
   718     /* Make sure we're not getting garbage or duplicate events */
   719     if (hat >= joystick->nhats) {
   720         return 0;
   721     }
   722     if (value == joystick->hats[hat]) {
   723         return 0;
   724     }
   725 
   726     /* We ignore events if we don't have keyboard focus, except for centering
   727      * events.
   728      */
   729     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   730         if (value != SDL_HAT_CENTERED) {
   731             return 0;
   732         }
   733     }
   734 
   735     /* Update internal joystick state */
   736     joystick->hats[hat] = value;
   737 
   738     /* Post the event, if desired */
   739     posted = 0;
   740 #if !SDL_EVENTS_DISABLED
   741     if (SDL_GetEventState(SDL_JOYHATMOTION) == SDL_ENABLE) {
   742         SDL_Event event;
   743         event.jhat.type = SDL_JOYHATMOTION;
   744         event.jhat.which = joystick->instance_id;
   745         event.jhat.hat = hat;
   746         event.jhat.value = value;
   747         posted = SDL_PushEvent(&event) == 1;
   748     }
   749 #endif /* !SDL_EVENTS_DISABLED */
   750     return (posted);
   751 }
   752 
   753 int
   754 SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
   755                         Sint16 xrel, Sint16 yrel)
   756 {
   757     int posted;
   758 
   759     /* Make sure we're not getting garbage events */
   760     if (ball >= joystick->nballs) {
   761         return 0;
   762     }
   763 
   764     /* We ignore events if we don't have keyboard focus. */
   765     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   766         return 0;
   767     }
   768 
   769     /* Update internal mouse state */
   770     joystick->balls[ball].dx += xrel;
   771     joystick->balls[ball].dy += yrel;
   772 
   773     /* Post the event, if desired */
   774     posted = 0;
   775 #if !SDL_EVENTS_DISABLED
   776     if (SDL_GetEventState(SDL_JOYBALLMOTION) == SDL_ENABLE) {
   777         SDL_Event event;
   778         event.jball.type = SDL_JOYBALLMOTION;
   779         event.jball.which = joystick->instance_id;
   780         event.jball.ball = ball;
   781         event.jball.xrel = xrel;
   782         event.jball.yrel = yrel;
   783         posted = SDL_PushEvent(&event) == 1;
   784     }
   785 #endif /* !SDL_EVENTS_DISABLED */
   786     return (posted);
   787 }
   788 
   789 int
   790 SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
   791 {
   792     int posted;
   793 #if !SDL_EVENTS_DISABLED
   794     SDL_Event event;
   795 
   796     switch (state) {
   797     case SDL_PRESSED:
   798         event.type = SDL_JOYBUTTONDOWN;
   799         break;
   800     case SDL_RELEASED:
   801         event.type = SDL_JOYBUTTONUP;
   802         break;
   803     default:
   804         /* Invalid state -- bail */
   805         return (0);
   806     }
   807 #endif /* !SDL_EVENTS_DISABLED */
   808 
   809     /* Make sure we're not getting garbage or duplicate events */
   810     if (button >= joystick->nbuttons) {
   811         return 0;
   812     }
   813     if (state == joystick->buttons[button]) {
   814         return 0;
   815     }
   816 
   817     /* We ignore events if we don't have keyboard focus, except for button
   818      * release. */
   819     if (SDL_PrivateJoystickShouldIgnoreEvent()) {
   820         if (state == SDL_PRESSED) {
   821             return 0;
   822         }
   823     }
   824 
   825     /* Update internal joystick state */
   826     joystick->buttons[button] = state;
   827 
   828     /* Post the event, if desired */
   829     posted = 0;
   830 #if !SDL_EVENTS_DISABLED
   831     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   832         event.jbutton.which = joystick->instance_id;
   833         event.jbutton.button = button;
   834         event.jbutton.state = state;
   835         posted = SDL_PushEvent(&event) == 1;
   836     }
   837 #endif /* !SDL_EVENTS_DISABLED */
   838     return (posted);
   839 }
   840 
   841 void
   842 SDL_JoystickUpdate(void)
   843 {
   844     SDL_Joystick *joystick;
   845 
   846     SDL_LockJoystickList();
   847 
   848     if (SDL_updating_joystick) {
   849         /* The joysticks are already being updated */
   850         SDL_UnlockJoystickList();
   851         return;
   852     }
   853 
   854     SDL_updating_joystick = SDL_TRUE;
   855 
   856     /* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
   857     SDL_UnlockJoystickList();
   858 
   859     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   860         SDL_SYS_JoystickUpdate(joystick);
   861 
   862         if (joystick->force_recentering) {
   863             int i;
   864 
   865             /* Tell the app that everything is centered/unpressed... */
   866             for (i = 0; i < joystick->naxes; i++) {
   867                 if (joystick->axes[i].has_initial_value) {
   868                     SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
   869                 }
   870             }
   871 
   872             for (i = 0; i < joystick->nbuttons; i++) {
   873                 SDL_PrivateJoystickButton(joystick, i, 0);
   874             }
   875 
   876             for (i = 0; i < joystick->nhats; i++) {
   877                 SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
   878             }
   879 
   880             joystick->force_recentering = SDL_FALSE;
   881         }
   882     }
   883 
   884     SDL_LockJoystickList();
   885 
   886     SDL_updating_joystick = SDL_FALSE;
   887 
   888     /* If any joysticks were closed while updating, free them here */
   889     for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
   890         if (joystick->ref_count <= 0) {
   891             SDL_JoystickClose(joystick);
   892         }
   893     }
   894 
   895     /* this needs to happen AFTER walking the joystick list above, so that any
   896        dangling hardware data from removed devices can be free'd
   897      */
   898     SDL_SYS_JoystickDetect();
   899 
   900     SDL_UnlockJoystickList();
   901 }
   902 
   903 int
   904 SDL_JoystickEventState(int state)
   905 {
   906 #if SDL_EVENTS_DISABLED
   907     return SDL_DISABLE;
   908 #else
   909     const Uint32 event_list[] = {
   910         SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION,
   911         SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED
   912     };
   913     unsigned int i;
   914 
   915     switch (state) {
   916     case SDL_QUERY:
   917         state = SDL_DISABLE;
   918         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   919             state = SDL_EventState(event_list[i], SDL_QUERY);
   920             if (state == SDL_ENABLE) {
   921                 break;
   922             }
   923         }
   924         break;
   925     default:
   926         for (i = 0; i < SDL_arraysize(event_list); ++i) {
   927             SDL_EventState(event_list[i], state);
   928         }
   929         break;
   930     }
   931     return (state);
   932 #endif /* SDL_EVENTS_DISABLED */
   933 }
   934 
   935 static void GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version)
   936 {
   937     Uint16 *guid16 = (Uint16 *)guid.data;
   938 
   939     /* If the GUID fits the form of BUS 0000 VENDOR 0000 PRODUCT 0000, return the data */
   940     if (/* guid16[0] is device bus type */
   941         guid16[1] == 0x0000 &&
   942         /* guid16[2] is vendor ID */
   943         guid16[3] == 0x0000 &&
   944         /* guid16[4] is product ID */
   945         guid16[5] == 0x0000
   946         /* guid16[6] is product version */
   947     ) {
   948         if (vendor) {
   949             *vendor = guid16[2];
   950         }
   951         if (product) {
   952             *product = guid16[4];
   953         }
   954         if (version) {
   955             *version = guid16[6];
   956         }
   957     } else {
   958         if (vendor) {
   959             *vendor = 0;
   960         }
   961         if (product) {
   962             *product = 0;
   963         }
   964         if (version) {
   965             *version = 0;
   966         }
   967     }
   968 }
   969 
   970 /* return the guid for this index */
   971 SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
   972 {
   973     if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
   974         SDL_JoystickGUID emptyGUID;
   975         SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
   976         SDL_zero(emptyGUID);
   977         return emptyGUID;
   978     }
   979     return SDL_SYS_JoystickGetDeviceGUID(device_index);
   980 }
   981 
   982 Uint16 SDL_JoystickGetDeviceVendor(int device_index)
   983 {
   984     Uint16 vendor;
   985     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   986 
   987     GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
   988     return vendor;
   989 }
   990 
   991 Uint16 SDL_JoystickGetDeviceProduct(int device_index)
   992 {
   993     Uint16 product;
   994     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
   995 
   996     GetJoystickGUIDInfo(guid, NULL, &product, NULL);
   997     return product;
   998 }
   999 
  1000 Uint16 SDL_JoystickGetDeviceProductVersion(int device_index)
  1001 {
  1002     Uint16 version;
  1003     SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
  1004 
  1005     GetJoystickGUIDInfo(guid, NULL, NULL, &version);
  1006     return version;
  1007 }
  1008 
  1009 /* return the guid for this opened device */
  1010 SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
  1011 {
  1012     if (!SDL_PrivateJoystickValid(joystick)) {
  1013         SDL_JoystickGUID emptyGUID;
  1014         SDL_zero(emptyGUID);
  1015         return emptyGUID;
  1016     }
  1017     return SDL_SYS_JoystickGetGUID(joystick);
  1018 }
  1019 
  1020 Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
  1021 {
  1022     Uint16 vendor;
  1023     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1024 
  1025     GetJoystickGUIDInfo(guid, &vendor, NULL, NULL);
  1026     return vendor;
  1027 }
  1028 
  1029 Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
  1030 {
  1031     Uint16 product;
  1032     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1033 
  1034     GetJoystickGUIDInfo(guid, NULL, &product, NULL);
  1035     return product;
  1036 }
  1037 
  1038 Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
  1039 {
  1040     Uint16 version;
  1041     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
  1042 
  1043     GetJoystickGUIDInfo(guid, NULL, NULL, &version);
  1044     return version;
  1045 }
  1046 
  1047 /* convert the guid to a printable string */
  1048 void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
  1049 {
  1050     static const char k_rgchHexToASCII[] = "0123456789abcdef";
  1051     int i;
  1052 
  1053     if ((pszGUID == NULL) || (cbGUID <= 0)) {
  1054         return;
  1055     }
  1056 
  1057     for (i = 0; i < sizeof(guid.data) && i < (cbGUID-1)/2; i++) {
  1058         /* each input byte writes 2 ascii chars, and might write a null byte. */
  1059         /* If we don't have room for next input byte, stop */
  1060         unsigned char c = guid.data[i];
  1061 
  1062         *pszGUID++ = k_rgchHexToASCII[c >> 4];
  1063         *pszGUID++ = k_rgchHexToASCII[c & 0x0F];
  1064     }
  1065     *pszGUID = '\0';
  1066 }
  1067 
  1068 
  1069 /*-----------------------------------------------------------------------------
  1070  * Purpose: Returns the 4 bit nibble for a hex character
  1071  * Input  : c -
  1072  * Output : unsigned char
  1073  *-----------------------------------------------------------------------------*/
  1074 static unsigned char nibble(char c)
  1075 {
  1076     if ((c >= '0') && (c <= '9')) {
  1077         return (unsigned char)(c - '0');
  1078     }
  1079 
  1080     if ((c >= 'A') && (c <= 'F')) {
  1081         return (unsigned char)(c - 'A' + 0x0a);
  1082     }
  1083 
  1084     if ((c >= 'a') && (c <= 'f')) {
  1085         return (unsigned char)(c - 'a' + 0x0a);
  1086     }
  1087 
  1088     /* received an invalid character, and no real way to return an error */
  1089     /* AssertMsg1(false, "Q_nibble invalid hex character '%c' ", c); */
  1090     return 0;
  1091 }
  1092 
  1093 
  1094 /* convert the string version of a joystick guid to the struct */
  1095 SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
  1096 {
  1097     SDL_JoystickGUID guid;
  1098     int maxoutputbytes= sizeof(guid);
  1099     size_t len = SDL_strlen(pchGUID);
  1100     Uint8 *p;
  1101     size_t i;
  1102 
  1103     /* Make sure it's even */
  1104     len = (len) & ~0x1;
  1105 
  1106     SDL_memset(&guid, 0x00, sizeof(guid));
  1107 
  1108     p = (Uint8 *)&guid;
  1109     for (i = 0; (i < len) && ((p - (Uint8 *)&guid) < maxoutputbytes); i+=2, p++) {
  1110         *p = (nibble(pchGUID[i]) << 4) | nibble(pchGUID[i+1]);
  1111     }
  1112 
  1113     return guid;
  1114 }
  1115 
  1116 
  1117 /* update the power level for this joystick */
  1118 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
  1119 {
  1120     joystick->epowerlevel = ePowerLevel;
  1121 }
  1122 
  1123 
  1124 /* return its power level */
  1125 SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
  1126 {
  1127     if (!SDL_PrivateJoystickValid(joystick)) {
  1128         return (SDL_JOYSTICK_POWER_UNKNOWN);
  1129     }
  1130     return joystick->epowerlevel;
  1131 }
  1132 
  1133 
  1134 /* vi: set ts=4 sw=4 expandtab: */