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
408
Native/DecalInput/InputService.cpp
Normal file
408
Native/DecalInput/InputService.cpp
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
// InputService.cpp : Implementation of cInputService
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DecalInput.h"
|
||||
#include "InputService.h"
|
||||
|
||||
#include "Timer.h"
|
||||
#include "Hotkey.h"
|
||||
#include "WinMsgHook.h"
|
||||
#include "InputBuffer.h"
|
||||
|
||||
using cInputService::cCharNames;
|
||||
|
||||
static cCharNames _charnames[] = {
|
||||
{ _T( "BACKSPACE" ), VK_BACK },
|
||||
{ _T( "BS" ), VK_BACK },
|
||||
{ _T( "BKSP" ), VK_BACK },
|
||||
{ _T( "CAPSLOCK" ), VK_CAPITAL },
|
||||
{ _T( "DELETE" ), VK_DELETE },
|
||||
{ _T( "DEL" ), VK_DELETE },
|
||||
{ _T( "DOWN" ), VK_DOWN },
|
||||
{ _T( "END" ), VK_END },
|
||||
{ _T( "ENTER" ), VK_RETURN },
|
||||
{ _T( "ESC" ), VK_ESCAPE },
|
||||
{ _T( "HELP" ), VK_HELP },
|
||||
{ _T( "HOME" ), VK_HOME },
|
||||
{ _T( "INS" ), VK_INSERT },
|
||||
{ _T( "INSERT" ), VK_INSERT },
|
||||
{ _T( "LEFT" ), VK_LEFT },
|
||||
{ _T( "NUMLOCK" ), VK_NUMLOCK },
|
||||
{ _T( "PGDN" ), VK_NEXT },
|
||||
{ _T( "PGUP" ), VK_PRIOR },
|
||||
{ _T( "PRTSC" ), VK_SNAPSHOT },
|
||||
{ _T( "RIGHT" ), VK_RIGHT },
|
||||
{ _T( "SCROLLLOCK" ), VK_SCROLL },
|
||||
{ _T( "TAB" ), VK_TAB },
|
||||
{ _T( "UP" ), VK_UP },
|
||||
{ _T( "F1" ), VK_F1 },
|
||||
{ _T( "F2" ), VK_F2 },
|
||||
{ _T( "F3" ), VK_F3 },
|
||||
{ _T( "F4" ), VK_F4 },
|
||||
{ _T( "F5" ), VK_F5 },
|
||||
{ _T( "F6" ), VK_F6 },
|
||||
{ _T( "F7" ), VK_F7 },
|
||||
{ _T( "F8" ), VK_F8 },
|
||||
{ _T( "F9" ), VK_F9 },
|
||||
{ _T( "F10" ), VK_F10 },
|
||||
{ _T( "F11" ), VK_F11 },
|
||||
{ _T( "F12" ), VK_F12 },
|
||||
{ _T( "F13" ), VK_F13 },
|
||||
{ _T( "F14" ), VK_F14 },
|
||||
{ _T( "F15" ), VK_F15 },
|
||||
{ _T( "F16" ), VK_F16 },
|
||||
{ _T( "+" ), VK_ADD },
|
||||
{ _T( "SHIFT" ), VK_SHIFT },
|
||||
{ _T( "CTRL" ), VK_CONTROL },
|
||||
{ _T( "ALT" ), VK_MENU },
|
||||
{ _T( "LBUTTON" ), VK_LBUTTON },
|
||||
{ _T( "RBUTTON" ), VK_RBUTTON } },
|
||||
*_end_charnames = _charnames + ( sizeof(_charnames ) / sizeof( cCharNames ) );
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// cInputService
|
||||
|
||||
LRESULT cInputService::wndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
if( g_p == NULL || g_p->m_hWndHook != hWnd )
|
||||
{
|
||||
// We have no idea how to continue - this hook has been orphaned
|
||||
_ASSERT( FALSE );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( g_p->m_msghooks.size() > 0 )
|
||||
{
|
||||
// Fill out the message
|
||||
g_p->m_pMessage->loadMessage( hWnd, nMsg, wParam, lParam );
|
||||
|
||||
for( cWinMsgHookList::iterator i = g_p->m_msghooks.begin(); i != g_p->m_msghooks.end(); ++ i )
|
||||
{
|
||||
( *i )->Fire_Message( *i, g_p->m_pMessage );
|
||||
if( g_p->m_pMessage->m_bEaten )
|
||||
// This message was eaten, yummy
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: The hotkeys are not dispatched while an input buffer is running - tough luck
|
||||
if( nMsg == WM_KEYUP && g_p->m_pActive == NULL )
|
||||
{
|
||||
int nVK = static_cast< int >( wParam );
|
||||
|
||||
// Check if there's a matching hotkey
|
||||
for( cHotkeyList::iterator i = g_p->m_hotkeys.begin(); i != g_p->m_hotkeys.end(); ++ i )
|
||||
{
|
||||
if( ( *i )->m_nVK == nVK )
|
||||
{
|
||||
// Found a hotkey - fire the event and eat it
|
||||
( *i )->Fire_Hotkey( *i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return g_p->m_pfnHook( hWnd, nMsg, wParam, lParam );
|
||||
}
|
||||
|
||||
cInputService *cInputService::g_p = NULL;
|
||||
|
||||
HRESULT cInputService::onInitialize()
|
||||
{
|
||||
// ::DebugBreak();
|
||||
|
||||
USES_CONVERSION;
|
||||
|
||||
if( g_p == NULL )
|
||||
g_p = this;
|
||||
|
||||
// Create the message object
|
||||
CComObject< cWndMsg >::CreateInstance( &m_pMessage );
|
||||
m_pMessage->AddRef();
|
||||
|
||||
// Load the list of action types from the configuration data
|
||||
{
|
||||
static _bstr_t _strPrefix( _T( "Prefix" ) );
|
||||
|
||||
CComPtr< IDecalEnum > pActions;
|
||||
m_pDecal->get_Configuration( _bstr_t( _T( "InputActions" ) ), GUID_NULL, &pActions );
|
||||
while( pActions->Next() == S_OK )
|
||||
{
|
||||
VARIANT_BOOL bEnabled;
|
||||
HRESULT hRes = pActions->get_Enabled ( &bEnabled );
|
||||
_ASSERTE ( SUCCEEDED ( hRes ) );
|
||||
|
||||
if ( !bEnabled )
|
||||
continue;
|
||||
|
||||
cActionType at;
|
||||
pActions->get_ComClass( &at.m_clsid );
|
||||
|
||||
CComVariant v;
|
||||
if( FAILED( pActions->get_Property( _strPrefix, &v ) ) )
|
||||
continue;
|
||||
|
||||
::_tcscpy( at.szAction, OLE2T( v.bstrVal ) );
|
||||
::_tcslwr( at.szAction );
|
||||
m_actiontypes.push_back( at );
|
||||
}
|
||||
}
|
||||
|
||||
// Get the OS version
|
||||
OSVERSIONINFO ovi;
|
||||
ovi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
|
||||
::GetVersionEx( &ovi );
|
||||
|
||||
if( ovi.dwPlatformId == VER_PLATFORM_WIN32_NT )
|
||||
{
|
||||
m_eWindows = eWindowsNT;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// First check if there's version info in the registry
|
||||
RegKey key;
|
||||
key.Open( HKEY_LOCAL_MACHINE, _T( "Software\\Decal" ) );
|
||||
DWORD dwRegMajor, dwRegMinor;
|
||||
if( key.QueryDWORDValue( _T( "ACMajorVersion" ), dwRegMajor ) != ERROR_SUCCESS ||
|
||||
key.QueryDWORDValue( _T( "ACMinorVersion" ), dwRegMinor ) != ERROR_SUCCESS )
|
||||
{
|
||||
m_eWindows = eWindows98NoMemLocs;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
TCHAR szFilename[ MAX_PATH ];
|
||||
DWORD dwVerSize;
|
||||
|
||||
::GetModuleFileName( NULL, szFilename, MAX_PATH );
|
||||
if( ::GetFileVersionInfoSize( szFilename, &dwVerSize ) )
|
||||
{
|
||||
m_eWindows = eWindows98NoMemLocs;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BYTE *pbVersionInfo = reinterpret_cast< BYTE * >( ::_alloca( dwVerSize ) );
|
||||
|
||||
::GetFileVersionInfo( szFilename, 0, dwVerSize, pbVersionInfo );
|
||||
|
||||
VS_FIXEDFILEINFO *vffi;
|
||||
UINT nLength = sizeof( VS_FIXEDFILEINFO );
|
||||
if( ::VerQueryValue( pbVersionInfo, _T( "\\" ), reinterpret_cast< LPVOID * >( &vffi ), &nLength ) )
|
||||
{
|
||||
if( dwRegMajor == vffi->dwFileVersionMS && dwRegMinor == vffi->dwFileVersionLS )
|
||||
{
|
||||
DWORD dwOffset1, dwOffset2;
|
||||
if( key.QueryDWORDValue( _T( "MouseOffset1" ), dwOffset1 ) == ERROR_SUCCESS &&
|
||||
key.QueryDWORDValue( _T( "MouseOffset2" ), dwOffset2 ) == ERROR_SUCCESS )
|
||||
{
|
||||
m_eWindows = eWindows98WithMemLocs;
|
||||
m_pnOffset1 = reinterpret_cast< long * >( dwOffset1 );
|
||||
m_pnOffset2 = reinterpret_cast< long * >( dwOffset2 );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_eWindows = eWindows98NoMemLocs;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void cInputService::onTerminate()
|
||||
{
|
||||
// Create the message object
|
||||
m_pMessage->Release();
|
||||
m_pMessage = NULL;
|
||||
|
||||
if( g_p == this )
|
||||
g_p = NULL;
|
||||
}
|
||||
|
||||
cCharNames *cInputService::begin_chars()
|
||||
{
|
||||
return _charnames;
|
||||
}
|
||||
|
||||
cCharNames *cInputService::end_chars()
|
||||
{
|
||||
return _end_charnames;
|
||||
}
|
||||
|
||||
cCharNames *cInputService::charFromVK( int nVK )
|
||||
{
|
||||
for( cCharNames *i_chars = _charnames; i_chars != _end_charnames; ++ i_chars )
|
||||
{
|
||||
if( i_chars->m_nVKey == nVK )
|
||||
break;
|
||||
}
|
||||
|
||||
return i_chars;
|
||||
}
|
||||
|
||||
cCharNames *cInputService::charFromName( LPCTSTR szName, int nLength )
|
||||
{
|
||||
for( cCharNames *i_chars = _charnames; i_chars != _end_charnames; ++ i_chars )
|
||||
{
|
||||
if( ::strlen( i_chars->szName ) == nLength && std::equal( szName, szName + nLength, i_chars->szName ) )
|
||||
break;
|
||||
}
|
||||
|
||||
return i_chars;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::BeforePlugins()
|
||||
{
|
||||
// Hook the main plugin window
|
||||
long nWnd;
|
||||
m_pDecal->get_HWND( &nWnd );
|
||||
if( nWnd != 0 )
|
||||
{
|
||||
m_hWndHook = reinterpret_cast< HWND >( nWnd );
|
||||
m_pfnHook = reinterpret_cast< WNDPROC >( ::SetWindowLong( m_hWndHook, GWL_WNDPROC, reinterpret_cast< LONG >( wndProc ) ) );
|
||||
}
|
||||
|
||||
// Load the keymap
|
||||
RegKey key;
|
||||
if(key.Open( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00" ), KEY_READ ) != ERROR_SUCCESS)
|
||||
return E_FAIL;
|
||||
|
||||
TCHAR szFilename[ MAX_PATH ];
|
||||
TCHAR *pszInsert = szFilename;
|
||||
DWORD dwSize = MAX_PATH;
|
||||
key.QueryStringValue( _T("Path"), szFilename, &dwSize );
|
||||
pszInsert = &szFilename[dwSize-1];
|
||||
//pszInsert += dwSize;
|
||||
|
||||
::_tcscat( pszInsert, _T( "\\" ) );
|
||||
++ pszInsert;
|
||||
|
||||
dwSize = MAX_PATH - ( dwSize + 1 );
|
||||
key.QueryStringValue( _T( "CurrentInputMap" ), pszInsert, &dwSize );
|
||||
|
||||
// Looking good, open up the file and load the keys
|
||||
std::ifstream is( szFilename );
|
||||
|
||||
if( is.bad() )
|
||||
// Could not load the file
|
||||
return E_FAIL;
|
||||
|
||||
int nCount = 0;
|
||||
is >> nCount;
|
||||
for( ; nCount > 0; -- nCount )
|
||||
{
|
||||
int nInputType, nVK, nChording, nCommandType, nAnalogType;
|
||||
TCHAR szCommandName[ 64 ];
|
||||
|
||||
is >> nInputType >> nVK >> nChording >> szCommandName >> nCommandType >> nAnalogType;
|
||||
m_commands.insert( cCommandMap::value_type( szCommandName, static_cast< WORD >( nVK ) ) );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::AfterPlugins()
|
||||
{
|
||||
m_commands.clear();
|
||||
|
||||
if( m_hWndHook != NULL )
|
||||
{
|
||||
_ASSERTE( reinterpret_cast< LONG >( wndProc ) == ::GetWindowLong( m_hWndHook, GWL_WNDPROC ) );
|
||||
::SetWindowLong( m_hWndHook, GWL_WNDPROC, reinterpret_cast< LONG >( m_pfnHook ) );
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::get_Command(BSTR strCommandName, BSTR *pVal)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
|
||||
// First try to find the command in the list
|
||||
_bstr_t strCommand( strCommandName );
|
||||
cCommandMap::iterator i = m_commands.find( strCommand );
|
||||
|
||||
if( i == m_commands.end() )
|
||||
{
|
||||
*pVal = T2BSTR( _T( "" ) );
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
WORD nCommand = i->second;
|
||||
|
||||
// Scan to see if this command has a special name
|
||||
cCharNames *i_chars = charFromVK( nCommand );
|
||||
|
||||
if( i_chars != end_chars() )
|
||||
{
|
||||
TCHAR szFormat[ 12 ];
|
||||
::_stprintf( szFormat, _T( "{%s}" ), i_chars->szName );
|
||||
|
||||
*pVal = T2BSTR( szFormat );
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// Ok, we'll assume the char is printable
|
||||
TCHAR szString[ 2 ] = { nCommand, _T( '\0' ) };
|
||||
*pVal = T2BSTR( szString );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::Render2D()
|
||||
{
|
||||
long nTime = static_cast< long >( ::timeGetTime() );
|
||||
|
||||
cTimerList::iterator i = m_timers.begin();
|
||||
while( i != m_timers.end() )
|
||||
{
|
||||
cTimerList::iterator j = i++; // Make a copy of the iterator, increment it, then call the timeout.
|
||||
if( ( ( *j )->m_nStart + ( *j )->m_nInterval ) <= nTime )
|
||||
{
|
||||
( *j )->m_nStart = nTime;
|
||||
( *j )->Fire_Timeout( *j );
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if there's a delay paused
|
||||
if( m_pActive != NULL && m_pActive->m_bWaiting && m_pActive->m_nUntilTime <= nTime )
|
||||
// We've passed the timeout, continue processing actions
|
||||
m_pActive->runActions();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::ChangeHWND()
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::get_Decal(IDecal **pVal)
|
||||
{
|
||||
return m_pDecal->QueryInterface( pVal );
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::get_KeyByName(BSTR strName, long *pVal)
|
||||
{
|
||||
USES_CONVERSION;
|
||||
LPTSTR szName = OLE2T( strName );
|
||||
|
||||
cCharNames *i_c = charFromName( szName, ::_tcslen( szName ) );
|
||||
if( i_c == end_chars() )
|
||||
return E_INVALIDARG;
|
||||
|
||||
*pVal = i_c->m_nVKey;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP cInputService::get_CommandKey(BSTR strCommandName, long *pVal)
|
||||
{
|
||||
_bstr_t strCommand( strCommandName );
|
||||
cCommandMap::iterator i = m_commands.find( strCommand );
|
||||
|
||||
if( i == m_commands.end() )
|
||||
return E_FAIL;
|
||||
|
||||
*pVal = i->second;
|
||||
return S_OK;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue