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