//----------------------------------------------------------------------------- // File: MultiDI.h // // Desc: Multiple user DirectInput support using action mapping // // Copyright (C) Microsoft Corporation. All Rights Reserved. //----------------------------------------------------------------------------- #ifndef MULTIDI_H #define MULTIDI_H #ifndef DIRECTINPUT_VERSION #define DIRECTINPUT_VERSION 0x0800 #endif #include //----------------------------------------------------------------------------- // Miscellaneous helper functions //----------------------------------------------------------------------------- #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } HRESULT DXUtil_WriteStringRegKey( HKEY hKey, LPCTSTR strRegName, LPCTSTR strValue ); HRESULT DXUtil_ReadStringRegKeyCch( HKEY hKey, LPCTSTR strRegName, TCHAR* strDest, DWORD cchDest, LPCTSTR strDefault ); HRESULT DXUtil_ConvertGUIDToStringCch( const GUID* pGuidSrc, TCHAR* strDest, int cchDestChar ); HRESULT DXUtil_ConvertWideStringToGenericCch( TCHAR* tstrDestination, const WCHAR* wstrSource, int cchDestChar ); //----------------------------------------------------------------------------- // Name: DXUtil_Timer() // Desc: Performs timer opertations. Use the following commands: // TIMER_RESET - to reset the timer // TIMER_START - to start the timer // TIMER_STOP - to stop (or pause) the timer // TIMER_ADVANCE - to advance the timer by 0.1 seconds // TIMER_GETABSOLUTETIME - to get the absolute system time // TIMER_GETAPPTIME - to get the current time // TIMER_GETELAPSEDTIME - to get the time that elapsed between // TIMER_GETELAPSEDTIME calls //----------------------------------------------------------------------------- enum TIMER_COMMAND { TIMER_RESET, TIMER_START, TIMER_STOP, TIMER_ADVANCE, TIMER_GETABSOLUTETIME, TIMER_GETAPPTIME, TIMER_GETELAPSEDTIME }; FLOAT __stdcall DXUtil_Timer( TIMER_COMMAND command ); // E_DIUTILERR_PLAYERWITHOUTDEVICE is returned by the manager class after configuring // device, and there's a player that hasn't been assigned a device. #define E_DIUTILERR_PLAYERWITHOUTDEVICE MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,997) // E_DIUTILERR_DEVICESTAKEN is returned by the manager class when one player // on the machine has enough RECENT devices to prevent other players from // playing. This return code is needed because this sample attempts to give // all RECENT devices to that player. #define E_DIUTILERR_DEVICESTAKEN MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,998) // E_DIUTILERR_TOOMANYUSERS is returned by the manager class when the number of // players exceeds the number of devices present on the system. For example, // if you ask for 4 players on a machine that only has a keyboard and mouse, // you're 2 short of what you need. #define E_DIUTILERR_TOOMANYUSERS MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,999) //----------------------------------------------------------------------------- // Name: class CMultiplayerInputDeviceManager // Desc: Input device manager using DX8 action mapping //----------------------------------------------------------------------------- class CMultiplayerInputDeviceManager { public: struct PlayerInfo { DWORD dwPlayerIndex; // 0-based player number TCHAR strPlayerName[MAX_PATH]; // player name DWORD dwMaxDevices; // max number of elements in pDevices array DWORD dwNumDevices; // current number of elements in pDevices array BOOL bFoundDeviceForPlayer; // if a device has been found for this player yet }; struct DeviceInfo { LPDIRECTINPUTDEVICE8 pdidDevice; // dinput device pointer PlayerInfo* pPlayerInfo; // Player who owns this device BOOL bRelativeAxis; // TRUE if device is using relative axis BOOL bMapsPri1Actions; // TRUE if device maps pri 1 actions BOOL bMapsPri2Actions; // TRUE if device maps pri 2 actions LPVOID pParam; // app defined pointer assoicated with this device DIDEVICEINSTANCE didi; // device instance info }; typedef HRESULT (CALLBACK *LPDIMANAGERCALLBACK)(CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi, LPVOID); private: BOOL m_bCleanupCOM; HWND m_hWnd; LPDIRECTINPUT8 m_pDI; DIACTIONFORMAT* m_pdiaf; PlayerInfo** m_pUsers; DWORD m_dwNumUsers; DeviceInfo* m_pDeviceList; DWORD m_dwNumDevices; DWORD m_dwMaxDevices; LPDIMANAGERCALLBACK m_AddDeviceCallback; LPVOID m_AddDeviceCallbackParam; TCHAR* m_strKey; HKEY m_hKey; public: static BOOL CALLBACK StaticEnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwRemainingDevices, VOID* pContext ); static BOOL CALLBACK StaticBuildDeviceListCB( LPCDIDEVICEINSTANCE pdidi, VOID* pContext ); // Device control BOOL EnumDevice( const DIDEVICEINSTANCE* pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwDeviceRemaining ); BOOL BuildDeviceListCB( LPCDIDEVICEINSTANCE pdidi ); HRESULT AddDevice( DeviceInfo* pDeviceInfo, BOOL bForceReset ); HRESULT GetDevices( DeviceInfo** ppDeviceInfo, DWORD* pdwNumDevices ); HRESULT ConfigureDevices( HWND hWnd, IUnknown* pSurface, VOID* pCallback, DWORD dwFlags, LPVOID pvCBParam ); DWORD GetNumDevices() { return m_dwNumDevices; } VOID UnacquireDevices(); VOID SetFocus( HWND hWnd ); PlayerInfo* LookupPlayer( TCHAR* strPlayerName ); HRESULT SaveDeviceOwnershipKeys(); VOID DeleteDeviceOwnershipKeys(); HRESULT UpdateDeviceOwnership(); HRESULT AssignDevices(); HRESULT VerifyAssignment(); HRESULT AddAssignedDevices( BOOL bResetMappings ); HRESULT BuildDeviceList(); VOID CleanupDeviceList(); // Construction HRESULT SetActionFormat( DIACTIONFORMAT* pdiaf, BOOL bReenumerate, BOOL bResetOwnership, BOOL bResetMappings ); HRESULT Create( HWND hWnd, TCHAR* strUserNames[], DWORD dwNumUsers, DIACTIONFORMAT* pdiaf, LPDIMANAGERCALLBACK AddDeviceCallback, LPVOID pCallbackParam, BOOL bResetOwnership, BOOL bResetMappings ); CMultiplayerInputDeviceManager( TCHAR* strRegKey ); ~CMultiplayerInputDeviceManager(); VOID Cleanup(); }; #endif