src/joystick/windows/SDL_windowsjoystick.c
changeset 8972 dfc759d7486f
child 8988 1deb2998dbae
equal deleted inserted replaced
8971:c30e826412d1 8972:dfc759d7486f
       
     1 /*
       
     2   Simple DirectMedia Layer
       
     3   Copyright (C) 1997-2014 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 #if SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT
       
    24 
       
    25 /* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
       
    26  * A. Formiga's WINMM driver.
       
    27  *
       
    28  * Hats and sliders are completely untested; the app I'm writing this for mostly
       
    29  * doesn't use them and I don't own any joysticks with them.
       
    30  *
       
    31  * We don't bother to use event notification here.  It doesn't seem to work
       
    32  * with polled devices, and it's fine to call IDirectInputDevice8_GetDeviceData and
       
    33  * let it return 0 events. */
       
    34 
       
    35 #include "SDL_error.h"
       
    36 #include "SDL_assert.h"
       
    37 #include "SDL_events.h"
       
    38 #include "SDL_thread.h"
       
    39 #include "SDL_timer.h"
       
    40 #include "SDL_mutex.h"
       
    41 #include "SDL_events.h"
       
    42 #include "SDL_hints.h"
       
    43 #include "SDL_joystick.h"
       
    44 #include "../SDL_sysjoystick.h"
       
    45 #if !SDL_EVENTS_DISABLED
       
    46 #include "../../events/SDL_events_c.h"
       
    47 #endif
       
    48 #include "../../core/windows/SDL_windows.h"
       
    49 #include <dbt.h>
       
    50 
       
    51 #define INITGUID /* Only set here, if set twice will cause mingw32 to break. */
       
    52 #include "SDL_windowsjoystick_c.h"
       
    53 #include "SDL_dinputjoystick_c.h"
       
    54 #include "SDL_xinputjoystick_c.h"
       
    55 
       
    56 #include "../../haptic/windows/SDL_dinputhaptic_c.h"    /* For haptic hot plugging */
       
    57 #include "../../haptic/windows/SDL_xinputhaptic_c.h"    /* For haptic hot plugging */
       
    58 
       
    59 
       
    60 /* local variables */
       
    61 static SDL_bool s_bDeviceAdded = SDL_FALSE;
       
    62 static SDL_bool s_bDeviceRemoved = SDL_FALSE;
       
    63 static SDL_JoystickID s_nInstanceID = -1;
       
    64 static SDL_cond *s_condJoystickThread = NULL;
       
    65 static SDL_mutex *s_mutexJoyStickEnum = NULL;
       
    66 static SDL_Thread *s_threadJoystick = NULL;
       
    67 static SDL_bool s_bJoystickThreadQuit = SDL_FALSE;
       
    68 
       
    69 JoyStick_DeviceData *SYS_Joystick;    /* array to hold joystick ID values */
       
    70 
       
    71 static SDL_bool s_bWindowsDeviceChanged = SDL_FALSE;
       
    72 
       
    73 #ifdef __WINRT__
       
    74 
       
    75 typedef struct
       
    76 {
       
    77     int unused;
       
    78 } SDL_DeviceNotificationData;
       
    79 
       
    80 static void
       
    81 SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
       
    82 {
       
    83 }
       
    84 
       
    85 static int
       
    86 SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
       
    87 {
       
    88     return 0;
       
    89 }
       
    90 
       
    91 static void
       
    92 SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
       
    93 {
       
    94 }
       
    95 
       
    96 #else /* !__WINRT__ */
       
    97 
       
    98 typedef struct
       
    99 {
       
   100     HRESULT coinitialized;
       
   101     WNDCLASSEX wincl;
       
   102     HWND messageWindow;
       
   103     HDEVNOTIFY hNotify;
       
   104 } SDL_DeviceNotificationData;
       
   105 
       
   106 
       
   107 /* windowproc for our joystick detect thread message only window, to detect any USB device addition/removal */
       
   108 static LRESULT CALLBACK
       
   109 SDL_PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       
   110 {
       
   111     switch (message) {
       
   112     case WM_DEVICECHANGE:
       
   113         switch (wParam) {
       
   114         case DBT_DEVICEARRIVAL:
       
   115             if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
       
   116                 s_bWindowsDeviceChanged = SDL_TRUE;
       
   117             }
       
   118             break;
       
   119         case DBT_DEVICEREMOVECOMPLETE:
       
   120             if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
       
   121                 s_bWindowsDeviceChanged = SDL_TRUE;
       
   122             }
       
   123             break;
       
   124         }
       
   125         return 0;
       
   126     }
       
   127 
       
   128     return DefWindowProc (hwnd, message, wParam, lParam);
       
   129 }
       
   130 
       
   131 static void
       
   132 SDL_CleanupDeviceNotification(SDL_DeviceNotificationData *data)
       
   133 {
       
   134     if (data->hNotify)
       
   135         UnregisterDeviceNotification(data->hNotify);
       
   136 
       
   137     if (data->messageWindow)
       
   138         DestroyWindow(data->messageWindow);
       
   139 
       
   140     UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance);
       
   141 
       
   142     if (data->coinitialized == S_OK) {
       
   143         WIN_CoUninitialize();
       
   144     }
       
   145 }
       
   146 
       
   147 static int
       
   148 SDL_CreateDeviceNotification(SDL_DeviceNotificationData *data)
       
   149 {
       
   150     DEV_BROADCAST_DEVICEINTERFACE dbh;
       
   151     GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
       
   152 
       
   153     SDL_zerop(data);
       
   154 
       
   155     data->coinitialized = WIN_CoInitialize();
       
   156 
       
   157     data->wincl.hInstance = GetModuleHandle(NULL);
       
   158     data->wincl.lpszClassName = L"Message";
       
   159     data->wincl.lpfnWndProc = SDL_PrivateJoystickDetectProc;      /* This function is called by windows */
       
   160     data->wincl.cbSize = sizeof (WNDCLASSEX);
       
   161 
       
   162     if (!RegisterClassEx(&data->wincl)) {
       
   163         WIN_SetError("Failed to create register class for joystick autodetect");
       
   164         SDL_CleanupDeviceNotification(data);
       
   165         return -1;
       
   166     }
       
   167 
       
   168     data->messageWindow = (HWND)CreateWindowEx(0,  L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
       
   169     if (!data->messageWindow) {
       
   170         WIN_SetError("Failed to create message window for joystick autodetect");
       
   171         SDL_CleanupDeviceNotification(data);
       
   172         return -1;
       
   173     }
       
   174 
       
   175     SDL_zero(dbh);
       
   176     dbh.dbcc_size = sizeof(dbh);
       
   177     dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
       
   178     dbh.dbcc_classguid = GUID_DEVINTERFACE_HID;
       
   179 
       
   180     data->hNotify = RegisterDeviceNotification(data->messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE);
       
   181     if (!data->hNotify) {
       
   182         WIN_SetError("Failed to create notify device for joystick autodetect");
       
   183         SDL_CleanupDeviceNotification(data);
       
   184         return -1;
       
   185     }
       
   186     return 0;
       
   187 }
       
   188 
       
   189 static void
       
   190 SDL_CheckDeviceNotification(SDL_DeviceNotificationData *data)
       
   191 {
       
   192     MSG msg;
       
   193 
       
   194     if (!data->messageWindow) {
       
   195         return;
       
   196     }
       
   197 
       
   198     while (PeekMessage(&msg, data->messageWindow, 0, 0, PM_NOREMOVE)) {
       
   199         if (GetMessage(&msg, data->messageWindow, 0, 0) != 0)  {
       
   200             TranslateMessage(&msg);
       
   201             DispatchMessage(&msg);
       
   202         }
       
   203     }
       
   204 }
       
   205 
       
   206 #endif /* __WINRT__ */
       
   207 
       
   208 /* Function/thread to scan the system for joysticks. */
       
   209 static int
       
   210 SDL_JoystickThread(void *_data)
       
   211 {
       
   212     SDL_DeviceNotificationData notification_data;
       
   213 
       
   214 #if SDL_JOYSTICK_XINPUT
       
   215     SDL_bool bOpenedXInputDevices[XUSER_MAX_COUNT];
       
   216     SDL_zero(bOpenedXInputDevices);
       
   217 #endif
       
   218 
       
   219     if (SDL_CreateDeviceNotification(&notification_data) < 0) {
       
   220         return -1;
       
   221     }
       
   222 
       
   223     SDL_LockMutex(s_mutexJoyStickEnum);
       
   224     while (s_bJoystickThreadQuit == SDL_FALSE) {
       
   225         SDL_bool bXInputChanged = SDL_FALSE;
       
   226 
       
   227         SDL_CondWaitTimeout(s_condJoystickThread, s_mutexJoyStickEnum, 300);
       
   228 
       
   229         SDL_CheckDeviceNotification(&notification_data);
       
   230 
       
   231 #if SDL_JOYSTICK_XINPUT
       
   232         if (SDL_XINPUT_Enabled() && XINPUTGETCAPABILITIES) {
       
   233             /* scan for any change in XInput devices */
       
   234             Uint8 userId;
       
   235             for (userId = 0; userId < XUSER_MAX_COUNT; userId++) {
       
   236                 XINPUT_CAPABILITIES capabilities;
       
   237                 const DWORD result = XINPUTGETCAPABILITIES(userId, XINPUT_FLAG_GAMEPAD, &capabilities);
       
   238                 const SDL_bool available = (result == ERROR_SUCCESS);
       
   239                 if (bOpenedXInputDevices[userId] != available) {
       
   240                     bXInputChanged = SDL_TRUE;
       
   241                     bOpenedXInputDevices[userId] = available;
       
   242                 }
       
   243             }
       
   244         }
       
   245 #endif /* SDL_JOYSTICK_XINPUT */
       
   246 
       
   247         if (s_bWindowsDeviceChanged || bXInputChanged) {
       
   248             SDL_UnlockMutex(s_mutexJoyStickEnum);  /* let main thread go while we SDL_Delay(). */
       
   249             SDL_Delay(300); /* wait for direct input to find out about this device */
       
   250             SDL_LockMutex(s_mutexJoyStickEnum);
       
   251 
       
   252             s_bDeviceRemoved = SDL_TRUE;
       
   253             s_bDeviceAdded = SDL_TRUE;
       
   254             s_bWindowsDeviceChanged = SDL_FALSE;
       
   255         }
       
   256     }
       
   257     SDL_UnlockMutex(s_mutexJoyStickEnum);
       
   258 
       
   259     SDL_CleanupDeviceNotification(&notification_data);
       
   260 
       
   261     return 1;
       
   262 }
       
   263 
       
   264 void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device)
       
   265 {
       
   266     device->send_add_event = SDL_TRUE;
       
   267     device->nInstanceID = ++s_nInstanceID;
       
   268     device->pNext = SYS_Joystick;
       
   269     SYS_Joystick = device;
       
   270 
       
   271     s_bDeviceAdded = SDL_TRUE;
       
   272 }
       
   273 
       
   274 /* Function to scan the system for joysticks.
       
   275  * This function should set SDL_numjoysticks to the number of available
       
   276  * joysticks.  Joystick 0 should be the system default joystick.
       
   277  * It should return 0, or -1 on an unrecoverable fatal error.
       
   278  */
       
   279 int
       
   280 SDL_SYS_JoystickInit(void)
       
   281 {
       
   282     if (SDL_DINPUT_JoystickInit() < 0) {
       
   283         SDL_SYS_JoystickQuit();
       
   284         return -1;
       
   285     }
       
   286 
       
   287     if (SDL_XINPUT_JoystickInit() < 0) {
       
   288         SDL_SYS_JoystickQuit();
       
   289         return -1;
       
   290     }
       
   291 
       
   292     s_mutexJoyStickEnum = SDL_CreateMutex();
       
   293     s_condJoystickThread = SDL_CreateCond();
       
   294     s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */
       
   295 
       
   296     SDL_SYS_JoystickDetect();
       
   297 
       
   298     if (!s_threadJoystick) {
       
   299         s_bJoystickThreadQuit = SDL_FALSE;
       
   300         /* spin up the thread to detect hotplug of devices */
       
   301 #if defined(__WIN32__) && !defined(HAVE_LIBC)
       
   302 #undef SDL_CreateThread
       
   303 #if SDL_DYNAMIC_API
       
   304         s_threadJoystick= SDL_CreateThread_REAL(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL);
       
   305 #else
       
   306         s_threadJoystick= SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL, NULL, NULL);
       
   307 #endif
       
   308 #else
       
   309         s_threadJoystick = SDL_CreateThread(SDL_JoystickThread, "SDL_joystick", NULL);
       
   310 #endif
       
   311     }
       
   312     return SDL_SYS_NumJoysticks();
       
   313 }
       
   314 
       
   315 /* return the number of joysticks that are connected right now */
       
   316 int
       
   317 SDL_SYS_NumJoysticks()
       
   318 {
       
   319     int nJoysticks = 0;
       
   320     JoyStick_DeviceData *device = SYS_Joystick;
       
   321     while (device) {
       
   322         nJoysticks++;
       
   323         device = device->pNext;
       
   324     }
       
   325 
       
   326     return nJoysticks;
       
   327 }
       
   328 
       
   329 /* detect any new joysticks being inserted into the system */
       
   330 void
       
   331 SDL_SYS_JoystickDetect()
       
   332 {
       
   333     JoyStick_DeviceData *pCurList = NULL;
       
   334 #if !SDL_EVENTS_DISABLED
       
   335     SDL_Event event;
       
   336 #endif
       
   337 
       
   338     /* only enum the devices if the joystick thread told us something changed */
       
   339     if (!s_bDeviceAdded && !s_bDeviceRemoved) {
       
   340         return;  /* thread hasn't signaled, nothing to do right now. */
       
   341     }
       
   342 
       
   343     SDL_LockMutex(s_mutexJoyStickEnum);
       
   344 
       
   345     s_bDeviceAdded = SDL_FALSE;
       
   346     s_bDeviceRemoved = SDL_FALSE;
       
   347 
       
   348     pCurList = SYS_Joystick;
       
   349     SYS_Joystick = NULL;
       
   350 
       
   351     /* Look for DirectInput joysticks, wheels, head trackers, gamepads, etc.. */
       
   352     SDL_DINPUT_JoystickDetect(&pCurList);
       
   353 
       
   354     /* Look for XInput devices. Do this last, so they're first in the final list. */
       
   355     SDL_XINPUT_JoystickDetect(&pCurList);
       
   356 
       
   357     SDL_UnlockMutex(s_mutexJoyStickEnum);
       
   358 
       
   359     while (pCurList) {
       
   360         JoyStick_DeviceData *pListNext = NULL;
       
   361 
       
   362         if (pCurList->bXInputDevice) {
       
   363             SDL_XINPUT_MaybeRemoveDevice(pCurList->XInputUserId);
       
   364         } else {
       
   365             SDL_DINPUT_MaybeRemoveDevice(&pCurList->dxdevice);
       
   366         }
       
   367 
       
   368 #if !SDL_EVENTS_DISABLED
       
   369         SDL_zero(event);
       
   370         event.type = SDL_JOYDEVICEREMOVED;
       
   371 
       
   372         if (SDL_GetEventState(event.type) == SDL_ENABLE) {
       
   373             event.jdevice.which = pCurList->nInstanceID;
       
   374             if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
       
   375                 SDL_PushEvent(&event);
       
   376             }
       
   377         }
       
   378 #endif /* !SDL_EVENTS_DISABLED */
       
   379 
       
   380         pListNext = pCurList->pNext;
       
   381         SDL_free(pCurList->joystickname);
       
   382         SDL_free(pCurList);
       
   383         pCurList = pListNext;
       
   384     }
       
   385 
       
   386     if (s_bDeviceAdded) {
       
   387         JoyStick_DeviceData *pNewJoystick;
       
   388         int device_index = 0;
       
   389         s_bDeviceAdded = SDL_FALSE;
       
   390         pNewJoystick = SYS_Joystick;
       
   391         while (pNewJoystick) {
       
   392             if (pNewJoystick->send_add_event) {
       
   393                 if (pNewJoystick->bXInputDevice) {
       
   394                     SDL_XINPUT_MaybeAddDevice(pNewJoystick->XInputUserId);
       
   395                 } else {
       
   396                     SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice);
       
   397                 }
       
   398 
       
   399 #if !SDL_EVENTS_DISABLED
       
   400                 SDL_zero(event);
       
   401                 event.type = SDL_JOYDEVICEADDED;
       
   402 
       
   403                 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
       
   404                     event.jdevice.which = device_index;
       
   405                     if ((!SDL_EventOK) || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
       
   406                         SDL_PushEvent(&event);
       
   407                     }
       
   408                 }
       
   409 #endif /* !SDL_EVENTS_DISABLED */
       
   410                 pNewJoystick->send_add_event = SDL_FALSE;
       
   411             }
       
   412             device_index++;
       
   413             pNewJoystick = pNewJoystick->pNext;
       
   414         }
       
   415     }
       
   416 }
       
   417 
       
   418 /* Function to get the device-dependent name of a joystick */
       
   419 const char *
       
   420 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
       
   421 {
       
   422     JoyStick_DeviceData *device = SYS_Joystick;
       
   423 
       
   424     for (; device_index > 0; device_index--)
       
   425         device = device->pNext;
       
   426 
       
   427     return device->joystickname;
       
   428 }
       
   429 
       
   430 /* Function to perform the mapping between current device instance and this joysticks instance id */
       
   431 SDL_JoystickID
       
   432 SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
       
   433 {
       
   434     JoyStick_DeviceData *device = SYS_Joystick;
       
   435     int index;
       
   436 
       
   437     for (index = device_index; index > 0; index--)
       
   438         device = device->pNext;
       
   439 
       
   440     return device->nInstanceID;
       
   441 }
       
   442 
       
   443 /* Function to open a joystick for use.
       
   444    The joystick to open is specified by the index field of the joystick.
       
   445    This should fill the nbuttons and naxes fields of the joystick structure.
       
   446    It returns 0, or -1 if there is an error.
       
   447  */
       
   448 int
       
   449 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
       
   450 {
       
   451     JoyStick_DeviceData *joystickdevice = SYS_Joystick;
       
   452 
       
   453     for (; device_index > 0; device_index--)
       
   454         joystickdevice = joystickdevice->pNext;
       
   455 
       
   456     /* allocate memory for system specific hardware data */
       
   457     joystick->instance_id = joystickdevice->nInstanceID;
       
   458     joystick->closed = SDL_FALSE;
       
   459     joystick->hwdata =
       
   460         (struct joystick_hwdata *) SDL_malloc(sizeof(struct joystick_hwdata));
       
   461     if (joystick->hwdata == NULL) {
       
   462         return SDL_OutOfMemory();
       
   463     }
       
   464     SDL_zerop(joystick->hwdata);
       
   465     joystick->hwdata->guid = joystickdevice->guid;
       
   466 
       
   467     if (joystickdevice->bXInputDevice) {
       
   468         return SDL_XINPUT_JoystickOpen(joystick, joystickdevice);
       
   469     } else {
       
   470         return SDL_DINPUT_JoystickOpen(joystick, joystickdevice);
       
   471     }
       
   472 }
       
   473 
       
   474 /* return true if this joystick is plugged in right now */
       
   475 SDL_bool 
       
   476 SDL_SYS_JoystickAttached(SDL_Joystick * joystick)
       
   477 {
       
   478     return !joystick->closed && !joystick->hwdata->removed;
       
   479 }
       
   480 
       
   481 void
       
   482 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
       
   483 {
       
   484     if (joystick->closed || !joystick->hwdata) {
       
   485         return;
       
   486     }
       
   487 
       
   488     if (joystick->hwdata->bXInputDevice) {
       
   489         SDL_XINPUT_JoystickUpdate(joystick);
       
   490     } else {
       
   491         SDL_DINPUT_JoystickUpdate(joystick);
       
   492     }
       
   493 
       
   494     if (joystick->hwdata->removed) {
       
   495         joystick->closed = SDL_TRUE;
       
   496         joystick->uncentered = SDL_TRUE;
       
   497     }
       
   498 }
       
   499 
       
   500 /* Function to close a joystick after use */
       
   501 void
       
   502 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
       
   503 {
       
   504     if (joystick->hwdata->bXInputDevice) {
       
   505         SDL_XINPUT_JoystickClose(joystick);
       
   506     } else {
       
   507         SDL_DINPUT_JoystickClose(joystick);
       
   508     }
       
   509 
       
   510     /* free system specific hardware data */
       
   511     SDL_free(joystick->hwdata);
       
   512 
       
   513     joystick->closed = SDL_TRUE;
       
   514 }
       
   515 
       
   516 /* Function to perform any system-specific joystick related cleanup */
       
   517 void
       
   518 SDL_SYS_JoystickQuit(void)
       
   519 {
       
   520     JoyStick_DeviceData *device = SYS_Joystick;
       
   521 
       
   522     while (device) {
       
   523         JoyStick_DeviceData *device_next = device->pNext;
       
   524         SDL_free(device->joystickname);
       
   525         SDL_free(device);
       
   526         device = device_next;
       
   527     }
       
   528     SYS_Joystick = NULL;
       
   529 
       
   530     if (s_threadJoystick) {
       
   531         SDL_LockMutex(s_mutexJoyStickEnum);
       
   532         s_bJoystickThreadQuit = SDL_TRUE;
       
   533         SDL_CondBroadcast(s_condJoystickThread); /* signal the joystick thread to quit */
       
   534         SDL_UnlockMutex(s_mutexJoyStickEnum);
       
   535         SDL_WaitThread(s_threadJoystick, NULL); /* wait for it to bugger off */
       
   536 
       
   537         SDL_DestroyMutex(s_mutexJoyStickEnum);
       
   538         SDL_DestroyCond(s_condJoystickThread);
       
   539         s_condJoystickThread= NULL;
       
   540         s_mutexJoyStickEnum = NULL;
       
   541         s_threadJoystick = NULL;
       
   542     }
       
   543 
       
   544     SDL_DINPUT_JoystickQuit();
       
   545     SDL_XINPUT_JoystickQuit();
       
   546 }
       
   547 
       
   548 /* return the stable device guid for this device index */
       
   549 SDL_JoystickGUID
       
   550 SDL_SYS_JoystickGetDeviceGUID(int device_index)
       
   551 {
       
   552     JoyStick_DeviceData *device = SYS_Joystick;
       
   553     int index;
       
   554 
       
   555     for (index = device_index; index > 0; index--)
       
   556         device = device->pNext;
       
   557 
       
   558     return device->guid;
       
   559 }
       
   560 
       
   561 SDL_JoystickGUID
       
   562 SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
       
   563 {
       
   564     return joystick->hwdata->guid;
       
   565 }
       
   566 
       
   567 #endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */
       
   568 
       
   569 /* vi: set ts=4 sw=4 expandtab: */