// InputBuffer.cpp : Implementation of cInputBuffer #include "stdafx.h" #include "DecalInput.h" #include "InputBuffer.h" #include "InputService.h" ///////////////////////////////////////////////////////////////////////////// // cInputBuffer void cInputBuffer::FinalRelease() { if( cInputService::g_p != NULL && cInputService::g_p->m_pActive == this ) Stop(); } bool cInputBuffer::checkState() { if( cInputService::g_p == NULL || cInputService::g_p->m_pActive == this ) { // There must be an input service and it must be inactive _ASSERT( FALSE ); return false; } return true; } HRESULT cInputBuffer::addItem( BSTR strInit, IInputAction **ppAction ) { USES_CONVERSION; LPTSTR szType = OLE2T( strInit ); size_t iInitData = ::_tcscspn( szType, _T( ":" ) ); if( iInitData == -1 ) return E_INVALIDARG; szType[ iInitData ] = _T( '\0' ); LPCTSTR szInitData = szType + iInitData + 1; ::_tcslwr( szType ); for( cInputService::cActionTypeList::iterator i = cInputService::g_p->m_actiontypes.begin(); i != cInputService::g_p->m_actiontypes.end(); ++ i ) { if( ::_tcscmp( szType, i->szAction ) == 0 ) break; } if( i == cInputService::g_p->m_actiontypes.end() ) return E_INVALIDARG; // Get the configuration object for this inputaction static _bstr_t _strActions( _T( "InputActions" ) ); CComPtr< IDecalEnum > pInputEnum; if( cInputService::g_p->m_pDecal->get_Configuration( _strActions, i->m_clsid, &pInputEnum ) != S_OK ) // What used to be there is gone return E_FAIL; HRESULT hRes = pInputEnum->CreateInstance( __uuidof( IInputAction ), reinterpret_cast< void ** >( ppAction ) ); if( FAILED( hRes ) ) // Could not create our object return hRes; return ( *ppAction )->Initialize( this, _bstr_t( szInitData ) ); } void cInputBuffer::runActions() { m_bWaiting = false; while( m_play != m_entries.end() ) { HRESULT hRes; switch( m_play->m_eType ) { case eExecute: hRes = m_play->m_pAction->Execute(); break; case ePush: m_playstack.push( &*m_play ); hRes = m_play->m_pAction->Push(); break; case ePop: m_playstack.pop(); hRes = m_play->m_pAction->Pop(); break; default: hRes = E_FAIL; } if( FAILED( hRes ) ) { _ASSERT( FALSE ); Stop(); return; } if( m_bWaiting || cInputService::g_p->m_pActive != this ) // If we're now waiting, return from our actions and continue return; ++ m_play; } // We're done here Stop(); } STDMETHODIMP cInputBuffer::get_Tag(VARIANT *pVal) { if( pVal == NULL ) { _ASSERT( FALSE ); return E_POINTER; } return ::VariantCopy( pVal, &m_tag ); } STDMETHODIMP cInputBuffer::put_Tag(VARIANT newVal) { m_tag = newVal; return S_OK; } STDMETHODIMP cInputBuffer::Add(BSTR strCommand) { if( !checkState() ) return E_FAIL; cEntry e; HRESULT hRes = addItem( strCommand, &e.m_pAction ); if( FAILED( hRes ) ) return hRes; e.m_eType = eExecute; m_entries.push_back( e ); return S_OK; } STDMETHODIMP cInputBuffer::Push(BSTR Command) { if( !checkState() ) return E_FAIL; cEntry e; HRESULT hRes = addItem( Command, &e.m_pAction ); if( FAILED( hRes ) ) return hRes; VARIANT_BOOL bStackable; e.m_pAction->get_Stackable( &bStackable ); if( !bStackable ) return E_INVALIDARG; e.m_eType = ePush; m_entries.push_back( e ); m_insertstack.push( &m_entries.back() ); return S_OK; } STDMETHODIMP cInputBuffer::Pop() { if( !checkState() ) return E_FAIL; if( m_insertstack.size() == 0 ) { _ASSERT( FALSE ); return E_FAIL; } cEntry e; e.m_eType = ePop; e.m_pAction = m_insertstack.top()->m_pAction; m_entries.push_back( e ); m_insertstack.pop(); return S_OK; } STDMETHODIMP cInputBuffer::get_CanRun(VARIANT_BOOL *pVal) { if( pVal == NULL ) { _ASSERT( FALSE ); return E_POINTER; } if( cInputService::g_p == NULL ) { // There must be an input service _ASSERT( FALSE ); return E_FAIL; } *pVal = ( cInputService::g_p->m_pActive == NULL ) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP cInputBuffer::Run() { if( cInputService::g_p == NULL || cInputService::g_p->m_pActive != NULL ) { // There must be an input service and it must be inactive _ASSERT( FALSE ); return E_FAIL; } // First check if the insert stack is incomplete while( m_insertstack.size() > 0 ) Pop(); // Reset the cursors while( m_playstack.size() > 0 ) m_playstack.pop(); m_play = m_entries.begin(); cInputService::g_p->m_pActive = this; // Reset the actions for( cEntryList::iterator i = m_entries.begin(); i != m_entries.end(); ++ i ) i->m_pAction->Reset(); Fire_Begin( this ); // Lock down the user input ::BlockInput( TRUE ); runActions(); return S_OK; } STDMETHODIMP cInputBuffer::Stop() { if( cInputService::g_p == NULL ) { // There must be an input service _ASSERT( FALSE ); return E_FAIL; } if( cInputService::g_p->m_pActive == NULL ) return S_FALSE; if( cInputService::g_p->m_pActive != this ) return E_FAIL; // Stop immediately, flush all entries in the stack while( m_playstack.size() > 0 ) { m_playstack.top()->m_pAction->Pop(); m_playstack.pop(); } cInputService::g_p->m_pActive = NULL; ::BlockInput( FALSE ); Fire_End( this ); return S_OK; } STDMETHODIMP cInputBuffer::Delay(long Time, VARIANT_BOOL Advance) { if( Advance ) ++ m_play; m_bWaiting = true; m_nUntilTime = ::timeGetTime() + Time; return S_OK; } STDMETHODIMP cInputBuffer::FireEvent(long nEventID, VARIANT vParam) { Fire_Event( this, nEventID, vParam ); return S_OK; } STDMETHODIMP cInputBuffer::MoveMouse(long X, long Y) { if( cInputService::g_p == NULL ) { // There must be an input service _ASSERT( FALSE ); return E_FAIL; } // These are already traslated to screen coords cInputService *pis = cInputService::g_p; if( pis->m_eWindows == cInputService::eWindows98NoMemLocs ) return E_FAIL; // Otherwise, get the window proc and send some info to move the mouse WNDPROC wndProc = reinterpret_cast< WNDPROC >( ::GetWindowLong( pis->m_hWndHook, GWL_WNDPROC ) ); POINT ptScreen = { X, Y }; ::ClientToScreen( pis->m_hWndHook, &ptScreen ); ::SetCursorPos( ptScreen.x, ptScreen.y ); POINTS pts = { X, Y }; wndProc( pis->m_hWndHook, WM_MOUSEMOVE, 0, *reinterpret_cast< DWORD * >( &pts ) ); // Special additional functionality for win98 if( pis->m_eWindows == cInputService::eWindows98WithMemLocs ) { pis->m_pnOffset1[ 0 ] = X; pis->m_pnOffset1[ 1 ] = Y; pis->m_pnOffset2[ 0 ] = X; pis->m_pnOffset2[ 1 ] = Y; pis->m_pnOffset2[ 2 ] = X; pis->m_pnOffset2[ 3 ] = Y; pis->m_pnOffset2[ 4 ] = X; pis->m_pnOffset2[ 5 ] = Y; // Delay a couple frames to be sure it's taken effect Delay( 100, VARIANT_TRUE ); } return S_OK; } STDMETHODIMP cInputBuffer::get_Service(IInputService **pVal) { if( pVal == NULL ) { _ASSERT( FALSE ); return E_POINTER; } if( cInputService::g_p == NULL ) { // There must be an input service _ASSERT( FALSE ); return E_FAIL; } return static_cast< IInputService * >( cInputService::g_p )->QueryInterface( pVal ); }