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