Torque3D Documentation / _generateds / winDInputDevice.cpp

winDInputDevice.cpp

Engine/source/platformWin32/winDInputDevice.cpp

More...

Public Defines

define

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