src/joystick/win32/SDL_dxjoystick.c
changeset 2198 fe19afb86473
parent 1895 c121d94672cb
child 2576 034440120c38
child 2698 e1da92da346c
child 2713 0906692aa6a4
equal deleted inserted replaced
2197:2ff40f30af31 2198:fe19afb86473
    42 #define WIN32_LEAN_AND_MEAN
    42 #define WIN32_LEAN_AND_MEAN
    43 #include <windows.h>
    43 #include <windows.h>
    44 
    44 
    45 #define DIRECTINPUT_VERSION 0x0500
    45 #define DIRECTINPUT_VERSION 0x0500
    46 #include <dinput.h>
    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
    47 
    60 
    48 #define INPUT_QSIZE	32      /* Buffer up to 32 input messages */
    61 #define INPUT_QSIZE	32      /* Buffer up to 32 input messages */
    49 
       
    50 extern HINSTANCE SDL_Instance;
       
    51 extern int DX5_Load();
       
    52 extern void DX5_Unload();
       
    53 extern HRESULT(WINAPI * DInputCreate) (HINSTANCE hinst, DWORD dwVersion,
       
    54                                        LPDIRECTINPUT * ppDI,
       
    55                                        LPUNKNOWN punkOuter);
       
    56 
       
    57 static LPDIRECTINPUT dinput = NULL;
       
    58 
       
    59 #define MAX_JOYSTICKS	8
    62 #define MAX_JOYSTICKS	8
    60 #define MAX_INPUTS	256     /* each joystick can have up to 256 inputs */
    63 #define MAX_INPUTS	256     /* each joystick can have up to 256 inputs */
    61 #define AXIS_MIN	-32768  /* minimum value for axis coordinate */
    64 #define AXIS_MIN	-32768  /* minimum value for axis coordinate */
    62 #define AXIS_MAX	32767   /* maximum value for axis coordinate */
    65 #define AXIS_MAX	32767   /* maximum value for axis coordinate */
    63 #define JOY_AXIS_THRESHOLD	(((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
    66 #define JOY_AXIS_THRESHOLD	(((AXIS_MAX)-(AXIS_MIN))/100)   /* 1% motion */
    64 
    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 */
    65 typedef enum Type
    99 typedef enum Type
    66 { BUTTON, AXIS, HAT } Type;
   100 { BUTTON, AXIS, HAT } Type;
    67 
       
    68 /* array to hold joystick ID values */
       
    69 static DIDEVICEINSTANCE SYS_Joystick[MAX_JOYSTICKS];
       
    70 static int SYS_NumJoysticks;
       
    71 
       
    72 extern HWND SDL_Window;
       
    73 
   101 
    74 typedef struct input_t
   102 typedef struct input_t
    75 {
   103 {
    76     /* DirectInput offset for this input type: */
   104     /* DirectInput offset for this input type: */
    77     DWORD ofs;
   105     DWORD ofs;
    85 
   113 
    86 /* The private structure used to keep track of a joystick */
   114 /* The private structure used to keep track of a joystick */
    87 struct joystick_hwdata
   115 struct joystick_hwdata
    88 {
   116 {
    89     LPDIRECTINPUTDEVICE2 InputDevice;
   117     LPDIRECTINPUTDEVICE2 InputDevice;
       
   118     DIDEVCAPS Capabilities;
    90     int buffered;
   119     int buffered;
    91 
   120 
    92     input_t Inputs[MAX_INPUTS];
   121     input_t Inputs[MAX_INPUTS];
    93     int NumInputs;
   122     int NumInputs;
    94 };
   123 };
    95 
   124 
    96 /* Convert a DirectInput return code to a text message */
   125 /* Convert a DirectInput return code to a text message */
    97 static void
   126 static void
    98 SetDIerror(char *function, int code)
   127 SetDIerror(const char *function, HRESULT code)
    99 {
   128 {
   100     static char *error;
   129     SDL_SetError("%s() [%s]: %s", function,
   101     static char errbuf[1024];
   130                  DXGetErrorString9(code), DXGetErrorDescription9(code));
   102 
   131 }
   103     errbuf[0] = 0;
   132 
   104     switch (code) {
   133 
   105     case DIERR_GENERIC:
   134 /* Function to scan the system for joysticks.
   106         error = "Undefined error!";
   135  * This function should set SDL_numjoysticks to the number of available
   107         break;
   136  * joysticks.  Joystick 0 should be the system default joystick.
   108     case DIERR_OLDDIRECTINPUTVERSION:
   137  * It should return 0, or -1 on an unrecoverable fatal error.
   109         error = "Your version of DirectInput needs upgrading";
   138  */
   110         break;
   139 int
   111     case DIERR_INVALIDPARAM:
   140 SDL_SYS_JoystickInit(void)
   112         error = "Invalid parameters";
   141 {
   113         break;
   142     HRESULT result;
   114     case DIERR_OUTOFMEMORY:
   143 
   115         error = "Out of memory";
   144     SYS_NumJoysticks = 0;
   116         break;
   145 
   117     case DIERR_DEVICENOTREG:
   146     result = CoInitialize(NULL);
   118         error = "Device not registered";
   147     if (FAILED(result)) {
   119         break;
   148         SetDIerror("CoInitialize", result);
   120     case DIERR_NOINTERFACE:
   149         return (-1);
   121         error = "Interface not supported";
   150     }
   122         break;
   151 
   123     case DIERR_NOTINITIALIZED:
   152     result = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER,
   124         error = "Device not initialized";
   153                               &IID_IDirectInput, &dinput);
   125         break;
   154 
   126     default:
   155     if (FAILED(result)) {
   127         sprintf(errbuf, "%s: Unknown DirectInput error: 0x%x",
   156         SetDIerror("CoCreateInstance", result);
   128                 function, code);
   157         return (-1);
   129         break;
   158     }
   130     }
   159 
   131     if (!errbuf[0]) {
   160     /* Because we used CoCreateInstance, we need to Initialize it, first. */
   132         sprintf(errbuf, "%s: %s", function, error);
   161     result =
   133     }
   162         IDirectInput_Initialize(dinput, SDL_Instance, DIRECTINPUT_VERSION);
   134     SDL_SetError("%s", errbuf);
   163 
   135     return;
   164     if (FAILED(result)) {
   136 }
   165         SetDIerror("IDirectInput::Initialize", result);
   137 
   166         return (-1);
   138 
   167     }
   139 BOOL CALLBACK
   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
   140 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   179 EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
   141 {
   180 {
   142     memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
   181     memcpy(&SYS_Joystick[SYS_NumJoysticks], pdidInstance,
   143            sizeof(DIDEVICEINSTANCE));
   182            sizeof(DIDEVICEINSTANCE));
   144     SYS_NumJoysticks++;
   183     SYS_NumJoysticks++;
   147         return DIENUM_STOP;
   186         return DIENUM_STOP;
   148 
   187 
   149     return DIENUM_CONTINUE;
   188     return DIENUM_CONTINUE;
   150 }
   189 }
   151 
   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 
   152 static BOOL CALLBACK
   351 static BOOL CALLBACK
   153 DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   352 EnumDevObjectsCallback(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID pvRef)
   154 {
   353 {
   155     SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
   354     SDL_Joystick *joystick = (SDL_Joystick *) pvRef;
   156     HRESULT result;
   355     HRESULT result;
   157     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   356     input_t *in = &joystick->hwdata->Inputs[joystick->hwdata->NumInputs];
   158     const int SupportedMask = DIDFT_BUTTON | DIDFT_POV | DIDFT_AXIS;
       
   159     if (!(dev->dwType & SupportedMask))
       
   160         return DIENUM_CONTINUE; /* unsupported */
       
   161 
   357 
   162     in->ofs = dev->dwOfs;
   358     in->ofs = dev->dwOfs;
   163 
   359 
   164     if (dev->dwType & DIDFT_BUTTON) {
   360     if (dev->dwType & DIDFT_BUTTON) {
   165         in->type = BUTTON;
   361         in->type = BUTTON;
   167         joystick->nbuttons++;
   363         joystick->nbuttons++;
   168     } else if (dev->dwType & DIDFT_POV) {
   364     } else if (dev->dwType & DIDFT_POV) {
   169         in->type = HAT;
   365         in->type = HAT;
   170         in->num = joystick->nhats;
   366         in->num = joystick->nhats;
   171         joystick->nhats++;
   367         joystick->nhats++;
   172     } else {                    /* dev->dwType & DIDFT_AXIS */
   368     } else if (dev->dwType & DIDFT_AXIS) {
   173         DIPROPRANGE diprg;
   369         DIPROPRANGE diprg;
   174         DIPROPDWORD dilong;
   370         DIPROPDWORD dilong;
   175 
   371 
   176         in->type = AXIS;
   372         in->type = AXIS;
   177         in->num = joystick->naxes;
   373         in->num = joystick->naxes;
   184         diprg.lMax = AXIS_MAX;
   380         diprg.lMax = AXIS_MAX;
   185 
   381 
   186         result =
   382         result =
   187             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   383             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   188                                             DIPROP_RANGE, &diprg.diph);
   384                                             DIPROP_RANGE, &diprg.diph);
   189         if (result != DI_OK)
   385         if (FAILED(result)) {
   190             return DIENUM_CONTINUE;     /* don't use this axis */
   386             return DIENUM_CONTINUE;     /* don't use this axis */
       
   387         }
   191 
   388 
   192         /* Set dead zone to 0. */
   389         /* Set dead zone to 0. */
   193         dilong.diph.dwSize = sizeof(dilong);
   390         dilong.diph.dwSize = sizeof(dilong);
   194         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   391         dilong.diph.dwHeaderSize = sizeof(dilong.diph);
   195         dilong.diph.dwObj = dev->dwOfs;
   392         dilong.diph.dwObj = dev->dwOfs;
   196         dilong.diph.dwHow = DIPH_BYOFFSET;
   393         dilong.diph.dwHow = DIPH_BYOFFSET;
   197         dilong.dwData = 0;
   394         dilong.dwData = 0;
   198         result =
   395         result =
   199             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   396             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   200                                             DIPROP_DEADZONE, &dilong.diph);
   397                                             DIPROP_DEADZONE, &dilong.diph);
   201         if (result != DI_OK)
   398         if (FAILED(result)) {
   202             return DIENUM_CONTINUE;     /* don't use this axis */
   399             return DIENUM_CONTINUE;     /* don't use this axis */
       
   400         }
   203 
   401 
   204         joystick->naxes++;
   402         joystick->naxes++;
       
   403     } else {
       
   404         /* not supported at this time */
       
   405         return DIENUM_CONTINUE;
   205     }
   406     }
   206 
   407 
   207     joystick->hwdata->NumInputs++;
   408     joystick->hwdata->NumInputs++;
   208 
   409 
   209     if (joystick->hwdata->NumInputs == MAX_INPUTS)
   410     if (joystick->hwdata->NumInputs == MAX_INPUTS) {
   210         return DIENUM_STOP;     /* too many */
   411         return DIENUM_STOP;     /* too many */
       
   412     }
   211 
   413 
   212     return DIENUM_CONTINUE;
   414     return DIENUM_CONTINUE;
   213 }
   415 }
   214 
   416 
   215 /* Function to scan the system for joysticks.
   417 /* Function to update the state of a joystick - called as a device poll.
   216  * This function should set SDL_numjoysticks to the number of available
   418  * This function shouldn't update the joystick structure directly,
   217  * joysticks.  Joystick 0 should be the system default joystick.
   419  * but instead should call SDL_PrivateJoystick*() to deliver events
   218  * It should return 0, or -1 on an unrecoverable fatal error.
   420  * and update joystick device state.
   219  */
   421  */
   220 int
   422 void
   221 SDL_SYS_JoystickInit(void)
   423 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
   222 {
   424 {
       
   425     DIJOYSTATE2 state;
   223     HRESULT result;
   426     HRESULT result;
   224 
   427     int i;
   225     SYS_NumJoysticks = 0;
   428 
   226 
   429     result =
   227     /* Create the DirectInput object */
   430         IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   228     if (DX5_Load() < 0) {
   431                                            sizeof(DIJOYSTATE2), &state);
   229         SDL_SetError("Couldn't load DirectInput");
   432     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   230         return (-1);
   433         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   231     }
   434         result =
   232     result = DInputCreate(SDL_Instance, DIRECTINPUT_VERSION, &dinput, NULL);
   435             IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
   233     if (result != DI_OK) {
   436                                                sizeof(DIJOYSTATE2), &state);
   234         DX5_Unload();
   437     }
   235         SetDIerror("DirectInputCreate", result);
   438 
   236         return (-1);
   439     /* Set each known axis, button and POV. */
   237     }
   440     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
   238 
   441         const input_t *in = &joystick->hwdata->Inputs[i];
   239     result = IDirectInput_EnumDevices(dinput,
   442 
   240                                       DIDEVTYPE_JOYSTICK,
   443         switch (in->type) {
   241                                       EnumJoysticksCallback,
   444         case AXIS:
   242                                       NULL, DIEDFL_ATTACHEDONLY);
   445             switch (in->ofs) {
   243 
   446             case DIJOFS_X:
   244     return SYS_NumJoysticks;
   447                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   245 }
   448                                             (Sint16) state.lX);
   246 
   449                 break;
   247 /* Function to get the device-dependent name of a joystick */
   450             case DIJOFS_Y:
   248 const char *
   451                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   249 SDL_SYS_JoystickName(int index)
   452                                             (Sint16) state.lY);
   250 {
   453                 break;
   251         /***-> test for invalid index ? */
   454             case DIJOFS_Z:
   252     return (SYS_Joystick[index].tszProductName);
   455                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   253 }
   456                                             (Sint16) state.lZ);
   254 
   457                 break;
   255 /* Function to open a joystick for use.
   458             case DIJOFS_RX:
   256    The joystick to open is specified by the index field of the joystick.
   459                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   257    This should fill the nbuttons and naxes fields of the joystick structure.
   460                                             (Sint16) state.lRx);
   258    It returns 0, or -1 if there is an error.
   461                 break;
   259  */
   462             case DIJOFS_RY:
   260 int
   463                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
   261 SDL_SYS_JoystickOpen(SDL_Joystick * joystick)
   464                                             (Sint16) state.lRy);
   262 {
   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;
   263     HRESULT result;
   505     HRESULT result;
   264     LPDIRECTINPUTDEVICE device;
   506     DWORD numevents;
   265 
   507     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
   266     /* allocate memory for system specific hardware data */
   508 
   267     joystick->hwdata =
   509     numevents = INPUT_QSIZE;
   268         (struct joystick_hwdata *) malloc(sizeof(*joystick->hwdata));
   510     result =
   269     if (joystick->hwdata == NULL) {
   511         IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   270         SDL_OutOfMemory();
   512                                           sizeof(DIDEVICEOBJECTDATA), evtbuf,
   271         return (-1);
   513                                           &numevents, 0);
   272     }
   514     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
   273     memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   515         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
   274     joystick->hwdata->buffered = 1;
       
   275 
       
   276     result =
       
   277         IDirectInput_CreateDevice(dinput,
       
   278                                   &SYS_Joystick[joystick->index].
       
   279                                   guidInstance, &device, NULL);
       
   280     if (result != DI_OK) {
       
   281         SetDIerror("DirectInput::CreateDevice", result);
       
   282         return (-1);
       
   283     }
       
   284 
       
   285     result = IDirectInputDevice_QueryInterface(device,
       
   286                                                &IID_IDirectInputDevice2,
       
   287                                                (LPVOID *) & joystick->
       
   288                                                hwdata->InputDevice);
       
   289     IDirectInputDevice_Release(device);
       
   290     if (result != DI_OK) {
       
   291         SetDIerror("DirectInputDevice::QueryInterface", result);
       
   292         return (-1);
       
   293     }
       
   294 
       
   295     result =
       
   296         IDirectInputDevice2_SetCooperativeLevel(joystick->hwdata->
       
   297                                                 InputDevice, SDL_Window,
       
   298                                                 DISCL_NONEXCLUSIVE |
       
   299                                                 DISCL_BACKGROUND);
       
   300     if (result != DI_OK) {
       
   301         SetDIerror("DirectInputDevice::SetCooperativeLevel", result);
       
   302         return (-1);
       
   303     }
       
   304 
       
   305     result =
       
   306         IDirectInputDevice2_SetDataFormat(joystick->hwdata->InputDevice,
       
   307                                           &c_dfDIJoystick);
       
   308     if (result != DI_OK) {
       
   309         SetDIerror("DirectInputDevice::SetDataFormat", result);
       
   310         return (-1);
       
   311     }
       
   312 
       
   313     IDirectInputDevice2_EnumObjects(joystick->hwdata->InputDevice,
       
   314                                     DIJoystick_EnumDevObjectsProc,
       
   315                                     joystick,
       
   316                                     DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
       
   317 
       
   318     {
       
   319         DIPROPDWORD dipdw;
       
   320         memset(&dipdw, 0, sizeof(dipdw));
       
   321         dipdw.diph.dwSize = sizeof(dipdw);
       
   322         dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
       
   323         dipdw.diph.dwObj = 0;
       
   324         dipdw.diph.dwHow = DIPH_DEVICE;
       
   325         dipdw.dwData = INPUT_QSIZE;
       
   326         result =
   516         result =
   327             IDirectInputDevice2_SetProperty(joystick->hwdata->InputDevice,
   517             IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
   328                                             DIPROP_BUFFERSIZE, &dipdw.diph);
   518                                               sizeof(DIDEVICEOBJECTDATA),
   329 
   519                                               evtbuf, &numevents, 0);
   330         if (result == DI_POLLEDDEVICE) {
   520     }
   331             /* This device doesn't support buffering, so we're forced
   521 
   332              * to use less reliable polling. */
   522     /* Handle the events or punt */
   333             joystick->hwdata->buffered = 0;
   523     if (FAILED(result))
   334         } else if (result != DI_OK) {
   524         return;
   335             SetDIerror("DirectInputDevice::SetProperty", result);
   525 
   336             return (-1);
   526     for (i = 0; i < (int) numevents; ++i) {
   337         }
   527         int j;
   338     }
   528 
   339 
   529         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
   340     return (0);
   530             const input_t *in = &joystick->hwdata->Inputs[j];
   341 }
   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 
   342 
   556 
   343 static Uint8
   557 static Uint8
   344 TranslatePOV(DWORD value)
   558 TranslatePOV(DWORD value)
   345 {
   559 {
   346     const int HAT_VALS[] = {
   560     const int HAT_VALS[] = {
   393     if (joystick->buttons[button] != state)
   607     if (joystick->buttons[button] != state)
   394         return SDL_PrivateJoystickButton(joystick, button, state);
   608         return SDL_PrivateJoystickButton(joystick, button, state);
   395     return 0;
   609     return 0;
   396 }
   610 }
   397 
   611 
   398 /* Function to update the state of a joystick - called as a device poll.
       
   399  * This function shouldn't update the joystick structure directly,
       
   400  * but instead should call SDL_PrivateJoystick*() to deliver events
       
   401  * and update joystick device state.
       
   402  */
       
   403 void
       
   404 SDL_SYS_JoystickUpdate_Polled(SDL_Joystick * joystick)
       
   405 {
       
   406     DIJOYSTATE state;
       
   407     HRESULT result;
       
   408     int i;
       
   409 
       
   410     result =
       
   411         IDirectInputDevice2_GetDeviceState(joystick->hwdata->InputDevice,
       
   412                                            sizeof(state), &state);
       
   413     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
       
   414         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
       
   415         result =
       
   416             IDirectInputDevice2_GetDeviceState(joystick->hwdata->
       
   417                                                InputDevice, sizeof(state),
       
   418                                                &state);
       
   419     }
       
   420 
       
   421     /* Set each known axis, button and POV. */
       
   422     for (i = 0; i < joystick->hwdata->NumInputs; ++i) {
       
   423         const input_t *in = &joystick->hwdata->Inputs[i];
       
   424 
       
   425         switch (in->type) {
       
   426         case AXIS:
       
   427             switch (in->ofs) {
       
   428             case DIJOFS_X:
       
   429                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   430                                             (Sint16) state.lX);
       
   431                 break;
       
   432             case DIJOFS_Y:
       
   433                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   434                                             (Sint16) state.lY);
       
   435                 break;
       
   436             case DIJOFS_Z:
       
   437                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   438                                             (Sint16) state.lZ);
       
   439                 break;
       
   440             case DIJOFS_RX:
       
   441                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   442                                             (Sint16) state.lRx);
       
   443                 break;
       
   444             case DIJOFS_RY:
       
   445                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   446                                             (Sint16) state.lRy);
       
   447                 break;
       
   448             case DIJOFS_RZ:
       
   449                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   450                                             (Sint16) state.lRz);
       
   451                 break;
       
   452             case DIJOFS_SLIDER(0):
       
   453                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   454                                             (Sint16) state.rglSlider[0]);
       
   455                 break;
       
   456             case DIJOFS_SLIDER(1):
       
   457                 SDL_PrivateJoystickAxis_Int(joystick, in->num,
       
   458                                             (Sint16) state.rglSlider[0]);
       
   459                 break;
       
   460             }
       
   461 
       
   462             break;
       
   463 
       
   464         case BUTTON:
       
   465             SDL_PrivateJoystickButton_Int(joystick, in->num,
       
   466                                           (Uint8) (state.
       
   467                                                    rgbButtons[in->ofs -
       
   468                                                               DIJOFS_BUTTON0]
       
   469                                                    ? SDL_PRESSED :
       
   470                                                    SDL_RELEASED));
       
   471             break;
       
   472         case HAT:
       
   473             {
       
   474                 Uint8 pos =
       
   475                     TranslatePOV(state.rgdwPOV[in->ofs - DIJOFS_POV(0)]);
       
   476                 SDL_PrivateJoystickHat_Int(joystick, in->num, pos);
       
   477                 break;
       
   478             }
       
   479         }
       
   480     }
       
   481 }
       
   482 
       
   483 void
       
   484 SDL_SYS_JoystickUpdate_Buffered(SDL_Joystick * joystick)
       
   485 {
       
   486     int i;
       
   487     HRESULT result;
       
   488     DWORD numevents;
       
   489     DIDEVICEOBJECTDATA evtbuf[INPUT_QSIZE];
       
   490 
       
   491     numevents = INPUT_QSIZE;
       
   492     result =
       
   493         IDirectInputDevice2_GetDeviceData(joystick->hwdata->InputDevice,
       
   494                                           sizeof(DIDEVICEOBJECTDATA),
       
   495                                           evtbuf, &numevents, 0);
       
   496     if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) {
       
   497         IDirectInputDevice2_Acquire(joystick->hwdata->InputDevice);
       
   498         result =
       
   499             IDirectInputDevice2_GetDeviceData(joystick->hwdata->
       
   500                                               InputDevice,
       
   501                                               sizeof(DIDEVICEOBJECTDATA),
       
   502                                               evtbuf, &numevents, 0);
       
   503     }
       
   504 
       
   505     /* Handle the events */
       
   506     if (result != DI_OK)
       
   507         return;
       
   508 
       
   509     for (i = 0; i < (int) numevents; ++i) {
       
   510         int j;
       
   511 
       
   512         for (j = 0; j < joystick->hwdata->NumInputs; ++j) {
       
   513             const input_t *in = &joystick->hwdata->Inputs[j];
       
   514 
       
   515             if (evtbuf[i].dwOfs != in->ofs)
       
   516                 continue;
       
   517 
       
   518             switch (in->type) {
       
   519             case AXIS:
       
   520                 SDL_PrivateJoystickAxis(joystick, in->num,
       
   521                                         (Sint16) evtbuf[i].dwData);
       
   522                 break;
       
   523             case BUTTON:
       
   524                 SDL_PrivateJoystickButton(joystick, in->num,
       
   525                                           (Uint8) (evtbuf[i].
       
   526                                                    dwData ? SDL_PRESSED
       
   527                                                    : SDL_RELEASED));
       
   528                 break;
       
   529             case HAT:
       
   530                 {
       
   531                     Uint8 pos = TranslatePOV(evtbuf[i].dwData);
       
   532                     SDL_PrivateJoystickHat(joystick, in->num, pos);
       
   533                 }
       
   534             }
       
   535         }
       
   536     }
       
   537 }
       
   538 
       
   539 void
   612 void
   540 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   613 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   541 {
   614 {
   542     HRESULT result;
   615     HRESULT result;
   543 
   616 
   570 void
   643 void
   571 SDL_SYS_JoystickQuit(void)
   644 SDL_SYS_JoystickQuit(void)
   572 {
   645 {
   573     IDirectInput_Release(dinput);
   646     IDirectInput_Release(dinput);
   574     dinput = NULL;
   647     dinput = NULL;
   575     DX5_Unload();
       
   576 }
   648 }
   577 
   649 
   578 #endif /* SDL_JOYSTICK_DINPUT */
   650 #endif /* SDL_JOYSTICK_DINPUT */
   579 /* vi: set ts=4 sw=4 expandtab: */
   651 /* vi: set ts=4 sw=4 expandtab: */