2022-11-29 18:11:09 +01:00
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
2018-02-21 23:05:17 +01:00
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
2018-06-11 12:33:51 +02:00
// Implemented features:
2020-02-17 10:11:26 +01:00
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
2023-04-04 19:43:51 +02:00
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
2018-05-02 20:42:37 +02:00
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
2019-01-15 21:17:48 +01:00
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
2018-05-02 20:42:37 +02:00
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
2018-06-12 16:24:24 +02:00
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
2018-06-11 12:33:51 +02:00
2021-06-08 18:35:35 +02:00
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
2021-05-27 13:59:35 +02:00
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
2023-09-11 13:47:08 +02:00
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
2020-10-14 12:22:53 +02:00
2018-02-16 23:04:17 +01:00
# include "imgui.h"
2023-07-13 11:27:52 +02:00
# ifndef IMGUI_DISABLE
2018-02-16 23:04:17 +01:00
# include "imgui_impl_win32.h"
2018-08-09 17:32:31 +02:00
# ifndef WIN32_LEAN_AND_MEAN
2018-02-16 23:04:17 +01:00
# define WIN32_LEAN_AND_MEAN
2018-08-09 17:32:31 +02:00
# endif
2018-02-16 23:04:17 +01:00
# include <windows.h>
2022-01-12 16:29:20 +01:00
# include <windowsx.h> // GET_X_LPARAM(), GET_Y_LPARAM()
2018-02-27 23:26:51 +01:00
# include <tchar.h>
2021-02-18 15:51:07 +01:00
# include <dwmapi.h>
// Configuration flags to add in your imconfig.h file:
2021-06-08 18:35:35 +02:00
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.
2018-02-27 23:26:51 +01:00
2021-01-25 16:19:43 +01:00
// Using XInput for gamepad (will load DLL dynamically)
2020-01-14 14:58:32 +01:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-04-26 09:29:38 +02:00
# include <xinput.h>
2021-01-23 06:23:59 +01:00
typedef DWORD ( WINAPI * PFN_XInputGetCapabilities ) ( DWORD , DWORD , XINPUT_CAPABILITIES * ) ;
typedef DWORD ( WINAPI * PFN_XInputGetState ) ( DWORD , XINPUT_STATE * ) ;
2020-01-14 14:58:32 +01:00
# endif
2018-02-20 16:18:02 +01:00
// CHANGELOG
2018-04-26 16:07:54 +02:00
// (minor and older changes stripped away, please see git history for details)
2024-02-14 14:32:17 +01:00
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2023-10-05 21:26:07 +02:00
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
2023-09-25 10:58:29 +02:00
// 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL).
2023-09-05 13:20:48 +02:00
// 2023-09-07: Inputs: Added support for keyboard codepage conversion for when application is compiled in MBCS mode and using a non-Unicode window.
2023-04-19 15:57:38 +02:00
// 2023-04-19: Added ImGui_ImplWin32_InitForOpenGL() to facilitate combining raw Win32/Winapi with OpenGL. (#3218)
2023-04-04 19:43:51 +02:00
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen. (#2702)
2023-02-15 17:17:34 +01:00
// 2023-02-15: Inputs: Use WM_NCMOUSEMOVE / WM_NCMOUSELEAVE to track mouse position over non-client area (e.g. OS decorations) when app is not focused. (#6045, #6162)
2023-02-01 20:50:45 +01:00
// 2023-02-02: Inputs: Flipping WM_MOUSEHWHEEL (horizontal mouse-wheel) value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)
2022-10-11 12:22:29 +02:00
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
2022-09-28 17:00:45 +02:00
// 2022-09-28: Inputs: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode).
2022-09-22 18:58:33 +02:00
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
2022-01-20 17:12:11 +01:00
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
2022-01-17 17:22:37 +01:00
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
2022-01-21 17:32:35 +01:00
// 2022-01-17: Inputs: always update key mods next and before a key event (not in NewFrame) to fix input queue with very low framerates.
2022-01-17 14:57:55 +01:00
// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
// 2022-01-12: Inputs: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
2022-01-10 16:59:31 +01:00
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
2018-05-02 20:42:37 +02:00
// 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.
2021-08-02 20:17:26 +02:00
// 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.
2018-05-02 20:42:37 +02:00
// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.
2021-07-29 19:38:33 +02:00
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events).
2021-06-28 16:52:10 +02:00
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
2021-08-02 17:22:33 +02:00
// 2021-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).
2021-03-23 16:48:10 +01:00
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
2021-02-18 15:51:07 +01:00
// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
2021-02-17 19:41:02 +01:00
// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.
2021-01-25 16:19:43 +01:00
// 2021-01-25: Inputs: Dynamically loading XInput DLL.
2020-12-04 11:48:17 +01:00
// 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.
2020-03-03 17:45:06 +01:00
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
2020-02-17 11:11:08 +01:00
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
2020-01-14 14:58:32 +01:00
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
2019-12-05 15:43:05 +01:00
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
2019-05-11 10:33:56 +02:00
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
2019-01-17 16:55:23 +01:00
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
2019-01-15 21:17:48 +01:00
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
2018-11-30 18:18:15 +01:00
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
2018-06-29 16:30:41 +02:00
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
2018-06-11 17:34:56 +02:00
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
2018-06-08 19:37:33 +02:00
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
2018-04-06 23:34:43 +02:00
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
2018-02-20 16:18:02 +01:00
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
2018-03-20 22:14:34 +01:00
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
2018-02-20 16:18:02 +01:00
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
2019-01-20 17:56:17 +01:00
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
2022-10-11 12:22:29 +02:00
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(nullptr) when io.MouseDrawCursor is set.
2018-02-20 16:18:02 +01:00
2018-02-27 23:26:51 +01:00
// Forward Declarations
2023-04-19 16:46:22 +02:00
static void ImGui_ImplWin32_InitPlatformInterface ( bool platformHasOwnDC ) ;
2018-02-27 23:26:51 +01:00
static void ImGui_ImplWin32_ShutdownPlatformInterface ( ) ;
2018-04-26 16:07:54 +02:00
static void ImGui_ImplWin32_UpdateMonitors ( ) ;
2018-02-27 23:26:51 +01:00
2021-06-28 16:52:10 +02:00
struct ImGui_ImplWin32_Data
{
HWND hWnd ;
2021-07-29 19:38:33 +02:00
HWND MouseHwnd ;
2023-02-15 17:17:34 +01:00
int MouseTrackedArea ; // 0: not tracked, 1: client are, 2: non-client area
2022-01-12 16:11:10 +01:00
int MouseButtonsDown ;
2021-06-28 16:52:10 +02:00
INT64 Time ;
INT64 TicksPerSecond ;
ImGuiMouseCursor LastMouseCursor ;
2023-09-05 13:20:48 +02:00
UINT32 KeyboardCodePage ;
2021-06-29 14:53:25 +02:00
bool WantUpdateMonitors ;
2018-06-08 19:37:33 +02:00
2021-01-23 06:23:59 +01:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2022-10-25 12:39:27 +02:00
bool HasGamepad ;
bool WantUpdateHasGamepad ;
2021-06-28 16:52:10 +02:00
HMODULE XInputDLL ;
PFN_XInputGetCapabilities XInputGetCapabilities ;
PFN_XInputGetState XInputGetState ;
2021-01-25 16:19:43 +01:00
# endif
2021-01-23 06:23:59 +01:00
2022-03-13 07:15:32 +01:00
ImGui_ImplWin32_Data ( ) { memset ( ( void * ) this , 0 , sizeof ( * this ) ) ; }
2021-06-28 16:52:10 +02:00
} ;
2021-06-29 16:42:13 +02:00
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
2021-06-30 15:22:15 +02:00
static ImGui_ImplWin32_Data * ImGui_ImplWin32_GetBackendData ( )
{
2022-10-11 12:22:29 +02:00
return ImGui : : GetCurrentContext ( ) ? ( ImGui_ImplWin32_Data * ) ImGui : : GetIO ( ) . BackendPlatformUserData : nullptr ;
2021-06-30 15:22:15 +02:00
}
2021-01-23 06:23:59 +01:00
2018-02-16 23:04:17 +01:00
// Functions
2023-09-05 13:20:48 +02:00
static void ImGui_ImplWin32_UpdateKeyboardCodePage ( )
{
// Retrieve keyboard code page, required for handling of non-Unicode Windows.
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
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 )
bd - > KeyboardCodePage = CP_ACP ; // Fallback to default ANSI code page when fails.
}
2023-04-19 15:57:38 +02:00
static bool ImGui_ImplWin32_InitEx ( void * hwnd , bool platform_has_own_dc )
2018-02-16 23:04:17 +01:00
{
2021-06-28 16:52:10 +02:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2022-10-11 12:22:29 +02:00
IM_ASSERT ( io . BackendPlatformUserData = = nullptr & & " Already initialized a platform backend! " ) ;
2021-06-28 16:52:10 +02:00
INT64 perf_frequency , perf_counter ;
if ( ! : : QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & perf_frequency ) )
2018-02-16 23:04:17 +01:00
return false ;
2021-06-28 16:52:10 +02:00
if ( ! : : QueryPerformanceCounter ( ( LARGE_INTEGER * ) & perf_counter ) )
2018-02-16 23:04:17 +01:00
return false ;
2020-10-12 17:34:22 +02:00
// Setup backend capabilities flags
2021-06-30 15:22:15 +02:00
ImGui_ImplWin32_Data * bd = IM_NEW ( ImGui_ImplWin32_Data ) ( ) ;
2021-06-28 16:52:10 +02:00
io . BackendPlatformUserData = ( void * ) bd ;
io . BackendPlatformName = " imgui_impl_win32 " ;
2018-03-20 22:14:34 +01:00
io . BackendFlags | = ImGuiBackendFlags_HasMouseCursors ; // We can honor GetMouseCursor() values (optional)
io . BackendFlags | = ImGuiBackendFlags_HasSetMousePos ; // We can honor io.WantSetMousePos requests (optional, rarely used)
io . BackendFlags | = ImGuiBackendFlags_PlatformHasViewports ; // We can create multi-viewports on the Platform side (optional)
2022-01-18 17:24:59 +01:00
io . BackendFlags | = ImGuiBackendFlags_HasMouseHoveredViewport ; // We can call io.AddMouseViewportEvent() with correct data (optional)
2018-03-20 22:14:34 +01:00
2021-06-28 16:52:10 +02:00
bd - > hWnd = ( HWND ) hwnd ;
2021-07-09 20:16:19 +02:00
bd - > WantUpdateMonitors = true ;
2021-06-28 16:52:10 +02:00
bd - > TicksPerSecond = perf_frequency ;
bd - > Time = perf_counter ;
bd - > LastMouseCursor = ImGuiMouseCursor_COUNT ;
2023-09-05 13:20:48 +02:00
ImGui_ImplWin32_UpdateKeyboardCodePage ( ) ;
2021-06-28 16:52:10 +02:00
2018-03-20 22:14:34 +01:00
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2021-06-29 14:53:25 +02:00
main_viewport - > PlatformHandle = main_viewport - > PlatformHandleRaw = ( void * ) bd - > hWnd ;
2018-04-10 19:21:52 +02:00
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
2023-04-19 16:46:22 +02:00
ImGui_ImplWin32_InitPlatformInterface ( platform_has_own_dc ) ;
2018-02-16 23:04:17 +01:00
2021-01-25 16:19:43 +01:00
// Dynamically load XInput library
2021-01-23 06:23:59 +01:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2022-10-25 12:39:27 +02:00
bd - > WantUpdateHasGamepad = true ;
2021-01-25 16:19:43 +01:00
const char * xinput_dll_names [ ] =
2021-01-23 06:23:59 +01:00
{
2021-01-25 16:19:43 +01:00
" xinput1_4.dll " , // Windows 8+
" xinput1_3.dll " , // DirectX SDK
" xinput9_1_0.dll " , // Windows Vista, Windows 7
" xinput1_2.dll " , // DirectX SDK
" xinput1_1.dll " // DirectX SDK
} ;
for ( int n = 0 ; n < IM_ARRAYSIZE ( xinput_dll_names ) ; n + + )
if ( HMODULE dll = : : LoadLibraryA ( xinput_dll_names [ n ] ) )
2021-01-23 06:23:59 +01:00
{
2021-06-28 16:52:10 +02:00
bd - > XInputDLL = dll ;
bd - > XInputGetCapabilities = ( PFN_XInputGetCapabilities ) : : GetProcAddress ( dll , " XInputGetCapabilities " ) ;
bd - > XInputGetState = ( PFN_XInputGetState ) : : GetProcAddress ( dll , " XInputGetState " ) ;
2021-01-23 06:23:59 +01:00
break ;
}
# endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-02-25 13:04:07 +01:00
2018-02-27 23:26:51 +01:00
return true ;
2018-02-16 23:04:17 +01:00
}
2020-05-09 15:03:10 +02:00
IMGUI_IMPL_API bool ImGui_ImplWin32_Init ( void * hwnd )
{
2023-04-19 15:57:38 +02:00
return ImGui_ImplWin32_InitEx ( hwnd , false ) ;
2020-05-09 15:03:10 +02:00
}
IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL ( void * hwnd )
{
// OpenGL needs CS_OWNDC
2023-04-19 15:57:38 +02:00
return ImGui_ImplWin32_InitEx ( hwnd , true ) ;
2020-05-09 15:03:10 +02:00
}
2018-02-16 23:04:17 +01:00
void ImGui_ImplWin32_Shutdown ( )
{
2021-06-28 16:52:10 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2022-10-11 12:22:29 +02:00
IM_ASSERT ( bd ! = nullptr & & " No platform backend to shutdown, or already shutdown? " ) ;
2021-09-20 18:43:05 +02:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 16:52:10 +02:00
2018-02-27 23:26:51 +01:00
ImGui_ImplWin32_ShutdownPlatformInterface ( ) ;
2021-01-28 21:02:13 +01:00
2021-01-25 16:19:43 +01:00
// Unload XInput library
2021-01-23 06:23:59 +01:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-06-28 16:52:10 +02:00
if ( bd - > XInputDLL )
: : FreeLibrary ( bd - > XInputDLL ) ;
2021-01-23 06:23:59 +01:00
# endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-02-25 13:04:07 +01:00
2022-10-11 12:22:29 +02:00
io . BackendPlatformName = nullptr ;
io . BackendPlatformUserData = nullptr ;
2023-04-19 16:40:18 +02:00
io . BackendFlags & = ~ ( ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport ) ;
2021-06-30 15:22:15 +02:00
IM_DELETE ( bd ) ;
2018-02-16 23:04:17 +01:00
}
2018-03-20 22:14:34 +01:00
static bool ImGui_ImplWin32_UpdateMouseCursor ( )
2018-02-20 16:18:02 +01:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2018-04-06 23:34:43 +02:00
if ( io . ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange )
2018-03-20 22:14:34 +01:00
return false ;
2018-05-11 16:41:32 +02:00
ImGuiMouseCursor imgui_cursor = ImGui : : GetMouseCursor ( ) ;
if ( imgui_cursor = = ImGuiMouseCursor_None | | io . MouseDrawCursor )
2018-02-20 16:18:02 +01:00
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
2022-10-11 12:22:29 +02:00
: : SetCursor ( nullptr ) ;
2018-02-20 16:18:02 +01:00
}
else
{
2018-05-11 16:41:32 +02:00
// Show OS mouse cursor
2018-02-20 16:18:02 +01:00
LPTSTR win32_cursor = IDC_ARROW ;
switch ( imgui_cursor )
{
case ImGuiMouseCursor_Arrow : win32_cursor = IDC_ARROW ; break ;
case ImGuiMouseCursor_TextInput : win32_cursor = IDC_IBEAM ; break ;
case ImGuiMouseCursor_ResizeAll : win32_cursor = IDC_SIZEALL ; break ;
case ImGuiMouseCursor_ResizeEW : win32_cursor = IDC_SIZEWE ; break ;
case ImGuiMouseCursor_ResizeNS : win32_cursor = IDC_SIZENS ; break ;
case ImGuiMouseCursor_ResizeNESW : win32_cursor = IDC_SIZENESW ; break ;
case ImGuiMouseCursor_ResizeNWSE : win32_cursor = IDC_SIZENWSE ; break ;
2018-06-29 12:16:17 +02:00
case ImGuiMouseCursor_Hand : win32_cursor = IDC_HAND ; break ;
2019-12-02 09:52:06 +01:00
case ImGuiMouseCursor_NotAllowed : win32_cursor = IDC_NO ; break ;
2018-02-20 16:18:02 +01:00
}
2022-10-11 12:22:29 +02:00
: : SetCursor ( : : LoadCursor ( nullptr , win32_cursor ) ) ;
2018-02-20 16:18:02 +01:00
}
2018-03-20 22:14:34 +01:00
return true ;
2018-02-20 16:18:02 +01:00
}
2018-05-02 20:42:37 +02:00
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 )
{
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 ( )
{
// 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 ) ;
if ( ImGui : : IsKeyDown ( ImGuiKey_RightShift ) & & ! IsVkDown ( VK_RSHIFT ) )
ImGui_ImplWin32_AddKeyEvent ( 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 ) ;
if ( ImGui : : IsKeyDown ( ImGuiKey_RightSuper ) & & ! IsVkDown ( VK_RWIN ) )
ImGui_ImplWin32_AddKeyEvent ( ImGuiKey_RightSuper , false , VK_RWIN ) ;
}
static void ImGui_ImplWin32_UpdateKeyModifiers ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2022-09-22 18:58:33 +02:00
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_APPS ) ) ;
2018-05-02 20:42:37 +02:00
}
2018-12-06 16:30:10 +01:00
// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
// Because of that, it is a little more complicated than your typical single-viewport binding code!
2022-01-12 16:29:20 +01:00
static void ImGui_ImplWin32_UpdateMouseData ( )
2018-02-27 23:26:51 +01:00
{
2021-06-28 16:52:10 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2021-08-02 15:04:45 +02:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 16:52:10 +02:00
IM_ASSERT ( bd - > hWnd ! = 0 ) ;
2018-05-11 14:05:40 +02:00
2022-01-13 18:36:23 +01:00
POINT mouse_screen_pos ;
bool has_mouse_screen_pos = : : GetCursorPos ( & mouse_screen_pos ) ! = 0 ;
2021-08-02 15:04:45 +02:00
2021-07-29 19:38:33 +02:00
HWND focused_window = : : GetForegroundWindow ( ) ;
2022-01-13 18:36:23 +01:00
const bool is_app_focused = ( focused_window & & ( focused_window = = bd - > hWnd | | : : IsChild ( focused_window , bd - > hWnd ) | | ImGui : : FindViewportByPlatformHandle ( ( void * ) focused_window ) ) ) ;
2022-01-12 16:29:20 +01:00
if ( is_app_focused )
2018-05-11 14:05:40 +02:00
{
2022-01-12 16:29:20 +01:00
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
2022-01-13 18:36:23 +01:00
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
2022-01-12 16:29:20 +01:00
if ( io . WantSetMousePos )
{
POINT pos = { ( int ) io . MousePos . x , ( int ) io . MousePos . y } ;
2022-01-13 18:36:23 +01:00
if ( ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) = = 0 )
: : ClientToScreen ( focused_window , & pos ) ;
: : SetCursorPos ( pos . x , pos . y ) ;
2022-01-12 16:29:20 +01:00
}
2018-05-11 14:05:40 +02:00
2022-01-12 16:29:20 +01:00
// (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
2023-02-15 17:17:34 +01:00
// This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE
2023-02-15 18:18:47 +01:00
if ( ! io . WantSetMousePos & & bd - > MouseTrackedArea = = 0 & & has_mouse_screen_pos )
2022-01-12 16:29:20 +01:00
{
2022-01-13 18:36:23 +01:00
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// (This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.)
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
// (This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.)
POINT mouse_pos = mouse_screen_pos ;
if ( ! ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) )
: : ScreenToClient ( bd - > hWnd , & mouse_pos ) ;
2022-01-17 18:16:55 +01:00
io . AddMousePosEvent ( ( float ) mouse_pos . x , ( float ) mouse_pos . y ) ;
2022-01-12 16:29:20 +01:00
}
2018-12-06 16:30:10 +01:00
}
2018-05-11 14:05:40 +02:00
2022-01-18 17:24:59 +01:00
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
2022-01-18 16:59:19 +01:00
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
// - [X] Win32 backend correctly ignore viewports with the _NoInputs flag (here using ::WindowFromPoint with WM_NCHITTEST + HTTRANSPARENT in WndProc does that)
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
// by the backend, and use its flawed heuristic to guess the viewport behind.
// - [X] Win32 backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
2022-01-18 17:24:59 +01:00
ImGuiID mouse_viewport_id = 0 ;
2022-01-13 18:36:23 +01:00
if ( has_mouse_screen_pos )
if ( HWND hovered_hwnd = : : WindowFromPoint ( mouse_screen_pos ) )
if ( ImGuiViewport * viewport = ImGui : : FindViewportByPlatformHandle ( ( void * ) hovered_hwnd ) )
2022-01-18 17:24:59 +01:00
mouse_viewport_id = viewport - > ID ;
io . AddMouseViewportEvent ( mouse_viewport_id ) ;
2018-02-27 23:26:51 +01:00
}
2019-01-15 21:17:48 +01:00
// Gamepad navigation mapping
2019-02-14 18:55:08 +01:00
static void ImGui_ImplWin32_UpdateGamepads ( )
2019-01-15 21:17:48 +01:00
{
2020-01-14 14:58:32 +01:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 21:17:48 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 16:52:10 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2022-07-25 17:16:01 +02:00
//if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
// return;
2019-01-15 21:17:48 +01:00
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
2021-06-28 16:52:10 +02:00
if ( bd - > WantUpdateHasGamepad )
2019-01-15 21:17:48 +01:00
{
2022-01-20 17:12:11 +01:00
XINPUT_CAPABILITIES caps = { } ;
2021-06-28 16:52:10 +02:00
bd - > HasGamepad = bd - > XInputGetCapabilities ? ( bd - > XInputGetCapabilities ( 0 , XINPUT_FLAG_GAMEPAD , & caps ) = = ERROR_SUCCESS ) : false ;
bd - > WantUpdateHasGamepad = false ;
2019-01-15 21:17:48 +01:00
}
io . BackendFlags & = ~ ImGuiBackendFlags_HasGamepad ;
2021-01-25 16:19:43 +01:00
XINPUT_STATE xinput_state ;
2022-01-20 17:12:11 +01:00
XINPUT_GAMEPAD & gamepad = xinput_state . Gamepad ;
2022-10-11 12:22:29 +02:00
if ( ! bd - > HasGamepad | | bd - > XInputGetState = = nullptr | | bd - > XInputGetState ( 0 , & xinput_state ) ! = ERROR_SUCCESS )
2022-01-20 17:12:11 +01:00
return ;
io . BackendFlags | = ImGuiBackendFlags_HasGamepad ;
# define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
2022-01-20 17:39:25 +01:00
# define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
# define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }
2022-01-20 17:12:11 +01:00
MAP_BUTTON ( ImGuiKey_GamepadStart , XINPUT_GAMEPAD_START ) ;
MAP_BUTTON ( ImGuiKey_GamepadBack , XINPUT_GAMEPAD_BACK ) ;
MAP_BUTTON ( ImGuiKey_GamepadFaceLeft , XINPUT_GAMEPAD_X ) ;
2022-07-06 17:13:10 +02:00
MAP_BUTTON ( ImGuiKey_GamepadFaceRight , XINPUT_GAMEPAD_B ) ;
2022-01-20 17:12:11 +01:00
MAP_BUTTON ( ImGuiKey_GamepadFaceUp , XINPUT_GAMEPAD_Y ) ;
2022-07-06 17:13:10 +02:00
MAP_BUTTON ( ImGuiKey_GamepadFaceDown , XINPUT_GAMEPAD_A ) ;
2022-01-20 17:12:11 +01:00
MAP_BUTTON ( ImGuiKey_GamepadDpadLeft , XINPUT_GAMEPAD_DPAD_LEFT ) ;
MAP_BUTTON ( ImGuiKey_GamepadDpadRight , XINPUT_GAMEPAD_DPAD_RIGHT ) ;
MAP_BUTTON ( ImGuiKey_GamepadDpadUp , XINPUT_GAMEPAD_DPAD_UP ) ;
MAP_BUTTON ( ImGuiKey_GamepadDpadDown , XINPUT_GAMEPAD_DPAD_DOWN ) ;
MAP_BUTTON ( ImGuiKey_GamepadL1 , XINPUT_GAMEPAD_LEFT_SHOULDER ) ;
MAP_BUTTON ( ImGuiKey_GamepadR1 , XINPUT_GAMEPAD_RIGHT_SHOULDER ) ;
MAP_ANALOG ( ImGuiKey_GamepadL2 , gamepad . bLeftTrigger , XINPUT_GAMEPAD_TRIGGER_THRESHOLD , 255 ) ;
MAP_ANALOG ( ImGuiKey_GamepadR2 , gamepad . bRightTrigger , XINPUT_GAMEPAD_TRIGGER_THRESHOLD , 255 ) ;
MAP_BUTTON ( ImGuiKey_GamepadL3 , XINPUT_GAMEPAD_LEFT_THUMB ) ;
MAP_BUTTON ( ImGuiKey_GamepadR3 , XINPUT_GAMEPAD_RIGHT_THUMB ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickLeft , gamepad . sThumbLX , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickRight , gamepad . sThumbLX , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickUp , gamepad . sThumbLY , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadLStickDown , gamepad . sThumbLY , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickLeft , gamepad . sThumbRX , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32768 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickRight , gamepad . sThumbRX , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickUp , gamepad . sThumbRY , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiKey_GamepadRStickDown , gamepad . sThumbRY , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32768 ) ;
# undef MAP_BUTTON
# undef MAP_ANALOG
2020-01-14 14:58:32 +01:00
# endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 21:17:48 +01:00
}
2020-02-09 17:31:18 +01:00
static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc ( HMONITOR monitor , HDC , LPRECT , LPARAM )
{
2021-01-26 14:09:18 +01:00
MONITORINFO info = { } ;
2020-02-09 17:31:18 +01:00
info . cbSize = sizeof ( MONITORINFO ) ;
if ( ! : : GetMonitorInfo ( monitor , & info ) )
return TRUE ;
ImGuiPlatformMonitor imgui_monitor ;
imgui_monitor . MainPos = ImVec2 ( ( float ) info . rcMonitor . left , ( float ) info . rcMonitor . top ) ;
imgui_monitor . MainSize = ImVec2 ( ( float ) ( info . rcMonitor . right - info . rcMonitor . left ) , ( float ) ( info . rcMonitor . bottom - info . rcMonitor . top ) ) ;
imgui_monitor . WorkPos = ImVec2 ( ( float ) info . rcWork . left , ( float ) info . rcWork . top ) ;
imgui_monitor . WorkSize = ImVec2 ( ( float ) ( info . rcWork . right - info . rcWork . left ) , ( float ) ( info . rcWork . bottom - info . rcWork . top ) ) ;
imgui_monitor . DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor ( monitor ) ;
2023-04-21 15:10:44 +02:00
imgui_monitor . PlatformHandle = ( void * ) monitor ;
2020-02-09 17:31:18 +01:00
ImGuiPlatformIO & io = ImGui : : GetPlatformIO ( ) ;
if ( info . dwFlags & MONITORINFOF_PRIMARY )
io . Monitors . push_front ( imgui_monitor ) ;
else
io . Monitors . push_back ( imgui_monitor ) ;
return TRUE ;
}
static void ImGui_ImplWin32_UpdateMonitors ( )
{
2021-06-29 14:53:25 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2020-02-09 17:31:18 +01:00
ImGui : : GetPlatformIO ( ) . Monitors . resize ( 0 ) ;
2022-10-11 15:59:23 +02:00
: : EnumDisplayMonitors ( nullptr , nullptr , ImGui_ImplWin32_UpdateMonitors_EnumFunc , 0 ) ;
2021-06-29 14:53:25 +02:00
bd - > WantUpdateMonitors = false ;
2020-02-09 17:31:18 +01:00
}
2018-02-16 23:04:17 +01:00
void ImGui_ImplWin32_NewFrame ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 16:52:10 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2022-10-11 12:22:29 +02:00
IM_ASSERT ( bd ! = nullptr & & " Did you call ImGui_ImplWin32_Init()? " ) ;
2018-02-16 23:04:17 +01:00
// Setup display size (every frame to accommodate for window resizing)
2020-12-04 11:48:17 +01:00
RECT rect = { 0 , 0 , 0 , 0 } ;
2021-06-28 16:52:10 +02:00
: : GetClientRect ( bd - > hWnd , & rect ) ;
2018-02-16 23:04:17 +01:00
io . DisplaySize = ImVec2 ( ( float ) ( rect . right - rect . left ) , ( float ) ( rect . bottom - rect . top ) ) ;
2021-06-29 14:53:25 +02:00
if ( bd - > WantUpdateMonitors )
2018-04-26 16:07:54 +02:00
ImGui_ImplWin32_UpdateMonitors ( ) ;
2018-02-16 23:04:17 +01:00
// Setup time step
2020-12-04 11:48:17 +01:00
INT64 current_time = 0 ;
2020-06-30 15:31:54 +02:00
: : QueryPerformanceCounter ( ( LARGE_INTEGER * ) & current_time ) ;
2021-06-28 16:52:10 +02:00
io . DeltaTime = ( float ) ( current_time - bd - > Time ) / bd - > TicksPerSecond ;
bd - > Time = current_time ;
2018-02-16 23:04:17 +01:00
2022-01-12 16:29:20 +01:00
// Update OS mouse position
ImGui_ImplWin32_UpdateMouseData ( ) ;
2018-05-02 20:42:37 +02:00
// Process workarounds for known Windows key handling issues
ImGui_ImplWin32_ProcessKeyEventsWorkarounds ( ) ;
2018-02-20 16:18:02 +01:00
// Update OS mouse cursor with the cursor requested by imgui
ImGuiMouseCursor mouse_cursor = io . MouseDrawCursor ? ImGuiMouseCursor_None : ImGui : : GetMouseCursor ( ) ;
2021-06-28 16:52:10 +02:00
if ( bd - > LastMouseCursor ! = mouse_cursor )
2018-02-20 16:18:02 +01:00
{
2021-06-28 16:52:10 +02:00
bd - > LastMouseCursor = mouse_cursor ;
2018-02-20 16:18:02 +01:00
ImGui_ImplWin32_UpdateMouseCursor ( ) ;
}
2019-01-15 21:17:48 +01:00
2019-04-23 12:26:14 +02:00
// Update game controllers (if enabled and available)
2019-02-14 18:55:08 +01:00
ImGui_ImplWin32_UpdateGamepads ( ) ;
2018-02-16 23:04:17 +01:00
}
2018-05-02 20:42:37 +02:00
// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
# define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
// Map VK_xxx to ImGuiKey_xxx.
static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey ( WPARAM wParam )
{
switch ( wParam )
{
case VK_TAB : return ImGuiKey_Tab ;
case VK_LEFT : return ImGuiKey_LeftArrow ;
case VK_RIGHT : return ImGuiKey_RightArrow ;
case VK_UP : return ImGuiKey_UpArrow ;
case VK_DOWN : return ImGuiKey_DownArrow ;
case VK_PRIOR : return ImGuiKey_PageUp ;
case VK_NEXT : return ImGuiKey_PageDown ;
case VK_HOME : return ImGuiKey_Home ;
case VK_END : return ImGuiKey_End ;
case VK_INSERT : return ImGuiKey_Insert ;
case VK_DELETE : return ImGuiKey_Delete ;
case VK_BACK : return ImGuiKey_Backspace ;
case VK_SPACE : return ImGuiKey_Space ;
case VK_RETURN : return ImGuiKey_Enter ;
case VK_ESCAPE : return ImGuiKey_Escape ;
case VK_OEM_7 : return ImGuiKey_Apostrophe ;
case VK_OEM_COMMA : return ImGuiKey_Comma ;
case VK_OEM_MINUS : return ImGuiKey_Minus ;
case VK_OEM_PERIOD : return ImGuiKey_Period ;
case VK_OEM_2 : return ImGuiKey_Slash ;
case VK_OEM_1 : return ImGuiKey_Semicolon ;
case VK_OEM_PLUS : return ImGuiKey_Equal ;
case VK_OEM_4 : return ImGuiKey_LeftBracket ;
case VK_OEM_5 : return ImGuiKey_Backslash ;
case VK_OEM_6 : return ImGuiKey_RightBracket ;
case VK_OEM_3 : return ImGuiKey_GraveAccent ;
case VK_CAPITAL : return ImGuiKey_CapsLock ;
case VK_SCROLL : return ImGuiKey_ScrollLock ;
case VK_NUMLOCK : return ImGuiKey_NumLock ;
case VK_SNAPSHOT : return ImGuiKey_PrintScreen ;
case VK_PAUSE : return ImGuiKey_Pause ;
case VK_NUMPAD0 : return ImGuiKey_Keypad0 ;
case VK_NUMPAD1 : return ImGuiKey_Keypad1 ;
case VK_NUMPAD2 : return ImGuiKey_Keypad2 ;
case VK_NUMPAD3 : return ImGuiKey_Keypad3 ;
case VK_NUMPAD4 : return ImGuiKey_Keypad4 ;
case VK_NUMPAD5 : return ImGuiKey_Keypad5 ;
case VK_NUMPAD6 : return ImGuiKey_Keypad6 ;
case VK_NUMPAD7 : return ImGuiKey_Keypad7 ;
case VK_NUMPAD8 : return ImGuiKey_Keypad8 ;
case VK_NUMPAD9 : return ImGuiKey_Keypad9 ;
case VK_DECIMAL : return ImGuiKey_KeypadDecimal ;
case VK_DIVIDE : return ImGuiKey_KeypadDivide ;
case VK_MULTIPLY : return ImGuiKey_KeypadMultiply ;
case VK_SUBTRACT : return ImGuiKey_KeypadSubtract ;
case VK_ADD : return ImGuiKey_KeypadAdd ;
case IM_VK_KEYPAD_ENTER : return ImGuiKey_KeypadEnter ;
case VK_LSHIFT : return ImGuiKey_LeftShift ;
2022-01-17 15:41:04 +01:00
case VK_LCONTROL : return ImGuiKey_LeftCtrl ;
2018-05-02 20:42:37 +02:00
case VK_LMENU : return ImGuiKey_LeftAlt ;
case VK_LWIN : return ImGuiKey_LeftSuper ;
case VK_RSHIFT : return ImGuiKey_RightShift ;
2022-01-17 15:41:04 +01:00
case VK_RCONTROL : return ImGuiKey_RightCtrl ;
2018-05-02 20:42:37 +02:00
case VK_RMENU : return ImGuiKey_RightAlt ;
case VK_RWIN : return ImGuiKey_RightSuper ;
case VK_APPS : return ImGuiKey_Menu ;
case ' 0 ' : return ImGuiKey_0 ;
case ' 1 ' : return ImGuiKey_1 ;
case ' 2 ' : return ImGuiKey_2 ;
case ' 3 ' : return ImGuiKey_3 ;
case ' 4 ' : return ImGuiKey_4 ;
case ' 5 ' : return ImGuiKey_5 ;
case ' 6 ' : return ImGuiKey_6 ;
case ' 7 ' : return ImGuiKey_7 ;
case ' 8 ' : return ImGuiKey_8 ;
case ' 9 ' : return ImGuiKey_9 ;
case ' A ' : return ImGuiKey_A ;
case ' B ' : return ImGuiKey_B ;
case ' C ' : return ImGuiKey_C ;
case ' D ' : return ImGuiKey_D ;
case ' E ' : return ImGuiKey_E ;
case ' F ' : return ImGuiKey_F ;
case ' G ' : return ImGuiKey_G ;
case ' H ' : return ImGuiKey_H ;
case ' I ' : return ImGuiKey_I ;
case ' J ' : return ImGuiKey_J ;
case ' K ' : return ImGuiKey_K ;
case ' L ' : return ImGuiKey_L ;
case ' M ' : return ImGuiKey_M ;
case ' N ' : return ImGuiKey_N ;
case ' O ' : return ImGuiKey_O ;
case ' P ' : return ImGuiKey_P ;
case ' Q ' : return ImGuiKey_Q ;
case ' R ' : return ImGuiKey_R ;
case ' S ' : return ImGuiKey_S ;
case ' T ' : return ImGuiKey_T ;
case ' U ' : return ImGuiKey_U ;
case ' V ' : return ImGuiKey_V ;
case ' W ' : return ImGuiKey_W ;
case ' X ' : return ImGuiKey_X ;
case ' Y ' : return ImGuiKey_Y ;
case ' Z ' : return ImGuiKey_Z ;
case VK_F1 : return ImGuiKey_F1 ;
case VK_F2 : return ImGuiKey_F2 ;
case VK_F3 : return ImGuiKey_F3 ;
case VK_F4 : return ImGuiKey_F4 ;
case VK_F5 : return ImGuiKey_F5 ;
case VK_F6 : return ImGuiKey_F6 ;
case VK_F7 : return ImGuiKey_F7 ;
case VK_F8 : return ImGuiKey_F8 ;
case VK_F9 : return ImGuiKey_F9 ;
case VK_F10 : return ImGuiKey_F10 ;
case VK_F11 : return ImGuiKey_F11 ;
case VK_F12 : return ImGuiKey_F12 ;
2023-10-05 20:39:49 +02:00
case VK_F13 : return ImGuiKey_F13 ;
case VK_F14 : return ImGuiKey_F14 ;
case VK_F15 : return ImGuiKey_F15 ;
case VK_F16 : return ImGuiKey_F16 ;
case VK_F17 : return ImGuiKey_F17 ;
case VK_F18 : return ImGuiKey_F18 ;
case VK_F19 : return ImGuiKey_F19 ;
case VK_F20 : return ImGuiKey_F20 ;
case VK_F21 : return ImGuiKey_F21 ;
case VK_F22 : return ImGuiKey_F22 ;
case VK_F23 : return ImGuiKey_F23 ;
case VK_F24 : return ImGuiKey_F24 ;
2023-10-05 21:26:07 +02:00
case VK_BROWSER_BACK : return ImGuiKey_AppBack ;
case VK_BROWSER_FORWARD : return ImGuiKey_AppForward ;
2018-05-02 20:42:37 +02:00
default : return ImGuiKey_None ;
}
}
2018-04-04 19:39:42 +02:00
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
# ifndef WM_MOUSEHWHEEL
# define WM_MOUSEHWHEEL 0x020E
# endif
2019-01-15 21:17:48 +01:00
# ifndef DBT_DEVNODES_CHANGED
# define DBT_DEVNODES_CHANGED 0x0007
# endif
2018-04-04 19:39:42 +02:00
2020-02-17 10:11:26 +01:00
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
2022-02-28 20:50:58 +01:00
// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE.
2020-10-12 17:34:22 +02:00
// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
2022-02-28 20:50:58 +01:00
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
2020-02-17 10:11:26 +01:00
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
2019-03-09 10:10:17 +01:00
// 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.
2018-02-16 23:04:17 +01:00
// 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.
2020-02-17 10:11:26 +01:00
#if 0
// 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 ) ;
# endif
2023-04-04 19:43:51 +02:00
// See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
// Prefer to call this at the top of the message handler to avoid the possibility of other Win32 calls interfering with this.
static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo ( )
{
LPARAM extra_info = : : GetMessageExtraInfo ( ) ;
if ( ( extra_info & 0xFFFFFF80 ) = = 0xFF515700 )
return ImGuiMouseSource_Pen ;
if ( ( extra_info & 0xFFFFFF80 ) = = 0xFF515780 )
return ImGuiMouseSource_TouchScreen ;
return ImGuiMouseSource_Mouse ;
}
2018-06-21 12:04:00 +02:00
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler ( HWND hwnd , UINT msg , WPARAM wParam , LPARAM lParam )
2018-02-16 23:04:17 +01:00
{
2022-10-11 12:22:29 +02:00
if ( ImGui : : GetCurrentContext ( ) = = nullptr )
2018-02-16 23:04:17 +01:00
return 0 ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 16:52:10 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2018-02-16 23:04:17 +01:00
switch ( msg )
{
2021-07-29 19:38:33 +02:00
case WM_MOUSEMOVE :
2023-02-15 17:17:34 +01:00
case WM_NCMOUSEMOVE :
2022-01-13 18:36:23 +01:00
{
2021-07-29 19:38:33 +02:00
// We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
2023-04-04 19:43:51 +02:00
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo ( ) ;
2023-02-15 17:17:34 +01:00
const int area = ( msg = = WM_MOUSEMOVE ) ? 1 : 2 ;
2021-07-29 19:38:33 +02:00
bd - > MouseHwnd = hwnd ;
2023-02-15 17:17:34 +01:00
if ( bd - > MouseTrackedArea ! = area )
2021-07-29 19:38:33 +02:00
{
2023-02-15 17:17:34 +01:00
TRACKMOUSEEVENT tme_cancel = { sizeof ( tme_cancel ) , TME_CANCEL , hwnd , 0 } ;
TRACKMOUSEEVENT tme_track = { sizeof ( tme_track ) , ( DWORD ) ( ( area = = 2 ) ? ( TME_LEAVE | TME_NONCLIENT ) : TME_LEAVE ) , hwnd , 0 } ;
if ( bd - > MouseTrackedArea ! = 0 )
: : TrackMouseEvent ( & tme_cancel ) ;
: : TrackMouseEvent ( & tme_track ) ;
bd - > MouseTrackedArea = area ;
2021-07-29 19:38:33 +02:00
}
2022-01-13 18:36:23 +01:00
POINT mouse_pos = { ( LONG ) GET_X_LPARAM ( lParam ) , ( LONG ) GET_Y_LPARAM ( lParam ) } ;
2023-02-15 18:18:47 +01:00
bool want_absolute_pos = ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) ! = 0 ;
if ( msg = = WM_MOUSEMOVE & & want_absolute_pos ) // WM_MOUSEMOVE are client-relative coordinates.
2022-01-13 18:36:23 +01:00
: : ClientToScreen ( hwnd , & mouse_pos ) ;
2023-02-15 18:18:47 +01:00
if ( msg = = WM_NCMOUSEMOVE & & ! want_absolute_pos ) // WM_NCMOUSEMOVE are absolute coordinates.
: : ScreenToClient ( hwnd , & mouse_pos ) ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( mouse_source ) ;
2022-01-17 18:16:55 +01:00
io . AddMousePosEvent ( ( float ) mouse_pos . x , ( float ) mouse_pos . y ) ;
2021-07-29 19:38:33 +02:00
break ;
2022-01-13 18:36:23 +01:00
}
2021-07-29 19:38:33 +02:00
case WM_MOUSELEAVE :
2023-02-15 17:17:34 +01:00
case WM_NCMOUSELEAVE :
{
const int area = ( msg = = WM_MOUSELEAVE ) ? 1 : 2 ;
if ( bd - > MouseTrackedArea = = area )
{
if ( bd - > MouseHwnd = = hwnd )
bd - > MouseHwnd = nullptr ;
bd - > MouseTrackedArea = 0 ;
io . AddMousePosEvent ( - FLT_MAX , - FLT_MAX ) ;
}
2021-07-29 19:38:33 +02:00
break ;
2023-02-15 17:17:34 +01:00
}
2018-02-16 23:04:17 +01:00
case WM_LBUTTONDOWN : case WM_LBUTTONDBLCLK :
case WM_RBUTTONDOWN : case WM_RBUTTONDBLCLK :
case WM_MBUTTONDOWN : case WM_MBUTTONDBLCLK :
2019-01-17 16:55:23 +01:00
case WM_XBUTTONDOWN : case WM_XBUTTONDBLCLK :
2018-02-16 23:04:17 +01:00
{
2023-04-04 19:43:51 +02:00
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo ( ) ;
2018-02-16 23:04:17 +01:00
int button = 0 ;
2019-01-17 16:55:23 +01:00
if ( msg = = WM_LBUTTONDOWN | | msg = = WM_LBUTTONDBLCLK ) { button = 0 ; }
if ( msg = = WM_RBUTTONDOWN | | msg = = WM_RBUTTONDBLCLK ) { button = 1 ; }
if ( msg = = WM_MBUTTONDOWN | | msg = = WM_MBUTTONDBLCLK ) { button = 2 ; }
if ( msg = = WM_XBUTTONDOWN | | msg = = WM_XBUTTONDBLCLK ) { button = ( GET_XBUTTON_WPARAM ( wParam ) = = XBUTTON1 ) ? 3 : 4 ; }
2022-10-11 12:22:29 +02:00
if ( bd - > MouseButtonsDown = = 0 & & : : GetCapture ( ) = = nullptr )
2018-02-16 23:04:17 +01:00
: : SetCapture ( hwnd ) ;
2022-01-12 16:11:10 +01:00
bd - > MouseButtonsDown | = 1 < < button ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( mouse_source ) ;
2022-01-17 17:22:37 +01:00
io . AddMouseButtonEvent ( button , true ) ;
2018-02-16 23:04:17 +01:00
return 0 ;
}
case WM_LBUTTONUP :
case WM_RBUTTONUP :
case WM_MBUTTONUP :
2019-01-17 16:55:23 +01:00
case WM_XBUTTONUP :
2018-02-16 23:04:17 +01:00
{
2023-04-04 19:43:51 +02:00
ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo ( ) ;
2018-02-16 23:04:17 +01:00
int button = 0 ;
2019-01-17 16:55:23 +01:00
if ( msg = = WM_LBUTTONUP ) { button = 0 ; }
if ( msg = = WM_RBUTTONUP ) { button = 1 ; }
if ( msg = = WM_MBUTTONUP ) { button = 2 ; }
if ( msg = = WM_XBUTTONUP ) { button = ( GET_XBUTTON_WPARAM ( wParam ) = = XBUTTON1 ) ? 3 : 4 ; }
2022-01-12 16:11:10 +01:00
bd - > MouseButtonsDown & = ~ ( 1 < < button ) ;
if ( bd - > MouseButtonsDown = = 0 & & : : GetCapture ( ) = = hwnd )
2018-02-16 23:04:17 +01:00
: : ReleaseCapture ( ) ;
2023-04-04 19:43:51 +02:00
io . AddMouseSourceEvent ( mouse_source ) ;
2022-01-17 17:22:37 +01:00
io . AddMouseButtonEvent ( button , false ) ;
2018-02-16 23:04:17 +01:00
return 0 ;
}
case WM_MOUSEWHEEL :
2022-01-17 17:22:37 +01:00
io . AddMouseWheelEvent ( 0.0f , ( float ) GET_WHEEL_DELTA_WPARAM ( wParam ) / ( float ) WHEEL_DELTA ) ;
2018-02-16 23:04:17 +01:00
return 0 ;
case WM_MOUSEHWHEEL :
2023-02-01 20:50:45 +01:00
io . AddMouseWheelEvent ( - ( float ) GET_WHEEL_DELTA_WPARAM ( wParam ) / ( float ) WHEEL_DELTA , 0.0f ) ;
2018-02-16 23:04:17 +01:00
return 0 ;
case WM_KEYDOWN :
case WM_KEYUP :
2021-08-02 17:22:33 +02:00
case WM_SYSKEYDOWN :
2018-02-16 23:04:17 +01:00
case WM_SYSKEYUP :
2021-08-02 17:22:33 +02:00
{
2018-05-02 20:42:37 +02:00
const bool is_key_down = ( msg = = WM_KEYDOWN | | msg = = WM_SYSKEYDOWN ) ;
2018-02-16 23:04:17 +01:00
if ( wParam < 256 )
2018-05-02 20:42:37 +02:00
{
2022-01-17 14:57:55 +01:00
// Submit modifiers
ImGui_ImplWin32_UpdateKeyModifiers ( ) ;
2018-05-02 20:42:37 +02:00
// Obtain virtual key code
// (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.)
int vk = ( int ) wParam ;
if ( ( wParam = = VK_RETURN ) & & ( HIWORD ( lParam ) & KF_EXTENDED ) )
vk = IM_VK_KEYPAD_ENTER ;
const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey ( vk ) ;
const int scancode = ( int ) LOBYTE ( HIWORD ( lParam ) ) ;
2023-09-25 10:58:29 +02:00
// 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 ) ;
// Submit key event
2018-05-02 20:42:37 +02:00
if ( key ! = ImGuiKey_None )
ImGui_ImplWin32_AddKeyEvent ( 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 ) ; }
}
else if ( vk = = VK_CONTROL )
{
2022-01-17 15:41:04 +01:00
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 ) ; }
2018-05-02 20:42:37 +02:00
}
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 ) ; }
}
2018-05-02 20:42:37 +02:00
}
2018-02-16 23:04:17 +01:00
return 0 ;
2021-08-02 17:22:33 +02:00
}
2021-08-02 20:17:26 +02:00
case WM_SETFOCUS :
2021-03-23 16:48:10 +01:00
case WM_KILLFOCUS :
2021-08-02 20:17:26 +02:00
io . AddFocusEvent ( msg = = WM_SETFOCUS ) ;
2021-03-23 16:48:10 +01:00
return 0 ;
2023-09-05 13:20:48 +02:00
case WM_INPUTLANGCHANGE :
ImGui_ImplWin32_UpdateKeyboardCodePage ( ) ;
return 0 ;
2018-02-16 23:04:17 +01:00
case WM_CHAR :
2022-09-28 17:00:45 +02:00
if ( : : IsWindowUnicode ( hwnd ) )
{
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if ( wParam > 0 & & wParam < 0x10000 )
io . AddInputCharacterUTF16 ( ( unsigned short ) wParam ) ;
}
else
{
wchar_t wch = 0 ;
2023-09-05 13:20:48 +02:00
: : MultiByteToWideChar ( bd - > KeyboardCodePage , MB_PRECOMPOSED , ( char * ) & wParam , 1 , & wch , 1 ) ;
2022-09-28 17:00:45 +02:00
io . AddInputCharacter ( wch ) ;
}
2018-02-16 23:04:17 +01:00
return 0 ;
2018-02-20 16:18:02 +01:00
case WM_SETCURSOR :
2022-06-13 14:46:55 +02:00
// This is required to restore cursor when transitioning from e.g resize borders to client area.
2018-03-20 22:14:34 +01:00
if ( LOWORD ( lParam ) = = HTCLIENT & & ImGui_ImplWin32_UpdateMouseCursor ( ) )
2018-02-20 16:18:02 +01:00
return 1 ;
return 0 ;
2019-01-15 21:17:48 +01:00
case WM_DEVICECHANGE :
2022-10-25 12:39:27 +02:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 21:17:48 +01:00
if ( ( UINT ) wParam = = DBT_DEVNODES_CHANGED )
2021-06-28 16:52:10 +02:00
bd - > WantUpdateHasGamepad = true ;
2022-10-25 12:39:27 +02:00
# endif
2019-01-15 21:17:48 +01:00
return 0 ;
2018-04-26 16:07:54 +02:00
case WM_DISPLAYCHANGE :
2021-06-29 14:53:25 +02:00
bd - > WantUpdateMonitors = true ;
2018-04-26 16:07:54 +02:00
return 0 ;
2018-02-16 23:04:17 +01:00
}
return 0 ;
2018-02-16 23:15:14 +01:00
}
2018-02-27 23:26:51 +01:00
2020-02-17 11:11:08 +01:00
//--------------------------------------------------------------------------------------------------------
// DPI-related helpers (optional)
2018-04-24 12:40:38 +02:00
//--------------------------------------------------------------------------------------------------------
2020-02-17 11:11:08 +01:00
// - Use to enable DPI awareness without having to create an application manifest.
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
2018-03-09 19:02:52 +01:00
//---------------------------------------------------------------------------------------------------------
2020-02-17 11:11:08 +01:00
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
2020-10-12 17:34:22 +02:00
// If you are trying to implement your own backend for your own engine, you may ignore that noise.
2018-03-09 19:02:52 +01:00
//---------------------------------------------------------------------------------------------------------
2021-06-08 18:35:35 +02:00
// Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they
// require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200
static BOOL _IsWindowsVersionOrGreater ( WORD major , WORD minor , WORD )
2018-03-09 19:02:52 +01:00
{
2021-06-08 18:35:35 +02:00
typedef LONG ( WINAPI * PFN_RtlVerifyVersionInfo ) ( OSVERSIONINFOEXW * , ULONG , ULONGLONG ) ;
2022-10-11 12:22:29 +02:00
static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = nullptr ;
if ( RtlVerifyVersionInfoFn = = nullptr )
2021-06-08 18:35:35 +02:00
if ( HMODULE ntdllModule = : : GetModuleHandleA ( " ntdll.dll " ) )
RtlVerifyVersionInfoFn = ( PFN_RtlVerifyVersionInfo ) GetProcAddress ( ntdllModule , " RtlVerifyVersionInfo " ) ;
2022-10-11 12:22:29 +02:00
if ( RtlVerifyVersionInfoFn = = nullptr )
2021-06-24 15:13:21 +02:00
return FALSE ;
2021-06-08 18:35:35 +02:00
2021-07-05 16:46:12 +02:00
RTL_OSVERSIONINFOEXW versionInfo = { } ;
ULONGLONG conditionMask = 0 ;
versionInfo . dwOSVersionInfoSize = sizeof ( RTL_OSVERSIONINFOEXW ) ;
versionInfo . dwMajorVersion = major ;
2021-06-08 18:35:35 +02:00
versionInfo . dwMinorVersion = minor ;
VER_SET_CONDITION ( conditionMask , VER_MAJORVERSION , VER_GREATER_EQUAL ) ;
VER_SET_CONDITION ( conditionMask , VER_MINORVERSION , VER_GREATER_EQUAL ) ;
return ( RtlVerifyVersionInfoFn ( & versionInfo , VER_MAJORVERSION | VER_MINORVERSION , conditionMask ) = = 0 ) ? TRUE : FALSE ;
2018-03-09 19:02:52 +01:00
}
2021-06-08 18:35:35 +02:00
# define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
# define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
# define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
# define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
2018-03-09 19:02:52 +01:00
# ifndef DPI_ENUMS_DECLARED
typedef enum { PROCESS_DPI_UNAWARE = 0 , PROCESS_SYSTEM_DPI_AWARE = 1 , PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS ;
typedef enum { MDT_EFFECTIVE_DPI = 0 , MDT_ANGULAR_DPI = 1 , MDT_RAW_DPI = 2 , MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE ;
# endif
2018-04-13 00:01:55 +02:00
# ifndef _DPI_AWARENESS_CONTEXTS_
DECLARE_HANDLE ( DPI_AWARENESS_CONTEXT ) ;
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
2019-01-17 14:35:26 +01:00
# endif
# ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
2018-04-13 00:01:55 +02:00
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
# endif
2020-02-17 11:11:08 +01:00
typedef HRESULT ( WINAPI * PFN_SetProcessDpiAwareness ) ( PROCESS_DPI_AWARENESS ) ; // Shcore.lib + dll, Windows 8.1+
typedef HRESULT ( WINAPI * PFN_GetDpiForMonitor ) ( HMONITOR , MONITOR_DPI_TYPE , UINT * , UINT * ) ; // Shcore.lib + dll, Windows 8.1+
typedef DPI_AWARENESS_CONTEXT ( WINAPI * PFN_SetThreadDpiAwarenessContext ) ( DPI_AWARENESS_CONTEXT ) ; // User32.lib + dll, Windows 10 v1607+ (Creators Update)
2018-03-09 19:02:52 +01:00
2020-02-17 11:11:08 +01:00
// Helper function to enable DPI awareness without setting up a manifest
2018-03-09 19:02:52 +01:00
void ImGui_ImplWin32_EnableDpiAwareness ( )
{
2020-05-08 22:02:15 +02:00
// Make sure monitors will be updated with latest correct scaling
2021-06-29 14:53:25 +02:00
if ( ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) )
bd - > WantUpdateMonitors = true ;
2020-05-08 22:02:15 +02:00
2021-06-08 18:35:35 +02:00
if ( _IsWindows10OrGreater ( ) )
2018-04-13 00:01:55 +02:00
{
static HINSTANCE user32_dll = : : LoadLibraryA ( " user32.dll " ) ; // Reference counted per-process
if ( PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = ( PFN_SetThreadDpiAwarenessContext ) : : GetProcAddress ( user32_dll , " SetThreadDpiAwarenessContext " ) )
{
SetThreadDpiAwarenessContextFn ( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ) ;
return ;
}
}
2021-06-08 18:35:35 +02:00
if ( _IsWindows8Point1OrGreater ( ) )
2018-03-09 19:02:52 +01:00
{
static HINSTANCE shcore_dll = : : LoadLibraryA ( " shcore.dll " ) ; // Reference counted per-process
if ( PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = ( PFN_SetProcessDpiAwareness ) : : GetProcAddress ( shcore_dll , " SetProcessDpiAwareness " ) )
2020-02-17 11:11:08 +01:00
{
2018-03-09 19:02:52 +01:00
SetProcessDpiAwarenessFn ( PROCESS_PER_MONITOR_DPI_AWARE ) ;
2020-02-17 11:11:08 +01:00
return ;
}
2018-03-09 19:02:52 +01:00
}
2020-05-04 20:46:20 +02:00
# if _WIN32_WINNT >= 0x0600
: : SetProcessDPIAware ( ) ;
# endif
2018-03-09 19:02:52 +01:00
}
2020-04-19 17:52:09 +02:00
# if defined(_MSC_VER) && !defined(NOGDI)
2021-02-18 15:51:07 +01:00
# pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
2019-02-01 15:23:25 +01:00
# endif
2018-03-09 19:02:52 +01:00
float ImGui_ImplWin32_GetDpiScaleForMonitor ( void * monitor )
{
UINT xdpi = 96 , ydpi = 96 ;
2021-06-08 18:35:35 +02:00
if ( _IsWindows8Point1OrGreater ( ) )
2018-03-09 19:02:52 +01:00
{
2021-06-08 18:35:35 +02:00
static HINSTANCE shcore_dll = : : LoadLibraryA ( " shcore.dll " ) ; // Reference counted per-process
2022-10-11 12:22:29 +02:00
static PFN_GetDpiForMonitor GetDpiForMonitorFn = nullptr ;
if ( GetDpiForMonitorFn = = nullptr & & shcore_dll ! = nullptr )
2021-06-08 18:35:35 +02:00
GetDpiForMonitorFn = ( PFN_GetDpiForMonitor ) : : GetProcAddress ( shcore_dll , " GetDpiForMonitor " ) ;
2022-10-11 12:22:29 +02:00
if ( GetDpiForMonitorFn ! = nullptr )
2021-06-08 18:35:35 +02:00
{
GetDpiForMonitorFn ( ( HMONITOR ) monitor , MDT_EFFECTIVE_DPI , & xdpi , & ydpi ) ;
IM_ASSERT ( xdpi = = ydpi ) ; // Please contact me if you hit this assert!
return xdpi / 96.0f ;
}
2018-03-09 19:02:52 +01:00
}
2020-04-19 17:52:09 +02:00
# ifndef NOGDI
2022-10-11 12:22:29 +02:00
const HDC dc = : : GetDC ( nullptr ) ;
2021-06-08 18:35:35 +02:00
xdpi = : : GetDeviceCaps ( dc , LOGPIXELSX ) ;
ydpi = : : GetDeviceCaps ( dc , LOGPIXELSY ) ;
2018-03-09 19:02:52 +01:00
IM_ASSERT ( xdpi = = ydpi ) ; // Please contact me if you hit this assert!
2022-10-11 12:22:29 +02:00
: : ReleaseDC ( nullptr , dc ) ;
2021-06-08 18:35:35 +02:00
# endif
2018-03-09 19:02:52 +01:00
return xdpi / 96.0f ;
}
float ImGui_ImplWin32_GetDpiScaleForHwnd ( void * hwnd )
{
HMONITOR monitor = : : MonitorFromWindow ( ( HWND ) hwnd , MONITOR_DEFAULTTONEAREST ) ;
return ImGui_ImplWin32_GetDpiScaleForMonitor ( monitor ) ;
}
2023-04-20 10:38:45 +02:00
//---------------------------------------------------------------------------------------------------------
// Transparency related helpers (optional)
2018-04-24 12:40:38 +02:00
//--------------------------------------------------------------------------------------------------------
2023-04-20 10:38:45 +02:00
# if defined(_MSC_VER)
# pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi'
# endif
// [experimental]
// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c
// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
void ImGui_ImplWin32_EnableAlphaCompositing ( void * hwnd )
{
if ( ! _IsWindowsVistaOrGreater ( ) )
return ;
BOOL composition ;
if ( FAILED ( : : DwmIsCompositionEnabled ( & composition ) ) | | ! composition )
return ;
BOOL opaque ;
DWORD color ;
if ( _IsWindows8OrGreater ( ) | | ( SUCCEEDED ( : : DwmGetColorizationColor ( & color , & opaque ) ) & & ! opaque ) )
{
HRGN region = : : CreateRectRgn ( 0 , 0 , - 1 , - 1 ) ;
DWM_BLURBEHIND bb = { } ;
bb . dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION ;
bb . hRgnBlur = region ;
bb . fEnable = TRUE ;
: : DwmEnableBlurBehindWindow ( ( HWND ) hwnd , & bb ) ;
: : DeleteObject ( region ) ;
}
else
{
DWM_BLURBEHIND bb = { } ;
bb . dwFlags = DWM_BB_ENABLE ;
: : DwmEnableBlurBehindWindow ( ( HWND ) hwnd , & bb ) ;
}
}
//---------------------------------------------------------------------------------------------------------
2018-04-24 17:09:50 +02:00
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
2020-10-14 14:43:45 +02:00
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
2018-04-24 17:09:50 +02:00
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
2018-04-24 12:40:38 +02:00
//--------------------------------------------------------------------------------------------------------
2018-02-27 23:26:51 +01:00
2023-04-11 16:19:59 +02:00
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
2021-06-29 15:34:54 +02:00
struct ImGui_ImplWin32_ViewportData
2018-02-27 23:26:51 +01:00
{
HWND Hwnd ;
2023-06-15 11:26:27 +02:00
HWND HwndParent ;
2018-04-09 22:01:24 +02:00
bool HwndOwned ;
2018-02-27 23:26:51 +01:00
DWORD DwStyle ;
DWORD DwExStyle ;
2023-06-15 11:26:27 +02:00
ImGui_ImplWin32_ViewportData ( ) { Hwnd = HwndParent = nullptr ; HwndOwned = false ; DwStyle = DwExStyle = 0 ; }
2022-10-11 15:59:23 +02:00
~ ImGui_ImplWin32_ViewportData ( ) { IM_ASSERT ( Hwnd = = nullptr ) ; }
2018-02-27 23:26:51 +01:00
} ;
2019-01-02 16:06:58 +01:00
static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags ( ImGuiViewportFlags flags , DWORD * out_style , DWORD * out_ex_style )
{
if ( flags & ImGuiViewportFlags_NoDecoration )
* out_style = WS_POPUP ;
else
* out_style = WS_OVERLAPPEDWINDOW ;
if ( flags & ImGuiViewportFlags_NoTaskBarIcon )
* out_ex_style = WS_EX_TOOLWINDOW ;
else
* out_ex_style = WS_EX_APPWINDOW ;
if ( flags & ImGuiViewportFlags_TopMost )
* out_ex_style | = WS_EX_TOPMOST ;
}
2023-06-15 11:26:27 +02:00
static HWND ImGui_ImplWin32_GetHwndFromViewportID ( ImGuiID viewport_id )
{
if ( viewport_id ! = 0 )
if ( ImGuiViewport * viewport = ImGui : : FindViewportByID ( viewport_id ) )
return ( HWND ) viewport - > PlatformHandle ;
return nullptr ;
}
2018-03-18 18:44:57 +01:00
static void ImGui_ImplWin32_CreateWindow ( ImGuiViewport * viewport )
2018-02-27 23:26:51 +01:00
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = IM_NEW ( ImGui_ImplWin32_ViewportData ) ( ) ;
viewport - > PlatformUserData = vd ;
2018-02-27 23:26:51 +01:00
2019-01-02 16:06:58 +01:00
// Select style and parent window
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_GetWin32StyleFromViewportFlags ( viewport - > Flags , & vd - > DwStyle , & vd - > DwExStyle ) ;
2023-06-15 11:26:27 +02:00
vd - > HwndParent = ImGui_ImplWin32_GetHwndFromViewportID ( viewport - > ParentViewportId ) ;
2018-02-27 23:26:51 +01:00
// Create window
2018-04-20 21:29:16 +02:00
RECT rect = { ( LONG ) viewport - > Pos . x , ( LONG ) viewport - > Pos . y , ( LONG ) ( viewport - > Pos . x + viewport - > Size . x ) , ( LONG ) ( viewport - > Pos . y + viewport - > Size . y ) } ;
2021-06-29 15:34:54 +02:00
: : AdjustWindowRectEx ( & rect , vd - > DwStyle , FALSE , vd - > DwExStyle ) ;
vd - > Hwnd = : : CreateWindowEx (
2022-10-11 15:59:23 +02:00
vd - > DwExStyle , _T ( " ImGui Platform " ) , _T ( " Untitled " ) , vd - > DwStyle , // Style, class name, window name
2019-01-02 16:06:58 +01:00
rect . left , rect . top , rect . right - rect . left , rect . bottom - rect . top , // Window area
2023-06-15 11:26:27 +02:00
vd - > HwndParent , nullptr , : : GetModuleHandle ( nullptr ) , nullptr ) ; // Owner window, Menu, Instance, Param
2021-06-29 15:34:54 +02:00
vd - > HwndOwned = true ;
2018-03-15 10:54:27 +01:00
viewport - > PlatformRequestResize = false ;
2021-06-29 15:34:54 +02:00
viewport - > PlatformHandle = viewport - > PlatformHandleRaw = vd - > Hwnd ;
2018-02-27 23:26:51 +01:00
}
2018-03-18 18:44:57 +01:00
static void ImGui_ImplWin32_DestroyWindow ( ImGuiViewport * viewport )
2018-02-27 23:26:51 +01:00
{
2021-06-29 14:53:25 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2021-06-29 15:34:54 +02:00
if ( ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData )
2018-02-27 23:26:51 +01:00
{
2021-06-29 15:34:54 +02:00
if ( : : GetCapture ( ) = = vd - > Hwnd )
2018-02-27 23:26:51 +01:00
{
2018-04-10 22:58:39 +02:00
// Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
2018-02-27 23:26:51 +01:00
: : ReleaseCapture ( ) ;
2021-06-29 14:53:25 +02:00
: : SetCapture ( bd - > hWnd ) ;
2018-02-27 23:26:51 +01:00
}
2021-06-29 15:34:54 +02:00
if ( vd - > Hwnd & & vd - > HwndOwned )
: : DestroyWindow ( vd - > Hwnd ) ;
2022-10-11 15:59:23 +02:00
vd - > Hwnd = nullptr ;
2021-06-29 15:34:54 +02:00
IM_DELETE ( vd ) ;
2018-02-27 23:26:51 +01:00
}
2022-10-11 15:59:23 +02:00
viewport - > PlatformUserData = viewport - > PlatformHandle = nullptr ;
2018-02-27 23:26:51 +01:00
}
static void ImGui_ImplWin32_ShowWindow ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2018-02-27 23:26:51 +01:00
if ( viewport - > Flags & ImGuiViewportFlags_NoFocusOnAppearing )
2021-06-29 15:34:54 +02:00
: : ShowWindow ( vd - > Hwnd , SW_SHOWNA ) ;
2018-02-27 23:26:51 +01:00
else
2021-06-29 15:34:54 +02:00
: : ShowWindow ( vd - > Hwnd , SW_SHOW ) ;
2018-02-27 23:26:51 +01:00
}
2019-01-02 16:06:58 +01:00
static void ImGui_ImplWin32_UpdateWindow ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2023-06-15 11:26:27 +02:00
// Update Win32 parent if it changed _after_ creation
// Unlike style settings derived from configuration flags, this is more likely to change for advanced apps that are manipulating ParentViewportID manually.
HWND new_parent = ImGui_ImplWin32_GetHwndFromViewportID ( viewport - > ParentViewportId ) ;
if ( new_parent ! = vd - > HwndParent )
{
// Win32 windows can either have a "Parent" (for WS_CHILD window) or an "Owner" (which among other thing keeps window above its owner).
// Our Dear Imgui-side concept of parenting only mostly care about what Win32 call "Owner".
// The parent parameter of CreateWindowEx() sets up Parent OR Owner depending on WS_CHILD flag. In our case an Owner as we never use WS_CHILD.
// Calling ::SetParent() here would be incorrect: it will create a full child relation, alter coordinate system and clipping.
// Calling ::SetWindowLongPtr() with GWLP_HWNDPARENT seems correct although poorly documented.
// https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613
vd - > HwndParent = new_parent ;
: : SetWindowLongPtr ( vd - > Hwnd , GWLP_HWNDPARENT , ( LONG_PTR ) vd - > HwndParent ) ;
}
// (Optional) Update Win32 style if it changed _after_ creation.
// Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
2019-01-02 16:06:58 +01:00
DWORD new_style ;
DWORD new_ex_style ;
ImGui_ImplWin32_GetWin32StyleFromViewportFlags ( viewport - > Flags , & new_style , & new_ex_style ) ;
// Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
2021-06-29 15:34:54 +02:00
if ( vd - > DwStyle ! = new_style | | vd - > DwExStyle ! = new_ex_style )
2019-01-02 16:06:58 +01:00
{
2020-09-17 02:58:23 +02:00
// (Optional) Update TopMost state if it changed _after_ creation
2021-06-29 15:34:54 +02:00
bool top_most_changed = ( vd - > DwExStyle & WS_EX_TOPMOST ) ! = ( new_ex_style & WS_EX_TOPMOST ) ;
2020-09-17 02:58:23 +02:00
HWND insert_after = top_most_changed ? ( ( viewport - > Flags & ImGuiViewportFlags_TopMost ) ? HWND_TOPMOST : HWND_NOTOPMOST ) : 0 ;
UINT swp_flag = top_most_changed ? 0 : SWP_NOZORDER ;
// Apply flags and position (since it is affected by flags)
2021-06-29 15:34:54 +02:00
vd - > DwStyle = new_style ;
vd - > DwExStyle = new_ex_style ;
: : SetWindowLong ( vd - > Hwnd , GWL_STYLE , vd - > DwStyle ) ;
: : SetWindowLong ( vd - > Hwnd , GWL_EXSTYLE , vd - > DwExStyle ) ;
2019-01-02 16:06:58 +01:00
RECT rect = { ( LONG ) viewport - > Pos . x , ( LONG ) viewport - > Pos . y , ( LONG ) ( viewport - > Pos . x + viewport - > Size . x ) , ( LONG ) ( viewport - > Pos . y + viewport - > Size . y ) } ;
2021-06-29 15:34:54 +02:00
: : AdjustWindowRectEx ( & rect , vd - > DwStyle , FALSE , vd - > DwExStyle ) ; // Client to Screen
: : SetWindowPos ( vd - > Hwnd , insert_after , rect . left , rect . top , rect . right - rect . left , rect . bottom - rect . top , swp_flag | SWP_NOACTIVATE | SWP_FRAMECHANGED ) ;
: : ShowWindow ( vd - > Hwnd , SW_SHOWNA ) ; // This is necessary when we alter the style
2019-01-02 16:06:58 +01:00
viewport - > PlatformRequestMove = viewport - > PlatformRequestResize = true ;
}
}
2018-02-27 23:26:51 +01:00
static ImVec2 ImGui_ImplWin32_GetWindowPos ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2018-02-27 23:26:51 +01:00
POINT pos = { 0 , 0 } ;
2021-06-29 15:34:54 +02:00
: : ClientToScreen ( vd - > Hwnd , & pos ) ;
2018-02-27 23:26:51 +01:00
return ImVec2 ( ( float ) pos . x , ( float ) pos . y ) ;
}
static void ImGui_ImplWin32_SetWindowPos ( ImGuiViewport * viewport , ImVec2 pos )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2018-02-27 23:26:51 +01:00
RECT rect = { ( LONG ) pos . x , ( LONG ) pos . y , ( LONG ) pos . x , ( LONG ) pos . y } ;
2021-06-29 15:34:54 +02:00
: : AdjustWindowRectEx ( & rect , vd - > DwStyle , FALSE , vd - > DwExStyle ) ;
2023-04-11 16:19:59 +02:00
: : SetWindowPos ( vd - > Hwnd , nullptr , rect . left , rect . top , 0 , 0 , SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE ) ;
2018-02-27 23:26:51 +01:00
}
static ImVec2 ImGui_ImplWin32_GetWindowSize ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2018-02-27 23:26:51 +01:00
RECT rect ;
2021-06-29 15:34:54 +02:00
: : GetClientRect ( vd - > Hwnd , & rect ) ;
2018-02-27 23:26:51 +01:00
return ImVec2 ( float ( rect . right - rect . left ) , float ( rect . bottom - rect . top ) ) ;
}
static void ImGui_ImplWin32_SetWindowSize ( ImGuiViewport * viewport , ImVec2 size )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2018-02-27 23:26:51 +01:00
RECT rect = { 0 , 0 , ( LONG ) size . x , ( LONG ) size . y } ;
2021-06-29 15:34:54 +02:00
: : AdjustWindowRectEx ( & rect , vd - > DwStyle , FALSE , vd - > DwExStyle ) ; // Client to Screen
2022-10-11 15:59:23 +02:00
: : SetWindowPos ( vd - > Hwnd , nullptr , 0 , 0 , rect . right - rect . left , rect . bottom - rect . top , SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE ) ;
2018-02-27 23:26:51 +01:00
}
2018-04-25 15:15:14 +02:00
static void ImGui_ImplWin32_SetWindowFocus ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
: : BringWindowToTop ( vd - > Hwnd ) ;
: : SetForegroundWindow ( vd - > Hwnd ) ;
: : SetFocus ( vd - > Hwnd ) ;
2018-04-25 15:15:14 +02:00
}
static bool ImGui_ImplWin32_GetWindowFocus ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
return : : GetForegroundWindow ( ) = = vd - > Hwnd ;
2018-04-25 15:15:14 +02:00
}
2018-11-23 16:18:30 +01:00
static bool ImGui_ImplWin32_GetWindowMinimized ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
return : : IsIconic ( vd - > Hwnd ) ! = 0 ;
2018-11-23 16:18:30 +01:00
}
2018-02-27 23:26:51 +01:00
static void ImGui_ImplWin32_SetWindowTitle ( ImGuiViewport * viewport , const char * title )
{
2018-11-05 17:37:06 +01:00
// ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string.
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2022-10-11 15:59:23 +02:00
int n = : : MultiByteToWideChar ( CP_UTF8 , 0 , title , - 1 , nullptr , 0 ) ;
2018-11-05 17:37:06 +01:00
ImVector < wchar_t > title_w ;
title_w . resize ( n ) ;
: : MultiByteToWideChar ( CP_UTF8 , 0 , title , - 1 , title_w . Data , n ) ;
2021-06-29 15:34:54 +02:00
: : SetWindowTextW ( vd - > Hwnd , title_w . Data ) ;
2018-02-27 23:26:51 +01:00
}
2018-04-05 17:06:23 +02:00
static void ImGui_ImplWin32_SetWindowAlpha ( ImGuiViewport * viewport , float alpha )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
2018-04-05 17:06:23 +02:00
IM_ASSERT ( alpha > = 0.0f & & alpha < = 1.0f ) ;
if ( alpha < 1.0f )
{
2021-06-29 15:34:54 +02:00
DWORD style = : : GetWindowLongW ( vd - > Hwnd , GWL_EXSTYLE ) | WS_EX_LAYERED ;
: : SetWindowLongW ( vd - > Hwnd , GWL_EXSTYLE , style ) ;
: : SetLayeredWindowAttributes ( vd - > Hwnd , 0 , ( BYTE ) ( 255 * alpha ) , LWA_ALPHA ) ;
2018-04-05 17:06:23 +02:00
}
else
{
2021-06-29 15:34:54 +02:00
DWORD style = : : GetWindowLongW ( vd - > Hwnd , GWL_EXSTYLE ) & ~ WS_EX_LAYERED ;
: : SetWindowLongW ( vd - > Hwnd , GWL_EXSTYLE , style ) ;
2018-04-05 17:06:23 +02:00
}
}
2018-03-09 19:08:47 +01:00
static float ImGui_ImplWin32_GetWindowDpiScale ( ImGuiViewport * viewport )
{
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = ( ImGui_ImplWin32_ViewportData * ) viewport - > PlatformUserData ;
IM_ASSERT ( vd - > Hwnd ! = 0 ) ;
return ImGui_ImplWin32_GetDpiScaleForHwnd ( vd - > Hwnd ) ;
2018-03-09 19:08:47 +01:00
}
2018-04-23 18:27:38 +02:00
// FIXME-DPI: Testing DPI related ideas
static void ImGui_ImplWin32_OnChangedViewport ( ImGuiViewport * viewport )
{
( void ) viewport ;
#if 0
ImGuiStyle default_style ;
//default_style.WindowPadding = ImVec2(0, 0);
//default_style.WindowBorderSize = 0.0f;
//default_style.ItemSpacing.y = 3.0f;
//default_style.FramePadding = ImVec2(0, 0);
default_style . ScaleAllSizes ( viewport - > DpiScale ) ;
ImGuiStyle & style = ImGui : : GetStyle ( ) ;
style = default_style ;
# endif
}
2018-02-27 23:26:51 +01:00
static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow ( HWND hWnd , UINT msg , WPARAM wParam , LPARAM lParam )
{
if ( ImGui_ImplWin32_WndProcHandler ( hWnd , msg , wParam , lParam ) )
return true ;
if ( ImGuiViewport * viewport = ImGui : : FindViewportByPlatformHandle ( ( void * ) hWnd ) )
{
switch ( msg )
{
case WM_CLOSE :
viewport - > PlatformRequestClose = true ;
return 0 ;
case WM_MOVE :
2018-03-15 10:54:27 +01:00
viewport - > PlatformRequestMove = true ;
break ;
case WM_SIZE :
viewport - > PlatformRequestResize = true ;
2018-02-27 23:26:51 +01:00
break ;
2019-01-30 21:21:59 +01:00
case WM_MOUSEACTIVATE :
if ( viewport - > Flags & ImGuiViewportFlags_NoFocusOnClick )
return MA_NOACTIVATE ;
break ;
2018-02-27 23:26:51 +01:00
case WM_NCHITTEST :
2022-01-18 17:24:59 +01:00
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() correctly. (which is optional).
2018-04-05 12:00:07 +02:00
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
2020-03-06 17:53:09 +01:00
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
2018-02-27 23:26:51 +01:00
if ( viewport - > Flags & ImGuiViewportFlags_NoInputs )
return HTTRANSPARENT ;
break ;
}
}
return DefWindowProc ( hWnd , msg , wParam , lParam ) ;
}
2023-04-19 16:48:07 +02:00
static void ImGui_ImplWin32_InitPlatformInterface ( bool platform_has_own_dc )
2018-02-27 23:26:51 +01:00
{
WNDCLASSEX wcex ;
wcex . cbSize = sizeof ( WNDCLASSEX ) ;
2023-04-19 16:48:07 +02:00
wcex . style = CS_HREDRAW | CS_VREDRAW | ( platform_has_own_dc ? CS_OWNDC : 0 ) ;
2018-02-27 23:26:51 +01:00
wcex . lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow ;
wcex . cbClsExtra = 0 ;
wcex . cbWndExtra = 0 ;
2022-10-11 15:59:23 +02:00
wcex . hInstance = : : GetModuleHandle ( nullptr ) ;
wcex . hIcon = nullptr ;
wcex . hCursor = nullptr ;
2018-02-27 23:26:51 +01:00
wcex . hbrBackground = ( HBRUSH ) ( COLOR_BACKGROUND + 1 ) ;
2022-10-11 15:59:23 +02:00
wcex . lpszMenuName = nullptr ;
2018-02-27 23:26:51 +01:00
wcex . lpszClassName = _T ( " ImGui Platform " ) ;
2022-10-11 15:59:23 +02:00
wcex . hIconSm = nullptr ;
2018-02-27 23:26:51 +01:00
: : RegisterClassEx ( & wcex ) ;
2018-04-10 22:32:08 +02:00
ImGui_ImplWin32_UpdateMonitors ( ) ;
2018-02-27 23:26:51 +01:00
// Register platform interface (will be coupled with a renderer interface)
2018-03-18 18:44:57 +01:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
platform_io . Platform_CreateWindow = ImGui_ImplWin32_CreateWindow ;
platform_io . Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow ;
platform_io . Platform_ShowWindow = ImGui_ImplWin32_ShowWindow ;
platform_io . Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos ;
platform_io . Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos ;
platform_io . Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize ;
platform_io . Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize ;
2018-04-25 15:15:14 +02:00
platform_io . Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus ;
platform_io . Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus ;
2018-11-23 16:18:30 +01:00
platform_io . Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized ;
2018-03-18 18:44:57 +01:00
platform_io . Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle ;
2018-04-05 17:06:23 +02:00
platform_io . Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha ;
2019-01-02 16:06:58 +01:00
platform_io . Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow ;
2018-12-14 11:59:44 +01:00
platform_io . Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale ; // FIXME-DPI
2018-04-23 18:27:38 +02:00
platform_io . Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport ; // FIXME-DPI
2018-02-27 23:26:51 +01:00
2018-04-09 22:01:24 +02:00
// Register main window handle (which is owned by the main application, not by us)
2020-01-20 19:33:46 +01:00
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
2018-02-27 23:26:51 +01:00
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2021-06-29 14:53:25 +02:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2021-06-29 15:34:54 +02:00
ImGui_ImplWin32_ViewportData * vd = IM_NEW ( ImGui_ImplWin32_ViewportData ) ( ) ;
vd - > Hwnd = bd - > hWnd ;
vd - > HwndOwned = false ;
main_viewport - > PlatformUserData = vd ;
2021-06-29 14:53:25 +02:00
main_viewport - > PlatformHandle = ( void * ) bd - > hWnd ;
2018-02-27 23:26:51 +01:00
}
static void ImGui_ImplWin32_ShutdownPlatformInterface ( )
{
2022-10-11 15:59:23 +02:00
: : UnregisterClass ( _T ( " ImGui Platform " ) , : : GetModuleHandle ( nullptr ) ) ;
2021-10-15 17:16:26 +02:00
ImGui : : DestroyPlatformWindows ( ) ;
2018-02-27 23:26:51 +01:00
}
2020-02-17 18:33:59 +01:00
2020-02-17 11:11:08 +01:00
//---------------------------------------------------------------------------------------------------------
2023-07-13 11:27:52 +02:00
# endif // #ifndef IMGUI_DISABLE