| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590 | //-----------------------------------------------------------------------------// Copyright (c) 2012 GarageGames, LLC//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS// IN THE SOFTWARE.//-----------------------------------------------------------------------------#ifndef INITGUID#define INITGUID#endif#include "platform/platform.h"#include "platformWin32/winDInputDevice.h"#include "math/mMath.h"#include "console/console.h"#include "core/strings/unicode.h"#include "windowManager/platformWindowMgr.h"// Static class data:LPDIRECTINPUT8 DInputDevice::smDInputInterface;U8    DInputDevice::smDeviceCount[ NUM_INPUT_DEVICE_TYPES ];bool  DInputDevice::smInitialized = false;#ifdef LOG_INPUTconst char* getKeyName( U16 key );#endif//------------------------------------------------------------------------------DInputDevice::DInputDevice( const DIDEVICEINSTANCE* dii ){   mDeviceInstance   = *dii;   mDevice           = NULL;   mAcquired         = false;   mNeedSync         = false;   mObjInstance      = NULL;   mObjFormat        = NULL;   mObjInfo          = NULL;   mObjBuffer1       = NULL;   mObjBuffer2       = NULL;   mPrevObjBuffer    = NULL;   mForceFeedbackEffect    = NULL;   mNumForceFeedbackAxes   = 0;   mForceFeedbackAxes[0]   = 0;   mForceFeedbackAxes[1]   = 0;   const char* deviceTypeName = "unknown";   U8 deviceType = UnknownDeviceType;   switch ( GET_DIDEVICE_TYPE( mDeviceInstance.dwDevType ) )   {      // [rene, 12/09/2008] why do we turn a gamepad into a joystick here?	        case DI8DEVTYPE_DRIVING:      case DI8DEVTYPE_GAMEPAD:      case DI8DEVTYPE_JOYSTICK:         deviceTypeName    = "joystick";         deviceType        = JoystickDeviceType;         break;      case DI8DEVTYPE_KEYBOARD:         deviceTypeName    = "keyboard";         deviceType        = KeyboardDeviceType;         break;      case DI8DEVTYPE_MOUSE:         deviceTypeName    = "mouse";         deviceType        = MouseDeviceType;         break;   }   mDeviceType    = deviceType;   mDeviceID      = smDeviceCount[ deviceType ] ++;   dSprintf( mName, 29, "%s%d", deviceTypeName, mDeviceID );}//------------------------------------------------------------------------------DInputDevice::~DInputDevice(){   destroy();}//------------------------------------------------------------------------------void DInputDevice::init(){   // Reset all of the static variables:   smDInputInterface    = NULL;   dMemset( smDeviceCount, 0, sizeof( smDeviceCount ) );}//------------------------------------------------------------------------------bool DInputDevice::create(){   HRESULT result;   if ( smDInputInterface )   {      result = smDInputInterface->CreateDevice( mDeviceInstance.guidInstance, &mDevice, NULL );      if ( result == DI_OK )      {		 mDeviceCaps.dwSize = sizeof( DIDEVCAPS );         if ( FAILED( mDevice->GetCapabilities( &mDeviceCaps ) ) )         {            Con::errorf( "  Failed to get the capabilities of the %s input device.", mName );#ifdef LOG_INPUT            Input::log( "Failed to get the capabilities of &s!\n", mName );#endif            return false;         }#ifdef LOG_INPUT         Input::log( "%s detected, created as %s (%s).\n", mDeviceInstance.tszProductName, mName, ( isPolled() ? "polled" : "asynchronous" ) );#endif         if ( enumerateObjects() )         {			   // Set the device's data format:            DIDATAFORMAT dataFormat;            dMemset( &dataFormat, 0, sizeof( DIDATAFORMAT ) );            dataFormat.dwSize       = sizeof( DIDATAFORMAT );            dataFormat.dwObjSize    = sizeof( DIOBJECTDATAFORMAT );			   dataFormat.dwFlags      = ( mDeviceType == MouseDeviceType ) ? DIDF_RELAXIS : DIDF_ABSAXIS;            dataFormat.dwDataSize   = mObjBufferSize;            dataFormat.dwNumObjs    = mObjCount;            dataFormat.rgodf        = mObjFormat;					            result = mDevice->SetDataFormat( &dataFormat );            if ( FAILED( result ) )            {				               Con::errorf( "  Failed to set the data format for the %s input device.", mName );#ifdef LOG_INPUT               Input::log( "Failed to set the data format for %s!\n", mName );#endif			   return false;            }            // Set up the data buffer for buffered input:            DIPROPDWORD prop;            prop.diph.dwSize        = sizeof( DIPROPDWORD );            prop.diph.dwHeaderSize  = sizeof( DIPROPHEADER );            prop.diph.dwObj         = 0;            prop.diph.dwHow         = DIPH_DEVICE;            if ( isPolled() )               prop.dwData = mObjBufferSize;            else               prop.dwData = QUEUED_BUFFER_SIZE;            result = mDevice->SetProperty( DIPROP_BUFFERSIZE, &prop.diph );            if ( FAILED( result ) )            {               Con::errorf( "  Failed to set the buffer size property for the %s input device.", mName );#ifdef LOG_INPUT               Input::log( "Failed to set the buffer size property for %s!\n", mName );#endif               return false;            }            // If this device is a mouse, set it to relative axis mode:            if ( mDeviceType == MouseDeviceType )            {               prop.diph.dwObj   = 0;               prop.diph.dwHow   = DIPH_DEVICE;               prop.dwData       = DIPROPAXISMODE_REL;               result = mDevice->SetProperty( DIPROP_AXISMODE, &prop.diph );               if ( FAILED( result ) )               {                  Con::errorf( "  Failed to set relative axis mode for the %s input device.", mName );#ifdef LOG_INPUT                  Input::log( "Failed to set relative axis mode for %s!\n", mName );#endif                  return false;               }            }         }      }      else      {#ifdef LOG_INPUT         switch ( result )         {            case DIERR_DEVICENOTREG:               Input::log( "CreateDevice failed -- The device or device instance is not registered with DirectInput.\n" );               break;            case DIERR_INVALIDPARAM:               Input::log( "CreateDevice failed -- Invalid parameter.\n" );               break;            case DIERR_NOINTERFACE:               Input::log( "CreateDevice failed -- The specified interface is not supported by the object.\n" );               break;            case DIERR_OUTOFMEMORY:               Input::log( "CreateDevice failed -- Out of memory.\n" );               break;            default:               Input::log( "CreateDevice failed -- Unknown error.\n" );               break;         };#endif // LOG_INPUT         Con::printf( "  CreateDevice failed for the %s input device!", mName );         return false;      }   }   Con::printf( "   %s input device created.", mName );   return true;}//------------------------------------------------------------------------------void DInputDevice::destroy(){   if ( mDevice )   {      unacquire();      // Tear down our forcefeedback.      if (mForceFeedbackEffect)      {         mForceFeedbackEffect->Release();         mForceFeedbackEffect = NULL;         mNumForceFeedbackAxes = 0;#ifdef LOG_INPUT         Input::log("DInputDevice::destroy - releasing constant force feeback effect\n"); #endif      }      mDevice->Release();      mDevice = NULL;      delete [] mObjInstance;      delete [] mObjFormat;      delete [] mObjInfo;      delete [] mObjBuffer1;      delete [] mObjBuffer2;      mObjInstance   = NULL;      mObjFormat     = NULL;      mObjInfo       = NULL;      mObjBuffer1    = NULL;      mObjBuffer2    = NULL;      mPrevObjBuffer = NULL;      mName[0]       = 0;   }}//------------------------------------------------------------------------------bool DInputDevice::acquire(){   if ( mDevice )   {      if ( mAcquired )         return( true );      bool result = false;      // Set the cooperative level:      // (do this here so that we have a valid app window)      DWORD coopLevel = DISCL_BACKGROUND;      if ( mDeviceType == JoystickDeviceType// #ifndef DEBUG//         || mDeviceType == MouseDeviceType// #endif         )         // Exclusive access is required in order to perform force feedback         coopLevel = DISCL_EXCLUSIVE | DISCL_FOREGROUND;      else         coopLevel |= DISCL_NONEXCLUSIVE;      result = mDevice->SetCooperativeLevel( getWin32WindowHandle(), coopLevel );      if ( FAILED( result ) )      {         Con::errorf( "Failed to set the cooperative level for the %s input device.", mName );#ifdef LOG_INPUT         Input::log( "Failed to set the cooperative level for %s!\n", mName );#endif         return false;      }      // Enumerate joystick axes to enable force feedback      if ( NULL == mForceFeedbackEffect && JoystickDeviceType == mDeviceType)      {         // Since we will be playing force feedback effects, we should disable the auto-centering spring.         DIPROPDWORD dipdw;         dipdw.diph.dwSize       = sizeof(DIPROPDWORD);         dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);         dipdw.diph.dwObj        = 0;         dipdw.diph.dwHow        = DIPH_DEVICE;         dipdw.dwData            = FALSE;         if( FAILED( result = mDevice->SetProperty( DIPROP_AUTOCENTER, &dipdw.diph ) ) )            return false;      }      S32 code = mDevice->Acquire();      result = SUCCEEDED( code );      if ( result )      {         Con::printf( "%s input device acquired.", mName );#ifdef LOG_INPUT         Input::log( "%s acquired.\n", mName );#endif         mAcquired = true;         // If we were previously playing a force feedback effect, before         // losing acquisition, we do not automatically restart it. This is         // where you could call mForceFeedbackEffect->Start( INFINITE, 0 );          // if you want that behavior.         // Update all of the key states:         if ( !isPolled() )            mNeedSync = true;      }      else      {         const char* reason;         switch ( code )         {            case DIERR_INVALIDPARAM:      reason = "Invalid parameter"  ; break;            case DIERR_NOTINITIALIZED:    reason = "Not initialized"; break;            case DIERR_OTHERAPPHASPRIO:   reason = "Other app has priority"; break;            case S_FALSE:                 reason = "Already acquired"; break;            default:                      reason = "Unknown error"; break;         }         Con::warnf( "%s input device NOT acquired: %s", mName, reason );#ifdef LOG_INPUT         Input::log( "Failed to acquire %s: %s\n", mName, reason );#endif      }      return( result );   }   return( false );}//------------------------------------------------------------------------------bool DInputDevice::unacquire(){   if ( mDevice )   {      if ( !mAcquired )         return( true );      bool result = false;      result = SUCCEEDED( mDevice->Unacquire() );      if ( result )      {         Con::printf( "%s input device unacquired.", mName );#ifdef LOG_INPUT         Input::log( "%s unacquired.\n", mName );#endif         mAcquired = false;      }      else      {         Con::warnf( ConsoleLogEntry::General, "%s input device NOT unacquired.", mName );#ifdef LOG_INPUT         Input::log( "Failed to unacquire %s!\n", mName );#endif      }      return( result );   }   return( false );}//------------------------------------------------------------------------------BOOL CALLBACK DInputDevice::EnumObjectsProc( const DIDEVICEOBJECTINSTANCE* doi, LPVOID pvRef ){   // Don't enumerate unknown types:   if ( doi->guidType == GUID_Unknown )      return (DIENUM_CONTINUE);   // Reduce a couple pointers:   DInputDevice* diDevice = (DInputDevice*) pvRef;   DIDEVICEOBJECTINSTANCE* objInstance = &diDevice->mObjInstance[diDevice->mObjEnumCount];   DIOBJECTDATAFORMAT*     objFormat   = &diDevice->mObjFormat[diDevice->mObjEnumCount];   // Fill in the object instance structure:   *objInstance = *doi;   // DWORD objects must be DWORD aligned:   if ( !(objInstance->dwType & DIDFT_BUTTON ) )      diDevice->mObjBufferOfs = ( diDevice->mObjBufferOfs + 3 ) & ~3;   objInstance->dwOfs = diDevice->mObjBufferOfs;   // Fill in the object data format structure:   objFormat->pguid  = &objInstance->guidType;   objFormat->dwType = objInstance->dwType;   objFormat->dwFlags= 0;   objFormat->dwOfs  = diDevice->mObjBufferOfs;   // Advance the enumeration counters:   if ( objFormat->dwType & DIDFT_BUTTON )      diDevice->mObjBufferOfs += SIZEOF_BUTTON;   else      diDevice->mObjBufferOfs += SIZEOF_AXIS;   diDevice->mObjEnumCount++;   return (DIENUM_CONTINUE);}//------------------------------------------------------------------------------bool DInputDevice::enumerateObjects(){   if ( !mDevice )      return false;   // Calculate the needed buffer sizes and allocate them:   mObjCount = ( mDeviceCaps.dwAxes + mDeviceCaps.dwButtons + mDeviceCaps.dwPOVs );   mObjBufferSize = mObjCount * sizeof( DWORD );   mObjInstance   = new DIDEVICEOBJECTINSTANCE[mObjCount];   mObjFormat     = new DIOBJECTDATAFORMAT[mObjCount];   mObjInfo       = new ObjInfo[mObjCount];   if ( isPolled() )   {      mObjBuffer1 = new U8[mObjBufferSize];      dMemset( mObjBuffer1, 0, mObjBufferSize );      mObjBuffer2 = new U8[mObjBufferSize];      dMemset( mObjBuffer2, 0, mObjBufferSize );   }   mObjEnumCount = 0;   mObjBufferOfs = 0;   // We are about to enumerate, clear the axes we claim to know about   mNumForceFeedbackAxes = 0;   // Enumerate all of the 'objects' detected on the device:   if ( FAILED( mDevice->EnumObjects( EnumObjectsProc, this, DIDFT_ALL ) ) )      return false;   // We only supports one or two axis joysticks   if( mNumForceFeedbackAxes > 2 )      mNumForceFeedbackAxes = 2;   // if we enumerated fewer objects than are supposedly available, reset the   // object count   if (mObjEnumCount < mObjCount)	   mObjCount = mObjEnumCount;   mObjBufferSize = ( mObjBufferSize + 3 ) & ~3;   // Fill in the actual size to nearest DWORD   U32 buttonCount   = 0;   U32 povCount      = 0;   U32 keyCount      = 0;   U32 unknownCount  = 0;   // Fill in the device object's info structure:   for ( U32 i = 0; i < mObjCount; i++ )   {      if ( mObjInstance[i].guidType == GUID_Button )      {         mObjInfo[i].mType = SI_BUTTON;         mObjInfo[i].mInst = (InputObjectInstances)(KEY_BUTTON0 + buttonCount++);      }      else if ( mObjInstance[i].guidType == GUID_POV )      {         // This is actually intentional - the POV handling code lower down         // takes the instance number and converts everything to button events.         mObjInfo[i].mType = SI_POV;         mObjInfo[i].mInst = (InputObjectInstances)povCount++;      }      else if ( mObjInstance[i].guidType == GUID_XAxis )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_XAXIS;         if (mObjInstance[i].dwFFMaxForce > 0)            mForceFeedbackAxes[mNumForceFeedbackAxes++] = mObjInstance[i].dwOfs;      }      else if ( mObjInstance[i].guidType == GUID_YAxis )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_YAXIS;         if (mObjInstance[i].dwFFMaxForce > 0)            mForceFeedbackAxes[mNumForceFeedbackAxes++] = mObjInstance[i].dwOfs;      }      else if ( mObjInstance[i].guidType == GUID_ZAxis )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_ZAXIS;      }      else if ( mObjInstance[i].guidType == GUID_RxAxis )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_RXAXIS;      }      else if ( mObjInstance[i].guidType == GUID_RyAxis )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_RYAXIS;      }      else if ( mObjInstance[i].guidType == GUID_RzAxis )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_RZAXIS;      }      else if ( mObjInstance[i].guidType == GUID_Slider )      {         mObjInfo[i].mType = SI_AXIS;         mObjInfo[i].mInst = SI_SLIDER;      }      else if ( mObjInstance[i].guidType == GUID_Key )      {         mObjInfo[i].mType = SI_KEY;         mObjInfo[i].mInst = DIK_to_Key( DIDFT_GETINSTANCE( mObjFormat[i].dwType ) );         keyCount++;      }      else      {         mObjInfo[i].mType = SI_UNKNOWN;         mObjInfo[i].mInst = (InputObjectInstances)unknownCount++;      }      // Set the device object's min and max values:      if ( mObjInstance[i].guidType == GUID_Button        || mObjInstance[i].guidType == GUID_Key        || mObjInstance[i].guidType == GUID_POV )      {         mObjInfo[i].mMin = DIPROPRANGE_NOMIN;         mObjInfo[i].mMax = DIPROPRANGE_NOMAX;      }      else      {         // This is an axis or a slider, so find out its range:         DIPROPRANGE pr;         pr.diph.dwSize       = sizeof( pr );         pr.diph.dwHeaderSize = sizeof( pr.diph );         pr.diph.dwHow        = DIPH_BYID;         pr.diph.dwObj        = mObjFormat[i].dwType;         if ( SUCCEEDED( mDevice->GetProperty( DIPROP_RANGE, &pr.diph ) ) )         {            mObjInfo[i].mMin = pr.lMin;            mObjInfo[i].mMax = pr.lMax;         }         else         {            mObjInfo[i].mMin = DIPROPRANGE_NOMIN;            mObjInfo[i].mMax = DIPROPRANGE_NOMAX;         }      }   }#ifdef LOG_INPUT   Input::log( "  %d total objects detected.\n", mObjCount );   if ( buttonCount )      Input::log( "  %d buttons.\n", buttonCount );   if ( povCount )      Input::log( "  %d POVs.\n", povCount );   if ( keyCount )      Input::log( "  %d keys.\n", keyCount );   if ( unknownCount )      Input::log( "  %d unknown objects.\n", unknownCount );   Input::log( "\n" );#endif   return true;}//------------------------------------------------------------------------------const char* DInputDevice::getName(){#ifdef UNICODE   static UTF8 buf[512];   convertUTF16toUTF8(mDeviceInstance.tszInstanceName, buf);   return (const char *)buf;#else   return mDeviceInstance.tszInstanceName;#endif}//------------------------------------------------------------------------------const char* DInputDevice::getProductName(){#ifdef UNICODE   static UTF8 buf[512];   convertUTF16toUTF8(mDeviceInstance.tszProductName, buf);   return (const char *)buf;#else   return mDeviceInstance.tszProductName;#endif}//------------------------------------------------------------------------------bool DInputDevice::process(){   if ( mAcquired )   {      if ( isPolled() )         return processImmediate();      else         return processAsync();   }   return false;}//------------------------------------------------------------------------------bool DInputDevice::processAsync(){   DIDEVICEOBJECTDATA eventBuffer[QUEUED_BUFFER_SIZE];   DWORD numEvents = QUEUED_BUFFER_SIZE;   HRESULT result;   if ( !mDevice )      return false;   do   {      result = mDevice->GetDeviceData( sizeof( DIDEVICEOBJECTDATA ), eventBuffer, &numEvents, 0 );	      if ( !SUCCEEDED( result ) )      {         switch ( result )         {            case DIERR_INPUTLOST:               // Data stream was interrupted, so try to reacquire the device:               mAcquired = false;               acquire();               break;            case DIERR_INVALIDPARAM:               Con::errorf( "DInputDevice::processAsync -- Invalid parameter passed to GetDeviceData of the %s input device!", mName );#ifdef LOG_INPUT               Input::log( "Invalid parameter passed to GetDeviceData for %s!\n", mName );#endif               break;            case DIERR_NOTACQUIRED:               // We can't get the device, so quit:               mAcquired = false;               // Don't error out - this is actually a natural occurrence...               //Con::errorf( "DInputDevice::processAsync -- GetDeviceData called when %s input device is not acquired!", mName );#ifdef LOG_INPUT               Input::log( "GetDeviceData called when %s is not acquired!\n", mName );#endif               break;         }         return false;      }      // We have buffered input, so act on it:      for ( DWORD i = 0; i < numEvents; i++ )         buildEvent( findObjInstance( eventBuffer[i].dwOfs ), eventBuffer[i].dwData, eventBuffer[i].dwData );      // Check for buffer overflow:      if ( result == DI_BUFFEROVERFLOW )	  {         // This is a problem, but we can keep going...         Con::errorf( "DInputDevice::processAsync -- %s input device's event buffer overflowed!", mName );#ifdef LOG_INPUT         Input::log( "%s event buffer overflowed!\n", mName );#endif         mNeedSync = true; // Let it know to resync next time through...      }   }   while ( numEvents );   return true;}//------------------------------------------------------------------------------bool DInputDevice::processImmediate(){   if ( !mDevice )      return false;   mDevice->Poll();   U8* buffer = ( mPrevObjBuffer == mObjBuffer1 ) ? mObjBuffer2 : mObjBuffer1;   HRESULT result = mDevice->GetDeviceState( mObjBufferSize, buffer );   if ( !SUCCEEDED( result ) )   {      switch ( result )      {         case DIERR_INPUTLOST:            // Data stream was interrupted, so try to reacquire the device:            mAcquired = false;            acquire();            break;         case DIERR_INVALIDPARAM:            Con::errorf( "DInputDevice::processPolled -- invalid parameter passed to GetDeviceState on %s input device!", mName );#ifdef LOG_INPUT            Input::log( "Invalid parameter passed to GetDeviceState on %s.\n", mName );#endif            break;         case DIERR_NOTACQUIRED:            Con::errorf( "DInputDevice::processPolled -- GetDeviceState called when %s input device is not acquired!", mName );#ifdef LOG_INPUT            Input::log( "GetDeviceState called when %s is not acquired!\n", mName );#endif            break;         case E_PENDING:            Con::warnf( "DInputDevice::processPolled -- Data not yet available for the %s input device!", mName );#ifdef LOG_INPUT            Input::log( "Data pending for %s.", mName );#endif            break;      }      return false;   }   // Loop through all of the objects and produce events where   // the states have changed:   // (oldData = 0 prevents a crashing bug in Torque. There is a case where    //  Torque accessed oldData without it ever being set.)   S32 newData, oldData = 0;                             for ( DWORD i = 0; i < mObjCount; i++ )   {      if ( mObjFormat[i].dwType & DIDFT_BUTTON )      {         if ( mPrevObjBuffer )         {            newData = *( (U8*) ( buffer + mObjFormat[i].dwOfs ) );            oldData = *( (U8*) ( mPrevObjBuffer + mObjFormat[i].dwOfs ) );            if ( newData == oldData )               continue;         }         else            continue;      }      else if ( mObjFormat[i].dwType & DIDFT_POV )      {         if ( mPrevObjBuffer )         {            newData = *( (S32*) ( buffer + mObjFormat[i].dwOfs ) );            oldData = *( (S32*) ( mPrevObjBuffer + mObjFormat[i].dwOfs ) );            if ( LOWORD( newData ) == LOWORD( oldData ) )               continue;         }         else            continue;      }      else      {         // report normal axes every time through the loop:         newData = *( (S32*) ( buffer + mObjFormat[i].dwOfs ) );      }      // Build an event:      buildEvent( i, newData, oldData );   }   mPrevObjBuffer = buffer;   return true;}//------------------------------------------------------------------------------DWORD DInputDevice::findObjInstance( DWORD offset ){   DIDEVICEOBJECTINSTANCE *inst = mObjInstance;   for ( U32 i = 0; i < mObjCount; i++, inst++ )   {      if ( inst->dwOfs == offset )         return i;   }   AssertFatal( false, "DInputDevice::findObjInstance -- failed to locate object instance." );   return 0;}//------------------------------------------------------------------------------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,};static const U32 Win32POVQuadrantMap[] = {   POVq_up,    POVq_upright,    POVq_right, POVq_downright,    POVq_down,  POVq_downleft,   POVq_left,  POVq_upleft};static U32 _Win32GetPOVDirs(U32 data){   U32 quadrant = (data / 4500) % 8;   U32 dirs = (data == 0xffff) ? POVq_center : Win32POVQuadrantMap[quadrant];   return dirs;}#if defined(LOG_INPUT)static void _Win32LogPOVInput(InputEventInfo &newEvent){   U32 inst = 0xffff;   const char* sstate = ( newEvent.action == SI_MAKE ) ? "pressed" : "released";   const char* dir = "";   switch( newEvent.objInst )   {   case SI_UPOV:   case SI_UPOV2:      dir = "Up"; inst = (newEvent.objInst == SI_UPOV) ? 1 : 2; break;   case SI_RPOV:   case SI_RPOV2:      dir = "Right"; inst = (newEvent.objInst == SI_RPOV) ? 1 : 2; break;   case SI_DPOV:   case SI_DPOV2:      dir = "Down"; inst = (newEvent.objInst == SI_DPOV) ? 1 : 2; break;   case SI_LPOV:   case SI_LPOV2:      dir = "Left"; inst = (newEvent.objInst == SI_LPOV) ? 1 : 2; break;   }   Con::printf( "EVENT (DInput): %s POV %d %s.\n", dir, inst, sstate);}#else#define _Win32LogPOVInput( a )#endif//------------------------------------------------------------------------------bool DInputDevice::buildEvent( DWORD offset, S32 newData, S32 oldData ){   ObjInfo &objInfo = mObjInfo[offset];   if ( objInfo.mType == SI_UNKNOWN )      return false;   InputEventInfo newEvent;   newEvent.deviceType  = (InputDeviceTypes)mDeviceType;   newEvent.deviceInst  = mDeviceID;   newEvent.objType     = objInfo.mType;   newEvent.objInst     = objInfo.mInst;   newEvent.modifier    = (InputModifiers)0;   switch ( newEvent.objType )   {      case SI_AXIS:         newEvent.action = SI_MOVE;         if ( newEvent.deviceType == MouseDeviceType )         {            newEvent.fValue = float( newData );#ifdef LOG_INPUT#ifdef LOG_MOUSEMOVE            if ( newEvent.objInst == SI_XAXIS )               Input::log( "EVENT (DInput): %s move (%.1f, 0.0).\n", mName, newEvent.fValue );            else if ( newEvent.objInst == SI_YAXIS )               Input::log( "EVENT (DInput): %s move (0.0, %.1f).\n", mName, newEvent.fValue );            else#endif            if ( newEvent.objInst == SI_ZAXIS )               Input::log( "EVENT (DInput): %s wheel move %.1f.\n", mName, newEvent.fValue );#endif         }         else  // Joystick or other device:         {            // Scale to the range -1.0 to 1.0:            if ( objInfo.mMin != DIPROPRANGE_NOMIN && objInfo.mMax != DIPROPRANGE_NOMAX )            {               F32 range = F32( objInfo.mMax - objInfo.mMin );               newEvent.fValue = F32( ( 2 * newData ) - objInfo.mMax - objInfo.mMin ) / range;            }            else               newEvent.fValue = (F32)newData;#ifdef LOG_INPUT            // Keep this commented unless you REALLY want these messages for something--            // they come once per each iteration of the main game loop.            //switch ( newEvent.objType )            //{               //case SI_XAXIS:                  //if ( newEvent.fValue < -0.01f || newEvent.fValue > 0.01f )                     //Input::log( "EVENT (DInput): %s X-axis move %.2f.\n", mName, newEvent.fValue );                  //break;               //case SI_YAXIS:                  //if ( newEvent.fValue < -0.01f || newEvent.fValue > 0.01f )                     //Input::log( "EVENT (DInput): %s Y-axis move %.2f.\n", mName, newEvent.fValue );                  //break;               //case SI_ZAXIS:                  //Input::log( "EVENT (DInput): %s Z-axis move %.1f.\n", mName, newEvent.fValue );                  //break;               //case SI_RXAXIS:                  //Input::log( "EVENT (DInput): %s R-axis move %.1f.\n", mName, newEvent.fValue );                  //break;               //case SI_RYAXIS:                  //Input::log( "EVENT (DInput): %s U-axis move %.1f.\n", mName, newEvent.fValue );                  //break;               //case SI_RZAXIS:                  //Input::log( "EVENT (DInput): %s V-axis move %.1f.\n", mName, newEvent.fValue );                  //break;               //case SI_SLIDER:                  //Input::log( "EVENT (DInput): %s slider move %.1f.\n", mName, newEvent.fValue );                  //break;            //};#endif         }         newEvent.postToSignal(Input::smInputEvent);         break;      case SI_BUTTON:         newEvent.action   = ( newData & 0x80 ) ? SI_MAKE : SI_BREAK;         newEvent.fValue   = ( newEvent.action == SI_MAKE ) ? 1.0f : 0.0f;#ifdef LOG_INPUT         if ( newEvent.action == SI_MAKE )            Input::log( "EVENT (DInput): %s button%d pressed.\n", mName, newEvent.objInst - KEY_BUTTON0 );         else            Input::log( "EVENT (DInput): %s button%d released.\n", mName, newEvent.objInst - KEY_BUTTON0 );#endif         newEvent.postToSignal(Input::smInputEvent);         break;      case SI_POV:         // Handle artificial POV up/down/left/right buttons         // If we're not a polling device, oldData and newData are the same, so "fake" transitions         if(!isPolled()) {            oldData = mPrevPOVPos;            mPrevPOVPos = newData;         }         newData = LOWORD( newData );         oldData = LOWORD( oldData );         newData = _Win32GetPOVDirs(newData);         oldData = _Win32GetPOVDirs(oldData);                  U32 setkeys = newData & (~oldData);         U32 clearkeys = oldData & (~newData);         U32 objInst = newEvent.objInst;         if ( setkeys || clearkeys )         {            if ( clearkeys )            {               newEvent.action = SI_BREAK;               newEvent.fValue = 0.0f;               // post events for all buttons that need to be cleared.               if( clearkeys & POV_up)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_UPOV : SI_UPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }               if( clearkeys & POV_right)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_RPOV : SI_RPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }               if( clearkeys & POV_down)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }               if( clearkeys & POV_left)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_LPOV : SI_LPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }            } // clear keys            if ( setkeys )            {               newEvent.action = SI_MAKE;               newEvent.fValue = 1.0f;               // post events for all buttons that need to be set.               if( setkeys & POV_up)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_UPOV : SI_UPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }               if( setkeys & POV_right)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_RPOV : SI_RPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }               if( setkeys & POV_down)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_DPOV : SI_DPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }               if( setkeys & POV_left)               {                  newEvent.objInst = ( objInst == 0 ) ? SI_LPOV : SI_LPOV2;                  _Win32LogPOVInput(newEvent);                  newEvent.postToSignal(Input::smInputEvent);               }            } // set keys         }         break;   }   return true;}void DInputDevice::rumble(F32 x, F32 y){   LONG            rglDirection[2] = { 0, 0 };   DICONSTANTFORCE cf              = { 0 };   HRESULT         result;   // Now set the new parameters and start the effect immediately.   if (!mForceFeedbackEffect)   {#ifdef LOG_INPUT      Input::log("DInputDevice::rumbleJoystick - creating constant force feeback effect\n"); #endif      DIEFFECT eff;      ZeroMemory( &eff, sizeof(eff) );      eff.dwSize                  = sizeof(DIEFFECT);      eff.dwFlags                 = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;      eff.dwDuration              = INFINITE;      eff.dwSamplePeriod          = 0;      eff.dwGain                  = DI_FFNOMINALMAX;      eff.dwTriggerButton         = DIEB_NOTRIGGER;      eff.dwTriggerRepeatInterval = 0;      eff.cAxes                   = mNumForceFeedbackAxes;      eff.rgdwAxes                = mForceFeedbackAxes;      eff.rglDirection            = rglDirection;      eff.lpEnvelope              = 0;      eff.cbTypeSpecificParams    = sizeof(DICONSTANTFORCE);      eff.lpvTypeSpecificParams   = &cf;      eff.dwStartDelay            = 0;      // Create the prepared effect      if ( FAILED( result = mDevice->CreateEffect( GUID_ConstantForce, &eff, &mForceFeedbackEffect, NULL ) ) )      {#ifdef LOG_INPUT         Input::log( "DInputDevice::rumbleJoystick - %s does not support force feedback.\n", mName );#endif	      Con::errorf( "DInputDevice::rumbleJoystick - %s does not support force feedback.\n", mName );	      return;      }      else      {#ifdef LOG_INPUT         Input::log( "DInputDevice::rumbleJoystick - %s supports force feedback.\n", mName );#endif	      Con::printf( "DInputDevice::rumbleJoystick - %s supports force feedback.\n", mName );      }   }   // Clamp the input floats to [0 - 1]   x = max(0, min(1, x));   y = max(0, min(1, y));   if ( 1 == mNumForceFeedbackAxes )   {      cf.lMagnitude = (DWORD)( x * DI_FFNOMINALMAX );   }   else   {      rglDirection[0] = (DWORD)( x * DI_FFNOMINALMAX );      rglDirection[1] = (DWORD)( y * DI_FFNOMINALMAX );      cf.lMagnitude = (DWORD)sqrt( (double)(x * x * DI_FFNOMINALMAX * DI_FFNOMINALMAX + y * y * DI_FFNOMINALMAX * DI_FFNOMINALMAX) );   }   DIEFFECT eff;   ZeroMemory( &eff, sizeof(eff) );   eff.dwSize                  = sizeof(DIEFFECT);   eff.dwFlags                 = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;   eff.dwDuration              = INFINITE;   eff.dwSamplePeriod          = 0;   eff.dwGain                  = DI_FFNOMINALMAX;   eff.dwTriggerButton         = DIEB_NOTRIGGER;   eff.dwTriggerRepeatInterval = 0;   eff.cAxes                   = mNumForceFeedbackAxes;   eff.rglDirection            = rglDirection;   eff.lpEnvelope              = 0;   eff.cbTypeSpecificParams    = sizeof(DICONSTANTFORCE);   eff.lpvTypeSpecificParams   = &cf;   eff.dwStartDelay            = 0;   if ( FAILED( result = mForceFeedbackEffect->SetParameters( &eff, DIEP_DIRECTION | DIEP_TYPESPECIFICPARAMS | DIEP_START ) ) )   {      const char* errorString = NULL;      switch ( result )      {         case DIERR_INPUTLOST:            errorString = "DIERR_INPUTLOST";            break;         case DIERR_INVALIDPARAM:            errorString = "DIERR_INVALIDPARAM";            break;         case DIERR_NOTACQUIRED:            errorString = "DIERR_NOTACQUIRED";            break;         default:            errorString = "Unknown Error";      }#ifdef LOG_INPUT      Input::log( "DInputDevice::rumbleJoystick - %s - Failed to start rumble effect\n", errorString );#endif      Con::errorf( "DInputDevice::rumbleJoystick - %s - Failed to start rumble effect\n", errorString );   }}//------------------------------------------------------------------------------//// This function translates the DirectInput scan code to the associated// internal key code (as defined in event.h).////------------------------------------------------------------------------------InputObjectInstances DIK_to_Key( U8 dikCode ){   switch ( dikCode )   {      case DIK_ESCAPE:        return KEY_ESCAPE;      case DIK_1:             return KEY_1;      case DIK_2:             return KEY_2;      case DIK_3:             return KEY_3;      case DIK_4:             return KEY_4;      case DIK_5:             return KEY_5;      case DIK_6:             return KEY_6;      case DIK_7:             return KEY_7;      case DIK_8:             return KEY_8;      case DIK_9:             return KEY_9;      case DIK_0:             return KEY_0;      case DIK_MINUS:         return KEY_MINUS;      case DIK_EQUALS:        return KEY_EQUALS;      case DIK_BACK:          return KEY_BACKSPACE;      case DIK_TAB:           return KEY_TAB;      case DIK_Q:             return KEY_Q;      case DIK_W:             return KEY_W;      case DIK_E:             return KEY_E;      case DIK_R:             return KEY_R;      case DIK_T:             return KEY_T;      case DIK_Y:             return KEY_Y;      case DIK_U:             return KEY_U;      case DIK_I:             return KEY_I;      case DIK_O:             return KEY_O;      case DIK_P:             return KEY_P;      case DIK_LBRACKET:      return KEY_LBRACKET;      case DIK_RBRACKET:      return KEY_RBRACKET;      case DIK_RETURN:        return KEY_RETURN;      case DIK_LCONTROL:      return KEY_LCONTROL;      case DIK_A:             return KEY_A;      case DIK_S:             return KEY_S;      case DIK_D:             return KEY_D;      case DIK_F:             return KEY_F;      case DIK_G:             return KEY_G;      case DIK_H:             return KEY_H;      case DIK_J:             return KEY_J;      case DIK_K:             return KEY_K;      case DIK_L:             return KEY_L;      case DIK_SEMICOLON:     return KEY_SEMICOLON;      case DIK_APOSTROPHE:    return KEY_APOSTROPHE;      case DIK_GRAVE:         return KEY_TILDE;      case DIK_LSHIFT:        return KEY_LSHIFT;      case DIK_BACKSLASH:     return KEY_BACKSLASH;      case DIK_Z:             return KEY_Z;      case DIK_X:             return KEY_X;      case DIK_C:             return KEY_C;      case DIK_V:             return KEY_V;      case DIK_B:             return KEY_B;      case DIK_N:             return KEY_N;      case DIK_M:             return KEY_M;      case DIK_COMMA:         return KEY_COMMA;      case DIK_PERIOD:        return KEY_PERIOD;      case DIK_SLASH:         return KEY_SLASH;      case DIK_RSHIFT:        return KEY_RSHIFT;      case DIK_MULTIPLY:      return KEY_MULTIPLY;      case DIK_LALT:          return KEY_LALT;      case DIK_SPACE:         return KEY_SPACE;      case DIK_CAPSLOCK:      return KEY_CAPSLOCK;      case DIK_F1:            return KEY_F1;      case DIK_F2:            return KEY_F2;      case DIK_F3:            return KEY_F3;      case DIK_F4:            return KEY_F4;      case DIK_F5:            return KEY_F5;      case DIK_F6:            return KEY_F6;      case DIK_F7:            return KEY_F7;      case DIK_F8:            return KEY_F8;      case DIK_F9:            return KEY_F9;      case DIK_F10:           return KEY_F10;      case DIK_NUMLOCK:       return KEY_NUMLOCK;      case DIK_SCROLL:        return KEY_SCROLLLOCK;      case DIK_NUMPAD7:       return KEY_NUMPAD7;      case DIK_NUMPAD8:       return KEY_NUMPAD8;      case DIK_NUMPAD9:       return KEY_NUMPAD9;      case DIK_SUBTRACT:      return KEY_SUBTRACT;      case DIK_NUMPAD4:       return KEY_NUMPAD4;      case DIK_NUMPAD5:       return KEY_NUMPAD5;      case DIK_NUMPAD6:       return KEY_NUMPAD6;      case DIK_ADD:           return KEY_ADD;      case DIK_NUMPAD1:       return KEY_NUMPAD1;      case DIK_NUMPAD2:       return KEY_NUMPAD2;      case DIK_NUMPAD3:       return KEY_NUMPAD3;      case DIK_NUMPAD0:       return KEY_NUMPAD0;      case DIK_DECIMAL:       return KEY_DECIMAL;      case DIK_F11:           return KEY_F11;      case DIK_F12:           return KEY_F12;      case DIK_F13:           return KEY_F13;      case DIK_F14:           return KEY_F14;      case DIK_F15:           return KEY_F15;      case DIK_KANA:          return KEY_NULL;      case DIK_CONVERT:       return KEY_NULL;      case DIK_NOCONVERT:     return KEY_NULL;      case DIK_YEN:           return KEY_NULL;      case DIK_NUMPADEQUALS:  return KEY_NULL;      case DIK_CIRCUMFLEX:    return KEY_NULL;      case DIK_AT:            return KEY_NULL;      case DIK_COLON:         return KEY_NULL;      case DIK_UNDERLINE:     return KEY_NULL;      case DIK_KANJI:         return KEY_NULL;      case DIK_STOP:          return KEY_NULL;      case DIK_AX:            return KEY_NULL;      case DIK_UNLABELED:     return KEY_NULL;      case DIK_NUMPADENTER:   return KEY_NUMPADENTER;      case DIK_RCONTROL:      return KEY_RCONTROL;      case DIK_NUMPADCOMMA:   return KEY_SEPARATOR;      case DIK_DIVIDE:        return KEY_DIVIDE;      case DIK_SYSRQ:         return KEY_PRINT;      case DIK_RALT:          return KEY_RALT;      case DIK_PAUSE:         return KEY_PAUSE;      case DIK_HOME:          return KEY_HOME;      case DIK_UP:            return KEY_UP;      case DIK_PGUP:          return KEY_PAGE_UP;      case DIK_LEFT:          return KEY_LEFT;      case DIK_RIGHT:         return KEY_RIGHT;      case DIK_END:           return KEY_END;      case DIK_DOWN:          return KEY_DOWN;      case DIK_PGDN:          return KEY_PAGE_DOWN;      case DIK_INSERT:        return KEY_INSERT;      case DIK_DELETE:        return KEY_DELETE;      case DIK_LWIN:          return KEY_WIN_LWINDOW;      case DIK_RWIN:          return KEY_WIN_RWINDOW;      case DIK_APPS:          return KEY_WIN_APPS;      case DIK_OEM_102:       return KEY_OEM_102;   }   return KEY_NULL;}//------------------------------------------------------------------------------//// This function translates an internal key code to the associated// DirectInput scan code////------------------------------------------------------------------------------U8 Key_to_DIK( U16 keyCode ){   switch ( keyCode )   {      case KEY_BACKSPACE:     return DIK_BACK;      case KEY_TAB:           return DIK_TAB;      case KEY_RETURN:        return DIK_RETURN;      //KEY_CONTROL:      //KEY_ALT:      //KEY_SHIFT:      case KEY_PAUSE:         return DIK_PAUSE;      case KEY_CAPSLOCK:      return DIK_CAPSLOCK;      case KEY_ESCAPE:        return DIK_ESCAPE;      case KEY_SPACE:         return DIK_SPACE;      case KEY_PAGE_DOWN:     return DIK_PGDN;      case KEY_PAGE_UP:       return DIK_PGUP;      case KEY_END:           return DIK_END;      case KEY_HOME:          return DIK_HOME;      case KEY_LEFT:          return DIK_LEFT;      case KEY_UP:            return DIK_UP;      case KEY_RIGHT:         return DIK_RIGHT;      case KEY_DOWN:          return DIK_DOWN;      case KEY_PRINT:         return DIK_SYSRQ;      case KEY_INSERT:        return DIK_INSERT;      case KEY_DELETE:        return DIK_DELETE;      case KEY_HELP:          return 0;      case KEY_0:             return DIK_0;      case KEY_1:             return DIK_1;      case KEY_2:             return DIK_2;      case KEY_3:             return DIK_3;      case KEY_4:             return DIK_4;      case KEY_5:             return DIK_5;      case KEY_6:             return DIK_6;      case KEY_7:             return DIK_7;      case KEY_8:             return DIK_8;      case KEY_9:             return DIK_9;      case KEY_A:             return DIK_A;      case KEY_B:             return DIK_B;      case KEY_C:             return DIK_C;      case KEY_D:             return DIK_D;      case KEY_E:             return DIK_E;      case KEY_F:             return DIK_F;      case KEY_G:             return DIK_G;      case KEY_H:             return DIK_H;      case KEY_I:             return DIK_I;      case KEY_J:             return DIK_J;      case KEY_K:             return DIK_K;      case KEY_L:             return DIK_L;      case KEY_M:             return DIK_M;      case KEY_N:             return DIK_N;      case KEY_O:             return DIK_O;      case KEY_P:             return DIK_P;      case KEY_Q:             return DIK_Q;      case KEY_R:             return DIK_R;      case KEY_S:             return DIK_S;      case KEY_T:             return DIK_T;      case KEY_U:             return DIK_U;      case KEY_V:             return DIK_V;      case KEY_W:             return DIK_W;      case KEY_X:             return DIK_X;      case KEY_Y:             return DIK_Y;      case KEY_Z:             return DIK_Z;      case KEY_TILDE:         return DIK_GRAVE;      case KEY_MINUS:         return DIK_MINUS;      case KEY_EQUALS:        return DIK_EQUALS;      case KEY_LBRACKET:      return DIK_LBRACKET;      case KEY_RBRACKET:      return DIK_RBRACKET;      case KEY_BACKSLASH:     return DIK_BACKSLASH;      case KEY_SEMICOLON:     return DIK_SEMICOLON;      case KEY_APOSTROPHE:    return DIK_APOSTROPHE;      case KEY_COMMA:         return DIK_COMMA;      case KEY_PERIOD:        return DIK_PERIOD;      case KEY_SLASH:         return DIK_SLASH;      case KEY_NUMPAD0:       return DIK_NUMPAD0;      case KEY_NUMPAD1:       return DIK_NUMPAD1;      case KEY_NUMPAD2:       return DIK_NUMPAD2;      case KEY_NUMPAD3:       return DIK_NUMPAD3;      case KEY_NUMPAD4:       return DIK_NUMPAD4;      case KEY_NUMPAD5:       return DIK_NUMPAD5;      case KEY_NUMPAD6:       return DIK_NUMPAD6;      case KEY_NUMPAD7:       return DIK_NUMPAD7;      case KEY_NUMPAD8:       return DIK_NUMPAD8;      case KEY_NUMPAD9:       return DIK_NUMPAD9;      case KEY_MULTIPLY:      return DIK_MULTIPLY;      case KEY_ADD:           return DIK_ADD;      case KEY_SEPARATOR:     return DIK_NUMPADCOMMA;      case KEY_SUBTRACT:      return DIK_SUBTRACT;      case KEY_DECIMAL:       return DIK_DECIMAL;      case KEY_DIVIDE:        return DIK_DIVIDE;      case KEY_NUMPADENTER:   return DIK_NUMPADENTER;      case KEY_F1:            return DIK_F1;      case KEY_F2:            return DIK_F2;      case KEY_F3:            return DIK_F3;      case KEY_F4:            return DIK_F4;      case KEY_F5:            return DIK_F5;      case KEY_F6:            return DIK_F6;      case KEY_F7:            return DIK_F7;      case KEY_F8:            return DIK_F8;      case KEY_F9:            return DIK_F9;      case KEY_F10:           return DIK_F10;      case KEY_F11:           return DIK_F11;      case KEY_F12:           return DIK_F12;      case KEY_F13:           return DIK_F13;      case KEY_F14:           return DIK_F14;      case KEY_F15:           return DIK_F15;      case KEY_F16:      case KEY_F17:      case KEY_F18:      case KEY_F19:      case KEY_F20:      case KEY_F21:      case KEY_F22:      case KEY_F23:      case KEY_F24:           return 0;      case KEY_NUMLOCK:       return DIK_NUMLOCK;      case KEY_SCROLLLOCK:    return DIK_SCROLL;      case KEY_LCONTROL:      return DIK_LCONTROL;      case KEY_RCONTROL:      return DIK_RCONTROL;      case KEY_LALT:          return DIK_LALT;      case KEY_RALT:          return DIK_RALT;      case KEY_LSHIFT:        return DIK_LSHIFT;      case KEY_RSHIFT:        return DIK_RSHIFT;      case KEY_WIN_LWINDOW:   return DIK_LWIN;      case KEY_WIN_RWINDOW:   return DIK_RWIN;      case KEY_WIN_APPS:      return DIK_APPS;      case KEY_OEM_102:       return DIK_OEM_102;   };   return 0;}#ifdef LOG_INPUT//------------------------------------------------------------------------------const char* getKeyName( U16 key ){   switch ( key )   {      case KEY_BACKSPACE:     return "Backspace";      case KEY_TAB:           return "Tab";      case KEY_RETURN:        return "Return";      case KEY_PAUSE:         return "Pause";      case KEY_CAPSLOCK:      return "CapsLock";      case KEY_ESCAPE:        return "Esc";      case KEY_SPACE:         return "SpaceBar";      case KEY_PAGE_DOWN:     return "PageDown";      case KEY_PAGE_UP:       return "PageUp";      case KEY_END:           return "End";      case KEY_HOME:          return "Home";      case KEY_LEFT:          return "Left";      case KEY_UP:            return "Up";      case KEY_RIGHT:         return "Right";      case KEY_DOWN:          return "Down";      case KEY_PRINT:         return "PrintScreen";      case KEY_INSERT:        return "Insert";      case KEY_DELETE:        return "Delete";      case KEY_HELP:          return "Help";      case KEY_NUMPAD0:       return "Numpad 0";      case KEY_NUMPAD1:       return "Numpad 1";      case KEY_NUMPAD2:       return "Numpad 2";      case KEY_NUMPAD3:       return "Numpad 3";      case KEY_NUMPAD4:       return "Numpad 4";      case KEY_NUMPAD5:       return "Numpad 5";      case KEY_NUMPAD6:       return "Numpad 6";      case KEY_NUMPAD7:       return "Numpad 7";      case KEY_NUMPAD8:       return "Numpad 8";      case KEY_NUMPAD9:       return "Numpad 9";      case KEY_MULTIPLY:      return "Multiply";      case KEY_ADD:           return "Add";      case KEY_SEPARATOR:     return "Separator";      case KEY_SUBTRACT:      return "Subtract";      case KEY_DECIMAL:       return "Decimal";      case KEY_DIVIDE:        return "Divide";      case KEY_NUMPADENTER:   return "Numpad Enter";      case KEY_F1:            return "F1";      case KEY_F2:            return "F2";      case KEY_F3:            return "F3";      case KEY_F4:            return "F4";      case KEY_F5:            return "F5";      case KEY_F6:            return "F6";      case KEY_F7:            return "F7";      case KEY_F8:            return "F8";      case KEY_F9:            return "F9";      case KEY_F10:           return "F10";      case KEY_F11:           return "F11";      case KEY_F12:           return "F12";      case KEY_F13:           return "F13";      case KEY_F14:           return "F14";      case KEY_F15:           return "F15";      case KEY_F16:           return "F16";      case KEY_F17:           return "F17";      case KEY_F18:           return "F18";      case KEY_F19:           return "F19";      case KEY_F20:           return "F20";      case KEY_F21:           return "F21";      case KEY_F22:           return "F22";      case KEY_F23:           return "F23";      case KEY_F24:           return "F24";      case KEY_NUMLOCK:       return "NumLock";      case KEY_SCROLLLOCK:    return "ScrollLock";      case KEY_LCONTROL:      return "LCtrl";      case KEY_RCONTROL:      return "RCtrl";      case KEY_LALT:          return "LAlt";      case KEY_RALT:          return "RAlt";      case KEY_LSHIFT:        return "LShift";      case KEY_RSHIFT:        return "RShift";      case KEY_WIN_LWINDOW:   return "LWin";      case KEY_WIN_RWINDOW:   return "RWin";      case KEY_WIN_APPS:      return "Apps";   }   static char returnString[5];   dSprintf( returnString, sizeof( returnString ), "%c", Input::getAscii( key, STATE_UPPER ) );   return returnString;}#endif // LOG_INPUT//------------------------------------------------------------------------------const char* DInputDevice::getJoystickAxesString(){   if ( mDeviceType != JoystickDeviceType )      return( "" );   U32 axisCount = mDeviceCaps.dwAxes;   char buf[64];   dSprintf( buf, sizeof( buf ), "%d", axisCount );   for ( U32 i = 0; i < mObjCount; i++ )   {      switch ( mObjInfo[i].mInst )      {         case SI_XAXIS:            dStrcat( buf, "\tX" );            break;         case SI_YAXIS:            dStrcat( buf, "\tY" );            break;         case SI_ZAXIS:            dStrcat( buf, "\tZ" );            break;         case SI_RXAXIS:            dStrcat( buf, "\tR" );            break;         case SI_RYAXIS:            dStrcat( buf, "\tU" );            break;         case SI_RZAXIS:            dStrcat( buf, "\tV" );            break;         case SI_SLIDER:            dStrcat( buf, "\tS" );            break;      }   }   char* returnString = Con::getReturnBuffer( dStrlen( buf ) + 1 );   dStrcpy( returnString, buf );   return( returnString );}//------------------------------------------------------------------------------bool DInputDevice::joystickDetected(){   return( smDeviceCount[ JoystickDeviceType ] > 0 );}
 |