Home | History | Annotate | Download | only in win32
      1 /*
      2 The zlib/libpng License
      3 
      4 Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
      5 
      6 This software is provided 'as-is', without any express or implied warranty. In no event will
      7 the authors be held liable for any damages arising from the use of this software.
      8 
      9 Permission is granted to anyone to use this software for any purpose, including commercial
     10 applications, and to alter it and redistribute it freely, subject to the following
     11 restrictions:
     12 
     13     1. The origin of this software must not be misrepresented; you must not claim that
     14 		you wrote the original software. If you use this software in a product,
     15 		an acknowledgment in the product documentation would be appreciated but is
     16 		not required.
     17 
     18     2. Altered source versions must be plainly marked as such, and must not be
     19 		misrepresented as being the original software.
     20 
     21     3. This notice may not be removed or altered from any source distribution.
     22 */
     23 #include "win32/Win32JoyStick.h"
     24 #include "win32/Win32InputManager.h"
     25 #include "win32/Win32ForceFeedback.h"
     26 #include "OISEvents.h"
     27 #include "OISException.h"
     28 
     29 #include <cassert>
     30 
     31 // Only if xinput support is enabled
     32 #ifdef OIS_WIN32_XINPUT_SUPPORT
     33 #include <wbemidl.h>
     34 #include <oleauto.h>
     35 //#include <wmsstd.h>
     36 #ifndef SAFE_RELEASE
     37 #define SAFE_RELEASE(x) \
     38    if(x != NULL)        \
     39    {                    \
     40       x->Release();     \
     41       x = NULL;         \
     42    }
     43 #endif
     44 
     45 #pragma comment(lib, "xinput.lib")
     46 #endif
     47 
     48 //DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it
     49 #undef DIJOFS_BUTTON
     50 #undef DIJOFS_POV
     51 
     52 #define DIJOFS_BUTTON(n)  (FIELD_OFFSET(DIJOYSTATE2, rgbButtons) + (n))
     53 #define DIJOFS_POV(n)     (FIELD_OFFSET(DIJOYSTATE2, rgdwPOV)+(n)*sizeof(DWORD))
     54 #define DIJOFS_SLIDER0(n) (FIELD_OFFSET(DIJOYSTATE2, rglSlider)+(n) * sizeof(LONG))
     55 #define DIJOFS_SLIDER1(n) (FIELD_OFFSET(DIJOYSTATE2, rglVSlider)+(n) * sizeof(LONG))
     56 #define DIJOFS_SLIDER2(n) (FIELD_OFFSET(DIJOYSTATE2, rglASlider)+(n) * sizeof(LONG))
     57 #define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG))
     58 
     59 #define XINPUT_TRANSLATED_BUTTON_COUNT 12
     60 #define XINPUT_TRANSLATED_AXIS_COUNT 6
     61 
     62 using namespace OIS;
     63 
     64 //--------------------------------------------------------------------------------------------------//
     65 Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings, const JoyStickInfo &info ) :
     66 	JoyStick(info.vendor, buffered, info.devId, creator),
     67 	mDirectInput(pDI),
     68 	coopSetting(coopSettings),
     69 	mJoyStick(0),
     70 	mJoyInfo(info),
     71 	mFfDevice(0)
     72 {
     73 }
     74 
     75 //--------------------------------------------------------------------------------------------------//
     76 Win32JoyStick::~Win32JoyStick()
     77 {
     78 	delete mFfDevice;
     79 
     80 	if(mJoyStick)
     81 	{
     82 		mJoyStick->Unacquire();
     83 		mJoyStick->Release();
     84 		mJoyStick = 0;
     85 	}
     86 
     87 	//Return joystick to pool
     88 	static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(mJoyInfo);
     89 }
     90 
     91 //--------------------------------------------------------------------------------------------------//
     92 void Win32JoyStick::_initialize()
     93 {
     94     if (mJoyInfo.isXInput)
     95     {
     96         _enumerate();
     97     }
     98     else
     99     {
    100 	    //Clear old state
    101 	    mState.mAxes.clear();
    102 
    103 	    delete mFfDevice;
    104 	    mFfDevice = 0;
    105 
    106 	    DIPROPDWORD dipdw;
    107 
    108 	    dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
    109 	    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    110 	    dipdw.diph.dwObj        = 0;
    111 	    dipdw.diph.dwHow        = DIPH_DEVICE;
    112 	    dipdw.dwData            = JOYSTICK_DX_BUFFERSIZE;
    113 
    114 	    if(FAILED(mDirectInput->CreateDevice(mJoyInfo.deviceID, &mJoyStick, NULL)))
    115 		    OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
    116 
    117 	    if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
    118 		    OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
    119 
    120 	    HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
    121 
    122 	    if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
    123 		    OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
    124 
    125 	    if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
    126 		    OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" );
    127 
    128 	    //Enumerate all axes/buttons/sliders/etc before aquiring
    129 	    _enumerate();
    130 
    131 	    mState.clear();
    132 
    133 	    capture();
    134     }
    135 }
    136 
    137 //--------------------------------------------------------------------------------------------------//
    138 void Win32JoyStick::_enumerate()
    139 {
    140     if (mJoyInfo.isXInput)
    141     {
    142         mPOVs = 1;
    143 
    144         mState.mButtons.resize(XINPUT_TRANSLATED_BUTTON_COUNT);
    145 	    mState.mAxes.resize(XINPUT_TRANSLATED_AXIS_COUNT);
    146     }
    147     else
    148     {
    149 		// Get joystick capabilities.
    150 		mDIJoyCaps.dwSize = sizeof(DIDEVCAPS);
    151 		if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) )
    152 			OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" );
    153 
    154 	    mPOVs = (short)mDIJoyCaps.dwPOVs;
    155 
    156 	    mState.mButtons.resize(mDIJoyCaps.dwButtons);
    157 	    mState.mAxes.resize(mDIJoyCaps.dwAxes);
    158 
    159 	    //Reset the axis mapping enumeration value
    160 	    _AxisNumber = 0;
    161 
    162 	    //Enumerate Force Feedback (if any)
    163 	    mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
    164 
    165 	    //Enumerate and set axis constraints (and check FF Axes)
    166 	    mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
    167     }
    168 }
    169 
    170 //--------------------------------------------------------------------------------------------------//
    171 BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
    172 {
    173 	Win32JoyStick* _this = (Win32JoyStick*)pvRef;
    174 
    175 	//Setup mappings
    176 	DIPROPPOINTER diptr;
    177 	diptr.diph.dwSize       = sizeof(DIPROPPOINTER);
    178 	diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    179 	diptr.diph.dwHow        = DIPH_BYID;
    180 	diptr.diph.dwObj        = lpddoi->dwType;
    181 	//Add a magic number to recognise we set seomthing
    182 	diptr.uData             = 0x13130000 | _this->_AxisNumber;
    183 
    184 	//Check if axis is slider, if so, do not treat as regular axis
    185 	if(GUID_Slider == lpddoi->guidType)
    186 	{
    187 		++_this->mSliders;
    188 
    189 		//Decrease Axes, since this slider shows up in a different place
    190 		_this->mState.mAxes.pop_back();
    191 	}
    192 	else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph)))
    193 	{	//If for some reason we could not set needed user data, just ignore this axis
    194 		return DIENUM_CONTINUE;
    195 	}
    196 
    197 	//Increase for next time through
    198 	if(GUID_Slider != lpddoi->guidType)
    199 		_this->_AxisNumber += 1;
    200 
    201 	//Set range
    202 	DIPROPRANGE diprg;
    203 	diprg.diph.dwSize       = sizeof(DIPROPRANGE);
    204 	diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    205 	diprg.diph.dwHow        = DIPH_BYID;
    206 	diprg.diph.dwObj        = lpddoi->dwType;
    207 	diprg.lMin              = MIN_AXIS;
    208 	diprg.lMax              = MAX_AXIS;
    209 
    210 	if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph)))
    211 		OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
    212 
    213 	//Check if FF Axes, and if so, increment counter
    214 	if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
    215 	{
    216 		if( _this->mFfDevice )
    217 		{
    218 			_this->mFfDevice->_addFFAxis();
    219 		}
    220 	}
    221 
    222 	//Force the flags for gain and auto-center support to true,
    223 	//as DInput has no API to query the device for these capabilities
    224 	//(the only way to know is to try them ...)
    225 	if( _this->mFfDevice )
    226 	{
    227 	    _this->mFfDevice->_setGainSupport(true);
    228 	    _this->mFfDevice->_setAutoCenterSupport(true);
    229 	}
    230 
    231 	return DIENUM_CONTINUE;
    232 }
    233 
    234 //--------------------------------------------------------------------------------------------------//
    235 BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef)
    236 {
    237 	Win32JoyStick* _this = (Win32JoyStick*)pvRef;
    238 
    239 	//Create the FF instance only after we know there is at least one effect type
    240 	if( _this->mFfDevice == 0 )
    241 		_this->mFfDevice = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
    242 
    243 	_this->mFfDevice->_addEffectSupport(pdei);
    244 
    245 	return DIENUM_CONTINUE;
    246 }
    247 
    248 //--------------------------------------------------------------------------------------------------//
    249 void Win32JoyStick::capture()
    250 {
    251 #ifdef OIS_WIN32_XINPUT_SUPPORT
    252 	//handle xbox controller differently
    253     if (mJoyInfo.isXInput)
    254 	{
    255 		captureXInput();
    256 		return;
    257 	}
    258 #endif
    259 
    260 	//handle directinput based devices
    261 	DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
    262 	DWORD entries = JOYSTICK_DX_BUFFERSIZE;
    263 
    264 	// Poll the device to read the current state
    265 	HRESULT hr = mJoyStick->Poll();
    266 	if( hr == DI_OK )
    267 		hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
    268 
    269 	if( hr != DI_OK )
    270 	{
    271 		hr = mJoyStick->Acquire();
    272 		while( hr == DIERR_INPUTLOST )
    273 			hr = mJoyStick->Acquire();
    274 
    275 		// Poll the device to read the current state
    276 		mJoyStick->Poll();
    277 		hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
    278 		//Perhaps the user just tabbed away
    279 		if( FAILED(hr) )
    280 			return;
    281 	}
    282 
    283 	bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,
    284 						  false,false,false,false,false,false,false,false};
    285 	bool sliderMoved[4] = {false,false,false,false};
    286 
    287 	//Loop through all the events
    288 	for(unsigned int i = 0; i < entries; ++i)
    289 	{
    290 		//This may seem outof order, but is in order of the way these variables
    291 		//are declared in the JoyStick State 2 structure.
    292 		switch(diBuff[i].dwOfs)
    293 		{
    294 		//------ slider -//
    295 		case DIJOFS_SLIDER0(0):
    296 			sliderMoved[0] = true;
    297 			mState.mSliders[0].abX = diBuff[i].dwData;
    298 			break;
    299 		case DIJOFS_SLIDER0(1):
    300 			sliderMoved[0] = true;
    301 			mState.mSliders[0].abY = diBuff[i].dwData;
    302 			break;
    303 		//----- Max 4 POVs Next ---------------//
    304 		case DIJOFS_POV(0):
    305 			if(!_changePOV(0,diBuff[i]))
    306 				return;
    307 			break;
    308 		case DIJOFS_POV(1):
    309 			if(!_changePOV(1,diBuff[i]))
    310 				return;
    311 			break;
    312 		case DIJOFS_POV(2):
    313 			if(!_changePOV(2,diBuff[i]))
    314 				return;
    315 			break;
    316 		case DIJOFS_POV(3):
    317 			if(!_changePOV(3,diBuff[i]))
    318 				return;
    319 			break;
    320 		case DIJOFS_SLIDER1(0):
    321 			sliderMoved[1] = true;
    322 			mState.mSliders[1].abX = diBuff[i].dwData;
    323 			break;
    324 		case DIJOFS_SLIDER1(1):
    325 			sliderMoved[1] = true;
    326 			mState.mSliders[1].abY = diBuff[i].dwData;
    327 			break;
    328 		case DIJOFS_SLIDER2(0):
    329 			sliderMoved[2] = true;
    330 			mState.mSliders[2].abX = diBuff[i].dwData;
    331 			break;
    332 		case DIJOFS_SLIDER2(1):
    333 			sliderMoved[2] = true;
    334 			mState.mSliders[2].abY = diBuff[i].dwData;
    335 			break;
    336 		case DIJOFS_SLIDER3(0):
    337 			sliderMoved[3] = true;
    338 			mState.mSliders[3].abX = diBuff[i].dwData;
    339 			break;
    340 		case DIJOFS_SLIDER3(1):
    341 			sliderMoved[3] = true;
    342 			mState.mSliders[3].abY = diBuff[i].dwData;
    343 			break;
    344 		//-----------------------------------------//
    345 		default:
    346 			//Handle Button Events Easily using the DX Offset Macros
    347 			if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) )
    348 			{
    349 				if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i]))
    350 					return;
    351 			}
    352 			else if((short)(diBuff[i].uAppData >> 16) == 0x1313)
    353 			{	//If it was nothing else, might be axis enumerated earlier (determined by magic number)
    354 				int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit
    355 				assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!");
    356 
    357 				if(axis >= 0 && axis < (int)mState.mAxes.size())
    358 				{
    359 					mState.mAxes[axis].abs = diBuff[i].dwData;
    360 					axisMoved[axis] = true;
    361 				}
    362 			}
    363 
    364 			break;
    365 		} //end case
    366 	} //end for
    367 
    368 	//Check to see if any of the axes values have changed.. if so send events
    369 	if( mBuffered && mListener && entries > 0 )
    370 	{
    371 		JoyStickEvent temp(this, mState);
    372 
    373 		//Update axes
    374 		for( int i = 0; i < 24; ++i )
    375 			if( axisMoved[i] )
    376 				if( mListener->axisMoved( temp, i ) == false )
    377 					return;
    378 
    379 		//Now update sliders
    380 		for( int i = 0; i < 4; ++i )
    381 			if( sliderMoved[i] )
    382 				if( mListener->sliderMoved( temp, i ) == false )
    383 					return;
    384 	}
    385 }
    386 
    387 //--------------------------------------------------------------------------------------------------//
    388 void Win32JoyStick::captureXInput()
    389 {
    390 #ifdef OIS_WIN32_XINPUT_SUPPORT
    391     XINPUT_STATE inputState;
    392 	if (XInputGetState((DWORD)mJoyInfo.xInputDev, &inputState) != ERROR_SUCCESS)
    393         memset(&inputState, 0, sizeof(inputState));
    394 
    395     //Sticks and triggers
    396 	int value;
    397     bool axisMoved[XINPUT_TRANSLATED_AXIS_COUNT] = {false,false,false,false,false,false};
    398 
    399 	//LeftY
    400 	value = -(int)inputState.Gamepad.sThumbLY;
    401 	mState.mAxes[0].rel = value - mState.mAxes[0].abs;
    402 	mState.mAxes[0].abs = value;
    403 	if(mState.mAxes[0].rel != 0)
    404         axisMoved[0] = true;
    405 
    406 	//LeftX
    407     mState.mAxes[1].rel = inputState.Gamepad.sThumbLX - mState.mAxes[1].abs;
    408     mState.mAxes[1].abs = inputState.Gamepad.sThumbLX;
    409 
    410 	if(mState.mAxes[1].rel != 0)
    411         axisMoved[1] = true;
    412 
    413 	//RightY
    414 	value = -(int)inputState.Gamepad.sThumbRY;
    415     mState.mAxes[2].rel = value - mState.mAxes[2].abs;
    416     mState.mAxes[2].abs = value;
    417 	if(mState.mAxes[2].rel != 0)
    418         axisMoved[2] = true;
    419 
    420 	//RightX
    421     mState.mAxes[3].rel = inputState.Gamepad.sThumbRX - mState.mAxes[3].abs;
    422     mState.mAxes[3].abs = inputState.Gamepad.sThumbRX;
    423 	if(mState.mAxes[3].rel != 0)
    424 		axisMoved[3] = true;
    425 
    426 	//Left trigger
    427     value = inputState.Gamepad.bLeftTrigger * 129;
    428 	if(value > JoyStick::MAX_AXIS)
    429 		value = JoyStick::MAX_AXIS;
    430 
    431     mState.mAxes[4].rel = value - mState.mAxes[4].abs;
    432     mState.mAxes[4].abs = value;
    433 	if(mState.mAxes[4].rel != 0)
    434 		axisMoved[4] = true;
    435 
    436 	//Right trigger
    437     value = (int)inputState.Gamepad.bRightTrigger * 129;
    438 	if(value > JoyStick::MAX_AXIS)
    439 		value = JoyStick::MAX_AXIS;
    440 
    441 	mState.mAxes[5].rel = value - mState.mAxes[5].abs;
    442     mState.mAxes[5].abs = value;
    443 	if(mState.mAxes[5].rel != 0)
    444 		axisMoved[5] = true;
    445 
    446     //POV
    447     int previousPov = mState.mPOV[0].direction;
    448     int& pov = mState.mPOV[0].direction;
    449     pov = Pov::Centered;
    450     if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
    451         pov |= Pov::North;
    452     else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
    453         pov |= Pov::South;
    454     if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
    455         pov |= Pov::West;
    456     else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
    457         pov |= Pov::East;
    458 
    459     //Buttons - The first 4 buttons don't need to be checked since they represent the dpad
    460     bool previousButtons[XINPUT_TRANSLATED_BUTTON_COUNT];
    461     std::copy(mState.mButtons.begin(), mState.mButtons.end(), previousButtons);
    462     for (size_t i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
    463         mState.mButtons[i] = (inputState.Gamepad.wButtons & (1 << (i + 4))) != 0;
    464 
    465     //Send events
    466     if (mBuffered && mListener)
    467     {
    468 	    JoyStickEvent joystickEvent(this, mState);
    469 
    470 	    //Axes
    471 	    for (int i = 0; i < XINPUT_TRANSLATED_AXIS_COUNT; i++)
    472         {
    473 		    if (axisMoved[i] && !mListener->axisMoved(joystickEvent, i))
    474 			    return;
    475         }
    476 
    477         //POV
    478         if (previousPov != pov && !mListener->povMoved(joystickEvent, 0))
    479             return;
    480 
    481         //Buttons
    482         for (int i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
    483         {
    484             if (!previousButtons[i] && mState.mButtons[i])
    485             {
    486                 if (!mListener->buttonPressed(joystickEvent, i))
    487                     return;
    488             }
    489             else if (previousButtons[i] && !mState.mButtons[i])
    490             {
    491                 if (!mListener->buttonReleased(joystickEvent, i))
    492                     return;
    493             }
    494         }
    495     }
    496 #endif
    497 }
    498 
    499 //--------------------------------------------------------------------------------------------------//
    500 bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
    501 {
    502 	if( di.dwData & 0x80 )
    503 	{
    504 		mState.mButtons[button] = true;
    505 		if( mBuffered && mListener )
    506 			return mListener->buttonPressed( JoyStickEvent( this, mState ), button );
    507 	}
    508 	else
    509 	{
    510 		mState.mButtons[button] = false;
    511 		if( mBuffered && mListener )
    512 			return mListener->buttonReleased( JoyStickEvent( this, mState ), button );
    513 	}
    514 
    515 	return true;
    516 }
    517 
    518 //--------------------------------------------------------------------------------------------------//
    519 bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di )
    520 {
    521 	//Some drivers report a value of 65,535, instead of 1,
    522 	//for the center position
    523 	if(LOWORD(di.dwData) == 0xFFFF)
    524 	{
    525 		mState.mPOV[pov].direction = Pov::Centered;
    526 	}
    527 	else
    528 	{
    529 		switch(di.dwData)
    530 		{
    531 			case 0: mState.mPOV[pov].direction = Pov::North; break;
    532 			case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break;
    533 			case 9000: mState.mPOV[pov].direction = Pov::East; break;
    534 			case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break;
    535 			case 18000: mState.mPOV[pov].direction = Pov::South; break;
    536 			case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break;
    537 			case 27000: mState.mPOV[pov].direction = Pov::West; break;
    538 			case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break;
    539 		}
    540 	}
    541 
    542 	if( mBuffered && mListener )
    543 		return mListener->povMoved( JoyStickEvent( this, mState ), pov );
    544 
    545 	return true;
    546 }
    547 
    548 //--------------------------------------------------------------------------------------------------//
    549 void Win32JoyStick::setBuffered(bool buffered)
    550 {
    551 	mBuffered = buffered;
    552 }
    553 
    554 //--------------------------------------------------------------------------------------------------//
    555 Interface* Win32JoyStick::queryInterface(Interface::IType type)
    556 {
    557 	if( mFfDevice && type == Interface::ForceFeedback )
    558 		return mFfDevice;
    559 	else
    560 		return 0;
    561 }
    562 
    563 //--------------------------------------------------------------------------------------------------//
    564 #ifdef OIS_WIN32_XINPUT_SUPPORT
    565 void Win32JoyStick::CheckXInputDevices(JoyStickInfoList &joys)
    566 {
    567     IWbemLocator*           pIWbemLocator  = NULL;
    568     IEnumWbemClassObject*   pEnumDevices   = NULL;
    569     IWbemClassObject*       pDevices[20]   = {0};
    570     IWbemServices*          pIWbemServices = NULL;
    571     BSTR                    bstrNamespace  = NULL;
    572     BSTR                    bstrDeviceID   = NULL;
    573     BSTR                    bstrClassName  = NULL;
    574     DWORD                   uReturned      = 0;
    575     bool                    bIsXinputDevice= false;
    576 	DWORD                   iDevice        = 0;
    577 	int                     xDevice        = 0;
    578     VARIANT                 var;
    579     HRESULT                 hr;
    580 
    581 	if(joys.size() == 0)
    582 		return;
    583 
    584     // CoInit if needed
    585     hr = CoInitialize(NULL);
    586     bool bCleanupCOM = SUCCEEDED(hr);
    587 
    588     // Create WMI
    589     hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator);
    590     if( FAILED(hr) || pIWbemLocator == NULL )
    591         goto LCleanup;
    592 
    593     bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );
    594 	if( bstrNamespace == NULL )
    595 		goto LCleanup;
    596 
    597     bstrClassName = SysAllocString( L"Win32_PNPEntity" );
    598 	if( bstrClassName == NULL )
    599 		goto LCleanup;
    600 
    601     bstrDeviceID  = SysAllocString( L"DeviceID" );
    602 	if( bstrDeviceID == NULL )
    603 		goto LCleanup;
    604 
    605     // Connect to WMI
    606     hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices );
    607     if( FAILED(hr) || pIWbemServices == NULL )
    608         goto LCleanup;
    609 
    610     // Switch security level to IMPERSONATE.
    611     CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
    612 
    613     hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices );
    614     if( FAILED(hr) || pEnumDevices == NULL )
    615         goto LCleanup;
    616 
    617     // Loop over all devices
    618     for( ;; )
    619     {
    620         // Get 20 at a time
    621         hr = pEnumDevices->Next(5000, 20, pDevices, &uReturned);
    622         if( FAILED(hr) )
    623             goto LCleanup;
    624 
    625         if( uReturned == 0 )
    626             break;
    627 
    628         for(iDevice = 0; iDevice < uReturned; iDevice++)
    629         {
    630             // For each device, get its device ID
    631             hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL);
    632             if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL)
    633             {
    634                 // Check if the device ID contains "IG_".  If it does, then it's an XInput device - This information can not be found from DirectInput
    635                 if(wcsstr(var.bstrVal, L"IG_"))
    636                 {
    637                     // If it does, then get the VID/PID from var.bstrVal
    638                     DWORD dwPid = 0, dwVid = 0;
    639                     WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" );
    640                     if(strVid && swscanf_s( strVid, L"VID_%4X", &dwVid ) != 1)
    641 						dwVid = 0;
    642 
    643                     WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );
    644                     if(strPid && swscanf_s( strPid, L"PID_%4X", &dwPid ) != 1)
    645                         dwPid = 0;
    646 
    647                     // Compare the VID/PID to the DInput device
    648                     DWORD dwVidPid = MAKELONG(dwVid, dwPid);
    649 					for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i)
    650 					{
    651 						if(!i->isXInput && dwVidPid == i->productGuid.Data1)
    652 						{
    653 							i->isXInput = true;
    654 							i->xInputDev = xDevice;
    655 							++xDevice;
    656 						}
    657 					}
    658 
    659 					if(joys.size() == 0)
    660 						goto LCleanup;
    661                 }
    662             }
    663 
    664             SAFE_RELEASE(pDevices[iDevice]);
    665         }
    666     }
    667 
    668 LCleanup:
    669     if(bstrNamespace)
    670         SysFreeString(bstrNamespace);
    671 
    672     if(bstrDeviceID)
    673         SysFreeString(bstrDeviceID);
    674 
    675     if(bstrClassName)
    676         SysFreeString(bstrClassName);
    677 
    678     for(iDevice=0; iDevice < 20; iDevice++)
    679         SAFE_RELEASE(pDevices[iDevice]);
    680 
    681     SAFE_RELEASE(pEnumDevices);
    682     SAFE_RELEASE(pIWbemLocator);
    683     SAFE_RELEASE(pIWbemServices);
    684 
    685     if(bCleanupCOM)
    686         CoUninitialize();
    687 }
    688 #endif
    689