winDInputDevice.cpp
Engine/source/platformWin32/winDInputDevice.cpp
Public Defines
define
define
INITGUID()
Public Enumerations
enum
Win32POVDirBits { POV_up = 1 << 0 POV_right = 1 << 1 POV_down = 1 << 2 POV_left = 1 << 3 }
enum
Win32POVDirsInQuadrant { POVq_center = 0 POVq_up = POV_up POVq_upright = POV_up | POV_right POVq_right = POV_right POVq_downright = POV_down | POV_right POVq_down = POV_down POVq_downleft = POV_down | POV_left POVq_left = POV_left POVq_upleft = POV_up | POV_left }
Public Variables
Public Functions
Detailed Description
Public Defines
_Win32LogPOVInput(a)
INITGUID()
Public Enumerations
Win32POVDirBits
Enumerator
- POV_up = 1 << 0
- POV_right = 1 << 1
- POV_down = 1 << 2
- POV_left = 1 << 3
Win32POVDirsInQuadrant
Enumerator
- POVq_center = 0
- POVq_up = POV_up
- POVq_upright = POV_up | POV_right
- POVq_right = POV_right
- POVq_downright = POV_down | POV_right
- POVq_down = POV_down
- POVq_downleft = POV_down | POV_left
- POVq_left = POV_left
- POVq_upleft = POV_up | POV_left
Public Variables
const U32 Win32POVQuadrantMap []
Public Functions
_Win32GetPOVDirs(U32 data)
DIK_to_Key(U8 dikCode)
Key_to_DIK(U16 keyCode)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#ifndef INITGUID 25#define INITGUID 26#endif 27 28#include "platform/platform.h" 29#include "platformWin32/winDInputDevice.h" 30 31#include "math/mMath.h" 32#include "console/console.h" 33#include "core/strings/unicode.h" 34#include "windowManager/platformWindowMgr.h" 35 36// Static class data: 37LPDIRECTINPUT8 DInputDevice::smDInputInterface; 38U8 DInputDevice::smDeviceCount[ NUM_INPUT_DEVICE_TYPES ]; 39bool DInputDevice::smInitialized = false; 40 41#ifdef LOG_INPUT 42const char* getKeyName( U16 key ); 43#endif 44 45//------------------------------------------------------------------------------ 46DInputDevice::DInputDevice( const DIDEVICEINSTANCE* dii ) 47{ 48 mDeviceInstance = *dii; 49 mDevice = NULL; 50 mAcquired = false; 51 mNeedSync = false; 52 mObjInstance = NULL; 53 mObjFormat = NULL; 54 mObjInfo = NULL; 55 mObjBuffer1 = NULL; 56 mObjBuffer2 = NULL; 57 mPrevObjBuffer = NULL; 58 59 mForceFeedbackEffect = NULL; 60 mNumForceFeedbackAxes = 0; 61 mForceFeedbackAxes[0] = 0; 62 mForceFeedbackAxes[1] = 0; 63 64 const char* deviceTypeName = "unknown"; 65 U8 deviceType = UnknownDeviceType; 66 67 switch ( GET_DIDEVICE_TYPE( mDeviceInstance.dwDevType ) ) 68 { 69 // [rene, 12/09/2008] why do we turn a gamepad into a joystick here? 70 71 case DI8DEVTYPE_DRIVING: 72 case DI8DEVTYPE_GAMEPAD: 73 case DI8DEVTYPE_JOYSTICK: 74 deviceTypeName = "joystick"; 75 deviceType = JoystickDeviceType; 76 break; 77 78 case DI8DEVTYPE_KEYBOARD: 79 deviceTypeName = "keyboard"; 80 deviceType = KeyboardDeviceType; 81 break; 82 83 case DI8DEVTYPE_MOUSE: 84 deviceTypeName = "mouse"; 85 deviceType = MouseDeviceType; 86 break; 87 } 88 89 mDeviceType = deviceType; 90 mDeviceID = smDeviceCount[ deviceType ] ++; 91 92 dSprintf( mName, 29, "%s%d", deviceTypeName, mDeviceID ); 93} 94 95//------------------------------------------------------------------------------ 96DInputDevice::~DInputDevice() 97{ 98 destroy(); 99} 100 101//------------------------------------------------------------------------------ 102void DInputDevice::init() 103{ 104 // Reset all of the static variables: 105 smDInputInterface = NULL; 106 dMemset( smDeviceCount, 0, sizeof( smDeviceCount ) ); 107} 108 109//------------------------------------------------------------------------------ 110bool DInputDevice::create() 111{ 112 HRESULT result; 113 114 if ( smDInputInterface ) 115 { 116 result = smDInputInterface->CreateDevice( mDeviceInstance.guidInstance, &mDevice, NULL ); 117 if ( result == DI_OK ) 118 { 119 mDeviceCaps.dwSize = sizeof( DIDEVCAPS ); 120 if ( FAILED( mDevice->GetCapabilities( &mDeviceCaps ) ) ) 121 { 122 Con::errorf( " Failed to get the capabilities of the %s input device.", mName ); 123#ifdef LOG_INPUT 124 Input::log( "Failed to get the capabilities of &s!\n", mName ); 125#endif 126 return false; 127 } 128 129#ifdef LOG_INPUT 130 Input::log( "%s detected, created as %s (%s).\n", mDeviceInstance.tszProductName, mName, ( isPolled() ? "polled" : "asynchronous" ) ); 131#endif 132 133 if ( enumerateObjects() ) 134 { 135 // Set the device's data format: 136 DIDATAFORMAT dataFormat; 137 dMemset( &dataFormat, 0, sizeof( DIDATAFORMAT ) ); 138 dataFormat.dwSize = sizeof( DIDATAFORMAT ); 139 dataFormat.dwObjSize = sizeof( DIOBJECTDATAFORMAT ); 140 dataFormat.dwFlags = ( mDeviceType == MouseDeviceType ) ? DIDF_RELAXIS : DIDF_ABSAXIS; 141 dataFormat.dwDataSize = mObjBufferSize; 142 dataFormat.dwNumObjs = mObjCount; 143 dataFormat.rgodf = mObjFormat; 144 145 result = mDevice->SetDataFormat( &dataFormat ); 146 if ( FAILED( result ) ) 147 { 148 Con::errorf( " Failed to set the data format for the %s input device.", mName ); 149#ifdef LOG_INPUT 150 Input::log( "Failed to set the data format for %s!\n", mName ); 151#endif 152 return false; 153 } 154 155 // Set up the data buffer for buffered input: 156 DIPROPDWORD prop; 157 prop.diph.dwSize = sizeof( DIPROPDWORD ); 158 prop.diph.dwHeaderSize = sizeof( DIPROPHEADER ); 159 prop.diph.dwObj = 0; 160 prop.diph.dwHow = DIPH_DEVICE; 161 if ( isPolled() ) 162 prop.dwData = mObjBufferSize; 163 else 164 prop.dwData = QUEUED_BUFFER_SIZE; 165 166 result = mDevice->SetProperty( DIPROP_BUFFERSIZE, &prop.diph ); 167 if ( FAILED( result ) ) 168 { 169 Con::errorf( " Failed to set the buffer size property for the %s input device.", mName ); 170#ifdef LOG_INPUT 171 Input::log( "Failed to set the buffer size property for %s!\n", mName ); 172#endif 173 return false; 174 } 175 176 // If this device is a mouse, set it to relative axis mode: 177 if ( mDeviceType == MouseDeviceType ) 178 { 179 prop.diph.dwObj = 0; 180 prop.diph.dwHow = DIPH_DEVICE; 181 prop.dwData = DIPROPAXISMODE_REL; 182 183 result = mDevice->SetProperty( DIPROP_AXISMODE, &prop.diph ); 184 if ( FAILED( result ) ) 185 { 186 Con::errorf( " Failed to set relative axis mode for the %s input device.", mName ); 187#ifdef LOG_INPUT 188 Input::log( "Failed to set relative axis mode for %s!\n", mName ); 189#endif 190 return false; 191 } 192 } 193 } 194 } 195 else 196 { 197#ifdef LOG_INPUT 198 switch ( result ) 199 { 200 case DIERR_DEVICENOTREG: 201 Input::log( "CreateDevice failed -- The device or device instance is not registered with DirectInput.\n" ); 202 break; 203 204 case DIERR_INVALIDPARAM: 205 Input::log( "CreateDevice failed -- Invalid parameter.\n" ); 206 break; 207 208 case DIERR_NOINTERFACE: 209 Input::log( "CreateDevice failed -- The specified interface is not supported by the object.\n" ); 210 break; 211 212 case DIERR_OUTOFMEMORY: 213 Input::log( "CreateDevice failed -- Out of memory.\n" ); 214 break; 215 216 default: 217 Input::log( "CreateDevice failed -- Unknown error.\n" ); 218 break; 219 }; 220#endif // LOG_INPUT 221 Con::printf( " CreateDevice failed for the %s input device!", mName ); 222 return false; 223 } 224 } 225 226 Con::printf( " %s input device created.", mName ); 227 return true; 228} 229 230//------------------------------------------------------------------------------ 231void DInputDevice::destroy() 232{ 233 if ( mDevice ) 234 { 235 unacquire(); 236 237 // Tear down our forcefeedback. 238 if (mForceFeedbackEffect) 239 { 240 mForceFeedbackEffect->Release(); 241 mForceFeedbackEffect = NULL; 242 mNumForceFeedbackAxes = 0; 243#ifdef LOG_INPUT 244 Input::log("DInputDevice::destroy - releasing constant force feeback effect\n"); 245#endif 246 } 247 248 mDevice->Release(); 249 mDevice = NULL; 250 251 delete [] mObjInstance; 252 delete [] mObjFormat; 253 delete [] mObjInfo; 254 delete [] mObjBuffer1; 255 delete [] mObjBuffer2; 256 257 mObjInstance = NULL; 258 mObjFormat = NULL; 259 mObjInfo = NULL; 260 mObjBuffer1 = NULL; 261 mObjBuffer2 = NULL; 262 mPrevObjBuffer = NULL; 263 mName[0] = 0; 264 } 265} 266 267//------------------------------------------------------------------------------ 268bool DInputDevice::acquire() 269{ 270 if ( mDevice ) 271 { 272 if ( mAcquired ) 273 return( true ); 274 275 bool result = false; 276 // Set the cooperative level: 277 // (do this here so that we have a valid app window) 278 DWORD coopLevel = DISCL_BACKGROUND; 279 if ( mDeviceType == JoystickDeviceType 280// #ifndef DEBUG 281// || mDeviceType == MouseDeviceType 282// #endif 283 ) 284 // Exclusive access is required in order to perform force feedback 285 coopLevel = DISCL_EXCLUSIVE | DISCL_FOREGROUND; 286 else 287 coopLevel |= DISCL_NONEXCLUSIVE; 288 289 result = mDevice->SetCooperativeLevel( getWin32WindowHandle(), coopLevel ); 290 if ( FAILED( result ) ) 291 { 292 Con::errorf( "Failed to set the cooperative level for the %s input device.", mName ); 293#ifdef LOG_INPUT 294 Input::log( "Failed to set the cooperative level for %s!\n", mName ); 295#endif 296 return false; 297 } 298 299 // Enumerate joystick axes to enable force feedback 300 if ( NULL == mForceFeedbackEffect && JoystickDeviceType == mDeviceType) 301 { 302 // Since we will be playing force feedback effects, we should disable the auto-centering spring. 303 DIPROPDWORD dipdw; 304 dipdw.diph.dwSize = sizeof(DIPROPDWORD); 305 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 306 dipdw.diph.dwObj = 0; 307 dipdw.diph.dwHow = DIPH_DEVICE; 308 dipdw.dwData = FALSE; 309 310 if( FAILED( result = mDevice->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ) ) ) 311 return false; 312 } 313 314 S32 code = mDevice->Acquire(); 315 result = SUCCEEDED( code ); 316 if ( result ) 317 { 318 Con::printf( "%s input device acquired.", mName ); 319#ifdef LOG_INPUT 320 Input::log( "%s acquired.\n", mName ); 321#endif 322 mAcquired = true; 323 324 // If we were previously playing a force feedback effect, before 325 // losing acquisition, we do not automatically restart it. This is 326 // where you could call mForceFeedbackEffect->Start( INFINITE, 0 ); 327 // if you want that behavior. 328 329 // Update all of the key states: 330 if ( !isPolled() ) 331 mNeedSync = true; 332 } 333 else 334 { 335 const char* reason; 336 switch ( code ) 337 { 338 case DIERR_INVALIDPARAM: reason = "Invalid parameter" ; break; 339 case DIERR_NOTINITIALIZED: reason = "Not initialized"; break; 340 case DIERR_OTHERAPPHASPRIO: reason = "Other app has priority"; break; 341 case S_FALSE: reason = "Already acquired"; break; 342 default: reason = "Unknown error"; break; 343 } 344 Con::warnf( "%s input device NOT acquired: %s", mName, reason ); 345#ifdef LOG_INPUT 346 Input::log( "Failed to acquire %s: %s\n", mName, reason ); 347#endif 348 } 349 350 return( result ); 351 } 352 353 return( false ); 354} 355 356//------------------------------------------------------------------------------ 357bool DInputDevice::unacquire() 358{ 359 if ( mDevice ) 360 { 361 if ( !mAcquired ) 362 return( true ); 363 364 bool result = false; 365 result = SUCCEEDED( mDevice->Unacquire() ); 366 if ( result ) 367 { 368 Con::printf( "%s input device unacquired.", mName ); 369#ifdef LOG_INPUT 370 Input::log( "%s unacquired.\n", mName ); 371#endif 372 mAcquired = false; 373 } 374 else 375 { 376 Con::warnf( ConsoleLogEntry::General, "%s input device NOT unacquired.", mName ); 377#ifdef LOG_INPUT 378 Input::log( "Failed to unacquire %s!\n", mName ); 379#endif 380 } 381 382 return( result ); 383 } 384 385 return( false ); 386} 387 388//------------------------------------------------------------------------------ 389BOOL CALLBACK DInputDevice::EnumObjectsProc( const DIDEVICEOBJECTINSTANCE* doi, LPVOID pvRef ) 390{ 391 // Don't enumerate unknown types: 392 if ( doi->guidType == GUID_Unknown ) 393 return (DIENUM_CONTINUE); 394 395 // Reduce a couple pointers: 396 DInputDevice* diDevice = (DInputDevice*) pvRef; 397 DIDEVICEOBJECTINSTANCE* objInstance = &diDevice->mObjInstance[diDevice->mObjEnumCount]; 398 DIOBJECTDATAFORMAT* objFormat = &diDevice->mObjFormat[diDevice->mObjEnumCount]; 399 400 // Fill in the object instance structure: 401 *objInstance = *doi; 402 403 // DWORD objects must be DWORD aligned: 404 if ( !(objInstance->dwType & DIDFT_BUTTON ) ) 405 diDevice->mObjBufferOfs = ( diDevice->mObjBufferOfs + 3 ) & ~3; 406 407 objInstance->dwOfs = diDevice->mObjBufferOfs; 408 409 // Fill in the object data format structure: 410 objFormat->pguid = &objInstance->guidType; 411 objFormat->dwType = objInstance->dwType; 412 objFormat->dwFlags= 0; 413 objFormat->dwOfs = diDevice->mObjBufferOfs; 414 415 // Advance the enumeration counters: 416 if ( objFormat->dwType & DIDFT_BUTTON ) 417 diDevice->mObjBufferOfs += SIZEOF_BUTTON; 418 else 419 diDevice->mObjBufferOfs += SIZEOF_AXIS; 420 diDevice->mObjEnumCount++; 421 422 return (DIENUM_CONTINUE); 423} 424 425//------------------------------------------------------------------------------ 426bool DInputDevice::enumerateObjects() 427{ 428 if ( !mDevice ) 429 return false; 430 431 // Calculate the needed buffer sizes and allocate them: 432 mObjCount = ( mDeviceCaps.dwAxes + mDeviceCaps.dwButtons + mDeviceCaps.dwPOVs ); 433 mObjBufferSize = mObjCount * sizeof( DWORD ); 434 435 mObjInstance = new DIDEVICEOBJECTINSTANCE[mObjCount]; 436 mObjFormat = new DIOBJECTDATAFORMAT[mObjCount]; 437 mObjInfo = new ObjInfo[mObjCount]; 438 439 if ( isPolled() ) 440 { 441 mObjBuffer1 = new U8[mObjBufferSize]; 442 dMemset( mObjBuffer1, 0, mObjBufferSize ); 443 mObjBuffer2 = new U8[mObjBufferSize]; 444 dMemset( mObjBuffer2, 0, mObjBufferSize ); 445 } 446 mObjEnumCount = 0; 447 mObjBufferOfs = 0; 448 449 // We are about to enumerate, clear the axes we claim to know about 450 mNumForceFeedbackAxes = 0; 451 452 // Enumerate all of the 'objects' detected on the device: 453 if ( FAILED( mDevice->EnumObjects( EnumObjectsProc, this, DIDFT_ALL ) ) ) 454 return false; 455 456 // We only supports one or two axis joysticks 457 if( mNumForceFeedbackAxes > 2 ) 458 mNumForceFeedbackAxes = 2; 459 460 // if we enumerated fewer objects than are supposedly available, reset the 461 // object count 462 if (mObjEnumCount < mObjCount) 463 mObjCount = mObjEnumCount; 464 465 mObjBufferSize = ( mObjBufferSize + 3 ) & ~3; // Fill in the actual size to nearest DWORD 466 467 U32 buttonCount = 0; 468 U32 povCount = 0; 469 U32 keyCount = 0; 470 U32 unknownCount = 0; 471 472 // Fill in the device object's info structure: 473 for ( U32 i = 0; i < mObjCount; i++ ) 474 { 475 if ( mObjInstance[i].guidType == GUID_Button ) 476 { 477 mObjInfo[i].mType = SI_BUTTON; 478 mObjInfo[i].mInst = (InputObjectInstances)(KEY_BUTTON0 + buttonCount++); 479 } 480 else if ( mObjInstance[i].guidType == GUID_POV ) 481 { 482 // This is actually intentional - the POV handling code lower down 483 // takes the instance number and converts everything to button events. 484 mObjInfo[i].mType = SI_POV; 485 mObjInfo[i].mInst = (InputObjectInstances)povCount++; 486 } 487 else if ( mObjInstance[i].guidType == GUID_XAxis ) 488 { 489 mObjInfo[i].mType = SI_AXIS; 490 mObjInfo[i].mInst = SI_XAXIS; 491 492 if (mObjInstance[i].dwFFMaxForce > 0) 493 mForceFeedbackAxes[mNumForceFeedbackAxes++] = mObjInstance[i].dwOfs; 494 } 495 else if ( mObjInstance[i].guidType == GUID_YAxis ) 496 { 497 mObjInfo[i].mType = SI_AXIS; 498 mObjInfo[i].mInst = SI_YAXIS; 499 500 if (mObjInstance[i].dwFFMaxForce > 0) 501 mForceFeedbackAxes[mNumForceFeedbackAxes++] = mObjInstance[i].dwOfs; 502 } 503 else if ( mObjInstance[i].guidType == GUID_ZAxis ) 504 { 505 mObjInfo[i].mType = SI_AXIS; 506 mObjInfo[i].mInst = SI_ZAXIS; 507 } 508 else if ( mObjInstance[i].guidType == GUID_RxAxis ) 509 { 510 mObjInfo[i].mType = SI_AXIS; 511 mObjInfo[i].mInst = SI_RXAXIS; 512 } 513 else if ( mObjInstance[i].guidType == GUID_RyAxis ) 514 { 515 mObjInfo[i].mType = SI_AXIS; 516 mObjInfo[i].mInst = SI_RYAXIS; 517 } 518 else if ( mObjInstance[i].guidType == GUID_RzAxis ) 519 { 520 mObjInfo[i].mType = SI_AXIS; 521 mObjInfo[i].mInst = SI_RZAXIS; 522 } 523 else if ( mObjInstance[i].guidType == GUID_Slider ) 524 { 525 mObjInfo[i].mType = SI_AXIS; 526 mObjInfo[i].mInst = SI_SLIDER; 527 } 528 else if ( mObjInstance[i].guidType == GUID_Key ) 529 { 530 mObjInfo[i].mType = SI_KEY; 531 mObjInfo[i].mInst = DIK_to_Key( DIDFT_GETINSTANCE( mObjFormat[i].dwType ) ); 532 keyCount++; 533 } 534 else 535 { 536 mObjInfo[i].mType = SI_UNKNOWN; 537 mObjInfo[i].mInst = (InputObjectInstances)unknownCount++; 538 } 539 540 // Set the device object's min and max values: 541 if ( mObjInstance[i].guidType == GUID_Button 542 || mObjInstance[i].guidType == GUID_Key 543 || mObjInstance[i].guidType == GUID_POV ) 544 { 545 mObjInfo[i].mMin = DIPROPRANGE_NOMIN; 546 mObjInfo[i].mMax = DIPROPRANGE_NOMAX; 547 } 548 else 549 { 550 // This is an axis or a slider, so find out its range: 551 DIPROPRANGE pr; 552 pr.diph.dwSize = sizeof( pr ); 553 pr.diph.dwHeaderSize = sizeof( pr.diph ); 554 pr.diph.dwHow = DIPH_BYID; 555 pr.diph.dwObj = mObjFormat[i].dwType; 556 557 if ( SUCCEEDED( mDevice->GetProperty( DIPROP_RANGE, &pr.diph ) ) ) 558 { 559 mObjInfo[i].mMin = pr.lMin; 560 mObjInfo[i].mMax = pr.lMax; 561 } 562 else 563 { 564 mObjInfo[i].mMin = DIPROPRANGE_NOMIN; 565 mObjInfo[i].mMax = DIPROPRANGE_NOMAX; 566 } 567 } 568 } 569 570#ifdef LOG_INPUT 571 Input::log( " %d total objects detected.\n", mObjCount ); 572 if ( buttonCount ) 573 Input::log( " %d buttons.\n", buttonCount ); 574 if ( povCount ) 575 Input::log( " %d POVs.\n", povCount ); 576 577 if ( keyCount ) 578 Input::log( " %d keys.\n", keyCount ); 579 if ( unknownCount ) 580 Input::log( " %d unknown objects.\n", unknownCount ); 581 Input::log( "\n" ); 582#endif 583 584 return true; 585} 586 587//------------------------------------------------------------------------------ 588const char* DInputDevice::getName() 589{ 590#ifdef UNICODE 591 static UTF8 buf[512]; 592 convertUTF16toUTF8(mDeviceInstance.tszInstanceName, buf); 593 return (const char *)buf; 594#else 595 return mDeviceInstance.tszInstanceName; 596#endif 597} 598 599//------------------------------------------------------------------------------ 600const char* DInputDevice::getProductName() 601{ 602#ifdef UNICODE 603 static UTF8 buf[512]; 604 convertUTF16toUTF8(mDeviceInstance.tszProductName, buf); 605 return (const char *)buf; 606#else 607 return mDeviceInstance.tszProductName; 608#endif 609} 610 611//------------------------------------------------------------------------------ 612bool DInputDevice::process() 613{ 614 if ( mAcquired ) 615 { 616 if ( isPolled() ) 617 return processImmediate(); 618 else 619 return processAsync(); 620 } 621 622 return false; 623} 624 625//------------------------------------------------------------------------------ 626bool DInputDevice::processAsync() 627{ 628 DIDEVICEOBJECTDATA eventBuffer[QUEUED_BUFFER_SIZE]; 629 DWORD numEvents = QUEUED_BUFFER_SIZE; 630 HRESULT result; 631 632 if ( !mDevice ) 633 return false; 634 635 do 636 { 637 result = mDevice->GetDeviceData( sizeof( DIDEVICEOBJECTDATA ), eventBuffer, &numEvents, 0 ); 638 639 if ( !SUCCEEDED( result ) ) 640 { 641 switch ( result ) 642 { 643 case DIERR_INPUTLOST: 644 // Data stream was interrupted, so try to reacquire the device: 645 mAcquired = false; 646 acquire(); 647 break; 648 649 case DIERR_INVALIDPARAM: 650 Con::errorf( "DInputDevice::processAsync -- Invalid parameter passed to GetDeviceData of the %s input device!", mName ); 651#ifdef LOG_INPUT 652 Input::log( "Invalid parameter passed to GetDeviceData for %s!\n", mName ); 653#endif 654 break; 655 656 case DIERR_NOTACQUIRED: 657 // We can't get the device, so quit: 658 mAcquired = false; 659 // Don't error out - this is actually a natural occurrence... 660 //Con::errorf( "DInputDevice::processAsync -- GetDeviceData called when %s input device is not acquired!", mName ); 661#ifdef LOG_INPUT 662 Input::log( "GetDeviceData called when %s is not acquired!\n", mName ); 663#endif 664 break; 665 } 666 667 return false; 668 } 669 670 // We have buffered input, so act on it: 671 for ( DWORD i = 0; i < numEvents; i++ ) 672 buildEvent( findObjInstance( eventBuffer[i].dwOfs ), eventBuffer[i].dwData, eventBuffer[i].dwData ); 673 674 // Check for buffer overflow: 675 if ( result == DI_BUFFEROVERFLOW ) 676 { 677 // This is a problem, but we can keep going... 678 Con::errorf( "DInputDevice::processAsync -- %s input device's event buffer overflowed!", mName ); 679#ifdef LOG_INPUT 680 Input::log( "%s event buffer overflowed!\n", mName ); 681#endif 682 mNeedSync = true; // Let it know to resync next time through... 683 } 684 } 685 while ( numEvents ); 686 687 return true; 688} 689 690//------------------------------------------------------------------------------ 691bool DInputDevice::processImmediate() 692{ 693 if ( !mDevice ) 694 return false; 695 696 mDevice->Poll(); 697 698 U8* buffer = ( mPrevObjBuffer == mObjBuffer1 ) ? mObjBuffer2 : mObjBuffer1; 699 HRESULT result = mDevice->GetDeviceState( mObjBufferSize, buffer ); 700 if ( !SUCCEEDED( result ) ) 701 { 702 switch ( result ) 703 { 704 case DIERR_INPUTLOST: 705 // Data stream was interrupted, so try to reacquire the device: 706 mAcquired = false; 707 acquire(); 708 break; 709 710 case DIERR_INVALIDPARAM: 711 Con::errorf( "DInputDevice::processPolled -- invalid parameter passed to GetDeviceState on %s input device!", mName ); 712#ifdef LOG_INPUT 713 Input::log( "Invalid parameter passed to GetDeviceState on %s.\n", mName ); 714#endif 715 break; 716 717 case DIERR_NOTACQUIRED: 718 Con::errorf( "DInputDevice::processPolled -- GetDeviceState called when %s input device is not acquired!", mName ); 719#ifdef LOG_INPUT 720 Input::log( "GetDeviceState called when %s is not acquired!\n", mName ); 721#endif 722 break; 723 724 case E_PENDING: 725 Con::warnf( "DInputDevice::processPolled -- Data not yet available for the %s input device!", mName ); 726#ifdef LOG_INPUT 727 Input::log( "Data pending for %s.", mName ); 728#endif 729 break; 730 } 731 732 return false; 733 } 734 735 // Loop through all of the objects and produce events where 736 // the states have changed: 737 738 // (oldData = 0 prevents a crashing bug in Torque. There is a case where 739 // Torque accessed oldData without it ever being set.) 740 S32 newData, oldData = 0; 741 for ( DWORD i = 0; i < mObjCount; i++ ) 742 { 743 if ( mObjFormat[i].dwType & DIDFT_BUTTON ) 744 { 745 if ( mPrevObjBuffer ) 746 { 747 newData = *( (U8*) ( buffer + mObjFormat[i].dwOfs ) ); 748 oldData = *( (U8*) ( mPrevObjBuffer + mObjFormat[i].dwOfs ) ); 749 if ( newData == oldData ) 750 continue; 751 } 752 else 753 continue; 754 } 755 else if ( mObjFormat[i].dwType & DIDFT_POV ) 756 { 757 if ( mPrevObjBuffer ) 758 { 759 newData = *( (S32*) ( buffer + mObjFormat[i].dwOfs ) ); 760 oldData = *( (S32*) ( mPrevObjBuffer + mObjFormat[i].dwOfs ) ); 761 if ( LOWORD( newData ) == LOWORD( oldData ) ) 762 continue; 763 } 764 else 765 continue; 766 } 767 else 768 { 769 // report normal axes every time through the loop: 770 newData = *( (S32*) ( buffer + mObjFormat[i].dwOfs ) ); 771 } 772 773 // Build an event: 774 buildEvent( i, newData, oldData ); 775 } 776 mPrevObjBuffer = buffer; 777 778 return true; 779} 780 781//------------------------------------------------------------------------------ 782DWORD DInputDevice::findObjInstance( DWORD offset ) 783{ 784 DIDEVICEOBJECTINSTANCE *inst = mObjInstance; 785 for ( U32 i = 0; i < mObjCount; i++, inst++ ) 786 { 787 if ( inst->dwOfs == offset ) 788 return i; 789 } 790 791 AssertFatal( false, "DInputDevice::findObjInstance -- failed to locate object instance." ); 792 return 0; 793} 794 795//------------------------------------------------------------------------------ 796enum Win32POVDirBits 797{ 798 POV_up = 1 << 0, 799 POV_right = 1 << 1, 800 POV_down = 1 << 2, 801 POV_left = 1 << 3, 802}; 803 804enum Win32POVDirsInQuadrant 805{ 806 POVq_center = 0, 807 POVq_up = POV_up, 808 POVq_upright = POV_up | POV_right, 809 POVq_right = POV_right, 810 POVq_downright = POV_down | POV_right, 811 POVq_down = POV_down, 812 POVq_downleft = POV_down | POV_left, 813 POVq_left = POV_left, 814 POVq_upleft = POV_up | POV_left, 815}; 816 817static const U32 Win32POVQuadrantMap[] = 818{ 819 POVq_up, POVq_upright, 820 POVq_right, POVq_downright, 821 POVq_down, POVq_downleft, 822 POVq_left, POVq_upleft 823}; 824 825static U32 _Win32GetPOVDirs(U32 data) 826{ 827 U32 quadrant = (data / 4500) % 8; 828 U32 dirs = (data == 0xffff) ? POVq_center : Win32POVQuadrantMap[quadrant]; 829 return dirs; 830} 831 832#if defined(LOG_INPUT) 833static void _Win32LogPOVInput(InputEventInfo &newEvent) 834{ 835 836 U32 inst = 0xffff; 837 const char* sstate = ( newEvent.action == SI_MAKE ) ? "pressed" : "released"; 838 const char* dir = ""; 839 switch( newEvent.objInst ) 840 { 841 case SI_UPOV: 842 case SI_UPOV2: 843 dir = "Up"; inst = (newEvent.objInst == SI_UPOV) ? 1 : 2; break; 844 case SI_RPOV: 845 case SI_RPOV2: 846 dir = "Right"; inst = (newEvent.objInst == SI_RPOV) ? 1 : 2; break; 847 case SI_DPOV: 848 case SI_DPOV2: 849 dir = "Down"; inst = (newEvent.objInst == SI_DPOV) ? 1 : 2; break; 850 case SI_LPOV: 851 case SI_LPOV2: 852 dir = "Left"; inst = (newEvent.objInst == SI_LPOV) ? 1 : 2; break; 853 } 854 Con::printf( "EVENT (DInput): %s POV %d %s.\n", dir, inst, sstate); 855} 856#else 857#define _Win32LogPOVInput( a ) 858#endif 859 860//------------------------------------------------------------------------------ 861bool DInputDevice::buildEvent( DWORD offset, S32 newData, S32 oldData ) 862{ 863 ObjInfo &objInfo = mObjInfo[offset]; 864 865 if ( objInfo.mType == SI_UNKNOWN ) 866 return false; 867 868 InputEventInfo newEvent; 869 newEvent.deviceType = (InputDeviceTypes)mDeviceType; 870 newEvent.deviceInst = mDeviceID; 871 newEvent.objType = objInfo.mType; 872 newEvent.objInst = objInfo.mInst; 873 newEvent.modifier = (InputModifiers)0; 874 875 switch ( newEvent.objType ) 876 { 877 case SI_AXIS: 878 newEvent.action = SI_MOVE; 879 if ( newEvent.deviceType == MouseDeviceType ) 880 { 881 newEvent.fValue = float( newData ); 882 883#ifdef LOG_INPUT 884#ifdef LOG_MOUSEMOVE 885 if ( newEvent.objInst == SI_XAXIS ) 886 Input::log( "EVENT (DInput): %s move (%.1f, 0.0).\n", mName, newEvent.fValue ); 887 else if ( newEvent.objInst == SI_YAXIS ) 888 Input::log( "EVENT (DInput): %s move (0.0, %.1f).\n", mName, newEvent.fValue ); 889 else 890#endif 891 if ( newEvent.objInst == SI_ZAXIS ) 892 Input::log( "EVENT (DInput): %s wheel move %.1f.\n", mName, newEvent.fValue ); 893#endif 894 } 895 else // Joystick or other device: 896 { 897 // Scale to the range -1.0 to 1.0: 898 if ( objInfo.mMin != DIPROPRANGE_NOMIN && objInfo.mMax != DIPROPRANGE_NOMAX ) 899 { 900 F32 range = F32( objInfo.mMax - objInfo.mMin ); 901 newEvent.fValue = F32( ( 2 * newData ) - objInfo.mMax - objInfo.mMin ) / range; 902 } 903 else 904 newEvent.fValue = (F32)newData; 905 906#ifdef LOG_INPUT 907 // Keep this commented unless you REALLY want these messages for something-- 908 // they come once per each iteration of the main game loop. 909 //switch ( newEvent.objType ) 910 //{ 911 //case SI_XAXIS: 912 //if ( newEvent.fValue < -0.01f || newEvent.fValue > 0.01f ) 913 //Input::log( "EVENT (DInput): %s X-axis move %.2f.\n", mName, newEvent.fValue ); 914 //break; 915 //case SI_YAXIS: 916 //if ( newEvent.fValue < -0.01f || newEvent.fValue > 0.01f ) 917 //Input::log( "EVENT (DInput): %s Y-axis move %.2f.\n", mName, newEvent.fValue ); 918 //break; 919 //case SI_ZAXIS: 920 //Input::log( "EVENT (DInput): %s Z-axis move %.1f.\n", mName, newEvent.fValue ); 921 //break; 922 //case SI_RXAXIS: 923 //Input::log( "EVENT (DInput): %s R-axis move %.1f.\n", mName, newEvent.fValue ); 924 //break; 925 //case SI_RYAXIS: 926 //Input::log( "EVENT (DInput): %s U-axis move %.1f.\n", mName, newEvent.fValue ); 927 //break; 928 //case SI_RZAXIS: 929 //Input::log( "EVENT (DInput): %s V-axis move %.1f.\n", mName, newEvent.fValue ); 930 //break; 931 //case SI_SLIDER: 932 //Input::log( "EVENT (DInput): %s slider move %.1f.\n", mName, newEvent.fValue ); 933 //break; 934 //}; 935#endif 936 } 937 938 newEvent.postToSignal(Input::smInputEvent); 939 break; 940 941 case SI_BUTTON: 942 newEvent.action = ( newData & 0x80 ) ? SI_MAKE : SI_BREAK; 943 newEvent.fValue = ( newEvent.action == SI_MAKE ) ? 1.0f : 0.0f; 944 945#ifdef LOG_INPUT 946 if ( newEvent.action == SI_MAKE ) 947 Input::log( "EVENT (DInput): %s button%d pressed.\n", mName, newEvent.objInst - KEY_BUTTON0 ); 948 else 949 Input::log( "EVENT (DInput): %s button%d released.\n", mName, newEvent.objInst - KEY_BUTTON0 ); 950#endif 951 952 newEvent.postToSignal(Input::smInputEvent); 953 break; 954 955 case SI_POV: 956 // Handle artificial POV up/down/left/right buttons 957 958 // If we're not a polling device, oldData and newData are the same, so "fake" transitions 959 if(!isPolled()) { 960 oldData = mPrevPOVPos; 961 mPrevPOVPos = newData; 962 } 963 964 newData = LOWORD( newData ); 965 oldData = LOWORD( oldData ); 966 967 newData = _Win32GetPOVDirs(newData); 968 oldData = _Win32GetPOVDirs(oldData); 969 970 U32 setkeys = newData & (~oldData); 971 U32 clearkeys = oldData & (~newData); 972 U32 objInst = newEvent.objInst; 973 974 if ( setkeys || clearkeys ) 975 { 976 if ( clearkeys ) 977 { 978 newEvent.action = SI_BREAK; 979 newEvent.fValue = 0.0f; 980 // post events for all buttons that need to be cleared. 981 if( clearkeys & POV_up) 982 { 983 newEvent.objInst = ( objInst == 0 ) ? SI_UPOV : SI_UPOV2; 984 _Win32LogPOVInput(newEvent); 985 newEvent.postToSignal(Input::smInputEvent); 986 987 } 988 if( clearkeys & POV_right) 989 { 990 newEvent.objInst = ( objInst == 0 ) ? SI_RPOV : SI_RPOV2; 991 _Win32LogPOVInput(newEvent); 992 newEvent.postToSignal(Input::smInputEvent); 993 } 994 if( clearkeys & POV_down) 995 { 996 newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2; 997 _Win32LogPOVInput(newEvent); 998 newEvent.postToSignal(Input::smInputEvent); 999 } 1000 if( clearkeys & POV_left) 1001 { 1002 newEvent.objInst = ( objInst == 0 ) ? SI_LPOV : SI_LPOV2; 1003 _Win32LogPOVInput(newEvent); 1004 newEvent.postToSignal(Input::smInputEvent); 1005 } 1006 } // clear keys 1007 1008 if ( setkeys ) 1009 { 1010 newEvent.action = SI_MAKE; 1011 newEvent.fValue = 1.0f; 1012 // post events for all buttons that need to be set. 1013 if( setkeys & POV_up) 1014 { 1015 newEvent.objInst = ( objInst == 0 ) ? SI_UPOV : SI_UPOV2; 1016 _Win32LogPOVInput(newEvent); 1017 newEvent.postToSignal(Input::smInputEvent); 1018 } 1019 if( setkeys & POV_right) 1020 { 1021 newEvent.objInst = ( objInst == 0 ) ? SI_RPOV : SI_RPOV2; 1022 _Win32LogPOVInput(newEvent); 1023 newEvent.postToSignal(Input::smInputEvent); 1024 } 1025 if( setkeys & POV_down) 1026 { 1027 newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2; 1028 _Win32LogPOVInput(newEvent); 1029 newEvent.postToSignal(Input::smInputEvent); 1030 } 1031 if( setkeys & POV_left) 1032 { 1033 newEvent.objInst = ( objInst == 0 ) ? SI_LPOV : SI_LPOV2; 1034 _Win32LogPOVInput(newEvent); 1035 newEvent.postToSignal(Input::smInputEvent); 1036 } 1037 } // set keys 1038 } 1039 break; 1040 } 1041 1042 return true; 1043} 1044 1045void DInputDevice::rumble(F32 x, F32 y) 1046{ 1047 LONG rglDirection[2] = { 0, 0 }; 1048 DICONSTANTFORCE cf = { 0 }; 1049 HRESULT result; 1050 1051 // Now set the new parameters and start the effect immediately. 1052 if (!mForceFeedbackEffect) 1053 { 1054#ifdef LOG_INPUT 1055 Input::log("DInputDevice::rumbleJoystick - creating constant force feeback effect\n"); 1056#endif 1057 DIEFFECT eff; 1058 ZeroMemory( &eff, sizeof(eff) ); 1059 eff.dwSize = sizeof(DIEFFECT); 1060 eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; 1061 eff.dwDuration = INFINITE; 1062 eff.dwSamplePeriod = 0; 1063 eff.dwGain = DI_FFNOMINALMAX; 1064 eff.dwTriggerButton = DIEB_NOTRIGGER; 1065 eff.dwTriggerRepeatInterval = 0; 1066 eff.cAxes = mNumForceFeedbackAxes; 1067 eff.rgdwAxes = mForceFeedbackAxes; 1068 eff.rglDirection = rglDirection; 1069 eff.lpEnvelope = 0; 1070 eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); 1071 eff.lpvTypeSpecificParams = &cf; 1072 eff.dwStartDelay = 0; 1073 1074 // Create the prepared effect 1075 if ( FAILED( result = mDevice->CreateEffect( GUID_ConstantForce, &eff, &mForceFeedbackEffect, NULL ) ) ) 1076 { 1077#ifdef LOG_INPUT 1078 Input::log( "DInputDevice::rumbleJoystick - %s does not support force feedback.\n", mName ); 1079#endif 1080 Con::errorf( "DInputDevice::rumbleJoystick - %s does not support force feedback.\n", mName ); 1081 return; 1082 } 1083 else 1084 { 1085#ifdef LOG_INPUT 1086 Input::log( "DInputDevice::rumbleJoystick - %s supports force feedback.\n", mName ); 1087#endif 1088 Con::printf( "DInputDevice::rumbleJoystick - %s supports force feedback.\n", mName ); 1089 } 1090 } 1091 1092 // Clamp the input floats to [0 - 1] 1093 x = max(0, min(1, x)); 1094 y = max(0, min(1, y)); 1095 1096 if ( 1 == mNumForceFeedbackAxes ) 1097 { 1098 cf.lMagnitude = (DWORD)( x * DI_FFNOMINALMAX ); 1099 } 1100 else 1101 { 1102 rglDirection[0] = (DWORD)( x * DI_FFNOMINALMAX ); 1103 rglDirection[1] = (DWORD)( y * DI_FFNOMINALMAX ); 1104 cf.lMagnitude = (DWORD)sqrt( (double)(x * x * DI_FFNOMINALMAX * DI_FFNOMINALMAX + y * y * DI_FFNOMINALMAX * DI_FFNOMINALMAX) ); 1105 } 1106 1107 DIEFFECT eff; 1108 ZeroMemory( &eff, sizeof(eff) ); 1109 eff.dwSize = sizeof(DIEFFECT); 1110 eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; 1111 eff.dwDuration = INFINITE; 1112 eff.dwSamplePeriod = 0; 1113 eff.dwGain = DI_FFNOMINALMAX; 1114 eff.dwTriggerButton = DIEB_NOTRIGGER; 1115 eff.dwTriggerRepeatInterval = 0; 1116 eff.cAxes = mNumForceFeedbackAxes; 1117 eff.rglDirection = rglDirection; 1118 eff.lpEnvelope = 0; 1119 eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); 1120 eff.lpvTypeSpecificParams = &cf; 1121 eff.dwStartDelay = 0; 1122 1123 if ( FAILED( result = mForceFeedbackEffect->SetParameters( &eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START ) ) ) 1124 { 1125 const char* errorString = NULL; 1126 switch ( result ) 1127 { 1128 case DIERR_INPUTLOST: 1129 errorString = "DIERR_INPUTLOST"; 1130 break; 1131 1132 case DIERR_INVALIDPARAM: 1133 errorString = "DIERR_INVALIDPARAM"; 1134 break; 1135 1136 case DIERR_NOTACQUIRED: 1137 errorString = "DIERR_NOTACQUIRED"; 1138 break; 1139 1140 default: 1141 errorString = "Unknown Error"; 1142 } 1143 1144#ifdef LOG_INPUT 1145 Input::log( "DInputDevice::rumbleJoystick - %s - Failed to start rumble effect\n", errorString ); 1146#endif 1147 Con::errorf( "DInputDevice::rumbleJoystick - %s - Failed to start rumble effect\n", errorString ); 1148 } 1149} 1150 1151//------------------------------------------------------------------------------ 1152// 1153// This function translates the DirectInput scan code to the associated 1154// internal key code (as defined in event.h). 1155// 1156//------------------------------------------------------------------------------ 1157InputObjectInstances DIK_to_Key( U8 dikCode ) 1158{ 1159 switch ( dikCode ) 1160 { 1161 case DIK_ESCAPE: return KEY_ESCAPE; 1162 1163 case DIK_1: return KEY_1; 1164 case DIK_2: return KEY_2; 1165 case DIK_3: return KEY_3; 1166 case DIK_4: return KEY_4; 1167 case DIK_5: return KEY_5; 1168 case DIK_6: return KEY_6; 1169 case DIK_7: return KEY_7; 1170 case DIK_8: return KEY_8; 1171 case DIK_9: return KEY_9; 1172 case DIK_0: return KEY_0; 1173 1174 case DIK_MINUS: return KEY_MINUS; 1175 case DIK_EQUALS: return KEY_EQUALS; 1176 case DIK_BACK: return KEY_BACKSPACE; 1177 case DIK_TAB: return KEY_TAB; 1178 1179 case DIK_Q: return KEY_Q; 1180 case DIK_W: return KEY_W; 1181 case DIK_E: return KEY_E; 1182 case DIK_R: return KEY_R; 1183 case DIK_T: return KEY_T; 1184 case DIK_Y: return KEY_Y; 1185 case DIK_U: return KEY_U; 1186 case DIK_I: return KEY_I; 1187 case DIK_O: return KEY_O; 1188 case DIK_P: return KEY_P; 1189 1190 case DIK_LBRACKET: return KEY_LBRACKET; 1191 case DIK_RBRACKET: return KEY_RBRACKET; 1192 case DIK_RETURN: return KEY_RETURN; 1193 case DIK_LCONTROL: return KEY_LCONTROL; 1194 1195 case DIK_A: return KEY_A; 1196 case DIK_S: return KEY_S; 1197 case DIK_D: return KEY_D; 1198 case DIK_F: return KEY_F; 1199 case DIK_G: return KEY_G; 1200 case DIK_H: return KEY_H; 1201 case DIK_J: return KEY_J; 1202 case DIK_K: return KEY_K; 1203 case DIK_L: return KEY_L; 1204 1205 case DIK_SEMICOLON: return KEY_SEMICOLON; 1206 case DIK_APOSTROPHE: return KEY_APOSTROPHE; 1207 case DIK_GRAVE: return KEY_TILDE; 1208 case DIK_LSHIFT: return KEY_LSHIFT; 1209 case DIK_BACKSLASH: return KEY_BACKSLASH; 1210 1211 case DIK_Z: return KEY_Z; 1212 case DIK_X: return KEY_X; 1213 case DIK_C: return KEY_C; 1214 case DIK_V: return KEY_V; 1215 case DIK_B: return KEY_B; 1216 case DIK_N: return KEY_N; 1217 case DIK_M: return KEY_M; 1218 1219 case DIK_COMMA: return KEY_COMMA; 1220 case DIK_PERIOD: return KEY_PERIOD; 1221 case DIK_SLASH: return KEY_SLASH; 1222 case DIK_RSHIFT: return KEY_RSHIFT; 1223 case DIK_MULTIPLY: return KEY_MULTIPLY; 1224 case DIK_LALT: return KEY_LALT; 1225 case DIK_SPACE: return KEY_SPACE; 1226 case DIK_CAPSLOCK: return KEY_CAPSLOCK; 1227 1228 case DIK_F1: return KEY_F1; 1229 case DIK_F2: return KEY_F2; 1230 case DIK_F3: return KEY_F3; 1231 case DIK_F4: return KEY_F4; 1232 case DIK_F5: return KEY_F5; 1233 case DIK_F6: return KEY_F6; 1234 case DIK_F7: return KEY_F7; 1235 case DIK_F8: return KEY_F8; 1236 case DIK_F9: return KEY_F9; 1237 case DIK_F10: return KEY_F10; 1238 1239 case DIK_NUMLOCK: return KEY_NUMLOCK; 1240 case DIK_SCROLL: return KEY_SCROLLLOCK; 1241 1242 case DIK_NUMPAD7: return KEY_NUMPAD7; 1243 case DIK_NUMPAD8: return KEY_NUMPAD8; 1244 case DIK_NUMPAD9: return KEY_NUMPAD9; 1245 case DIK_SUBTRACT: return KEY_SUBTRACT; 1246 1247 case DIK_NUMPAD4: return KEY_NUMPAD4; 1248 case DIK_NUMPAD5: return KEY_NUMPAD5; 1249 case DIK_NUMPAD6: return KEY_NUMPAD6; 1250 case DIK_ADD: return KEY_ADD; 1251 1252 case DIK_NUMPAD1: return KEY_NUMPAD1; 1253 case DIK_NUMPAD2: return KEY_NUMPAD2; 1254 case DIK_NUMPAD3: return KEY_NUMPAD3; 1255 case DIK_NUMPAD0: return KEY_NUMPAD0; 1256 case DIK_DECIMAL: return KEY_DECIMAL; 1257 1258 case DIK_F11: return KEY_F11; 1259 case DIK_F12: return KEY_F12; 1260 case DIK_F13: return KEY_F13; 1261 case DIK_F14: return KEY_F14; 1262 case DIK_F15: return KEY_F15; 1263 1264 case DIK_KANA: return KEY_NULL; 1265 case DIK_CONVERT: return KEY_NULL; 1266 case DIK_NOCONVERT: return KEY_NULL; 1267 case DIK_YEN: return KEY_NULL; 1268 case DIK_NUMPADEQUALS: return KEY_NULL; 1269 case DIK_CIRCUMFLEX: return KEY_NULL; 1270 case DIK_AT: return KEY_NULL; 1271 case DIK_COLON: return KEY_NULL; 1272 case DIK_UNDERLINE: return KEY_NULL; 1273 case DIK_KANJI: return KEY_NULL; 1274 case DIK_STOP: return KEY_NULL; 1275 case DIK_AX: return KEY_NULL; 1276 case DIK_UNLABELED: return KEY_NULL; 1277 1278 case DIK_NUMPADENTER: return KEY_NUMPADENTER; 1279 case DIK_RCONTROL: return KEY_RCONTROL; 1280 case DIK_NUMPADCOMMA: return KEY_SEPARATOR; 1281 case DIK_DIVIDE: return KEY_DIVIDE; 1282 case DIK_SYSRQ: return KEY_PRINT; 1283 case DIK_RALT: return KEY_RALT; 1284 case DIK_PAUSE: return KEY_PAUSE; 1285 1286 case DIK_HOME: return KEY_HOME; 1287 case DIK_UP: return KEY_UP; 1288 case DIK_PGUP: return KEY_PAGE_UP; 1289 case DIK_LEFT: return KEY_LEFT; 1290 case DIK_RIGHT: return KEY_RIGHT; 1291 case DIK_END: return KEY_END; 1292 case DIK_DOWN: return KEY_DOWN; 1293 case DIK_PGDN: return KEY_PAGE_DOWN; 1294 case DIK_INSERT: return KEY_INSERT; 1295 case DIK_DELETE: return KEY_DELETE; 1296 1297 case DIK_LWIN: return KEY_WIN_LWINDOW; 1298 case DIK_RWIN: return KEY_WIN_RWINDOW; 1299 case DIK_APPS: return KEY_WIN_APPS; 1300 case DIK_OEM_102: return KEY_OEM_102; 1301 } 1302 1303 return KEY_NULL; 1304} 1305 1306//------------------------------------------------------------------------------ 1307// 1308// This function translates an internal key code to the associated 1309// DirectInput scan code 1310// 1311//------------------------------------------------------------------------------ 1312U8 Key_to_DIK( U16 keyCode ) 1313{ 1314 switch ( keyCode ) 1315 { 1316 case KEY_BACKSPACE: return DIK_BACK; 1317 case KEY_TAB: return DIK_TAB; 1318 case KEY_RETURN: return DIK_RETURN; 1319 //KEY_CONTROL: 1320 //KEY_ALT: 1321 //KEY_SHIFT: 1322 case KEY_PAUSE: return DIK_PAUSE; 1323 case KEY_CAPSLOCK: return DIK_CAPSLOCK; 1324 case KEY_ESCAPE: return DIK_ESCAPE; 1325 1326 case KEY_SPACE: return DIK_SPACE; 1327 case KEY_PAGE_DOWN: return DIK_PGDN; 1328 case KEY_PAGE_UP: return DIK_PGUP; 1329 case KEY_END: return DIK_END; 1330 case KEY_HOME: return DIK_HOME; 1331 case KEY_LEFT: return DIK_LEFT; 1332 case KEY_UP: return DIK_UP; 1333 case KEY_RIGHT: return DIK_RIGHT; 1334 case KEY_DOWN: return DIK_DOWN; 1335 case KEY_PRINT: return DIK_SYSRQ; 1336 case KEY_INSERT: return DIK_INSERT; 1337 case KEY_DELETE: return DIK_DELETE; 1338 case KEY_HELP: return 0; 1339 1340 case KEY_0: return DIK_0; 1341 case KEY_1: return DIK_1; 1342 case KEY_2: return DIK_2; 1343 case KEY_3: return DIK_3; 1344 case KEY_4: return DIK_4; 1345 case KEY_5: return DIK_5; 1346 case KEY_6: return DIK_6; 1347 case KEY_7: return DIK_7; 1348 case KEY_8: return DIK_8; 1349 case KEY_9: return DIK_9; 1350 1351 case KEY_A: return DIK_A; 1352 case KEY_B: return DIK_B; 1353 case KEY_C: return DIK_C; 1354 case KEY_D: return DIK_D; 1355 case KEY_E: return DIK_E; 1356 case KEY_F: return DIK_F; 1357 case KEY_G: return DIK_G; 1358 case KEY_H: return DIK_H; 1359 case KEY_I: return DIK_I; 1360 case KEY_J: return DIK_J; 1361 case KEY_K: return DIK_K; 1362 case KEY_L: return DIK_L; 1363 case KEY_M: return DIK_M; 1364 case KEY_N: return DIK_N; 1365 case KEY_O: return DIK_O; 1366 case KEY_P: return DIK_P; 1367 case KEY_Q: return DIK_Q; 1368 case KEY_R: return DIK_R; 1369 case KEY_S: return DIK_S; 1370 case KEY_T: return DIK_T; 1371 case KEY_U: return DIK_U; 1372 case KEY_V: return DIK_V; 1373 case KEY_W: return DIK_W; 1374 case KEY_X: return DIK_X; 1375 case KEY_Y: return DIK_Y; 1376 case KEY_Z: return DIK_Z; 1377 1378 case KEY_TILDE: return DIK_GRAVE; 1379 case KEY_MINUS: return DIK_MINUS; 1380 case KEY_EQUALS: return DIK_EQUALS; 1381 case KEY_LBRACKET: return DIK_LBRACKET; 1382 case KEY_RBRACKET: return DIK_RBRACKET; 1383 case KEY_BACKSLASH: return DIK_BACKSLASH; 1384 case KEY_SEMICOLON: return DIK_SEMICOLON; 1385 case KEY_APOSTROPHE: return DIK_APOSTROPHE; 1386 case KEY_COMMA: return DIK_COMMA; 1387 case KEY_PERIOD: return DIK_PERIOD; 1388 case KEY_SLASH: return DIK_SLASH; 1389 1390 case KEY_NUMPAD0: return DIK_NUMPAD0; 1391 case KEY_NUMPAD1: return DIK_NUMPAD1; 1392 case KEY_NUMPAD2: return DIK_NUMPAD2; 1393 case KEY_NUMPAD3: return DIK_NUMPAD3; 1394 case KEY_NUMPAD4: return DIK_NUMPAD4; 1395 case KEY_NUMPAD5: return DIK_NUMPAD5; 1396 case KEY_NUMPAD6: return DIK_NUMPAD6; 1397 case KEY_NUMPAD7: return DIK_NUMPAD7; 1398 case KEY_NUMPAD8: return DIK_NUMPAD8; 1399 case KEY_NUMPAD9: return DIK_NUMPAD9; 1400 case KEY_MULTIPLY: return DIK_MULTIPLY; 1401 case KEY_ADD: return DIK_ADD; 1402 case KEY_SEPARATOR: return DIK_NUMPADCOMMA; 1403 case KEY_SUBTRACT: return DIK_SUBTRACT; 1404 case KEY_DECIMAL: return DIK_DECIMAL; 1405 case KEY_DIVIDE: return DIK_DIVIDE; 1406 case KEY_NUMPADENTER: return DIK_NUMPADENTER; 1407 1408 case KEY_F1: return DIK_F1; 1409 case KEY_F2: return DIK_F2; 1410 case KEY_F3: return DIK_F3; 1411 case KEY_F4: return DIK_F4; 1412 case KEY_F5: return DIK_F5; 1413 case KEY_F6: return DIK_F6; 1414 case KEY_F7: return DIK_F7; 1415 case KEY_F8: return DIK_F8; 1416 case KEY_F9: return DIK_F9; 1417 case KEY_F10: return DIK_F10; 1418 case KEY_F11: return DIK_F11; 1419 case KEY_F12: return DIK_F12; 1420 case KEY_F13: return DIK_F13; 1421 case KEY_F14: return DIK_F14; 1422 case KEY_F15: return DIK_F15; 1423 case KEY_F16: 1424 case KEY_F17: 1425 case KEY_F18: 1426 case KEY_F19: 1427 case KEY_F20: 1428 case KEY_F21: 1429 case KEY_F22: 1430 case KEY_F23: 1431 case KEY_F24: return 0; 1432 1433 case KEY_NUMLOCK: return DIK_NUMLOCK; 1434 case KEY_SCROLLLOCK: return DIK_SCROLL; 1435 case KEY_LCONTROL: return DIK_LCONTROL; 1436 case KEY_RCONTROL: return DIK_RCONTROL; 1437 case KEY_LALT: return DIK_LALT; 1438 case KEY_RALT: return DIK_RALT; 1439 case KEY_LSHIFT: return DIK_LSHIFT; 1440 case KEY_RSHIFT: return DIK_RSHIFT; 1441 1442 case KEY_WIN_LWINDOW: return DIK_LWIN; 1443 case KEY_WIN_RWINDOW: return DIK_RWIN; 1444 case KEY_WIN_APPS: return DIK_APPS; 1445 case KEY_OEM_102: return DIK_OEM_102; 1446 1447 }; 1448 1449 return 0; 1450} 1451 1452#ifdef LOG_INPUT 1453//------------------------------------------------------------------------------ 1454const char* getKeyName( U16 key ) 1455{ 1456 switch ( key ) 1457 { 1458 case KEY_BACKSPACE: return "Backspace"; 1459 case KEY_TAB: return "Tab"; 1460 case KEY_RETURN: return "Return"; 1461 case KEY_PAUSE: return "Pause"; 1462 case KEY_CAPSLOCK: return "CapsLock"; 1463 case KEY_ESCAPE: return "Esc"; 1464 1465 case KEY_SPACE: return "SpaceBar"; 1466 case KEY_PAGE_DOWN: return "PageDown"; 1467 case KEY_PAGE_UP: return "PageUp"; 1468 case KEY_END: return "End"; 1469 case KEY_HOME: return "Home"; 1470 case KEY_LEFT: return "Left"; 1471 case KEY_UP: return "Up"; 1472 case KEY_RIGHT: return "Right"; 1473 case KEY_DOWN: return "Down"; 1474 case KEY_PRINT: return "PrintScreen"; 1475 case KEY_INSERT: return "Insert"; 1476 case KEY_DELETE: return "Delete"; 1477 case KEY_HELP: return "Help"; 1478 1479 case KEY_NUMPAD0: return "Numpad 0"; 1480 case KEY_NUMPAD1: return "Numpad 1"; 1481 case KEY_NUMPAD2: return "Numpad 2"; 1482 case KEY_NUMPAD3: return "Numpad 3"; 1483 case KEY_NUMPAD4: return "Numpad 4"; 1484 case KEY_NUMPAD5: return "Numpad 5"; 1485 case KEY_NUMPAD6: return "Numpad 6"; 1486 case KEY_NUMPAD7: return "Numpad 7"; 1487 case KEY_NUMPAD8: return "Numpad 8"; 1488 case KEY_NUMPAD9: return "Numpad 9"; 1489 case KEY_MULTIPLY: return "Multiply"; 1490 case KEY_ADD: return "Add"; 1491 case KEY_SEPARATOR: return "Separator"; 1492 case KEY_SUBTRACT: return "Subtract"; 1493 case KEY_DECIMAL: return "Decimal"; 1494 case KEY_DIVIDE: return "Divide"; 1495 case KEY_NUMPADENTER: return "Numpad Enter"; 1496 1497 case KEY_F1: return "F1"; 1498 case KEY_F2: return "F2"; 1499 case KEY_F3: return "F3"; 1500 case KEY_F4: return "F4"; 1501 case KEY_F5: return "F5"; 1502 case KEY_F6: return "F6"; 1503 case KEY_F7: return "F7"; 1504 case KEY_F8: return "F8"; 1505 case KEY_F9: return "F9"; 1506 case KEY_F10: return "F10"; 1507 case KEY_F11: return "F11"; 1508 case KEY_F12: return "F12"; 1509 case KEY_F13: return "F13"; 1510 case KEY_F14: return "F14"; 1511 case KEY_F15: return "F15"; 1512 case KEY_F16: return "F16"; 1513 case KEY_F17: return "F17"; 1514 case KEY_F18: return "F18"; 1515 case KEY_F19: return "F19"; 1516 case KEY_F20: return "F20"; 1517 case KEY_F21: return "F21"; 1518 case KEY_F22: return "F22"; 1519 case KEY_F23: return "F23"; 1520 case KEY_F24: return "F24"; 1521 1522 case KEY_NUMLOCK: return "NumLock"; 1523 case KEY_SCROLLLOCK: return "ScrollLock"; 1524 case KEY_LCONTROL: return "LCtrl"; 1525 case KEY_RCONTROL: return "RCtrl"; 1526 case KEY_LALT: return "LAlt"; 1527 case KEY_RALT: return "RAlt"; 1528 case KEY_LSHIFT: return "LShift"; 1529 case KEY_RSHIFT: return "RShift"; 1530 1531 case KEY_WIN_LWINDOW: return "LWin"; 1532 case KEY_WIN_RWINDOW: return "RWin"; 1533 case KEY_WIN_APPS: return "Apps"; 1534 } 1535 1536 static char returnString[5]; 1537 dSprintf( returnString, sizeof( returnString ), "%c", Input::getAscii( key, STATE_UPPER ) ); 1538 return returnString; 1539} 1540#endif // LOG_INPUT 1541 1542//------------------------------------------------------------------------------ 1543const char* DInputDevice::getJoystickAxesString() 1544{ 1545 if ( mDeviceType != JoystickDeviceType ) 1546 return( "" ); 1547 1548 U32 axisCount = mDeviceCaps.dwAxes; 1549 char buf[64]; 1550 dSprintf( buf, sizeof( buf ), "%d", axisCount ); 1551 for ( U32 i = 0; i < mObjCount; i++ ) 1552 { 1553 switch ( mObjInfo[i].mInst ) 1554 { 1555 case SI_XAXIS: 1556 dStrcat( buf, "\tX", 64 ); 1557 break; 1558 case SI_YAXIS: 1559 dStrcat( buf, "\tY", 64 ); 1560 break; 1561 case SI_ZAXIS: 1562 dStrcat( buf, "\tZ", 64 ); 1563 break; 1564 case SI_RXAXIS: 1565 dStrcat( buf, "\tR", 64 ); 1566 break; 1567 case SI_RYAXIS: 1568 dStrcat( buf, "\tU", 64 ); 1569 break; 1570 case SI_RZAXIS: 1571 dStrcat( buf, "\tV", 64 ); 1572 break; 1573 case SI_SLIDER: 1574 dStrcat( buf, "\tS", 64 ); 1575 break; 1576 } 1577 } 1578 1579 dsize_t returnLen = dStrlen(buf) + 1; 1580 char* returnString = Con::getReturnBuffer(returnLen); 1581 dStrcpy( returnString, buf, returnLen ); 1582 return( returnString ); 1583} 1584 1585//------------------------------------------------------------------------------ 1586bool DInputDevice::joystickDetected() 1587{ 1588 return( smDeviceCount[ JoystickDeviceType ] > 0 ); 1589} 1590 1591 1592 1593