Skip to content

Commit

Permalink
Merge pull request #1005 from maximegmd/feature/fix-cursor
Browse files Browse the repository at this point in the history
Fix ImGui spam of ShowCursor/HideCursor
  • Loading branch information
maximegmd authored Mar 1, 2025
2 parents c3fd1db + 16557fe commit 12873ce
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 94 deletions.
25 changes: 4 additions & 21 deletions src/d3d12/D3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,11 @@

void D3D12::SetTrapInputInImGui(const bool acEnabled)
{
// Must have an out-condition to this otherwise infinite loop
static int constexpr maxCursorDepth = 8;
int showCursorTries = 0;
int showCursorState;
if (acEnabled)
do
{
showCursorState = ShowCursor(TRUE);
} while (showCursorState < 0 && showCursorTries++ < maxCursorDepth);
else
do
{
showCursorState = ShowCursor(FALSE);
} while (showCursorState >= 0 && showCursorTries++ < maxCursorDepth);

// Turn off software cursor
if (showCursorTries < maxCursorDepth || acEnabled == false)
ImGui::GetIO().MouseDrawCursor = false;
static const RED4ext::CName cReason = "ImGui";
static RED4ext::UniversalRelocFunc<void (*)(RED4ext::CBaseEngine::UnkD0* apThis, RED4ext::CName aReason, bool aShow)>
forceCursor(CyberEngineTweaks::AddressHashes::InputSystemWin32Base_ForceCursor);

// Enable software cursor as fallback if necessary
else
ImGui::GetIO().MouseDrawCursor = acEnabled;
forceCursor(RED4ext::CGameEngine::Get()->unkD0, cReason, acEnabled);

m_trapInputInImGui = acEnabled;
}
Expand Down
4 changes: 3 additions & 1 deletion src/d3d12/D3D12_Functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ bool D3D12::Initialize()

