From fb8ef4f37964adf3d5128ccd98bff136af75e9bb Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sun, 16 Jun 2024 20:32:57 +0200 Subject: [PATCH] InputSystem: add reverse engineered 'InputStackSystem' class Reverse engineered as part of reverse engineering class 'CInput' which is for a future commit. Singleton pointer has been exposed to SDK through the pointer 'g_pInputStackSystem'. --- src/core/init.cpp | 2 + src/inputsystem/CMakeLists.txt | 3 + src/inputsystem/inputstacksystem.cpp | 239 +++++++++++++++++++++++++++ src/inputsystem/inputstacksystem.h | 80 +++++++++ 4 files changed, 324 insertions(+) create mode 100644 src/inputsystem/inputstacksystem.cpp create mode 100644 src/inputsystem/inputstacksystem.h diff --git a/src/core/init.cpp b/src/core/init.cpp index 1c7fbb50..5d106a71 100644 --- a/src/core/init.cpp +++ b/src/core/init.cpp @@ -151,6 +151,7 @@ #ifndef DEDICATED #include "public/idebugoverlay.h" #include "inputsystem/inputsystem.h" +#include "inputsystem/inputstacksystem.h" #include "windows/id3dx.h" #endif // !DEDICATED @@ -682,6 +683,7 @@ void DetourRegister() // Register detour classes to be searched and hooked. #ifndef DEDICATED REGISTER(VInputSystem); + REGISTER(VInputStackSystem); REGISTER(VDXGI); #endif // !DEDICATED } diff --git a/src/inputsystem/CMakeLists.txt b/src/inputsystem/CMakeLists.txt index 5d6ea714..06473a64 100644 --- a/src/inputsystem/CMakeLists.txt +++ b/src/inputsystem/CMakeLists.txt @@ -4,11 +4,14 @@ add_module( "lib" "inputsystem" "vpc" ${FOLDER_CONTEXT} TRUE TRUE ) start_sources() add_sources( SOURCE_GROUP "Private" + "inputstacksystem.cpp" + "inputstacksystem.h" "inputsystem.cpp" "inputsystem.h" ) add_sources( SOURCE_GROUP "Public" + "${ENGINE_SOURCE_DIR}/public/inputsystem/iinputstacksystem.h" "${ENGINE_SOURCE_DIR}/public/inputsystem/iinputsystem.h" "${ENGINE_SOURCE_DIR}/public/inputsystem/AnalogCode.h" "${ENGINE_SOURCE_DIR}/public/inputsystem/ButtonCode.h" diff --git a/src/inputsystem/inputstacksystem.cpp b/src/inputsystem/inputstacksystem.cpp new file mode 100644 index 00000000..cbab340f --- /dev/null +++ b/src/inputsystem/inputstacksystem.cpp @@ -0,0 +1,239 @@ +//===== Copyright © 1996-2010, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// + +#include "inputsystem.h" +#include "inputstacksystem.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Allocates an input context, pushing it on top of the input stack, +// thereby giving it top priority +//----------------------------------------------------------------------------- +InputContextHandle_t CInputStackSystem::PushInputContext() +{ + InputContext_t *pContext = new InputContext_t; + pContext->m_bEnabled = true; + pContext->m_bCursorVisible = true; + pContext->m_bMouseCaptureEnabled = false; + pContext->m_hCursorIcon = g_pInputSystem->GetStandardCursor( INPUT_CURSOR_ARROW ); + m_ContextStack.Push( pContext ); + + UpdateCursorState(); + + return (InputContextHandle_t)pContext; +} + + +//----------------------------------------------------------------------------- +// Pops the top input context off the input stack, and destroys it. +//----------------------------------------------------------------------------- +void CInputStackSystem::PopInputContext( InputContextHandle_t hContext ) +{ + if ( m_ContextStack.Count() == 0 ) + return; + + InputContext_t *pContext = NULL; + m_ContextStack.Pop( pContext ); + delete pContext; + + UpdateCursorState(); +} + + +//----------------------------------------------------------------------------- +// Enables/disables an input context, allowing something lower on the +// stack to have control of input. Disabling an input context which +// owns mouse capture +//----------------------------------------------------------------------------- +void CInputStackSystem::EnableInputContext( InputContextHandle_t hContext, bool bEnable ) +{ + InputContext_t *pContext = ( InputContext_t* )hContext; + if ( !pContext ) + return; + + if ( pContext->m_bEnabled == bEnable ) + return; + + // Disabling an input context will deactivate mouse capture, if it's active + if ( !bEnable ) + { + SetMouseCapture( hContext, false ); + } + + pContext->m_bEnabled = bEnable; + + // Updates the cursor state since the stack changed + UpdateCursorState(); +} + + +//----------------------------------------------------------------------------- +// Allows a context to make the cursor visible; +// the topmost enabled context wins +//----------------------------------------------------------------------------- +void CInputStackSystem::SetCursorVisible( InputContextHandle_t hContext, bool bVisible ) +{ + InputContext_t *pContext = ( InputContext_t* )hContext; + if ( !pContext ) + return; + + if ( pContext->m_bCursorVisible == bVisible ) + return; + + pContext->m_bCursorVisible = bVisible; + + // Updates the cursor state since the stack changed + UpdateCursorState(); +} + + +//----------------------------------------------------------------------------- +// Allows a context to set the cursor icon; +// the topmost enabled context wins +//----------------------------------------------------------------------------- +void CInputStackSystem::SetCursorIcon( InputContextHandle_t hContext, InputCursorHandle_t hCursor ) +{ + InputContext_t *pContext = ( InputContext_t* )hContext; + if ( !pContext ) + return; + + if ( pContext->m_hCursorIcon == hCursor ) + return; + + pContext->m_hCursorIcon = hCursor; + + // Updates the cursor state since the stack changed + UpdateCursorState(); +} + + +//----------------------------------------------------------------------------- +// Allows a context to enable mouse capture. Disabling an input context +// deactivates mouse capture. Capture will occur if it happens on the +// topmost enabled context +//----------------------------------------------------------------------------- +void CInputStackSystem::SetMouseCapture( InputContextHandle_t hContext, bool bEnable ) +{ + InputContext_t *pContext = ( InputContext_t* )hContext; + if ( !pContext ) + return; + + if ( pContext->m_bMouseCaptureEnabled == bEnable ) + return; + + pContext->m_bMouseCaptureEnabled = bEnable; + + // Updates the cursor state since the stack changed + UpdateCursorState(); +} + + +//----------------------------------------------------------------------------- +// Allows a context to set the mouse position. It only has any effect if the +// specified context is the topmost enabled context +//----------------------------------------------------------------------------- +void CInputStackSystem::SetCursorPosition( InputContextHandle_t hContext, int x, int y ) +{ + if ( IsTopmostEnabledContext( hContext ) ) + { + g_pInputSystem->SetCursorPosition( x, y ); + } +} + + +//----------------------------------------------------------------------------- +// This this context the topmost enabled context? +//----------------------------------------------------------------------------- +bool CInputStackSystem::IsTopmostEnabledContext( InputContextHandle_t hContext ) const +{ + InputContext_t *pContext = ( InputContext_t* )hContext; + if ( !pContext ) + return false; + + int nCount = m_ContextStack.Count(); + for ( int i = nCount; --i >= 0; ) + { + InputContext_t *pStackContext = m_ContextStack[i]; + if ( !pStackContext->m_bEnabled ) + continue; + + return ( pStackContext == pContext ); + } + return false; +} + + +//----------------------------------------------------------------------------- +// Updates the cursor based on the current state of the input stack +//----------------------------------------------------------------------------- +void CInputStackSystem::UpdateCursorState() +{ + int nCount = m_ContextStack.Count(); + for ( int i = nCount; --i >= 0; ) + { + InputContext_t *pContext = m_ContextStack[i]; + if ( !pContext->m_bEnabled ) + continue; + + if ( !pContext->m_bCursorVisible ) + { + g_pInputSystem->SetCursorIcon( INPUT_CURSOR_HANDLE_INVALID ); + } + else + { + g_pInputSystem->SetCursorIcon( pContext->m_hCursorIcon ); + } + + if ( pContext->m_bMouseCaptureEnabled ) + { + g_pInputSystem->EnableMouseCapture( g_pInputSystem->GetAttachedWindow() ); + } + else + { + g_pInputSystem->DisableMouseCapture( ); + } + break; + } +} + +//----------------------------------------------------------------------------- +// Get dependencies +//----------------------------------------------------------------------------- +//static AppSystemInfo_t s_Dependencies[] = +//{ +// { "inputsystem" DLL_EXT_STRING, INPUTSYSTEM_INTERFACE_VERSION }, +// { NULL, NULL } +//}; +// +//const AppSystemInfo_t* CInputStackSystem::GetDependencies() +//{ +// return s_Dependencies; +//} + + +//----------------------------------------------------------------------------- +// Shutdown +//----------------------------------------------------------------------------- +//void CInputStackSystem::Shutdown() +//{ +// // Delete any leaked contexts +// while( m_ContextStack.Count() ) +// { +// InputContext_t *pContext = NULL; +// m_ContextStack.Pop( pContext ); +// delete pContext; +// } +// +// BaseClass::Shutdown(); +//} + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +CInputStackSystem* g_pInputStackSystem = nullptr; diff --git a/src/inputsystem/inputstacksystem.h b/src/inputsystem/inputstacksystem.h new file mode 100644 index 00000000..8593a703 --- /dev/null +++ b/src/inputsystem/inputstacksystem.h @@ -0,0 +1,80 @@ +//===== Copyright © 1996-2010, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +//===========================================================================// +#ifndef INPUTCLIENTSTACK_H +#define INPUTCLIENTSTACK_H +#ifdef _WIN32 +#pragma once +#endif +#include "tier1/utlstack.h" +#include "inputsystem/iinputstacksystem.h" + +//----------------------------------------------------------------------------- +// An input context +//----------------------------------------------------------------------------- +struct InputContext_t +{ + InputCursorHandle_t m_hCursorIcon; + bool m_bEnabled; + bool m_bCursorVisible; + bool m_bMouseCaptureEnabled; +}; + +//----------------------------------------------------------------------------- +// Stack system implementation +//----------------------------------------------------------------------------- +class CInputStackSystem : public CTier1AppSystem< IInputStackSystem > +{ + typedef CTier1AppSystem< IInputStackSystem > BaseClass; + + // Methods of IAppSystem + // NOTE: currently, the implementation in the game engine is used. If the + // vtable ever gets swapped with the implementation in the SDK, make sure + // to implement BaseClass::Shutdown() and uncomment the functions below !!! + // The implementation in this SDK is identical to that of the engine. +public: + //virtual const AppSystemInfo_t* GetDependencies(); + //virtual void Shutdown(); + + // Methods of IInputStackSystem +public: + virtual InputContextHandle_t PushInputContext(); + virtual void PopInputContext( InputContextHandle_t hContext ); + virtual void EnableInputContext( InputContextHandle_t hContext, bool bEnable ); + virtual void SetCursorVisible( InputContextHandle_t hContext, bool bVisible ); + virtual void SetCursorIcon( InputContextHandle_t hContext, InputCursorHandle_t hCursor ); + virtual void SetMouseCapture( InputContextHandle_t hContext, bool bEnable ); + virtual void SetCursorPosition( InputContextHandle_t hContext, int x, int y ); + virtual bool IsTopmostEnabledContext( InputContextHandle_t hContext ) const; + +private: + // Updates the cursor based on the current state of the input stack + void UpdateCursorState(); + + CUtlStack< InputContext_t* > m_ContextStack; +}; + +extern CInputStackSystem* g_pInputStackSystem; + +/////////////////////////////////////////////////////////////////////////////// +class VInputStackSystem : public IDetour +{ + virtual void GetAdr(void) const + { + LogVarAdr("g_InputStackSystem", g_pInputStackSystem); + } + virtual void GetFun(void) const { } + virtual void GetVar(void) const + { + g_pInputStackSystem = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F9 E8 ?? ?? ?? ?? 33 C9").OffsetSelf(0x120) + .FindPatternSelf("48 8D", CMemory::Direction::DOWN, 40).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + } + virtual void GetCon(void) const { } + virtual void Detour(const bool bAttach) const { }; +}; +/////////////////////////////////////////////////////////////////////////////// + + +#endif // INPUTCLIENTSTACK_H