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/Win32ForceFeedback.h" 24 #include "OISException.h" 25 #include <math.h> 26 27 // 0 = No trace; 1 = Important traces; 2 = Debug traces 28 #define OIS_WIN32_JOYFF_DEBUG 1 29 30 #if (defined (_DEBUG) || defined(OIS_WIN32_JOYFF_DEBUG)) 31 #include <iostream> 32 #include <sstream> 33 using namespace std; 34 #endif 35 36 using namespace OIS; 37 38 //--------------------------------------------------------------// 39 Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* pDIJoy, const DIDEVCAPS* pDIJoyCaps) : 40 mHandles(0), mJoyStick(pDIJoy), mFFAxes(0), mpDIJoyCaps(pDIJoyCaps) 41 { 42 #if (OIS_WIN32_JOYFF_DEBUG > 0) 43 cout << "FFSamplePeriod : " << mpDIJoyCaps->dwFFSamplePeriod << " mu-s, " 44 << "FFMinTimeResolution : " << mpDIJoyCaps->dwFFMinTimeResolution << " mu-s," 45 << "" << endl; 46 #endif 47 } 48 49 //--------------------------------------------------------------// 50 Win32ForceFeedback::~Win32ForceFeedback() 51 { 52 //Get the effect - if it exists 53 for(EffectList::iterator i = mEffectList.begin(); i != mEffectList.end(); ++i ) 54 { 55 LPDIRECTINPUTEFFECT dxEffect = i->second; 56 if( dxEffect ) 57 { 58 dxEffect->Unload(); 59 dxEffect->Release(); 60 } 61 } 62 63 mEffectList.clear(); 64 } 65 66 //--------------------------------------------------------------// 67 short Win32ForceFeedback::getFFAxesNumber() 68 { 69 return mFFAxes; 70 } 71 72 //--------------------------------------------------------------// 73 unsigned short Win32ForceFeedback::getFFMemoryLoad() 74 { 75 DIPROPDWORD dipdw; // DIPROPDWORD contains a DIPROPHEADER structure. 76 dipdw.diph.dwSize = sizeof(DIPROPDWORD); 77 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 78 dipdw.diph.dwObj = 0; // device property 79 dipdw.diph.dwHow = DIPH_DEVICE; 80 dipdw.dwData = 0; // In case of any error. 81 82 const HRESULT hr = mJoyStick->GetProperty(DIPROP_FFLOAD, &dipdw.diph); 83 if(FAILED(hr)) 84 { 85 if (hr == DIERR_NOTEXCLUSIVEACQUIRED) 86 OIS_EXCEPT(E_General, "Can't query FF memory load as device was not acquired in exclusive mode"); 87 else 88 OIS_EXCEPT(E_General, "Unknown error querying FF memory load ->.."); 89 } 90 91 return (unsigned short)dipdw.dwData; 92 } 93 94 //--------------------------------------------------------------// 95 void Win32ForceFeedback::upload( const Effect* effect ) 96 { 97 switch( effect->force ) 98 { 99 case OIS::Effect::ConstantForce: _updateConstantEffect(effect); break; 100 case OIS::Effect::RampForce: _updateRampEffect(effect); break; 101 case OIS::Effect::PeriodicForce: _updatePeriodicEffect(effect); break; 102 case OIS::Effect::ConditionalForce: _updateConditionalEffect(effect); break; 103 //case OIS::Effect::CustomForce: _updateCustomEffect(effect); break; 104 default: OIS_EXCEPT(E_NotImplemented, "Requested Force not Implemented yet, sorry!"); break; 105 } 106 } 107 108 //--------------------------------------------------------------// 109 void Win32ForceFeedback::modify( const Effect* eff ) 110 { 111 //Modifying is essentially the same as an upload, so, just reuse that function 112 upload(eff); 113 } 114 115 //--------------------------------------------------------------// 116 void Win32ForceFeedback::remove( const Effect* eff ) 117 { 118 //Get the effect - if it exists 119 EffectList::iterator i = mEffectList.find(eff->_handle); 120 if( i != mEffectList.end() ) 121 { 122 LPDIRECTINPUTEFFECT dxEffect = i->second; 123 if( dxEffect ) 124 { 125 dxEffect->Stop(); 126 //We care about the return value - as the effect might not 127 //have been unlaoded 128 if( SUCCEEDED(dxEffect->Unload()) ) 129 { 130 dxEffect->Release(); 131 mEffectList.erase(i); 132 } 133 } 134 else 135 mEffectList.erase(i); 136 } 137 } 138 139 //--------------------------------------------------------------// 140 void Win32ForceFeedback::setMasterGain( float level ) 141 { 142 //Between 0 - 10,000 143 int gain_level = (int)(10000.0f * level); 144 145 if( gain_level > 10000 ) 146 gain_level = 10000; 147 else if( gain_level < 0 ) 148 gain_level = 0; 149 150 DIPROPDWORD DIPropGain; 151 DIPropGain.diph.dwSize = sizeof(DIPropGain); 152 DIPropGain.diph.dwHeaderSize = sizeof(DIPROPHEADER); 153 DIPropGain.diph.dwObj = 0; 154 DIPropGain.diph.dwHow = DIPH_DEVICE; 155 DIPropGain.dwData = gain_level; 156 157 #if (OIS_WIN32_JOYFF_DEBUG > 0) 158 cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting master gain to " 159 << level << " => " << DIPropGain.dwData << endl; 160 #endif 161 162 const HRESULT hr = mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph); 163 164 #if defined (_DEBUG) 165 if(FAILED(hr)) 166 cout << "Failed to change master gain" << endl; 167 #endif 168 } 169 170 //--------------------------------------------------------------// 171 void Win32ForceFeedback::setAutoCenterMode( bool auto_on ) 172 { 173 DIPROPDWORD DIPropAutoCenter; 174 DIPropAutoCenter.diph.dwSize = sizeof(DIPropAutoCenter); 175 DIPropAutoCenter.diph.dwHeaderSize = sizeof(DIPROPHEADER); 176 DIPropAutoCenter.diph.dwObj = 0; 177 DIPropAutoCenter.diph.dwHow = DIPH_DEVICE; 178 DIPropAutoCenter.dwData = (auto_on ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF); 179 180 #if (OIS_WIN32_JOYFF_DEBUG > 0) 181 cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting auto-center mode to " 182 << auto_on << " => " << DIPropAutoCenter.dwData << endl; 183 #endif 184 185 const HRESULT hr = mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph); 186 187 #if defined (_DEBUG) 188 if(FAILED(hr)) 189 cout << "Failed to change auto-center mode" << endl; 190 #endif 191 } 192 193 //--------------------------------------------------------------// 194 void Win32ForceFeedback::_updateConstantEffect( const Effect* effect ) 195 { 196 ConstantEffect *eff = static_cast<ConstantEffect*>(effect->getForceEffect()); 197 198 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; 199 LONG rglDirection[2] = { 0, 0 }; 200 DIENVELOPE diEnvelope; 201 DICONSTANTFORCE cf; 202 DIEFFECT diEffect; 203 204 //Currently only support 1 axis 205 //if( effect->getNumAxes() == 1 ) 206 cf.lMagnitude = eff->level; 207 208 #if (OIS_WIN32_JOYFF_DEBUG > 1) 209 cout << " Level : " << eff->level 210 << " => " << cf.lMagnitude << endl; 211 #endif 212 213 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONSTANTFORCE), &cf, effect, &eff->envelope); 214 _upload(GUID_ConstantForce, &diEffect, effect); 215 } 216 217 //--------------------------------------------------------------// 218 void Win32ForceFeedback::_updateRampEffect( const Effect* effect ) 219 { 220 RampEffect *eff = static_cast<RampEffect*>(effect->getForceEffect()); 221 222 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; 223 LONG rglDirection[2] = { 0, 0 }; 224 DIENVELOPE diEnvelope; 225 DIRAMPFORCE rf; 226 DIEFFECT diEffect; 227 228 //Currently only support 1 axis 229 rf.lStart = eff->startLevel; 230 rf.lEnd = eff->endLevel; 231 232 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIRAMPFORCE), &rf, effect, &eff->envelope ); 233 _upload(GUID_RampForce, &diEffect, effect); 234 } 235 236 //--------------------------------------------------------------// 237 void Win32ForceFeedback::_updatePeriodicEffect( const Effect* effect ) 238 { 239 PeriodicEffect *eff = static_cast<PeriodicEffect*>(effect->getForceEffect()); 240 241 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; 242 LONG rglDirection[2] = { 0, 0 }; 243 DIENVELOPE diEnvelope; 244 DIPERIODIC pf; 245 DIEFFECT diEffect; 246 247 //Currently only support 1 axis 248 pf.dwMagnitude = eff->magnitude; 249 pf.lOffset = eff->offset; 250 pf.dwPhase = eff->phase; 251 pf.dwPeriod = eff->period; 252 253 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIPERIODIC), &pf, effect, &eff->envelope ); 254 255 switch( effect->type ) 256 { 257 case OIS::Effect::Square: _upload(GUID_Square, &diEffect, effect); break; 258 case OIS::Effect::Triangle: _upload(GUID_Triangle, &diEffect, effect); break; 259 case OIS::Effect::Sine: _upload(GUID_Sine, &diEffect, effect); break; 260 case OIS::Effect::SawToothUp: _upload(GUID_SawtoothUp, &diEffect, effect); break; 261 case OIS::Effect::SawToothDown: _upload(GUID_SawtoothDown, &diEffect, effect); break; 262 default: break; 263 } 264 } 265 266 //--------------------------------------------------------------// 267 void Win32ForceFeedback::_updateConditionalEffect( const Effect* effect ) 268 { 269 ConditionalEffect *eff = static_cast<ConditionalEffect*>(effect->getForceEffect()); 270 271 DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; 272 LONG rglDirection[2] = { 0, 0 }; 273 DIENVELOPE diEnvelope; 274 DICONDITION cf; 275 DIEFFECT diEffect; 276 277 cf.lOffset = eff->deadband; 278 cf.lPositiveCoefficient = eff->rightCoeff; 279 cf.lNegativeCoefficient = eff->leftCoeff; 280 cf.dwPositiveSaturation = eff->rightSaturation; 281 cf.dwNegativeSaturation = eff->leftSaturation; 282 cf.lDeadBand = eff->deadband; 283 284 _setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONDITION), &cf, effect, 0 ); 285 286 switch( effect->type ) 287 { 288 case OIS::Effect::Friction: _upload(GUID_Friction, &diEffect, effect); break; 289 case OIS::Effect::Damper: _upload(GUID_Damper, &diEffect, effect); break; 290 case OIS::Effect::Inertia: _upload(GUID_Inertia, &diEffect, effect); break; 291 case OIS::Effect::Spring: _upload(GUID_Spring, &diEffect, effect); break; 292 default: break; 293 } 294 } 295 296 //--------------------------------------------------------------// 297 void Win32ForceFeedback::_updateCustomEffect( const Effect* /*effect*/ ) 298 { 299 //CustomEffect *eff = static_cast<CustomEffect*>(effect->getForceEffect()); 300 // 301 //DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y }; 302 //LONG rglDirection[2] = { 0, 0 }; 303 //DIENVELOPE diEnvelope; 304 //DICUSTOMFORCE cf; 305 //DIEFFECT diEffect; 306 //cf.cChannels = 0; 307 //cf.dwSamplePeriod = 0; 308 //cf.cSamples = 0; 309 //cf.rglForceData = 0; 310 //_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICUSTOMFORCE), &cf, effect, &eff->envelope); 311 //_upload(GUID_CustomForce, &diEffect, effect); 312 } 313 314 //--------------------------------------------------------------// 315 void Win32ForceFeedback::_setCommonProperties( 316 DIEFFECT* diEffect, DWORD* rgdwAxes, 317 LONG* rglDirection, DIENVELOPE* diEnvelope, DWORD struct_size, 318 LPVOID struct_type, const Effect* effect, const Envelope* envelope ) 319 { 320 ZeroMemory(diEffect, sizeof(DIEFFECT)); 321 322 diEffect->dwSize = sizeof(DIEFFECT); 323 diEffect->dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; 324 diEffect->dwGain = DI_FFNOMINALMAX; 325 326 diEffect->dwTriggerButton = DIEB_NOTRIGGER; // effect->trigger_button; // TODO: Conversion 327 diEffect->dwTriggerRepeatInterval = effect->trigger_interval; 328 329 #if (OIS_WIN32_JOYFF_DEBUG > 1) 330 cout << " Trigger :" << endl 331 << " Button : " << effect->trigger_button 332 << " => " << diEffect->dwTriggerButton << endl 333 << " Interval : " << effect->trigger_interval 334 << " => " << diEffect->dwTriggerRepeatInterval << endl; 335 #endif 336 337 diEffect->cAxes = 1; // effect->getNumAxes(); 338 diEffect->rgdwAxes = rgdwAxes; 339 340 diEffect->rglDirection = rglDirection; // TODO: conversion from effect->direction 341 342 #if (OIS_WIN32_JOYFF_DEBUG > 1) 343 cout << " Direction : " << Effect::getDirectionName(effect->direction) 344 << " => {"; 345 for (int iDir=0; iDir < (int)diEffect->cAxes; iDir++) 346 cout << " " << diEffect->rglDirection[iDir]; 347 cout << "}" << endl; 348 #endif 349 350 if (diEnvelope && envelope && envelope->isUsed()) 351 { 352 diEnvelope->dwSize = sizeof(DIENVELOPE); 353 diEnvelope->dwAttackLevel = envelope->attackLevel; 354 diEnvelope->dwAttackTime = envelope->attackLength; 355 diEnvelope->dwFadeLevel = envelope->fadeLevel; 356 diEnvelope->dwFadeTime = envelope->fadeLength; 357 diEffect->lpEnvelope = diEnvelope; 358 } 359 else 360 diEffect->lpEnvelope = 0; 361 362 #if (OIS_WIN32_JOYFF_DEBUG > 1) 363 if (diEnvelope && envelope && envelope->isUsed()) 364 { 365 cout << " Enveloppe :" << endl 366 << " AttackLen : " << envelope->attackLength 367 << " => " << diEnvelope->dwAttackTime << endl 368 << " AttackLvl : " << envelope->attackLevel 369 << " => " << diEnvelope->dwAttackLevel << endl 370 << " FadeLen : " << envelope->fadeLength 371 << " => " << diEnvelope->dwFadeTime << endl 372 << " FadeLvl : " << envelope->fadeLevel 373 << " => " << diEnvelope->dwFadeLevel << endl; 374 } 375 #endif 376 377 diEffect->dwSamplePeriod = 0; 378 diEffect->dwDuration = effect->replay_length; 379 diEffect->dwStartDelay = effect->replay_delay; 380 381 #if (OIS_WIN32_JOYFF_DEBUG > 1) 382 cout << " Replay :" << endl 383 << " Length : " << effect->replay_length 384 << " => " << diEffect->dwDuration << endl 385 << " Delay : " << effect->replay_delay 386 << " => " << diEffect->dwStartDelay << endl; 387 #endif 388 389 diEffect->cbTypeSpecificParams = struct_size; 390 diEffect->lpvTypeSpecificParams = struct_type; 391 } 392 393 //--------------------------------------------------------------// 394 void Win32ForceFeedback::_upload( GUID guid, DIEFFECT* diEffect, const Effect* effect) 395 { 396 LPDIRECTINPUTEFFECT dxEffect = 0; 397 398 //Get the effect - if it exists 399 EffectList::iterator i = mEffectList.find(effect->_handle); 400 //It has been created already 401 if( i != mEffectList.end() ) 402 dxEffect = i->second; 403 else //This effect has not yet been created - generate a handle 404 effect->_handle = mHandles++; 405 406 if( dxEffect == 0 ) 407 { 408 //This effect has not yet been created, so create it 409 HRESULT hr = mJoyStick->CreateEffect(guid, diEffect, &dxEffect, NULL); 410 if(SUCCEEDED(hr)) 411 { 412 mEffectList[effect->_handle] = dxEffect; 413 dxEffect->Start(INFINITE,0); 414 } 415 else if( hr == DIERR_DEVICEFULL ) 416 OIS_EXCEPT(E_DeviceFull, "Remove an effect before adding more!"); 417 else 418 OIS_EXCEPT(E_General, "Unknown error creating effect->.."); 419 } 420 else 421 { 422 //ToDo -- Update the Effect 423 HRESULT hr = dxEffect->SetParameters( diEffect, DIEP_DIRECTION | 424 DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | 425 DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS | DIEP_START ); 426 427 if(FAILED(hr)) OIS_EXCEPT(E_InvalidParam, "Error updating device!"); 428 } 429 } 430 431 //--------------------------------------------------------------// 432 void Win32ForceFeedback::_addEffectSupport( LPCDIEFFECTINFO pdei ) 433 { 434 #if (OIS_WIN32_JOYFF_DEBUG > 0) 435 // Dump some usefull information about the effect type. 436 cout << "Adding support for '" << pdei->tszName << "' effect type" << endl; 437 cout << " Supported static params: "; 438 if (pdei->dwStaticParams & DIEP_AXES) cout << " Axes"; 439 if (pdei->dwStaticParams & DIEP_DIRECTION) cout << " Direction"; 440 if (pdei->dwStaticParams & DIEP_DURATION) cout << " Duration"; 441 if (pdei->dwStaticParams & DIEP_ENVELOPE) cout << " Envelope"; 442 if (pdei->dwStaticParams & DIEP_GAIN) cout << " Gain"; 443 if (pdei->dwStaticParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod"; 444 if (pdei->dwStaticParams & DIEP_STARTDELAY) cout << " StartDelay"; 445 if (pdei->dwStaticParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton"; 446 if (pdei->dwStaticParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval"; 447 if (pdei->dwStaticParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams"; 448 cout << endl; 449 cout << " Supported dynamic params: "; 450 if (pdei->dwDynamicParams & DIEP_AXES) cout << " Axes"; 451 if (pdei->dwDynamicParams & DIEP_DIRECTION) cout << " Direction"; 452 if (pdei->dwDynamicParams & DIEP_DURATION) cout << " Duration"; 453 if (pdei->dwDynamicParams & DIEP_ENVELOPE) cout << " Envelope"; 454 if (pdei->dwDynamicParams & DIEP_GAIN) cout << " Gain"; 455 if (pdei->dwDynamicParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod"; 456 if (pdei->dwDynamicParams & DIEP_STARTDELAY) cout << " StartDelay"; 457 if (pdei->dwDynamicParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton"; 458 if (pdei->dwDynamicParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval"; 459 if (pdei->dwDynamicParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams"; 460 cout << endl; 461 cout << " More details about supported parameters support: "; 462 if (pdei->dwEffType & DIEFT_STARTDELAY) cout << " StartDelay"; 463 if (pdei->dwEffType & DIEFT_FFATTACK) cout << " Attack"; 464 if (pdei->dwEffType & DIEFT_FFFADE) cout << " Fade"; 465 if (pdei->dwEffType & DIEFT_DEADBAND) cout << " DeadBand"; 466 if (pdei->dwEffType & DIEFT_SATURATION) cout << " Saturation"; 467 if (pdei->dwEffType & DIEFT_POSNEGSATURATION) cout << " PosNegaturation"; 468 if (pdei->dwEffType & DIEFT_POSNEGCOEFFICIENTS) cout << " PosNegCoefficients"; 469 if (pdei->dwEffType & DIEFT_HARDWARE) cout << " HardwareSpecific"; 470 cout << endl; 471 #endif 472 473 Effect::EForce eForce; 474 switch (DIEFT_GETTYPE(pdei->dwEffType)) 475 { 476 case DIEFT_CONSTANTFORCE: 477 eForce = Effect::ConstantForce; 478 break; 479 case DIEFT_RAMPFORCE: 480 eForce = Effect::RampForce; 481 break; 482 case DIEFT_PERIODIC: 483 eForce = Effect::PeriodicForce; 484 break; 485 case DIEFT_CONDITION: 486 eForce = Effect::ConditionalForce; 487 break; 488 case DIEFT_CUSTOMFORCE: 489 eForce = Effect::CustomForce; 490 break; 491 default: 492 eForce = Effect::UnknownForce; 493 #if defined (_DEBUG) 494 cout << "Win32ForceFeedback: DirectInput8 Effect type support not implemented: " 495 << "DIEFT_GETTYPE="<< (int)DIEFT_GETTYPE(pdei->dwEffType) << endl; 496 #endif 497 return; 498 } 499 500 //Determine what the effect type is and how it corresponds to our OIS's Enums 501 //We could save the GUIDs too, however, we will just use the predefined ones later 502 if( pdei->guid == GUID_ConstantForce ) 503 _addEffectTypes(eForce, Effect::Constant ); 504 else if( pdei->guid == GUID_Triangle ) 505 _addEffectTypes(eForce, Effect::Triangle ); 506 else if( pdei->guid == GUID_Spring ) 507 _addEffectTypes(eForce, Effect::Spring ); 508 else if( pdei->guid == GUID_Friction ) 509 _addEffectTypes(eForce, Effect::Friction ); 510 else if( pdei->guid == GUID_Square ) 511 _addEffectTypes(eForce, Effect::Square ); 512 else if( pdei->guid == GUID_Sine ) 513 _addEffectTypes(eForce, Effect::Sine ); 514 else if( pdei->guid == GUID_SawtoothUp ) 515 _addEffectTypes(eForce, Effect::SawToothUp ); 516 else if( pdei->guid == GUID_SawtoothDown ) 517 _addEffectTypes(eForce, Effect::SawToothDown ); 518 else if( pdei->guid == GUID_Damper ) 519 _addEffectTypes(eForce, Effect::Damper ); 520 else if( pdei->guid == GUID_Inertia ) 521 _addEffectTypes(eForce, Effect::Inertia ); 522 else if( pdei->guid == GUID_CustomForce ) 523 _addEffectTypes(eForce, Effect::Custom ); 524 else if( pdei->guid == GUID_RampForce ) 525 _addEffectTypes(eForce, Effect::Ramp ); 526 527 #if defined (_DEBUG) 528 //Only care about this for Debugging Purposes 529 //else 530 //{ 531 // std::ostringstream ss; 532 // ss << "Win32ForceFeedback, DirectInput8 Effect not found. Reported as: " 533 // << pdei->tszName; 534 // OIS_EXCEPT( E_General, ss.str().c_str()); 535 //} 536 #endif 537 } 538 539 //--------------------------------------------------------------// 540 void Win32ForceFeedback::_addFFAxis() 541 { 542 mFFAxes++; 543 } 544