D3D12_DESCRIPTOR_HEAP_DESC srvdesc = {};
srvdesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvdesc.NumDescriptors = buffersCounts;
srvdesc.NumDescriptors = 200; // Same number as is used in scripting/Texture
srvdesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
if (FAILED(m_pd3d12Device->CreateDescriptorHeap(&srvdesc, IID_PPV_ARGS(&m_pd3dSrvDescHeap))))
{
Expand Down Expand Up @@ -313,6 +313,8 @@ bool D3D12::InitializeImGui(size_t aBuffersCounts)
ImGui::GetStyle() = m_styleReference;
ImGui::GetStyle().ScaleAllSizes(scaleFromReference);

ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; // Do not modify cursor from ImGui backend

if (!ImGui_ImplWin32_Init(m_window.GetWindow()))
{
Log::Error("D3D12::InitializeImGui() - ImGui_ImplWin32_Init call failed!");
Expand Down
14 changes: 2 additions & 12 deletions src/d3d12/D3D12_Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,6 @@

#include <VersionHelpers.h>

void* ApplyHook(void** vtable, size_t index, void* target)
{
DWORD oldProtect;
VirtualProtect(vtable + index, 8, PAGE_EXECUTE_READWRITE, &oldProtect);
const auto ret = vtable[index];
vtable[index] = target;
VirtualProtect(vtable + index, 8, oldProtect, nullptr);

return ret;
}

void* D3D12::CRenderNode_Present_InternalPresent(int32_t* apDeviceIndex, uint8_t aSomeSync, UINT aSyncInterval)
{
auto& d3d12 = CET::Get().GetD3D12();
Expand Down Expand Up @@ -80,10 +69,11 @@ ID3D12Device* D3D12::GetDevice() const
std::tuple<D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE> D3D12::CreateTextureDescriptor()
{
const UINT handle_increment = m_pd3d12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
static std::atomic descriptor_index = 1;
static std::atomic descriptor_index = 1; // 0 is used for ImGui font texture

const auto index = descriptor_index++;

// We allocate 200 descriptors
if (index >= 200)
return {{}, {}};

Expand Down
51 changes: 2 additions & 49 deletions src/overlay/Overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ void Overlay::PostInitialize()

auto& d3d12 = CET::Get().GetD3D12();
d3d12.DelayedSetTrapInputInImGui(true);
ClipToCenter(RED4ext::CGameEngine::Get()->unkD0);
}
else
{
Expand Down Expand Up @@ -194,8 +193,6 @@ void Overlay::Update()

auto& d3d12 = CET::Get().GetD3D12();
d3d12.DelayedSetTrapInputInImGui(m_enabled);
auto* pEngine = RED4ext::CGameEngine::Get();
ClipToCenter(pEngine->unkD0);
m_toggled = false;
}
}
Expand All @@ -211,9 +208,9 @@ void Overlay::Update()
ImGui::RenderNotifications();

//——————————————————————————————— WARNING ———————————————————————————————
// Argument MUST match the amount of ImGui::PushStyleVar() calls
// Argument MUST match the amount of ImGui::PushStyleVar() calls
ImGui::PopStyleVar(2);
// Argument MUST match the amount of ImGui::PushStyleColor() calls
// Argument MUST match the amount of ImGui::PushStyleColor() calls
ImGui::PopStyleColor(1);

if (!m_enabled)
Expand All @@ -240,48 +237,6 @@ bool Overlay::IsInitialized() const noexcept
return m_initialized;
}

BOOL Overlay::ClipToCenter(RED4ext::CGameEngine::UnkD0* apThis)
{
const auto wnd = static_cast<HWND>(apThis->hWnd);
const HWND foreground = GetForegroundWindow();

if (wnd == foreground && apThis->unk174 && !apThis->unk164 && !CET::Get().GetOverlay().IsEnabled())
{
RECT rect;
GetClientRect(wnd, &rect);
ClientToScreen(wnd, reinterpret_cast<POINT*>(&rect.left));
ClientToScreen(wnd, reinterpret_cast<POINT*>(&rect.right));
rect.left = (rect.left + rect.right) / 2;
rect.right = rect.left;
rect.bottom = (rect.bottom + rect.top) / 2;
rect.top = rect.bottom;
apThis->isClipped = true;
ShowCursor(FALSE);
return ClipCursor(&rect);
}

if (apThis->isClipped)
{
apThis->isClipped = false;
return ClipCursor(nullptr);
}

return 1;
}

void Overlay::Hook()
{
const RED4ext::UniversalRelocPtr<uint8_t> func(CyberEngineTweaks::AddressHashes::CWinapi_ClipToCenter);

if (auto* pLocation = func.GetAddr())
{
if (MH_CreateHook(pLocation, reinterpret_cast<void*>(&ClipToCenter), reinterpret_cast<void**>(&m_realClipToCenter)) != MH_OK || MH_EnableHook(pLocation) != MH_OK)
Log::Error("Could not hook mouse clip function!");
else
Log::Info("Hook mouse clip function!");
}
}

Overlay::Overlay(VKBindings& aBindings, Options& aOptions, PersistentState& aPersistentState, LuaVM& aVm)
: m_console(aOptions, aPersistentState, aVm)
, m_bindings(aBindings, aVm)
Expand All @@ -291,8 +246,6 @@ Overlay::Overlay(VKBindings& aBindings, Options& aOptions, PersistentState& aPer
, m_persistentState(aPersistentState)
, m_vm(aVm)
{
Hook();

GameMainThread::Get().AddBaseInitializationTask(
[this]
{
Expand Down
9 changes: 0 additions & 9 deletions src/overlay/Overlay.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
#include "widgets/GameLog.h"
#include "widgets/ImGuiDebug.h"

using TClipToCenter = HWND(RED4ext::CGameEngine::UnkD0*);

struct Overlay
{
Overlay(VKBindings& aBindings, Options& aOptions, PersistentState& aPersistentState, LuaVM& aVm);
Expand All @@ -27,11 +25,6 @@ struct Overlay

void Update();

protected:
void Hook();

static BOOL ClipToCenter(RED4ext::CGameEngine::UnkD0* apThis);

private:
void DrawToolbar();

Expand All @@ -42,8 +35,6 @@ struct Overlay
GameLog m_gameLog;
ImGuiDebug m_imguiDebug;

TClipToCenter* m_realClipToCenter{nullptr};

std::atomic_bool m_enabled{false};
std::atomic_bool m_toggled{false};
bool m_initialized{false};
Expand Down
4 changes: 2 additions & 2 deletions src/reverse/Addresses.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ constexpr uint32_t CScript_TweakDBLoad = 3602585178UL; // game::data::
constexpr uint32_t CShutdownState_OnTick = 4069332669UL; // red::GameAppShutdownState::OnTick
#pragma endregion

#pragma region CWinapi
constexpr uint32_t CWinapi_ClipToCenter = 261693736UL; // input::InputSystemWin32Base::Update
#pragma region InputSystemWin32Base
constexpr uint32_t InputSystemWin32Base_ForceCursor = 2130646213UL; // input::InputSystemWin32Base::ForceCursor
#pragma endregion

#pragma region gameIGameSystem
Expand Down

0 comments on commit 12873ce

Please sign in to comment.