Skip to content

Commit c8d9774

Browse files
authored
Merge pull request #979 from maximegmd/feature/fix-imgui-mouse
Fix ImGui mouse position when render resolution is different than window resolution
2 parents 960fa82 + 7aca66d commit c8d9774

File tree

1 file changed

+37
-17
lines changed

1 file changed

+37
-17
lines changed

src/imgui_impl/win32.cpp

+37-17
Original file line numberDiff line numberDiff line change
@@ -325,16 +325,39 @@ static void ImGui_ImplWin32_UpdateKeyModifiers()
325325
io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN));
326326
}
327327

328+
// CET: Scale to make sure coords are correct (fixes issues in fullscreen).
329+
static ImVec2 CET_GetScaleFactor()
330+
{
331+
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
332+
ImGuiIO& io = ImGui::GetIO();
333+
IM_ASSERT(bd->hWnd != 0);
334+
335+
if (io.DisplaySize.x == 0.0f || io.DisplaySize.y == 0.0f)
336+
return {-1.0f, -1.0f};
337+
338+
RECT clientRect;
339+
::GetClientRect(bd->hWnd, &clientRect);
340+
return {io.DisplaySize.x / (clientRect.right - clientRect.left), io.DisplaySize.y / (clientRect.bottom - clientRect.top)};
341+
}
342+
328343
// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
329344
// Because of that, it is a little more complicated than your typical single-viewport binding code!
330-
static void ImGui_ImplWin32_UpdateMouseData(SIZE aOutSize)
345+
static void ImGui_ImplWin32_UpdateMouseData()
331346
{
332347
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
333348
ImGuiIO& io = ImGui::GetIO();
334349
IM_ASSERT(bd->hWnd != 0);
335350

336351
POINT mouse_screen_pos;
337352
bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0;
353+
354+
// CET: Get and verify scale factor. If any scalar in the scale factor is <= 0, apply -FLT_MAX as mouse position event. Otherwise, process normally.
355+
const auto scale = CET_GetScaleFactor();
356+
if (scale.x <= 0.0f || scale.y <= 0.0f)
357+
{
358+
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
359+
return;
360+
}
338361

339362
HWND focused_window = ::GetForegroundWindow();
340363
const bool is_app_focused =
@@ -345,7 +368,7 @@ static void ImGui_ImplWin32_UpdateMouseData(SIZE aOutSize)
345368
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
346369
if (io.WantSetMousePos)
347370
{
348-
POINT pos = {(int)io.MousePos.x, (int)io.MousePos.y};
371+
POINT pos = {static_cast<int>(io.MousePos.x / scale.x), static_cast<int>(io.MousePos.y / scale.y)};
349372
if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
350373
::ClientToScreen(focused_window, &pos);
351374
::SetCursorPos(pos.x, pos.y);
@@ -363,17 +386,7 @@ static void ImGui_ImplWin32_UpdateMouseData(SIZE aOutSize)
363386
POINT mouse_pos = mouse_screen_pos;
364387
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
365388
::ScreenToClient(bd->hWnd, &mouse_pos);
366-
367-
static float xScale = 1.0;
368-
static float yScale = 1.0;
369-
if(aOutSize.cx && aOutSize.cy)
370-
{
371-
RECT clientRect;
372-
::GetClientRect(bd->hWnd, &clientRect);
373-
xScale = static_cast<float>(aOutSize.cx) / (clientRect.right - clientRect.left);
374-
yScale = static_cast<float>(aOutSize.cy) / (clientRect.bottom - clientRect.top);
375-
}
376-
io.AddMousePosEvent((float)mouse_pos.x * xScale, (float)mouse_pos.y * yScale);
389+
io.AddMousePosEvent((float)mouse_pos.x * scale.x, (float)mouse_pos.y * scale.y);
377390
}
378391
}
379392

@@ -494,8 +507,7 @@ void ImGui_ImplWin32_NewFrame(SIZE aOutSize)
494507
ImGuiIO& io = ImGui::GetIO();
495508

496509
// Setup display size (every frame to accommodate for window resizing)
497-
// RECT rect = {0, 0, 0, 0};
498-
// ::GetClientRect(bd->hWnd, &rect);
510+
// CET: Use size provided by the game to match DLSS and similar.
499511
io.DisplaySize = ImVec2(static_cast<float>(aOutSize.cx), static_cast<float>(aOutSize.cy));
500512
if (bd->WantUpdateMonitors)
501513
ImGui_ImplWin32_UpdateMonitors();
@@ -507,7 +519,7 @@ void ImGui_ImplWin32_NewFrame(SIZE aOutSize)
507519
bd->Time = current_time;
508520

509521
// Update OS mouse position
510-
ImGui_ImplWin32_UpdateMouseData(aOutSize);
522+
ImGui_ImplWin32_UpdateMouseData();
511523

512524
// Process workarounds for known Windows key handling issues
513525
ImGui_ImplWin32_ProcessKeyEventsWorkarounds();
@@ -702,6 +714,14 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
702714
case WM_MOUSEMOVE:
703715
case WM_NCMOUSEMOVE:
704716
{
717+
// CET: Get and verify scale factor. If any scalar in the scale factor is <= 0, apply -FLT_MAX as mouse position event. Otherwise, process normally.
718+
const auto scale = CET_GetScaleFactor();
719+
if (scale.x <= 0.0f || scale.y <= 0.0f)
720+
{
721+
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
722+
return 0;
723+
}
724+
705725
// We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
706726
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo();
707727
const int area = (msg == WM_MOUSEMOVE) ? 1 : 2;
@@ -722,7 +742,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
722742
if (msg == WM_NCMOUSEMOVE && !want_absolute_pos) // WM_NCMOUSEMOVE are absolute coordinates.
723743
::ScreenToClient(hwnd, &mouse_pos);
724744
io.AddMouseSourceEvent(mouse_source);
725-
io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
745+
io.AddMousePosEvent((float)mouse_pos.x * scale.x, (float)mouse_pos.y * scale.y);
726746
return 0;
727747
}
728748
case WM_MOUSELEAVE:

0 commit comments

Comments
 (0)