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