0001: //-----------------------------------------------------------------------------
0002: // File: DIUtil.cpp
0003: //
0004: // Desc: DirectInput framework class using semantic mapping.  Feel free to use 
0005: //       this class as a starting point for adding extra functionality.
0006: //-----------------------------------------------------------------------------
0007: #define STRICT
0008: #include <basetsd.h>
0009: #include <tchar.h>
0010: #include <stdio.h>
0011: #include "DIUtil.h"
0012: #include "DXUtil.h"
0013: 
0014: 
0015: 
0016:  
0017: 
0018: //-----------------------------------------------------------------------------
0019: // Name: CInputDeviceManager()
0020: // Desc: Constructor 
0021: //-----------------------------------------------------------------------------
0022: CInputDeviceManager::CInputDeviceManager()
0023: {
0024:     HRESULT hr = CoInitialize(NULL);
0025:     m_bCleanupCOM = SUCCEEDED(hr);
0026: 
0027:     m_dwNumDevices = 0;
0028:     m_dwMaxDevices = 10;
0029:     m_pDI          = NULL;
0030: 
0031:     // Allocate DeviceInfo structs
0032:     m_pDevices = (DeviceInfo*) malloc( m_dwMaxDevices*sizeof(DeviceInfo) );
0033:     if( m_pDevices )
0034:         ZeroMemory( m_pDevices, m_dwMaxDevices*sizeof(DeviceInfo) );
0035: }
0036: 
0037: 
0038: 
0039: 
0040: //-----------------------------------------------------------------------------
0041: // Name: ~CInputDeviceManager()
0042: // Desc: Destructor
0043: //-----------------------------------------------------------------------------
0044: CInputDeviceManager::~CInputDeviceManager()
0045: {
0046:     if( m_pDevices )
0047:     {
0048:         // Release() all devices
0049:         for( DWORD i=0; i<m_dwNumDevices; i++ )
0050:         {
0051:             if( m_pDevices[i].pdidDevice )
0052:                 m_pDevices[i].pdidDevice->Unacquire();
0053: 
0054:             SAFE_RELEASE( m_pDevices[i].pdidDevice );
0055:         }
0056: 
0057:         free( m_pDevices );
0058:     }
0059: 
0060:     // Release() base object
0061:     SAFE_RELEASE( m_pDI );
0062: 
0063:     if( m_bCleanupCOM )
0064:         CoUninitialize();
0065: }
0066: 
0067: 
0068: 
0069: 
0070: //-----------------------------------------------------------------------------
0071: // Name: GetDevices()
0072: // Desc: Get the DeviceInfo array and number of devices
0073: //-----------------------------------------------------------------------------
0074: HRESULT CInputDeviceManager::GetDevices( DeviceInfo** ppDeviceInfo, 
0075:                                          DWORD* pdwCount )
0076: {
0077:     if( NULL==ppDeviceInfo || NULL==pdwCount )
0078:         return E_INVALIDARG;
0079: 
0080:     (*ppDeviceInfo) = m_pDevices;
0081:     (*pdwCount) = m_dwNumDevices;
0082: 
0083:     return S_OK;
0084: }
0085: 
0086: 
0087: 
0088: 
0089: //-----------------------------------------------------------------------------
0090: // Name: AddDevice()
0091: // Desc: Add the provided device to the list and perform initialization
0092: //-----------------------------------------------------------------------------
0093: HRESULT CInputDeviceManager::AddDevice( const DIDEVICEINSTANCE* pdidi, 
0094:                                         const LPDIRECTINPUTDEVICE8 pdidDevice )
0095: {
0096:     HRESULT hr;
0097: 
0098:     // Sanity check
0099:     if( NULL == pdidDevice )
0100:         return E_INVALIDARG;
0101: 
0102:     pdidDevice->Unacquire();
0103: 
0104:     // Set the device's coop level
0105:     hr = pdidDevice->SetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
0106:     if( FAILED(hr) )
0107:         return hr;
0108: 
0109:     // Enlarge the array if needed
0110:     if( m_dwNumDevices >= m_dwMaxDevices )
0111:     {
0112:         // Attempt to reallocate memory
0113:         DWORD dwNewMax = m_dwMaxDevices + 10;
0114:         DeviceInfo* pNewDevices = (DeviceInfo*) realloc( m_pDevices, sizeof(DeviceInfo) * dwNewMax );
0115:         
0116:         // Check for out of memory condition
0117:         if( NULL == pNewDevices )
0118:             return E_OUTOFMEMORY;
0119: 
0120:         // Initialize the new memory block
0121:         ZeroMemory( pNewDevices + m_dwMaxDevices, sizeof(DeviceInfo) * (dwNewMax - m_dwMaxDevices) );
0122: 
0123:         // Copy the new pointer and update the max device count
0124:         m_pDevices = pNewDevices;
0125:         m_dwMaxDevices = dwNewMax;
0126:     }
0127: 
0128:     // Add new device to the end of the list, but don't finalize addition until
0129:     // the end of the function. If the remaining initialization calls fail, this
0130:     // spot will be used by the next valid device.
0131:     m_pDevices[m_dwNumDevices].pdidDevice = pdidDevice;
0132:     
0133:     // Callback into the app so it can adjust the device and set
0134:     // the m_pDevices[dwCurrentDevice].pParam field with a device state struct
0135:     if( m_AddDeviceCallback )
0136:     {
0137:         hr = m_AddDeviceCallback( &m_pDevices[m_dwNumDevices], pdidi, m_AddDeviceCallbackParam ); 
0138:         if( FAILED(hr) )    
0139:             return hr;
0140:     }
0141: 
0142:     // Build the action map
0143:     hr = m_pDevices[m_dwNumDevices].pdidDevice->BuildActionMap( &m_diaf, m_strUserName, 0 );
0144:     if( FAILED(hr) )
0145:         return hr;
0146: 
0147:     // Set the action map for the current device
0148:     hr = m_pDevices[m_dwNumDevices].pdidDevice->SetActionMap( &m_diaf, m_strUserName, 0 );
0149:     if( FAILED(hr) )
0150:         return hr;
0151: 
0152:     // Device addition succeeded. Increment reference and index.
0153:     m_pDevices[m_dwNumDevices].pdidDevice->AddRef();
0154:     m_dwNumDevices++;
0155: 
0156:     // Continue enumerating suitable devices
0157:     return S_OK;
0158: }
0159: 
0160: 
0161: 
0162: 
0163: //-----------------------------------------------------------------------------
0164: // Name: EnumSuitableDevicesCB()
0165: // Desc: Callback function for device enumeration. Adds all devices which
0166: //       met the search criteria
0167: //-----------------------------------------------------------------------------
0168: BOOL CALLBACK EnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi, 
0169:                                      LPDIRECTINPUTDEVICE8 pdidDevice, 
0170:                                      DWORD dwFlags, DWORD dwDeviceRemaining,
0171:                                      VOID* pContext )
0172: {
0173:     UNREFERENCED_PARAMETER( dwFlags );
0174:     UNREFERENCED_PARAMETER( dwDeviceRemaining );
0175:     
0176:     // Add the device to the device manager's internal list
0177:     ((CInputDeviceManager*)pContext)->AddDevice( pdidi, pdidDevice );
0178: 
0179:     // Continue enumerating suitable devices
0180:     return DIENUM_CONTINUE;
0181: }
0182: 
0183: 
0184: 
0185: 
0186: //-----------------------------------------------------------------------------
0187: // Name: SetActionFormat()
0188: // Desc: Set the action format to the provided DIACTIONFORMAT structure, and
0189: //       destroy and recreate device list if flagged
0190: //-----------------------------------------------------------------------------
0191: HRESULT CInputDeviceManager::SetActionFormat( DIACTIONFORMAT& diaf, BOOL bReenumerate )
0192: {
0193:     HRESULT hr = S_OK;
0194: 
0195:     // Store the new action format
0196:     m_diaf = diaf;
0197: 
0198:     // Only destroy and re-enumerate devices if the caller explicitly wants to. The 
0199:     // device list may be used within a loop, and kicking off an enumeration while 
0200:     // the device array is in use would cause problems.
0201:     if( bReenumerate )
0202:     {
0203:         // Cleanup any previously enumerated devices
0204:         for( DWORD i=0; i<m_dwNumDevices; i++ )
0205:         {
0206:             if( m_pDevices[i].pdidDevice )
0207:                 m_pDevices[i].pdidDevice->Unacquire();
0208: 
0209:             SAFE_RELEASE( m_pDevices[i].pdidDevice );
0210:         }
0211:         m_dwNumDevices = 0;
0212: 
0213:         // Enumerate suitable DirectInput devices
0214:         hr = m_pDI->EnumDevicesBySemantics( m_strUserName, &m_diaf, 
0215:                                             EnumSuitableDevicesCB, this, 0L );
0216:         if( FAILED(hr) )
0217:             return hr;
0218:     }
0219:     else // Just apply the new maps.
0220:     {
0221:         // Devices must be unacquired to have a new action map set.
0222:         UnacquireDevices();
0223: 
0224:         // Apply the new action map to the current devices.
0225:         for( DWORD i=0; i<m_dwNumDevices; i++ )
0226:         {
0227:             hr = m_pDevices[i].pdidDevice->BuildActionMap( &m_diaf, m_strUserName, 0 );
0228:             if( FAILED(hr) )
0229:                 return hr;
0230: 
0231:             hr = m_pDevices[i].pdidDevice->SetActionMap( &m_diaf, m_strUserName, 0 );
0232:             if( FAILED(hr) )
0233:                 return hr;
0234:         }
0235:     }
0236: 
0237:     return S_OK;
0238: }
0239: 
0240: 
0241: 
0242: 
0243: //-----------------------------------------------------------------------------
0244: // Name: Create()
0245: // Desc: Create DirectInput object and perform initialization
0246: //-----------------------------------------------------------------------------
0247: HRESULT CInputDeviceManager::Create( HWND hWnd, TCHAR* strUserName, 
0248:                                      DIACTIONFORMAT& diaf,
0249:                                      LPDIMANAGERCALLBACK AddDeviceCallback, 
0250:                                      LPVOID pCallbackParam )
0251: {
0252:     HRESULT hr;
0253: 
0254:     // Store data
0255:     m_hWnd        = hWnd;
0256:     m_strUserName = strUserName;
0257:     m_AddDeviceCallback = AddDeviceCallback;
0258:     m_AddDeviceCallbackParam = pCallbackParam;
0259:     
0260:     // Create the base DirectInput object
0261:     hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
0262:                               IID_IDirectInput8, (VOID**)&m_pDI, NULL );
0263:     if( FAILED(hr) )
0264:         return hr;
0265: 
0266:     hr = SetActionFormat( diaf, TRUE );
0267:     if( FAILED(hr) )
0268:         return hr;
0269: 
0270:     return S_OK;
0271: }
0272: 
0273: 
0274: 
0275: 
0276: //-----------------------------------------------------------------------------
0277: // Name: ConfigureDevices()
0278: // Desc: Pause input and display the device configuration UI
0279: //-----------------------------------------------------------------------------
0280: HRESULT CInputDeviceManager::ConfigureDevices( HWND hWnd, IUnknown* pSurface,
0281:                                                VOID* ConfigureDevicesCB,
0282:                                                DWORD dwFlags, LPVOID pvCBParam )
0283: {
0284:     HRESULT hr;
0285: 
0286:     // Initialize all the colors here
0287:     DICOLORSET dics;
0288:     ZeroMemory(&dics, sizeof(DICOLORSET));
0289:     dics.dwSize = sizeof(DICOLORSET);
0290: 
0291:     // Fill in all the params
0292:     DICONFIGUREDEVICESPARAMS dicdp;
0293:     ZeroMemory(&dicdp, sizeof(dicdp));
0294:     dicdp.dwSize = sizeof(dicdp);
0295:     dicdp.dwcFormats     = 1;
0296:     dicdp.lprgFormats    = &m_diaf;
0297:     dicdp.hwnd           = hWnd;
0298:     dicdp.lpUnkDDSTarget = pSurface;
0299: 
0300:     if( m_strUserName )
0301:     {
0302:         dicdp.dwcUsers       = 1;
0303:         dicdp.lptszUserNames = m_strUserName;
0304:     }
0305: 
0306:     // Unacquire the devices so that mouse doesn't control the game while in control panel
0307:     UnacquireDevices();
0308: 
0309:     hr = m_pDI->ConfigureDevices( (LPDICONFIGUREDEVICESCALLBACK)ConfigureDevicesCB, 
0310:                                   &dicdp, dwFlags, pvCBParam );
0311:     if( FAILED(hr) )
0312:         return hr;
0313: 
0314:     if( dwFlags & DICD_EDIT )
0315:     {
0316:         // Re-set up the devices
0317:         hr = SetActionFormat( m_diaf, TRUE );
0318:         if( FAILED(hr) )
0319:             return hr;
0320:     }
0321: 
0322:     return S_OK;
0323: }
0324: 
0325: 
0326: 
0327: //-----------------------------------------------------------------------------
0328: // Name: UnacquireDevices()
0329: // Desc: Unacquire all devices in the member list
0330: //-----------------------------------------------------------------------------
0331: VOID CInputDeviceManager::UnacquireDevices()
0332: {
0333:     for( DWORD i=0; i<m_dwNumDevices; i++ )
0334:         m_pDevices[i].pdidDevice->Unacquire();
0335: }
0336: 
0337: 
0338: 
0339: 
0340: //-----------------------------------------------------------------------------
0341: // Name: SetFocus()
0342: // Desc: Sets the DirectInput focus to a new HWND
0343: //-----------------------------------------------------------------------------
0344: VOID CInputDeviceManager::SetFocus( HWND hWnd ) 
0345: {
0346:     m_hWnd = hWnd;
0347: 
0348:     UnacquireDevices();
0349: 
0350:     for( DWORD i=0; i<m_dwNumDevices; i++ )
0351:     {
0352:         // Set the device's coop level
0353:         m_pDevices[i].pdidDevice->SetCooperativeLevel( m_hWnd, 
0354:                                         DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
0355:     }
0356: }
0357: 
0358: 
0359: