2020-10-12 18:34:22 +03:00
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
2018-06-08 20:37:33 +03:00
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
2018-06-11 13:33:51 +03:00
// Implemented features:
2020-02-17 12:11:26 +03:00
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
2018-06-11 13:33:51 +03:00
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
2018-06-30 15:33:45 +03:00
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
2019-01-15 23:17:48 +03:00
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
2018-06-11 13:33:51 +03:00
2021-06-08 19:35:35 +03:00
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
2021-05-27 14:59:35 +03: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.
2020-10-14 13:22:53 +03:00
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
2018-06-08 20:37:33 +03:00
# include "imgui.h"
# include "imgui_impl_win32.h"
2018-08-09 18:32:31 +03:00
# ifndef WIN32_LEAN_AND_MEAN
2018-06-08 20:37:33 +03:00
# define WIN32_LEAN_AND_MEAN
2018-08-09 18:32:31 +03:00
# endif
2018-06-08 20:37:33 +03:00
# include <windows.h>
# include <tchar.h>
2021-02-18 17:51:07 +03:00
# include <dwmapi.h>
// Configuration flags to add in your imconfig.h file:
2021-06-08 19:35:35 +03: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-06-08 20:37:33 +03:00
2021-01-25 18:19:43 +03:00
// Using XInput for gamepad (will load DLL dynamically)
2020-01-14 16:58:32 +03:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-04-26 10:29:38 +03:00
# include <xinput.h>
2021-01-23 08:23:59 +03:00
typedef DWORD ( WINAPI * PFN_XInputGetCapabilities ) ( DWORD , DWORD , XINPUT_CAPABILITIES * ) ;
typedef DWORD ( WINAPI * PFN_XInputGetState ) ( DWORD , XINPUT_STATE * ) ;
2020-01-14 16:58:32 +03:00
# endif
2018-06-08 20:37:33 +03:00
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
2021-06-28 17:52:10 +03: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-06-08 19:35:35 +03:00
// 2021-06-08: Fix 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 18:48:10 +03:00
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
2021-02-18 17:51:07 +03: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 21:41:02 +03: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 18:19:43 +03:00
// 2021-01-25: Inputs: Dynamically loading XInput DLL.
2020-12-04 13:48:17 +03:00
// 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.
2020-03-03 19:45:06 +03:00
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
2020-02-17 13:11:08 +03:00
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
2020-01-14 16:58:32 +03:00
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
2019-12-05 17:43:05 +03:00
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
2019-05-11 11:33:56 +03:00
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
2019-01-17 18:55:23 +03: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 23:17:48 +03:00
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
2018-11-30 20:18:15 +03:00
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
2018-06-29 17:30:41 +03:00
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
2018-06-11 18:34:56 +03:00
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
2018-06-08 20:37:33 +03:00
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 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-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
// 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 19:56:17 +03:00
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
2018-06-08 20:37:33 +03:00
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
2021-06-28 17:52:10 +03:00
struct ImGui_ImplWin32_Data
{
HWND hWnd ;
INT64 Time ;
INT64 TicksPerSecond ;
ImGuiMouseCursor LastMouseCursor ;
bool HasGamepad ;
bool WantUpdateHasGamepad ;
2018-06-08 20:37:33 +03:00
2021-01-23 08:23:59 +03:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-06-28 17:52:10 +03:00
HMODULE XInputDLL ;
PFN_XInputGetCapabilities XInputGetCapabilities ;
PFN_XInputGetState XInputGetState ;
2021-01-25 18:19:43 +03:00
# endif
2021-01-23 08:23:59 +03:00
2021-06-28 17:52:10 +03:00
ImGui_ImplWin32_Data ( ) { memset ( this , 0 , sizeof ( * this ) ) ; }
} ;
2021-06-29 17:42:13 +03: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 16:22:15 +03:00
static ImGui_ImplWin32_Data * ImGui_ImplWin32_GetBackendData ( )
{
return ImGui : : GetCurrentContext ( ) ? ( ImGui_ImplWin32_Data * ) ImGui : : GetIO ( ) . BackendPlatformUserData : NULL ;
}
2021-06-28 17:52:10 +03:00
2018-06-08 20:37:33 +03:00
// Functions
bool ImGui_ImplWin32_Init ( void * hwnd )
{
2021-06-28 17:52:10 +03:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
IM_ASSERT ( io . BackendPlatformUserData = = NULL & & " Already initialized a platform backend! " ) ;
INT64 perf_frequency , perf_counter ;
if ( ! : : QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & perf_frequency ) )
2018-06-08 20:37:33 +03:00
return false ;
2021-06-28 17:52:10 +03:00
if ( ! : : QueryPerformanceCounter ( ( LARGE_INTEGER * ) & perf_counter ) )
2018-06-08 20:37:33 +03:00
return false ;
2021-06-30 16:22:15 +03:00
// Setup backend capabilities flags
ImGui_ImplWin32_Data * bd = IM_NEW ( ImGui_ImplWin32_Data ) ( ) ;
io . BackendPlatformUserData = ( void * ) bd ;
io . BackendPlatformName = " imgui_impl_win32 " ;
io . BackendFlags | = ImGuiBackendFlags_HasMouseCursors ; // We can honor GetMouseCursor() values (optional)
io . BackendFlags | = ImGuiBackendFlags_HasSetMousePos ; // We can honor io.WantSetMousePos requests (optional, rarely used)
2021-06-28 17:52:10 +03:00
bd - > hWnd = ( HWND ) hwnd ;
bd - > WantUpdateHasGamepad = true ;
bd - > TicksPerSecond = perf_frequency ;
bd - > Time = perf_counter ;
bd - > LastMouseCursor = ImGuiMouseCursor_COUNT ;
2018-06-08 20:37:33 +03:00
io . ImeWindowHandle = hwnd ;
2021-03-04 13:03:40 +03:00
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
2018-06-08 20:37:33 +03:00
io . KeyMap [ ImGuiKey_Tab ] = VK_TAB ;
io . KeyMap [ ImGuiKey_LeftArrow ] = VK_LEFT ;
io . KeyMap [ ImGuiKey_RightArrow ] = VK_RIGHT ;
io . KeyMap [ ImGuiKey_UpArrow ] = VK_UP ;
io . KeyMap [ ImGuiKey_DownArrow ] = VK_DOWN ;
io . KeyMap [ ImGuiKey_PageUp ] = VK_PRIOR ;
io . KeyMap [ ImGuiKey_PageDown ] = VK_NEXT ;
io . KeyMap [ ImGuiKey_Home ] = VK_HOME ;
io . KeyMap [ ImGuiKey_End ] = VK_END ;
io . KeyMap [ ImGuiKey_Insert ] = VK_INSERT ;
io . KeyMap [ ImGuiKey_Delete ] = VK_DELETE ;
io . KeyMap [ ImGuiKey_Backspace ] = VK_BACK ;
io . KeyMap [ ImGuiKey_Space ] = VK_SPACE ;
io . KeyMap [ ImGuiKey_Enter ] = VK_RETURN ;
io . KeyMap [ ImGuiKey_Escape ] = VK_ESCAPE ;
2019-07-22 04:39:50 +03:00
io . KeyMap [ ImGuiKey_KeyPadEnter ] = VK_RETURN ;
2018-06-08 20:37:33 +03:00
io . KeyMap [ ImGuiKey_A ] = ' A ' ;
io . KeyMap [ ImGuiKey_C ] = ' C ' ;
io . KeyMap [ ImGuiKey_V ] = ' V ' ;
io . KeyMap [ ImGuiKey_X ] = ' X ' ;
io . KeyMap [ ImGuiKey_Y ] = ' Y ' ;
io . KeyMap [ ImGuiKey_Z ] = ' Z ' ;
2021-01-25 18:19:43 +03:00
// Dynamically load XInput library
2021-01-23 08:23:59 +03:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-01-25 18:19:43 +03:00
const char * xinput_dll_names [ ] =
2021-01-23 08:23:59 +03:00
{
2021-01-25 18:19:43 +03: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 08:23:59 +03:00
{
2021-06-28 17:52:10 +03:00
bd - > XInputDLL = dll ;
bd - > XInputGetCapabilities = ( PFN_XInputGetCapabilities ) : : GetProcAddress ( dll , " XInputGetCapabilities " ) ;
bd - > XInputGetState = ( PFN_XInputGetState ) : : GetProcAddress ( dll , " XInputGetState " ) ;
2021-01-23 08:23:59 +03:00
break ;
}
# endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-02-25 15:04:07 +03:00
2018-06-08 20:37:33 +03:00
return true ;
}
void ImGui_ImplWin32_Shutdown ( )
{
2021-06-28 17:52:10 +03:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2021-01-25 18:19:43 +03:00
// Unload XInput library
2021-01-23 08:23:59 +03:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-06-28 17:52:10 +03:00
if ( bd - > XInputDLL )
: : FreeLibrary ( bd - > XInputDLL ) ;
2021-01-23 08:23:59 +03:00
# endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2021-02-25 15:04:07 +03:00
2021-06-28 17:52:10 +03:00
io . BackendPlatformName = NULL ;
io . BackendPlatformUserData = NULL ;
2021-06-30 16:22:15 +03:00
IM_DELETE ( bd ) ;
2018-06-08 20:37:33 +03:00
}
static bool ImGui_ImplWin32_UpdateMouseCursor ( )
{
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
: : SetCursor ( NULL ) ;
}
else
{
// Show OS mouse cursor
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 13:16:17 +03:00
case ImGuiMouseCursor_Hand : win32_cursor = IDC_HAND ; break ;
2019-12-02 11:52:06 +03:00
case ImGuiMouseCursor_NotAllowed : win32_cursor = IDC_NO ; break ;
2018-06-08 20:37:33 +03:00
}
: : SetCursor ( : : LoadCursor ( NULL , win32_cursor ) ) ;
}
return true ;
}
static void ImGui_ImplWin32_UpdateMousePos ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 17:52:10 +03:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
IM_ASSERT ( bd - > hWnd ! = 0 ) ;
2018-06-08 20:37:33 +03:00
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if ( io . WantSetMousePos )
{
POINT pos = { ( int ) io . MousePos . x , ( int ) io . MousePos . y } ;
2021-06-28 17:52:10 +03:00
if ( : : ClientToScreen ( bd - > hWnd , & pos ) )
2020-12-04 13:48:17 +03:00
: : SetCursorPos ( pos . x , pos . y ) ;
2018-06-08 20:37:33 +03:00
}
// Set mouse position
io . MousePos = ImVec2 ( - FLT_MAX , - FLT_MAX ) ;
POINT pos ;
2019-01-17 13:45:32 +03:00
if ( HWND active_window = : : GetForegroundWindow ( ) )
2021-06-28 17:52:10 +03:00
if ( active_window = = bd - > hWnd | | : : IsChild ( active_window , bd - > hWnd ) )
if ( : : GetCursorPos ( & pos ) & & : : ScreenToClient ( bd - > hWnd , & pos ) )
2019-01-17 13:45:32 +03:00
io . MousePos = ImVec2 ( ( float ) pos . x , ( float ) pos . y ) ;
2018-06-08 20:37:33 +03:00
}
2019-01-15 23:17:48 +03:00
// Gamepad navigation mapping
2019-02-14 20:55:08 +03:00
static void ImGui_ImplWin32_UpdateGamepads ( )
2019-01-15 23:17:48 +03:00
{
2020-01-14 16:58:32 +03:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 23:17:48 +03:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 17:52:10 +03:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2019-01-15 23:17:48 +03:00
memset ( io . NavInputs , 0 , sizeof ( io . NavInputs ) ) ;
if ( ( io . ConfigFlags & ImGuiConfigFlags_NavEnableGamepad ) = = 0 )
return ;
2021-01-25 18:19:43 +03:00
2019-01-15 23:17:48 +03: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 17:52:10 +03:00
if ( bd - > WantUpdateHasGamepad )
2019-01-15 23:17:48 +03:00
{
2021-01-23 08:23:59 +03:00
XINPUT_CAPABILITIES caps ;
2021-06-28 17:52:10 +03:00
bd - > HasGamepad = bd - > XInputGetCapabilities ? ( bd - > XInputGetCapabilities ( 0 , XINPUT_FLAG_GAMEPAD , & caps ) = = ERROR_SUCCESS ) : false ;
bd - > WantUpdateHasGamepad = false ;
2019-01-15 23:17:48 +03:00
}
2021-01-25 18:19:43 +03:00
2019-01-15 23:17:48 +03:00
io . BackendFlags & = ~ ImGuiBackendFlags_HasGamepad ;
2021-01-25 18:19:43 +03:00
XINPUT_STATE xinput_state ;
2021-06-28 17:52:10 +03:00
if ( bd - > HasGamepad & & bd - > XInputGetState & & bd - > XInputGetState ( 0 , & xinput_state ) = = ERROR_SUCCESS )
2019-01-15 23:17:48 +03:00
{
2021-01-25 18:19:43 +03:00
const XINPUT_GAMEPAD & gamepad = xinput_state . Gamepad ;
2019-01-15 23:17:48 +03:00
io . BackendFlags | = ImGuiBackendFlags_HasGamepad ;
2021-01-25 18:19:43 +03:00
2019-01-15 23:17:48 +03:00
# define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
2021-01-25 18:19:43 +03:00
# define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
2019-01-15 23:17:48 +03:00
MAP_BUTTON ( ImGuiNavInput_Activate , XINPUT_GAMEPAD_A ) ; // Cross / A
MAP_BUTTON ( ImGuiNavInput_Cancel , XINPUT_GAMEPAD_B ) ; // Circle / B
MAP_BUTTON ( ImGuiNavInput_Menu , XINPUT_GAMEPAD_X ) ; // Square / X
MAP_BUTTON ( ImGuiNavInput_Input , XINPUT_GAMEPAD_Y ) ; // Triangle / Y
MAP_BUTTON ( ImGuiNavInput_DpadLeft , XINPUT_GAMEPAD_DPAD_LEFT ) ; // D-Pad Left
MAP_BUTTON ( ImGuiNavInput_DpadRight , XINPUT_GAMEPAD_DPAD_RIGHT ) ; // D-Pad Right
MAP_BUTTON ( ImGuiNavInput_DpadUp , XINPUT_GAMEPAD_DPAD_UP ) ; // D-Pad Up
MAP_BUTTON ( ImGuiNavInput_DpadDown , XINPUT_GAMEPAD_DPAD_DOWN ) ; // D-Pad Down
MAP_BUTTON ( ImGuiNavInput_FocusPrev , XINPUT_GAMEPAD_LEFT_SHOULDER ) ; // L1 / LB
MAP_BUTTON ( ImGuiNavInput_FocusNext , XINPUT_GAMEPAD_RIGHT_SHOULDER ) ; // R1 / RB
MAP_BUTTON ( ImGuiNavInput_TweakSlow , XINPUT_GAMEPAD_LEFT_SHOULDER ) ; // L1 / LB
MAP_BUTTON ( ImGuiNavInput_TweakFast , XINPUT_GAMEPAD_RIGHT_SHOULDER ) ; // R1 / RB
MAP_ANALOG ( ImGuiNavInput_LStickLeft , gamepad . sThumbLX , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32768 ) ;
MAP_ANALOG ( ImGuiNavInput_LStickRight , gamepad . sThumbLX , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiNavInput_LStickUp , gamepad . sThumbLY , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiNavInput_LStickDown , gamepad . sThumbLY , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32767 ) ;
# undef MAP_BUTTON
# undef MAP_ANALOG
}
2020-01-14 16:58:32 +03:00
# endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 23:17:48 +03:00
}
2018-06-08 20:37:33 +03:00
void ImGui_ImplWin32_NewFrame ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 17:52:10 +03:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2021-06-29 18:53:41 +03:00
IM_ASSERT ( bd ! = NULL & & " Did you call ImGui_ImplWin32_Init()? " ) ;
2018-06-08 20:37:33 +03:00
// Setup display size (every frame to accommodate for window resizing)
2020-12-04 13:48:17 +03:00
RECT rect = { 0 , 0 , 0 , 0 } ;
2021-06-28 17:52:10 +03:00
: : GetClientRect ( bd - > hWnd , & rect ) ;
2018-06-08 20:37:33 +03:00
io . DisplaySize = ImVec2 ( ( float ) ( rect . right - rect . left ) , ( float ) ( rect . bottom - rect . top ) ) ;
// Setup time step
2020-12-04 13:48:17 +03:00
INT64 current_time = 0 ;
2020-06-30 16:31:54 +03:00
: : QueryPerformanceCounter ( ( LARGE_INTEGER * ) & current_time ) ;
2021-06-28 17:52:10 +03:00
io . DeltaTime = ( float ) ( current_time - bd - > Time ) / bd - > TicksPerSecond ;
bd - > Time = current_time ;
2018-06-08 20:37:33 +03:00
// Read keyboard modifiers inputs
io . KeyCtrl = ( : : GetKeyState ( VK_CONTROL ) & 0x8000 ) ! = 0 ;
io . KeyShift = ( : : GetKeyState ( VK_SHIFT ) & 0x8000 ) ! = 0 ;
io . KeyAlt = ( : : GetKeyState ( VK_MENU ) & 0x8000 ) ! = 0 ;
2020-01-17 17:18:33 +03:00
io . KeySuper = false ;
2018-06-08 20:37:33 +03:00
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
// Update OS mouse position
ImGui_ImplWin32_UpdateMousePos ( ) ;
// Update OS mouse cursor with the cursor requested by imgui
ImGuiMouseCursor mouse_cursor = io . MouseDrawCursor ? ImGuiMouseCursor_None : ImGui : : GetMouseCursor ( ) ;
2021-06-28 17:52:10 +03:00
if ( bd - > LastMouseCursor ! = mouse_cursor )
2018-06-08 20:37:33 +03:00
{
2021-06-28 17:52:10 +03:00
bd - > LastMouseCursor = mouse_cursor ;
2018-06-08 20:37:33 +03:00
ImGui_ImplWin32_UpdateMouseCursor ( ) ;
}
2019-01-15 23:17:48 +03:00
2019-04-23 13:26:14 +03:00
// Update game controllers (if enabled and available)
2019-02-14 20:55:08 +03:00
ImGui_ImplWin32_UpdateGamepads ( ) ;
2018-06-08 20:37:33 +03: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 23:17:48 +03:00
# ifndef DBT_DEVNODES_CHANGED
# define DBT_DEVNODES_CHANGED 0x0007
# endif
2018-06-08 20:37:33 +03:00
2020-02-17 12:11:26 +03:00
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
// Call from your application's message handler.
2020-10-12 18:34:22 +03: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.
2018-06-08 20:37:33 +03:00
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
2020-02-17 12:11:26 +03: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 12:10:17 +03: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-06-08 20:37:33 +03: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 12:11:26 +03: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
2018-06-21 13:04:00 +03:00
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler ( HWND hwnd , UINT msg , WPARAM wParam , LPARAM lParam )
2018-06-08 20:37:33 +03:00
{
if ( ImGui : : GetCurrentContext ( ) = = NULL )
return 0 ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
2021-06-28 17:52:10 +03:00
ImGui_ImplWin32_Data * bd = ImGui_ImplWin32_GetBackendData ( ) ;
2018-06-08 20:37:33 +03:00
switch ( msg )
{
case WM_LBUTTONDOWN : case WM_LBUTTONDBLCLK :
case WM_RBUTTONDOWN : case WM_RBUTTONDBLCLK :
case WM_MBUTTONDOWN : case WM_MBUTTONDBLCLK :
2019-01-17 18:55:23 +03:00
case WM_XBUTTONDOWN : case WM_XBUTTONDBLCLK :
2018-06-08 20:37:33 +03:00
{
int button = 0 ;
2019-01-17 18:55:23 +03: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 ; }
2018-06-08 20:37:33 +03:00
if ( ! ImGui : : IsAnyMouseDown ( ) & & : : GetCapture ( ) = = NULL )
: : SetCapture ( hwnd ) ;
io . MouseDown [ button ] = true ;
return 0 ;
}
case WM_LBUTTONUP :
case WM_RBUTTONUP :
case WM_MBUTTONUP :
2019-01-17 18:55:23 +03:00
case WM_XBUTTONUP :
2018-06-08 20:37:33 +03:00
{
int button = 0 ;
2019-01-17 18:55:23 +03: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 ; }
2018-06-08 20:37:33 +03:00
io . MouseDown [ button ] = false ;
if ( ! ImGui : : IsAnyMouseDown ( ) & & : : GetCapture ( ) = = hwnd )
: : ReleaseCapture ( ) ;
return 0 ;
}
case WM_MOUSEWHEEL :
2018-06-11 18:34:56 +03:00
io . MouseWheel + = ( float ) GET_WHEEL_DELTA_WPARAM ( wParam ) / ( float ) WHEEL_DELTA ;
2018-06-08 20:37:33 +03:00
return 0 ;
case WM_MOUSEHWHEEL :
2018-06-11 18:34:56 +03:00
io . MouseWheelH + = ( float ) GET_WHEEL_DELTA_WPARAM ( wParam ) / ( float ) WHEEL_DELTA ;
2018-06-08 20:37:33 +03:00
return 0 ;
case WM_KEYDOWN :
case WM_SYSKEYDOWN :
if ( wParam < 256 )
io . KeysDown [ wParam ] = 1 ;
return 0 ;
case WM_KEYUP :
case WM_SYSKEYUP :
if ( wParam < 256 )
io . KeysDown [ wParam ] = 0 ;
return 0 ;
2021-03-23 18:48:10 +03:00
case WM_KILLFOCUS :
memset ( io . KeysDown , 0 , sizeof ( io . KeysDown ) ) ;
return 0 ;
2018-06-08 20:37:33 +03:00
case WM_CHAR :
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
2019-05-08 05:10:20 +03:00
if ( wParam > 0 & & wParam < 0x10000 )
io . AddInputCharacterUTF16 ( ( unsigned short ) wParam ) ;
2018-06-08 20:37:33 +03:00
return 0 ;
case WM_SETCURSOR :
if ( LOWORD ( lParam ) = = HTCLIENT & & ImGui_ImplWin32_UpdateMouseCursor ( ) )
return 1 ;
return 0 ;
2019-01-15 23:17:48 +03:00
case WM_DEVICECHANGE :
if ( ( UINT ) wParam = = DBT_DEVNODES_CHANGED )
2021-06-28 17:52:10 +03:00
bd - > WantUpdateHasGamepad = true ;
2019-01-15 23:17:48 +03:00
return 0 ;
2018-06-08 20:37:33 +03:00
}
return 0 ;
}
2020-02-17 13:11:08 +03:00
//--------------------------------------------------------------------------------------------------------
// DPI-related helpers (optional)
//--------------------------------------------------------------------------------------------------------
// - 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.
//---------------------------------------------------------------------------------------------------------
// 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 18:34:22 +03:00
// If you are trying to implement your own backend for your own engine, you may ignore that noise.
2020-02-17 13:11:08 +03:00
//---------------------------------------------------------------------------------------------------------
2021-06-08 19:35:35 +03: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 )
2020-02-17 13:11:08 +03:00
{
2021-06-08 19:35:35 +03:00
typedef LONG ( WINAPI * PFN_RtlVerifyVersionInfo ) ( OSVERSIONINFOEXW * , ULONG , ULONGLONG ) ;
static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL ;
if ( RtlVerifyVersionInfoFn = = NULL )
if ( HMODULE ntdllModule = : : GetModuleHandleA ( " ntdll.dll " ) )
RtlVerifyVersionInfoFn = ( PFN_RtlVerifyVersionInfo ) GetProcAddress ( ntdllModule , " RtlVerifyVersionInfo " ) ;
2021-06-24 16:13:21 +03:00
if ( RtlVerifyVersionInfoFn = = NULL )
return FALSE ;
2021-06-08 19:35:35 +03:00
2021-07-05 17:46:12 +03:00
RTL_OSVERSIONINFOEXW versionInfo = { } ;
ULONGLONG conditionMask = 0 ;
versionInfo . dwOSVersionInfoSize = sizeof ( RTL_OSVERSIONINFOEXW ) ;
versionInfo . dwMajorVersion = major ;
2021-06-08 19:35:35 +03: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 ;
2020-02-17 13:11:08 +03:00
}
2021-06-08 19:35:35 +03: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
2020-02-17 13:11:08 +03: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
# ifndef _DPI_AWARENESS_CONTEXTS_
DECLARE_HANDLE ( DPI_AWARENESS_CONTEXT ) ;
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
# endif
# ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
# endif
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)
// Helper function to enable DPI awareness without setting up a manifest
void ImGui_ImplWin32_EnableDpiAwareness ( )
{
2021-06-08 19:35:35 +03:00
if ( _IsWindows10OrGreater ( ) )
2020-02-17 13:11:08 +03: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 19:35:35 +03:00
if ( _IsWindows8Point1OrGreater ( ) )
2020-02-17 13:11:08 +03:00
{
static HINSTANCE shcore_dll = : : LoadLibraryA ( " shcore.dll " ) ; // Reference counted per-process
if ( PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = ( PFN_SetProcessDpiAwareness ) : : GetProcAddress ( shcore_dll , " SetProcessDpiAwareness " ) )
{
SetProcessDpiAwarenessFn ( PROCESS_PER_MONITOR_DPI_AWARE ) ;
return ;
}
}
2020-05-04 21:46:20 +03:00
# if _WIN32_WINNT >= 0x0600
: : SetProcessDPIAware ( ) ;
# endif
2020-02-17 13:11:08 +03:00
}
2020-04-19 18:52:09 +03:00
# if defined(_MSC_VER) && !defined(NOGDI)
2021-02-18 17:51:07 +03:00
# pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
2020-02-17 13:11:08 +03:00
# endif
float ImGui_ImplWin32_GetDpiScaleForMonitor ( void * monitor )
{
UINT xdpi = 96 , ydpi = 96 ;
2021-06-08 19:35:35 +03:00
if ( _IsWindows8Point1OrGreater ( ) )
2020-02-17 13:11:08 +03:00
{
2021-06-08 19:35:35 +03:00
static HINSTANCE shcore_dll = : : LoadLibraryA ( " shcore.dll " ) ; // Reference counted per-process
static PFN_GetDpiForMonitor GetDpiForMonitorFn = NULL ;
if ( GetDpiForMonitorFn = = NULL & & shcore_dll ! = NULL )
GetDpiForMonitorFn = ( PFN_GetDpiForMonitor ) : : GetProcAddress ( shcore_dll , " GetDpiForMonitor " ) ;
if ( GetDpiForMonitorFn ! = NULL )
{
GetDpiForMonitorFn ( ( HMONITOR ) monitor , MDT_EFFECTIVE_DPI , & xdpi , & ydpi ) ;
IM_ASSERT ( xdpi = = ydpi ) ; // Please contact me if you hit this assert!
return xdpi / 96.0f ;
}
2020-02-17 13:11:08 +03:00
}
2020-04-19 18:52:09 +03:00
# ifndef NOGDI
2021-06-08 19:35:35 +03:00
const HDC dc = : : GetDC ( NULL ) ;
xdpi = : : GetDeviceCaps ( dc , LOGPIXELSX ) ;
ydpi = : : GetDeviceCaps ( dc , LOGPIXELSY ) ;
2020-02-17 13:11:08 +03:00
IM_ASSERT ( xdpi = = ydpi ) ; // Please contact me if you hit this assert!
2021-06-08 19:35:35 +03:00
: : ReleaseDC ( NULL , dc ) ;
# endif
2020-02-17 13:11:08 +03:00
return xdpi / 96.0f ;
}
float ImGui_ImplWin32_GetDpiScaleForHwnd ( void * hwnd )
{
HMONITOR monitor = : : MonitorFromWindow ( ( HWND ) hwnd , MONITOR_DEFAULTTONEAREST ) ;
return ImGui_ImplWin32_GetDpiScaleForMonitor ( monitor ) ;
}
//---------------------------------------------------------------------------------------------------------
2021-02-18 17:51:07 +03:00
// Transparency related helpers (optional)
//--------------------------------------------------------------------------------------------------------
# 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 )
{
2021-06-08 19:35:35 +03:00
if ( ! _IsWindowsVistaOrGreater ( ) )
2021-02-18 17:51:07 +03:00
return ;
BOOL composition ;
if ( FAILED ( : : DwmIsCompositionEnabled ( & composition ) ) | | ! composition )
return ;
BOOL opaque ;
DWORD color ;
2021-06-08 19:35:35 +03:00
if ( _IsWindows8OrGreater ( ) | | ( SUCCEEDED ( : : DwmGetColorizationColor ( & color , & opaque ) ) & & ! opaque ) )
2021-02-18 17:51:07 +03:00
{
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 ) ;
}
}
//---------------------------------------------------------------------------------------------------------