From 75a9107ef820eb9bac1d61bacd4b14af2f9771d0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Oct 2024 16:45:15 +0100 Subject: [PATCH] Backends: Win32: rework to add ImGui_ImplWin32_WndProcHandlerEx() not using current context. (#8069, #6293, #5856, #586) --- backends/imgui_impl_win32.cpp | 90 +++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 97735ae33..4d5e5b83a 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -133,12 +133,16 @@ static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } +static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData(ImGuiIO& io) +{ + return (ImGui_ImplWin32_Data*)io.BackendPlatformUserData; +} // Functions -static void ImGui_ImplWin32_UpdateKeyboardCodePage() +static void ImGui_ImplWin32_UpdateKeyboardCodePage(ImGuiIO& io) { // Retrieve keyboard code page, required for handling of non-Unicode Windows. - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); HKL keyboard_layout = ::GetKeyboardLayout(0); LCID keyboard_lcid = MAKELCID(HIWORD(keyboard_layout), SORT_DEFAULT); if (::GetLocaleInfoA(keyboard_lcid, (LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE), (LPSTR)&bd->KeyboardCodePage, sizeof(bd->KeyboardCodePage)) == 0) @@ -168,7 +172,7 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) bd->TicksPerSecond = perf_frequency; bd->Time = perf_counter; bd->LastMouseCursor = ImGuiMouseCursor_COUNT; - ImGui_ImplWin32_UpdateKeyboardCodePage(); + ImGui_ImplWin32_UpdateKeyboardCodePage(io); // Set platform dependent data in viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); @@ -228,13 +232,11 @@ void ImGui_ImplWin32_Shutdown() IM_DELETE(bd); } -static bool ImGui_ImplWin32_UpdateMouseCursor() +static bool ImGui_ImplWin32_UpdateMouseCursor(ImGuiIO& io, ImGuiMouseCursor imgui_cursor) { - ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) return false; - ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) { // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor @@ -266,42 +268,39 @@ static bool IsVkDown(int vk) return (::GetKeyState(vk) & 0x8000) != 0; } -static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) +static void ImGui_ImplWin32_AddKeyEvent(ImGuiIO& io, ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) { - ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(key, down); io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code) IM_UNUSED(native_scancode); } -static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds() +static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds(ImGuiIO& io) { // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one. if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftShift, false, VK_LSHIFT); if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightShift, false, VK_RSHIFT); // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW). if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftSuper, false, VK_LWIN); if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightSuper, false, VK_RWIN); } -static void ImGui_ImplWin32_UpdateKeyModifiers() +static void ImGui_ImplWin32_UpdateKeyModifiers(ImGuiIO& io) { - ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL)); io.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT)); io.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU)); io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN)); } -static void ImGui_ImplWin32_UpdateMouseData() +static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io) { - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); IM_ASSERT(bd->hWnd != 0); HWND focused_window = ::GetForegroundWindow(); @@ -328,11 +327,10 @@ static void ImGui_ImplWin32_UpdateMouseData() } // Gamepad navigation mapping -static void ImGui_ImplWin32_UpdateGamepads() +static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) { #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. // return; @@ -381,7 +379,9 @@ static void ImGui_ImplWin32_UpdateGamepads() MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); #undef MAP_BUTTON #undef MAP_ANALOG -#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +#else // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + IM_UNUSED(io); +#endif } void ImGui_ImplWin32_NewFrame() @@ -402,21 +402,21 @@ void ImGui_ImplWin32_NewFrame() bd->Time = current_time; // Update OS mouse position - ImGui_ImplWin32_UpdateMouseData(); + ImGui_ImplWin32_UpdateMouseData(io); // Process workarounds for known Windows key handling issues - ImGui_ImplWin32_ProcessKeyEventsWorkarounds(); + ImGui_ImplWin32_ProcessKeyEventsWorkarounds(io); // Update OS mouse cursor with the cursor requested by imgui ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); if (bd->LastMouseCursor != mouse_cursor) { bd->LastMouseCursor = mouse_cursor; - ImGui_ImplWin32_UpdateMouseCursor(); + ImGui_ImplWin32_UpdateMouseCursor(io, mouse_cursor); } // Update game controllers (if enabled and available) - ImGui_ImplWin32_UpdateGamepads(); + ImGui_ImplWin32_UpdateGamepads(io); } // Map VK_xxx to ImGuiKey_xxx. @@ -581,18 +581,24 @@ static ImGuiMouseSource ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo() // PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. // PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. -// Copy this line into your .cpp file to forward declare the function: -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +// Copy either line into your .cpp file to forward declare the function: +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Use ImGui::GetCurrentContext() +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io); // Doesn't use ImGui::GetCurrentContext() IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). // We silently allow both context or just only backend data to be nullptr. - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); - if (bd == nullptr) + if (ImGui::GetCurrentContext() == NULL) return 0; - ImGuiIO& io = ImGui::GetIO(); + return ImGui_ImplWin32_WndProcHandlerEx(hwnd, msg, wParam, lParam, ImGui::GetIO()); +} +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io) +{ + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); + if (bd == NULL) + return 0; switch (msg) { case WM_MOUSEMOVE: @@ -692,7 +698,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA if (wParam < 256) { // Submit modifiers - ImGui_ImplWin32_UpdateKeyModifiers(); + ImGui_ImplWin32_UpdateKeyModifiers(io); // Obtain virtual key code and convert to ImGuiKey const ImGuiKey key = ImGui_ImplWin32_KeyEventToImGuiKey(wParam, lParam); @@ -701,28 +707,28 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA // Special behavior for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit the key down event. if (key == ImGuiKey_PrintScreen && !is_key_down) - ImGui_ImplWin32_AddKeyEvent(key, true, vk, scancode); + ImGui_ImplWin32_AddKeyEvent(io, key, true, vk, scancode); // Submit key event if (key != ImGuiKey_None) - ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode); + ImGui_ImplWin32_AddKeyEvent(io, key, is_key_down, vk, scancode); // Submit individual left/right modifier events if (vk == VK_SHIFT) { // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds() - if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } - if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } + if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } + if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } } else if (vk == VK_CONTROL) { - if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } - if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } + if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } + if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } } else if (vk == VK_MENU) { - if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } - if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } + if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } + if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } } } return 0; @@ -732,7 +738,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA io.AddFocusEvent(msg == WM_SETFOCUS); return 0; case WM_INPUTLANGCHANGE: - ImGui_ImplWin32_UpdateKeyboardCodePage(); + ImGui_ImplWin32_UpdateKeyboardCodePage(io); return 0; case WM_CHAR: if (::IsWindowUnicode(hwnd)) @@ -750,7 +756,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA return 0; case WM_SETCURSOR: // This is required to restore cursor when transitioning from e.g resize borders to client area. - if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor(io, bd->LastMouseCursor)) return 1; return 0; case WM_DEVICECHANGE: -- 2.42.0.windows.2