Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
d1442e3747
1382 changed files with 170725 additions and 0 deletions
351
Native/DecalInput/InputBuffer.cpp
Normal file
351
Native/DecalInput/InputBuffer.cpp
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
// 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 );
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue