src/joystick/win32/SDL_dxjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 15 Jul 2007 01:51:11 +0000
changeset 2198 fe19afb86473
parent 1895 c121d94672cb
child 2576 034440120c38
child 2698 e1da92da346c
child 2713 0906692aa6a4
permissions -rw-r--r--
Split acinclude.m4 into its component parts for easy updating
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #ifdef SDL_JOYSTICK_DINPUT
    25 
    26 /* DirectInput joystick driver; written by Glenn Maynard, based on Andrei de
    27  * A. Formiga's WINMM driver. 
    28  *
    29  * Hats and sliders are completely untested; the app I'm writing this for mostly
    30  * doesn't use them and I don't own any joysticks with them. 
    31  *
    32  * We don't bother to use event notification here.  It doesn't seem to work
    33  * with polled devices, and it's fine to call IDirectInputDevice2_GetDeviceData and
    34  * let it return 0 events. */
    35 
    36 #include "SDL_error.h"
    37 #include "SDL_events.h"
    38 #include "SDL_joystick.h"
    39 #include "../SDL_sysjoystick.h"
    40 #include "../SDL_joystick_c.h"
    41 
    42 #define WIN32_LEAN_AND_MEAN
    43 #include <windows.h>
    44 
    45 #define DIRECTINPUT_VERSION 0x0500
    46 #include <dinput.h>
    47 #ifdef _MSC_VER
    48     /* Used for the c_dfDIJoystick2 symbol (no imports are used) */
    49 #   pragma comment (lib, "dinput.lib")
    50 #endif
    51 #include <dxerr9.h>             /* From DirectX SDK 9c */
    52 #ifdef _MSC_VER
    53 #   pragma comment (lib, "dxerr9.lib")
    54 #endif
    55 
    56 /* an ISO hack for VisualC++ */
    57 #ifdef _MSC_VER
    58 #define   snprintf	_snprintf
    59 #endif
    60 
    61 #define INPUT_QSIZE	32      /* Buffer up to 32 input messages */
    62 #define MAX_JOYSTICKS	8
    63 #define MAX_INPUTS	256     /* each joystick can have up to 256 inputs */
    64 #define AXIS_MIN	-32768  /* minimum value for axis coordinate */
    65 #define AXIS_MAX	32767   /* maximum value for axis coordinate */
    66 #define JOY_AXIS_THRESHOLD	(((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
    67 
    68 /* external variables referenced. */
    69 extern HINSTANCE SDL_Instance;
    70 extern HWND SDL_Window;
    71 
    72 
    73 /* local variables */
    74 static LPDIRECTINPUT dinput = NULL;
    75 extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
    76                                        LPDIRECTINPUT * ppDI,
    77                                        LPUNKNOWN punkOuter);
    78 static DIDEVICEINSTANCE SYS_Joystick[MAX_JOYSTICKS];    /* array to hold joystick ID values */
    79 static int SYS_NumJoysticks;
    80 static HINSTANCE DInputDLL = NULL;
    81 
    82 
    83 /* local prototypes */
    84 static void SetDIerror(const char *function, HRESULT code);
    85 static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE *
    86                                            pdidInstance, VOID * pContext);
    87 static BOOL CALLBACK EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev,
    88                                             LPVOID pvRef);
    89 static Uint8 TranslatePOV(DWORD value);
    90 static int SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis,
    91                                        Sint16 value);
    92 static int SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat,
    93                                       Uint8 value);
    94 static int SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick,
    95                                          Uint8 button, Uint8 state);
    96 
    97 
    98 /* local types */
    99 typedef enum Type
   100 { BUTTON, AXIS, HAT } Type;
   101 
   102 typedef struct input_t
   103 {
   104     /* DirectInput offset for this input type: */
   105     DWORD ofs;
   106 
   107     /* Button, axis or hat: */
   108     Type type;
   109 
   110     /* SDL input offset: */
   111     Uint8 num;
   112 } input_t;
   113 
   114 /* The private structure used to keep track of a joystick */
   115 struct joystick_hwdata
   116 {
   117     LPDIRECTINPUTDEVICE2 InputDevice;
   118     DIDEVCAPS Capabilities;
   119     int buffered;
   120 
   121     input_t Inputs[MAX_INPUTS];
   122     int NumInputs;
   123 };
   124 
   125 /* Convert a DirectInput return code to a text message */
   126 static void
   127 SetDIerror(const char *function, HRESULT code)
   128 {
   129     SDL_SetError("%s() [%s]: %s", function,
   130                  DXGetErrorString9(code), DXGetErrorDescription9(code));
   131 }
   132 
   133 
   134 /* Function to scan the system for joysticks.
   135  * This function should set SDL_numjoysticks to the number of available
   136  * joysticks.  Joystick 0 should be the system default joystick.
   137  * It should return 0, or -1 on an unrecoverable fatal error.
   138  */
   139 int
   140 SDL_SYS_JoystickInit(void)
   141 {
   142     HRESULT result;
   143 
   144     SYS_NumJoysticks = 0;
   145 
   146     result = CoInitialize(NULL);
   147     if (FAILED(result)) {
   148         SetDIerror("CoInitialize", result);
   149         return (-1);
   150     }
   151 
   152     result = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
   153                               &IID_IDirectInput, &dinput);
   154 
   155     if (FAILED(result)) {
   156         SetDIerror("CoCreateInstance", result);
   157         return (-1);
   158     }
   159 
   160     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   161     result =
   162         IDirectInput_Initialize(dinput, SDL_Instance, DIRECTINPUT_VERSION);
   163 
   164     if (FAILED(result)) {
   165         SetDIerror("IDirectInput::Initialize", result);
   166         return (-1);
   167     }
   168 
   169     /* Look for joysticks, wheels, head trackers, gamepads, etc.. */
   170     result = IDirectInput_EnumDevices(dinput,
   171                                       DIDEVTYPE_JOYSTICK,
   172                                       EnumJoysticksCallback,
   173                                       NULL, DIEDFL_ATTACHEDONLY);
   174 
   175     return SYS_NumJoysticks;
   176 }
   177 
   178 static BOOL CALLBACK
   179 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   180 {
   181     memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
   182            sizeof(DIDEVICEINSTANCE));
   183     SYS_NumJoysticks++;
   184 
   185     if (SYS_NumJoysticks >= MAX_JOYSTICKS)
   186         return DIENUM_STOP;
   187 
   188     return DIENUM_CONTINUE;
   189 }
   190 
   191 /* Function to get the device-dependent name of a joystick */
   192 const char *
   193 SDL_SYS_JoystickName(int index)
   194 {
   195         /***-> test for invalid index ? */
   196     return (SYS_Joystick[index].tszProductName);
   197 }
   198 
   199 /* Function to open a joystick for use.
   200    The joystick to open is specified by the index field of the joystick.
   201    This should fill the nbuttons and naxes fields of the joystick structure.
   202    It returns 0, or -1 if there is an error.
   203  */
   204 int
   205 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
   206 {
   207     HRESULT result;
   208     LPDIRECTINPUTDEVICE device;
   209     DIPROPDWORD dipdw;
   210 
   211     ZeroMemory(&dipdw, sizeof(DIPROPDWORD));
   212     dipdw.diph.dwSize = sizeof(DIPROPDWORD);
   213     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
   214 
   215 
   216     /* allocate memory for system specific hardware data */
   217     joystick->hwdata =
   218         (struct joystick_hwdata *) malloc(sizeof(struct joystick_hwdata));
   219     if (joystick->hwdata == NULL) {
   220         SDL_OutOfMemory();
   221         return (-1);
   222     }
   223     ZeroMemory(joystick->hwdata, sizeof(struct joystick_hwdata));
   224     joystick->hwdata->buffered = 1;
   225     joystick->hwdata->Capabilities.dwSize = sizeof(DIDEVCAPS);
   226 
   227     result =
   228         IDirectInput_CreateDevice(dinput,
   229                                   &SYS_Joystick[joystick->index].
   230                                   guidInstance, &device, NULL);
   231     if (FAILED(result)) {
   232         SetDIerror("IDirectInput::CreateDevice", result);
   233         return (-1);
   234     }
   235 
   236     /* Now get the IDirectInputDevice2 interface, instead. */
   237     result = IDirectInputDevice_QueryInterface(device,
   238                                                &IID_IDirectInputDevice2,
   239                                                (LPVOID *) & joystick->
   240                                                hwdata->InputDevice);
   241     /* We are done with this object.  Use the stored one from now on. */
   242     IDirectInputDevice_Release(device);
   243 
   244     if (FAILED(result)) {
   245         SetDIerror("IDirectInputDevice::QueryInterface", result);
   246         return (-1);
   247     }
   248 
   249     /* Aquire shared access. Exclusive access is required for forces,
   250      * though. */
   251     result =
   252         IDirectInputDevice2_SetCooperativeLevel(joystick->hwdata->
   253                                                 InputDevice, SDL_Window,
   254                                                 DISCL_EXCLUSIVE |
   255                                                 DISCL_BACKGROUND);
   256     if (FAILED(result)) {
   257         SetDIerror("IDirectInputDevice2::SetCooperativeLevel", result);
   258         return (-1);
   259     }
   260 
   261     /* Use the extended data structure: DIJOYSTATE2. */
   262     result =
   263         IDirectInputDevice2_SetDataFormat(joystick->hwdata->InputDevice,
   264                                           &c_dfDIJoystick2);
   265     if (FAILED(result)) {
   266         SetDIerror("IDirectInputDevice2::SetDataFormat", result);
   267         return (-1);
   268     }
   269 
   270     /* Get device capabilities */
   271     result =
   272         IDirectInputDevice2_GetCapabilities(joystick->hwdata->InputDevice,
   273                                             &joystick->hwdata->Capabilities);
   274 
   275     if (FAILED(result)) {
   276         SetDIerror("IDirectInputDevice2::GetCapabilities", result);
   277         return (-1);
   278     }
   279 
   280     /* Force capable? */
   281     if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
   282 
   283         result = IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   284 
   285         if (FAILED(result)) {
   286             SetDIerror("IDirectInputDevice2::Acquire", result);
   287             return (-1);
   288         }
   289 
   290         /* reset all accuators. */
   291         result =
   292             IDirectInputDevice2_SendForceFeedbackCommand(joystick->hwdata->
   293                                                          InputDevice,
   294                                                          DISFFC_RESET);
   295 
   296         if (FAILED(result)) {
   297             SetDIerror("IDirectInputDevice2::SendForceFeedbackCommand",
   298                        result);
   299             return (-1);
   300         }
   301 
   302         result = IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   303 
   304         if (FAILED(result)) {
   305             SetDIerror("IDirectInputDevice2::Unacquire", result);
   306             return (-1);
   307         }
   308 
   309         /* Turn on auto-centering for a ForceFeedback device (until told
   310          * otherwise). */
   311         dipdw.diph.dwObj = 0;
   312         dipdw.diph.dwHow = DIPH_DEVICE;
   313         dipdw.dwData = DIPROPAUTOCENTER_ON;
   314 
   315         result =
   316             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   317                                             DIPROP_AUTOCENTER, &dipdw.diph);
   318 
   319         if (FAILED(result)) {
   320             SetDIerror("IDirectInputDevice2::SetProperty", result);
   321             return (-1);
   322         }
   323     }
   324 
   325     /* What buttons and axes does it have? */
   326     IDirectInputDevice2_EnumObjects(joystick->hwdata->InputDevice,
   327                                     EnumDevObjectsCallback, joystick,
   328                                     DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
   329 
   330     dipdw.diph.dwObj = 0;
   331     dipdw.diph.dwHow = DIPH_DEVICE;
   332     dipdw.dwData = INPUT_QSIZE;
   333 
   334     /* Set the buffer size */
   335     result =
   336         IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   337                                         DIPROP_BUFFERSIZE, &dipdw.diph);
   338 
   339     if (result == DI_POLLEDDEVICE) {
   340         /* This device doesn't support buffering, so we're forced
   341          * to use less reliable polling. */
   342         joystick->hwdata->buffered = 0;
   343     } else if (FAILED(result)) {
   344         SetDIerror("IDirectInputDevice2::SetProperty", result);
   345         return (-1);
   346     }
   347 
   348     return (0);
   349 }
   350 
   351 static BOOL CALLBACK
   352 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   353 {
   354     SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
   355     HRESULT result;
   356     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   357 
   358     in->ofs = dev->dwOfs;
   359 
   360     if (dev->dwType & DIDFT_BUTTON) {
   361         in->type = BUTTON;
   362         in->num = joystick->nbuttons;
   363         joystick->nbuttons++;
   364     } else if (dev->dwType & DIDFT_POV) {
   365         in->type = HAT;
   366         in->num = joystick->nhats;
   367         joystick->nhats++;
   368     } else if (dev->dwType & DIDFT_AXIS) {
   369         DIPROPRANGE diprg;
   370         DIPROPDWORD dilong;
   371 
   372         in->type = AXIS;
   373         in->num = joystick->naxes;
   374 
   375         diprg.diph.dwSize = sizeof(diprg);
   376         diprg.diph.dwHeaderSize = sizeof(diprg.diph);
   377         diprg.diph.dwObj = dev->dwOfs;
   378         diprg.diph.dwHow = DIPH_BYOFFSET;
   379         diprg.lMin = AXIS_MIN;
   380         diprg.lMax = AXIS_MAX;
   381 
   382         result =
   383             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   384                                             DIPROP_RANGE, &diprg.diph);
   385         if (FAILED(result)) {
   386             return DIENUM_CONTINUE;     /* don't use this axis */
   387         }
   388 
   389         /* Set dead zone to 0. */
   390         dilong.diph.dwSize = sizeof(dilong);
   391         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   392         dilong.diph.dwObj = dev->dwOfs;
   393         dilong.diph.dwHow = DIPH_BYOFFSET;
   394         dilong.dwData = 0;
   395         result =
   396             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   397                                             DIPROP_DEADZONE, &dilong.diph);
   398         if (FAILED(result)) {
   399             return DIENUM_CONTINUE;     /* don't use this axis */
   400         }
   401 
   402         joystick->naxes++;
   403     } else {
   404         /* not supported at this time */
   405         return DIENUM_CONTINUE;
   406     }
   407 
   408     joystick->hwdata->NumInputs++;
   409 
   410     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   411         return DIENUM_STOP;     /* too many */
   412     }
   413 
   414     return DIENUM_CONTINUE;
   415 }
   416 
   417 /* Function to update the state of a joystick - called as a device poll.
   418  * This function shouldn't update the joystick structure directly,
   419  * but instead should call SDL_PrivateJoystick*() to deliver events
   420  * and update joystick device state.
   421  */
   422 void
   423 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
   424 {
   425     DIJOYSTATE2 state;
   426     HRESULT result;
   427     int i;
   428 
   429     result =
   430         IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   431                                            sizeof(DIJOYSTATE2), &state);
   432     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   433         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   434         result =
   435             IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   436                                                sizeof(DIJOYSTATE2), &state);
   437     }
   438 
   439     /* Set each known axis, button and POV. */
   440     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   441         const input_t *in = &joystick->hwdata->Inputs[i];
   442 
   443         switch (in->type) {
   444         case AXIS:
   445             switch (in->ofs) {
   446             case DIJOFS_X:
   447                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   448                                             (Sint16) state.lX);
   449                 break;
   450             case DIJOFS_Y:
   451                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   452                                             (Sint16) state.lY);
   453                 break;
   454             case DIJOFS_Z:
   455                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   456                                             (Sint16) state.lZ);
   457                 break;
   458             case DIJOFS_RX:
   459                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   460                                             (Sint16) state.lRx);
   461                 break;
   462             case DIJOFS_RY:
   463                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   464                                             (Sint16) state.lRy);
   465                 break;
   466             case DIJOFS_RZ:
   467                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   468                                             (Sint16) state.lRz);
   469                 break;
   470             case DIJOFS_SLIDER(0):
   471                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   472                                             (Sint16) state.rglSlider[0]);
   473                 break;
   474             case DIJOFS_SLIDER(1):
   475                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   476                                             (Sint16) state.rglSlider[1]);
   477                 break;
   478             }
   479 
   480             break;
   481 
   482         case BUTTON:
   483             SDL_PrivateJoystickButton_Int(joystick, in->num,
   484                                           (Uint8) (state.
   485                                                    rgbButtons[in->ofs -
   486                                                               DIJOFS_BUTTON0]
   487                                                    ? SDL_PRESSED :
   488                                                    SDL_RELEASED));
   489             break;
   490         case HAT:
   491             {
   492                 Uint8 pos = TranslatePOV(state.rgdwPOV[in->ofs -
   493                                                        DIJOFS_POV(0)]);
   494                 SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
   495                 break;
   496             }
   497         }
   498     }
   499 }
   500 
   501 void
   502 SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
   503 {
   504     int i;
   505     HRESULT result;
   506     DWORD numevents;
   507     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   508 
   509     numevents = INPUT_QSIZE;
   510     result =
   511         IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   512                                           sizeof(DIDEVICEOBJECTDATA), evtbuf,
   513                                           &numevents, 0);
   514     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   515         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   516         result =
   517             IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   518                                               sizeof(DIDEVICEOBJECTDATA),
   519                                               evtbuf, &numevents, 0);
   520     }
   521 
   522     /* Handle the events or punt */
   523     if (FAILED(result))
   524         return;
   525 
   526     for (i = 0; i < (int) numevents; ++i) {
   527         int j;
   528 
   529         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   530             const input_t *in = &joystick->hwdata->Inputs[j];
   531 
   532             if (evtbuf[i].dwOfs != in->ofs)
   533                 continue;
   534 
   535             switch (in->type) {
   536             case AXIS:
   537                 SDL_PrivateJoystickAxis(joystick, in->num,
   538                                         (Sint16) evtbuf[i].dwData);
   539                 break;
   540             case BUTTON:
   541                 SDL_PrivateJoystickButton(joystick, in->num,
   542                                           (Uint8) (evtbuf[i].
   543                                                    dwData ? SDL_PRESSED :
   544                                                    SDL_RELEASED));
   545                 break;
   546             case HAT:
   547                 {
   548                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
   549                     SDL_PrivateJoystickHat(joystick, in->num, pos);
   550                 }
   551             }
   552         }
   553     }
   554 }
   555 
   556 
   557 static Uint8
   558 TranslatePOV(DWORD value)
   559 {
   560     const int HAT_VALS[] = {
   561         SDL_HAT_UP,
   562         SDL_HAT_UP | SDL_HAT_RIGHT,
   563         SDL_HAT_RIGHT,
   564         SDL_HAT_DOWN | SDL_HAT_RIGHT,
   565         SDL_HAT_DOWN,
   566         SDL_HAT_DOWN | SDL_HAT_LEFT,
   567         SDL_HAT_LEFT,
   568         SDL_HAT_UP | SDL_HAT_LEFT
   569     };
   570 
   571     if (LOWORD(value) == 0xFFFF)
   572         return SDL_HAT_CENTERED;
   573 
   574     /* Round the value up: */
   575     value += 4500 / 2;
   576     value %= 36000;
   577     value /= 4500;
   578 
   579     if (value >= 8)
   580         return SDL_HAT_CENTERED;        /* shouldn't happen */
   581 
   582     return HAT_VALS[value];
   583 }
   584 
   585 /* SDL_PrivateJoystick* doesn't discard duplicate events, so we need to
   586  * do it. */
   587 static int
   588 SDL_PrivateJoystickAxis_Int(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
   589 {
   590     if (joystick->axes[axis] != value)
   591         return SDL_PrivateJoystickAxis(joystick, axis, value);
   592     return 0;
   593 }
   594 
   595 static int
   596 SDL_PrivateJoystickHat_Int(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
   597 {
   598     if (joystick->hats[hat] != value)
   599         return SDL_PrivateJoystickHat(joystick, hat, value);
   600     return 0;
   601 }
   602 
   603 static int
   604 SDL_PrivateJoystickButton_Int(SDL_Joystick * joystick, Uint8 button,
   605                               Uint8 state)
   606 {
   607     if (joystick->buttons[button] != state)
   608         return SDL_PrivateJoystickButton(joystick, button, state);
   609     return 0;
   610 }
   611 
   612 void
   613 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   614 {
   615     HRESULT result;
   616 
   617     result = IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   618     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   619         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   620         IDirectInputDevice2_Poll(joystick->hwdata->InputDevice);
   621     }
   622 
   623     if (joystick->hwdata->buffered)
   624         SDL_SYS_JoystickUpdate_Buffered(joystick);
   625     else
   626         SDL_SYS_JoystickUpdate_Polled(joystick);
   627 }
   628 
   629 /* Function to close a joystick after use */
   630 void
   631 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   632 {
   633     IDirectInputDevice2_Unacquire(joystick->hwdata->InputDevice);
   634     IDirectInputDevice2_Release(joystick->hwdata->InputDevice);
   635 
   636     if (joystick->hwdata != NULL) {
   637         /* free system specific hardware data */
   638         free(joystick->hwdata);
   639     }
   640 }
   641 
   642 /* Function to perform any system-specific joystick related cleanup */
   643 void
   644 SDL_SYS_JoystickQuit(void)
   645 {
   646     IDirectInput_Release(dinput);
   647     dinput = NULL;
   648 }
   649 
   650 #endif /* SDL_JOYSTICK_DINPUT */
   651 /* vi: set ts=4 sw=4 expandtab: */