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 //--------------------------------------------------------------------------------------------------//
Win32JoyStick(InputManager * creator,IDirectInput8 * pDI,bool buffered,DWORD coopSettings,const JoyStickInfo & info)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 //--------------------------------------------------------------------------------------------------//
~Win32JoyStick()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 //--------------------------------------------------------------------------------------------------//
_initialize()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 //--------------------------------------------------------------------------------------------------//
_enumerate()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 //--------------------------------------------------------------------------------------------------//
DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi,LPVOID pvRef)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 //--------------------------------------------------------------------------------------------------//
DIEnumEffectsCallback(LPCDIEFFECTINFO pdei,LPVOID pvRef)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 //--------------------------------------------------------------------------------------------------//
capture()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 //--------------------------------------------------------------------------------------------------//
captureXInput()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 //--------------------------------------------------------------------------------------------------//
_doButtonClick(int button,DIDEVICEOBJECTDATA & di)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 //--------------------------------------------------------------------------------------------------//
_changePOV(int pov,DIDEVICEOBJECTDATA & di)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 //--------------------------------------------------------------------------------------------------//
setBuffered(bool buffered)549 void Win32JoyStick::setBuffered(bool buffered)
550 {
551 mBuffered = buffered;
552 }
553
554 //--------------------------------------------------------------------------------------------------//
queryInterface(Interface::IType type)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
CheckXInputDevices(JoyStickInfoList & joys)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