PageRenderTime 70ms CodeModel.GetById 17ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 1ms

/src/ois/src/win32/Win32JoyStick.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 688 lines | 489 code | 103 blank | 96 comment | 154 complexity | de3b5defe323dc848581d00fc5d4b971 MD5 | raw file
  1/*
  2The zlib/libpng License
  3
  4Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com)
  5
  6This software is provided 'as-is', without any express or implied warranty. In no event will
  7the authors be held liable for any damages arising from the use of this software.
  8
  9Permission is granted to anyone to use this software for any purpose, including commercial
 10applications, and to alter it and redistribute it freely, subject to the following
 11restrictions:
 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
 62using namespace OIS;
 63
 64//--------------------------------------------------------------------------------------------------//
 65Win32JoyStick::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//--------------------------------------------------------------------------------------------------//
 76Win32JoyStick::~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//--------------------------------------------------------------------------------------------------//
 92void 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//--------------------------------------------------------------------------------------------------//
138void 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//--------------------------------------------------------------------------------------------------//
171BOOL 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//--------------------------------------------------------------------------------------------------//
235BOOL 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//--------------------------------------------------------------------------------------------------//
249void 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//--------------------------------------------------------------------------------------------------//
388void 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//--------------------------------------------------------------------------------------------------//
500bool 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//--------------------------------------------------------------------------------------------------//
519bool 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//--------------------------------------------------------------------------------------------------//
549void Win32JoyStick::setBuffered(bool buffered)
550{
551	mBuffered = buffered;
552}
553
554//--------------------------------------------------------------------------------------------------//
555Interface* 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
565void 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
668LCleanup:
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