imgui_impl_win32.cpp 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. // dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
  2. // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
  3. // Implemented features:
  4. // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
  5. // [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]
  6. // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
  7. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
  8. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
  9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
  10. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
  11. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
  12. // Read online: https://github.com/ocornut/imgui/tree/master/docs
  13. #include "imgui.h"
  14. #include "imgui_impl_win32.h"
  15. #ifndef WIN32_LEAN_AND_MEAN
  16. #define WIN32_LEAN_AND_MEAN
  17. #endif
  18. #include <windows.h>
  19. #include <tchar.h>
  20. #include <dwmapi.h>
  21. // Configuration flags to add in your imconfig.h file:
  22. //#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.
  23. // Using XInput for gamepad (will load DLL dynamically)
  24. #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  25. #include <xinput.h>
  26. typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
  27. typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
  28. #endif
  29. // CHANGELOG
  30. // (minor and older changes stripped away, please see git history for details)
  31. // 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
  32. // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
  33. // 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.
  34. // 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.
  35. // 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.
  36. // 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).
  37. // 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).
  38. // 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).
  39. // 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
  40. // 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
  41. // 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.
  42. // 2021-01-25: Inputs: Dynamically loading XInput DLL.
  43. // 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.
  44. // 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
  45. // 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
  46. // 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
  47. // 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
  48. // 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
  49. // 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
  50. // 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
  51. // 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
  52. // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
  53. // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
  54. // 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
  55. // 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
  56. // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
  57. // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
  58. // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
  59. // 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
  60. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
  61. // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
  62. // 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
  63. // 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
  64. // 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
  65. // 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
  66. // 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
  67. // Forward Declarations
  68. static void ImGui_ImplWin32_InitPlatformInterface();
  69. static void ImGui_ImplWin32_ShutdownPlatformInterface();
  70. static void ImGui_ImplWin32_UpdateMonitors();
  71. struct ImGui_ImplWin32_Data
  72. {
  73. HWND hWnd;
  74. HWND MouseHwnd;
  75. bool MouseTracked;
  76. INT64 Time;
  77. INT64 TicksPerSecond;
  78. ImGuiMouseCursor LastMouseCursor;
  79. bool HasGamepad;
  80. bool WantUpdateHasGamepad;
  81. bool WantUpdateMonitors;
  82. #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  83. HMODULE XInputDLL;
  84. PFN_XInputGetCapabilities XInputGetCapabilities;
  85. PFN_XInputGetState XInputGetState;
  86. #endif
  87. ImGui_ImplWin32_Data() { memset(this, 0, sizeof(*this)); }
  88. };
  89. // Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
  90. // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
  91. // FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
  92. // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
  93. static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData()
  94. {
  95. return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : NULL;
  96. }
  97. // Functions
  98. bool ImGui_ImplWin32_Init(void* hwnd)
  99. {
  100. ImGuiIO& io = ImGui::GetIO();
  101. IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
  102. INT64 perf_frequency, perf_counter;
  103. if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&perf_frequency))
  104. return false;
  105. if (!::QueryPerformanceCounter((LARGE_INTEGER*)&perf_counter))
  106. return false;
  107. // Setup backend capabilities flags
  108. ImGui_ImplWin32_Data* bd = IM_NEW(ImGui_ImplWin32_Data)();
  109. io.BackendPlatformUserData = (void*)bd;
  110. io.BackendPlatformName = "imgui_impl_win32";
  111. io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
  112. io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
  113. io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
  114. io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
  115. bd->hWnd = (HWND)hwnd;
  116. bd->WantUpdateHasGamepad = true;
  117. bd->WantUpdateMonitors = true;
  118. bd->TicksPerSecond = perf_frequency;
  119. bd->Time = perf_counter;
  120. bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
  121. // Our mouse update function expect PlatformHandle to be filled for the main viewport
  122. ImGuiViewport* main_viewport = ImGui::GetMainViewport();
  123. main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd;
  124. if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
  125. ImGui_ImplWin32_InitPlatformInterface();
  126. // Dynamically load XInput library
  127. #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  128. const char* xinput_dll_names[] =
  129. {
  130. "xinput1_4.dll", // Windows 8+
  131. "xinput1_3.dll", // DirectX SDK
  132. "xinput9_1_0.dll", // Windows Vista, Windows 7
  133. "xinput1_2.dll", // DirectX SDK
  134. "xinput1_1.dll" // DirectX SDK
  135. };
  136. for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)
  137. if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))
  138. {
  139. bd->XInputDLL = dll;
  140. bd->XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
  141. bd->XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
  142. break;
  143. }
  144. #endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  145. return true;
  146. }
  147. void ImGui_ImplWin32_Shutdown()
  148. {
  149. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  150. IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
  151. ImGuiIO& io = ImGui::GetIO();
  152. ImGui_ImplWin32_ShutdownPlatformInterface();
  153. // Unload XInput library
  154. #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  155. if (bd->XInputDLL)
  156. ::FreeLibrary(bd->XInputDLL);
  157. #endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  158. io.BackendPlatformName = NULL;
  159. io.BackendPlatformUserData = NULL;
  160. IM_DELETE(bd);
  161. }
  162. static bool ImGui_ImplWin32_UpdateMouseCursor()
  163. {
  164. ImGuiIO& io = ImGui::GetIO();
  165. if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
  166. return false;
  167. ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
  168. if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
  169. {
  170. // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
  171. ::SetCursor(NULL);
  172. }
  173. else
  174. {
  175. // Show OS mouse cursor
  176. LPTSTR win32_cursor = IDC_ARROW;
  177. switch (imgui_cursor)
  178. {
  179. case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break;
  180. case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break;
  181. case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break;
  182. case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break;
  183. case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break;
  184. case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break;
  185. case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break;
  186. case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break;
  187. case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break;
  188. }
  189. ::SetCursor(::LoadCursor(NULL, win32_cursor));
  190. }
  191. return true;
  192. }
  193. static bool IsVkDown(int vk)
  194. {
  195. return (::GetKeyState(vk) & 0x8000) != 0;
  196. }
  197. static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)
  198. {
  199. ImGuiIO& io = ImGui::GetIO();
  200. io.AddKeyEvent(key, down);
  201. io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code)
  202. IM_UNUSED(native_scancode);
  203. }
  204. static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
  205. {
  206. // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one.
  207. if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT))
  208. ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);
  209. if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT))
  210. ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);
  211. // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW).
  212. if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN))
  213. ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);
  214. if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN))
  215. ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);
  216. }
  217. static void ImGui_ImplWin32_UpdateKeyModifiers()
  218. {
  219. ImGuiIO& io = ImGui::GetIO();
  220. ImGuiKeyModFlags key_mods =
  221. ((IsVkDown(VK_LCONTROL) || IsVkDown(VK_RCONTROL)) ? ImGuiKeyModFlags_Ctrl : 0) |
  222. ((IsVkDown(VK_LSHIFT) || IsVkDown(VK_RSHIFT)) ? ImGuiKeyModFlags_Shift : 0) |
  223. ((IsVkDown(VK_LMENU) || IsVkDown(VK_RMENU)) ? ImGuiKeyModFlags_Alt : 0) |
  224. ((IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN)) ? ImGuiKeyModFlags_Super : 0);
  225. io.AddKeyModsEvent(key_mods);
  226. }
  227. // This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
  228. // Because of that, it is a little more complicated than your typical single-viewport binding code!
  229. static void ImGui_ImplWin32_UpdateMousePos()
  230. {
  231. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  232. ImGuiIO& io = ImGui::GetIO();
  233. IM_ASSERT(bd->hWnd != 0);
  234. const ImVec2 mouse_pos_prev = io.MousePos;
  235. io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
  236. io.MouseHoveredViewport = 0;
  237. // Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing)
  238. HWND focused_window = ::GetForegroundWindow();
  239. HWND hovered_window = bd->MouseHwnd;
  240. HWND mouse_window = NULL;
  241. if (hovered_window && (hovered_window == bd->hWnd || ::IsChild(hovered_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)hovered_window)))
  242. mouse_window = hovered_window;
  243. else if (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)focused_window)))
  244. mouse_window = focused_window;
  245. if (mouse_window == NULL)
  246. return;
  247. // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
  248. // (When multi-viewports are enabled, all Dear ImGui positions are same as OS positions)
  249. if (io.WantSetMousePos)
  250. {
  251. POINT pos = { (int)mouse_pos_prev.x, (int)mouse_pos_prev.y };
  252. if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
  253. ::ClientToScreen(mouse_window, &pos);
  254. ::SetCursorPos(pos.x, pos.y);
  255. }
  256. // Set Dear ImGui mouse position from OS position
  257. POINT mouse_screen_pos;
  258. if (!::GetCursorPos(&mouse_screen_pos))
  259. return;
  260. if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
  261. {
  262. // 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)
  263. // 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.
  264. io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y);
  265. }
  266. else
  267. {
  268. // 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)
  269. // This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.
  270. POINT mouse_client_pos = mouse_screen_pos;
  271. ::ScreenToClient(bd->hWnd, &mouse_client_pos);
  272. io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y);
  273. }
  274. // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
  275. // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
  276. // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
  277. // - This is _regardless_ of whether another viewport is focused or being dragged from.
  278. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the
  279. // rectangles and last focused time of every viewports it knows about. It will be unaware of foreign windows that may be sitting between or over your windows.
  280. if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
  281. if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd))
  282. if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated?
  283. io.MouseHoveredViewport = viewport->ID;
  284. }
  285. // Gamepad navigation mapping
  286. static void ImGui_ImplWin32_UpdateGamepads()
  287. {
  288. #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  289. ImGuiIO& io = ImGui::GetIO();
  290. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  291. memset(io.NavInputs, 0, sizeof(io.NavInputs));
  292. if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
  293. return;
  294. // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
  295. // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
  296. if (bd->WantUpdateHasGamepad)
  297. {
  298. XINPUT_CAPABILITIES caps;
  299. bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
  300. bd->WantUpdateHasGamepad = false;
  301. }
  302. io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
  303. XINPUT_STATE xinput_state;
  304. if (bd->HasGamepad && bd->XInputGetState && bd->XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
  305. {
  306. const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
  307. io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
  308. #define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
  309. #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; }
  310. MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
  311. MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
  312. MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
  313. MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
  314. MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
  315. MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
  316. MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
  317. MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
  318. MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
  319. MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
  320. MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
  321. MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
  322. MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
  323. MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
  324. MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
  325. MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
  326. #undef MAP_BUTTON
  327. #undef MAP_ANALOG
  328. }
  329. #endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
  330. }
  331. static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM)
  332. {
  333. MONITORINFO info = {};
  334. info.cbSize = sizeof(MONITORINFO);
  335. if (!::GetMonitorInfo(monitor, &info))
  336. return TRUE;
  337. ImGuiPlatformMonitor imgui_monitor;
  338. imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top);
  339. imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top));
  340. imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top);
  341. imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top));
  342. imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
  343. ImGuiPlatformIO& io = ImGui::GetPlatformIO();
  344. if (info.dwFlags & MONITORINFOF_PRIMARY)
  345. io.Monitors.push_front(imgui_monitor);
  346. else
  347. io.Monitors.push_back(imgui_monitor);
  348. return TRUE;
  349. }
  350. static void ImGui_ImplWin32_UpdateMonitors()
  351. {
  352. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  353. ImGui::GetPlatformIO().Monitors.resize(0);
  354. ::EnumDisplayMonitors(NULL, NULL, ImGui_ImplWin32_UpdateMonitors_EnumFunc, 0);
  355. bd->WantUpdateMonitors = false;
  356. }
  357. void ImGui_ImplWin32_NewFrame()
  358. {
  359. ImGuiIO& io = ImGui::GetIO();
  360. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  361. IM_ASSERT(bd != NULL && "Did you call ImGui_ImplWin32_Init()?");
  362. // Setup display size (every frame to accommodate for window resizing)
  363. RECT rect = { 0, 0, 0, 0 };
  364. ::GetClientRect(bd->hWnd, &rect);
  365. io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
  366. if (bd->WantUpdateMonitors)
  367. ImGui_ImplWin32_UpdateMonitors();
  368. // Setup time step
  369. INT64 current_time = 0;
  370. ::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
  371. io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond;
  372. bd->Time = current_time;
  373. // Process workarounds for known Windows key handling issues
  374. ImGui_ImplWin32_ProcessKeyEventsWorkarounds();
  375. // Update key modifiers
  376. ImGui_ImplWin32_UpdateKeyModifiers();
  377. // Update OS mouse position
  378. ImGui_ImplWin32_UpdateMousePos();
  379. // Update OS mouse cursor with the cursor requested by imgui
  380. ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
  381. if (bd->LastMouseCursor != mouse_cursor)
  382. {
  383. bd->LastMouseCursor = mouse_cursor;
  384. ImGui_ImplWin32_UpdateMouseCursor();
  385. }
  386. // Update game controllers (if enabled and available)
  387. ImGui_ImplWin32_UpdateGamepads();
  388. }
  389. // 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)
  390. #define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
  391. // Map VK_xxx to ImGuiKey_xxx.
  392. static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)
  393. {
  394. switch (wParam)
  395. {
  396. case VK_TAB: return ImGuiKey_Tab;
  397. case VK_LEFT: return ImGuiKey_LeftArrow;
  398. case VK_RIGHT: return ImGuiKey_RightArrow;
  399. case VK_UP: return ImGuiKey_UpArrow;
  400. case VK_DOWN: return ImGuiKey_DownArrow;
  401. case VK_PRIOR: return ImGuiKey_PageUp;
  402. case VK_NEXT: return ImGuiKey_PageDown;
  403. case VK_HOME: return ImGuiKey_Home;
  404. case VK_END: return ImGuiKey_End;
  405. case VK_INSERT: return ImGuiKey_Insert;
  406. case VK_DELETE: return ImGuiKey_Delete;
  407. case VK_BACK: return ImGuiKey_Backspace;
  408. case VK_SPACE: return ImGuiKey_Space;
  409. case VK_RETURN: return ImGuiKey_Enter;
  410. case VK_ESCAPE: return ImGuiKey_Escape;
  411. case VK_OEM_7: return ImGuiKey_Apostrophe;
  412. case VK_OEM_COMMA: return ImGuiKey_Comma;
  413. case VK_OEM_MINUS: return ImGuiKey_Minus;
  414. case VK_OEM_PERIOD: return ImGuiKey_Period;
  415. case VK_OEM_2: return ImGuiKey_Slash;
  416. case VK_OEM_1: return ImGuiKey_Semicolon;
  417. case VK_OEM_PLUS: return ImGuiKey_Equal;
  418. case VK_OEM_4: return ImGuiKey_LeftBracket;
  419. case VK_OEM_5: return ImGuiKey_Backslash;
  420. case VK_OEM_6: return ImGuiKey_RightBracket;
  421. case VK_OEM_3: return ImGuiKey_GraveAccent;
  422. case VK_CAPITAL: return ImGuiKey_CapsLock;
  423. case VK_SCROLL: return ImGuiKey_ScrollLock;
  424. case VK_NUMLOCK: return ImGuiKey_NumLock;
  425. case VK_SNAPSHOT: return ImGuiKey_PrintScreen;
  426. case VK_PAUSE: return ImGuiKey_Pause;
  427. case VK_NUMPAD0: return ImGuiKey_Keypad0;
  428. case VK_NUMPAD1: return ImGuiKey_Keypad1;
  429. case VK_NUMPAD2: return ImGuiKey_Keypad2;
  430. case VK_NUMPAD3: return ImGuiKey_Keypad3;
  431. case VK_NUMPAD4: return ImGuiKey_Keypad4;
  432. case VK_NUMPAD5: return ImGuiKey_Keypad5;
  433. case VK_NUMPAD6: return ImGuiKey_Keypad6;
  434. case VK_NUMPAD7: return ImGuiKey_Keypad7;
  435. case VK_NUMPAD8: return ImGuiKey_Keypad8;
  436. case VK_NUMPAD9: return ImGuiKey_Keypad9;
  437. case VK_DECIMAL: return ImGuiKey_KeypadDecimal;
  438. case VK_DIVIDE: return ImGuiKey_KeypadDivide;
  439. case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
  440. case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
  441. case VK_ADD: return ImGuiKey_KeypadAdd;
  442. case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
  443. case VK_LSHIFT: return ImGuiKey_LeftShift;
  444. case VK_LCONTROL: return ImGuiKey_LeftControl;
  445. case VK_LMENU: return ImGuiKey_LeftAlt;
  446. case VK_LWIN: return ImGuiKey_LeftSuper;
  447. case VK_RSHIFT: return ImGuiKey_RightShift;
  448. case VK_RCONTROL: return ImGuiKey_RightControl;
  449. case VK_RMENU: return ImGuiKey_RightAlt;
  450. case VK_RWIN: return ImGuiKey_RightSuper;
  451. case VK_APPS: return ImGuiKey_Menu;
  452. case '0': return ImGuiKey_0;
  453. case '1': return ImGuiKey_1;
  454. case '2': return ImGuiKey_2;
  455. case '3': return ImGuiKey_3;
  456. case '4': return ImGuiKey_4;
  457. case '5': return ImGuiKey_5;
  458. case '6': return ImGuiKey_6;
  459. case '7': return ImGuiKey_7;
  460. case '8': return ImGuiKey_8;
  461. case '9': return ImGuiKey_9;
  462. case 'A': return ImGuiKey_A;
  463. case 'B': return ImGuiKey_B;
  464. case 'C': return ImGuiKey_C;
  465. case 'D': return ImGuiKey_D;
  466. case 'E': return ImGuiKey_E;
  467. case 'F': return ImGuiKey_F;
  468. case 'G': return ImGuiKey_G;
  469. case 'H': return ImGuiKey_H;
  470. case 'I': return ImGuiKey_I;
  471. case 'J': return ImGuiKey_J;
  472. case 'K': return ImGuiKey_K;
  473. case 'L': return ImGuiKey_L;
  474. case 'M': return ImGuiKey_M;
  475. case 'N': return ImGuiKey_N;
  476. case 'O': return ImGuiKey_O;
  477. case 'P': return ImGuiKey_P;
  478. case 'Q': return ImGuiKey_Q;
  479. case 'R': return ImGuiKey_R;
  480. case 'S': return ImGuiKey_S;
  481. case 'T': return ImGuiKey_T;
  482. case 'U': return ImGuiKey_U;
  483. case 'V': return ImGuiKey_V;
  484. case 'W': return ImGuiKey_W;
  485. case 'X': return ImGuiKey_X;
  486. case 'Y': return ImGuiKey_Y;
  487. case 'Z': return ImGuiKey_Z;
  488. case VK_F1: return ImGuiKey_F1;
  489. case VK_F2: return ImGuiKey_F2;
  490. case VK_F3: return ImGuiKey_F3;
  491. case VK_F4: return ImGuiKey_F4;
  492. case VK_F5: return ImGuiKey_F5;
  493. case VK_F6: return ImGuiKey_F6;
  494. case VK_F7: return ImGuiKey_F7;
  495. case VK_F8: return ImGuiKey_F8;
  496. case VK_F9: return ImGuiKey_F9;
  497. case VK_F10: return ImGuiKey_F10;
  498. case VK_F11: return ImGuiKey_F11;
  499. case VK_F12: return ImGuiKey_F12;
  500. default: return ImGuiKey_None;
  501. }
  502. }
  503. // Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
  504. #ifndef WM_MOUSEHWHEEL
  505. #define WM_MOUSEHWHEEL 0x020E
  506. #endif
  507. #ifndef DBT_DEVNODES_CHANGED
  508. #define DBT_DEVNODES_CHANGED 0x0007
  509. #endif
  510. // Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
  511. // Call from your application's message handler.
  512. // When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
  513. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
  514. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
  515. // Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
  516. // 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.
  517. // 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.
  518. #if 0
  519. // Copy this line into your .cpp file to forward declare the function.
  520. extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
  521. #endif
  522. IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  523. {
  524. if (ImGui::GetCurrentContext() == NULL)
  525. return 0;
  526. ImGuiIO& io = ImGui::GetIO();
  527. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  528. switch (msg)
  529. {
  530. case WM_MOUSEMOVE:
  531. // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
  532. bd->MouseHwnd = hwnd;
  533. if (!bd->MouseTracked)
  534. {
  535. TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hwnd, 0 };
  536. ::TrackMouseEvent(&tme);
  537. bd->MouseTracked = true;
  538. }
  539. break;
  540. case WM_MOUSELEAVE:
  541. if (bd->MouseHwnd == hwnd)
  542. bd->MouseHwnd = NULL;
  543. bd->MouseTracked = false;
  544. break;
  545. case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
  546. case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
  547. case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
  548. case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
  549. {
  550. int button = 0;
  551. if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
  552. if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
  553. if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
  554. if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
  555. if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
  556. ::SetCapture(hwnd);
  557. io.MouseDown[button] = true;
  558. return 0;
  559. }
  560. case WM_LBUTTONUP:
  561. case WM_RBUTTONUP:
  562. case WM_MBUTTONUP:
  563. case WM_XBUTTONUP:
  564. {
  565. int button = 0;
  566. if (msg == WM_LBUTTONUP) { button = 0; }
  567. if (msg == WM_RBUTTONUP) { button = 1; }
  568. if (msg == WM_MBUTTONUP) { button = 2; }
  569. if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
  570. io.MouseDown[button] = false;
  571. if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
  572. ::ReleaseCapture();
  573. return 0;
  574. }
  575. case WM_MOUSEWHEEL:
  576. io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
  577. return 0;
  578. case WM_MOUSEHWHEEL:
  579. io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
  580. return 0;
  581. case WM_KEYDOWN:
  582. case WM_KEYUP:
  583. case WM_SYSKEYDOWN:
  584. case WM_SYSKEYUP:
  585. {
  586. const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
  587. if (wParam < 256)
  588. {
  589. // Obtain virtual key code
  590. // (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.)
  591. int vk = (int)wParam;
  592. if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
  593. vk = IM_VK_KEYPAD_ENTER;
  594. // Submit key event
  595. const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);
  596. const int scancode = (int)LOBYTE(HIWORD(lParam));
  597. if (key != ImGuiKey_None)
  598. ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode);
  599. // Submit individual left/right modifier events
  600. if (vk == VK_SHIFT)
  601. {
  602. // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
  603. if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); }
  604. if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); }
  605. }
  606. else if (vk == VK_CONTROL)
  607. {
  608. if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftControl, is_key_down, VK_LCONTROL, scancode); }
  609. if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightControl, is_key_down, VK_RCONTROL, scancode); }
  610. }
  611. else if (vk == VK_MENU)
  612. {
  613. if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); }
  614. if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); }
  615. }
  616. }
  617. return 0;
  618. }
  619. case WM_SETFOCUS:
  620. case WM_KILLFOCUS:
  621. io.AddFocusEvent(msg == WM_SETFOCUS);
  622. return 0;
  623. case WM_CHAR:
  624. // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
  625. if (wParam > 0 && wParam < 0x10000)
  626. io.AddInputCharacterUTF16((unsigned short)wParam);
  627. return 0;
  628. case WM_SETCURSOR:
  629. if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
  630. return 1;
  631. return 0;
  632. case WM_DEVICECHANGE:
  633. if ((UINT)wParam == DBT_DEVNODES_CHANGED)
  634. bd->WantUpdateHasGamepad = true;
  635. return 0;
  636. case WM_DISPLAYCHANGE:
  637. bd->WantUpdateMonitors = true;
  638. return 0;
  639. }
  640. return 0;
  641. }
  642. //--------------------------------------------------------------------------------------------------------
  643. // DPI-related helpers (optional)
  644. //--------------------------------------------------------------------------------------------------------
  645. // - Use to enable DPI awareness without having to create an application manifest.
  646. // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
  647. // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
  648. // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
  649. // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
  650. //---------------------------------------------------------------------------------------------------------
  651. // This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
  652. // ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
  653. // If you are trying to implement your own backend for your own engine, you may ignore that noise.
  654. //---------------------------------------------------------------------------------------------------------
  655. // Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they
  656. // require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200
  657. static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD)
  658. {
  659. typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);
  660. static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL;
  661. if (RtlVerifyVersionInfoFn == NULL)
  662. if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll"))
  663. RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo");
  664. if (RtlVerifyVersionInfoFn == NULL)
  665. return FALSE;
  666. RTL_OSVERSIONINFOEXW versionInfo = { };
  667. ULONGLONG conditionMask = 0;
  668. versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
  669. versionInfo.dwMajorVersion = major;
  670. versionInfo.dwMinorVersion = minor;
  671. VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
  672. VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
  673. return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE;
  674. }
  675. #define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
  676. #define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
  677. #define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
  678. #define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
  679. #ifndef DPI_ENUMS_DECLARED
  680. typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
  681. typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;
  682. #endif
  683. #ifndef _DPI_AWARENESS_CONTEXTS_
  684. DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
  685. #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
  686. #endif
  687. #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
  688. #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
  689. #endif
  690. typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
  691. typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
  692. typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
  693. // Helper function to enable DPI awareness without setting up a manifest
  694. void ImGui_ImplWin32_EnableDpiAwareness()
  695. {
  696. // Make sure monitors will be updated with latest correct scaling
  697. if (ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData())
  698. bd->WantUpdateMonitors = true;
  699. if (_IsWindows10OrGreater())
  700. {
  701. static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
  702. if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
  703. {
  704. SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
  705. return;
  706. }
  707. }
  708. if (_IsWindows8Point1OrGreater())
  709. {
  710. static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
  711. if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
  712. {
  713. SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
  714. return;
  715. }
  716. }
  717. #if _WIN32_WINNT >= 0x0600
  718. ::SetProcessDPIAware();
  719. #endif
  720. }
  721. #if defined(_MSC_VER) && !defined(NOGDI)
  722. #pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
  723. #endif
  724. float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
  725. {
  726. UINT xdpi = 96, ydpi = 96;
  727. if (_IsWindows8Point1OrGreater())
  728. {
  729. static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
  730. static PFN_GetDpiForMonitor GetDpiForMonitorFn = NULL;
  731. if (GetDpiForMonitorFn == NULL && shcore_dll != NULL)
  732. GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor");
  733. if (GetDpiForMonitorFn != NULL)
  734. {
  735. GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
  736. IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
  737. return xdpi / 96.0f;
  738. }
  739. }
  740. #ifndef NOGDI
  741. const HDC dc = ::GetDC(NULL);
  742. xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
  743. ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
  744. IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
  745. ::ReleaseDC(NULL, dc);
  746. #endif
  747. return xdpi / 96.0f;
  748. }
  749. float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
  750. {
  751. HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
  752. return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
  753. }
  754. //--------------------------------------------------------------------------------------------------------
  755. // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
  756. // This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
  757. // 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..
  758. //--------------------------------------------------------------------------------------------------------
  759. // Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
  760. struct ImGui_ImplWin32_ViewportData
  761. {
  762. HWND Hwnd;
  763. bool HwndOwned;
  764. DWORD DwStyle;
  765. DWORD DwExStyle;
  766. ImGui_ImplWin32_ViewportData() { Hwnd = NULL; HwndOwned = false; DwStyle = DwExStyle = 0; }
  767. ~ImGui_ImplWin32_ViewportData() { IM_ASSERT(Hwnd == NULL); }
  768. };
  769. static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style)
  770. {
  771. if (flags & ImGuiViewportFlags_NoDecoration)
  772. *out_style = WS_POPUP;
  773. else
  774. *out_style = WS_OVERLAPPEDWINDOW;
  775. if (flags & ImGuiViewportFlags_NoTaskBarIcon)
  776. *out_ex_style = WS_EX_TOOLWINDOW;
  777. else
  778. *out_ex_style = WS_EX_APPWINDOW;
  779. if (flags & ImGuiViewportFlags_TopMost)
  780. *out_ex_style |= WS_EX_TOPMOST;
  781. }
  782. static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
  783. {
  784. ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
  785. viewport->PlatformUserData = vd;
  786. // Select style and parent window
  787. ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &vd->DwStyle, &vd->DwExStyle);
  788. HWND parent_window = NULL;
  789. if (viewport->ParentViewportId != 0)
  790. if (ImGuiViewport* parent_viewport = ImGui::FindViewportByID(viewport->ParentViewportId))
  791. parent_window = (HWND)parent_viewport->PlatformHandle;
  792. // Create window
  793. RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
  794. ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle);
  795. vd->Hwnd = ::CreateWindowEx(
  796. vd->DwExStyle, _T("ImGui Platform"), _T("Untitled"), vd->DwStyle, // Style, class name, window name
  797. rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
  798. parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param
  799. vd->HwndOwned = true;
  800. viewport->PlatformRequestResize = false;
  801. viewport->PlatformHandle = viewport->PlatformHandleRaw = vd->Hwnd;
  802. }
  803. static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)
  804. {
  805. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  806. if (ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData)
  807. {
  808. if (::GetCapture() == vd->Hwnd)
  809. {
  810. // Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
  811. ::ReleaseCapture();
  812. ::SetCapture(bd->hWnd);
  813. }
  814. if (vd->Hwnd && vd->HwndOwned)
  815. ::DestroyWindow(vd->Hwnd);
  816. vd->Hwnd = NULL;
  817. IM_DELETE(vd);
  818. }
  819. viewport->PlatformUserData = viewport->PlatformHandle = NULL;
  820. }
  821. static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
  822. {
  823. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  824. IM_ASSERT(vd->Hwnd != 0);
  825. if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
  826. ::ShowWindow(vd->Hwnd, SW_SHOWNA);
  827. else
  828. ::ShowWindow(vd->Hwnd, SW_SHOW);
  829. }
  830. static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport)
  831. {
  832. // (Optional) Update Win32 style if it changed _after_ creation.
  833. // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
  834. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  835. IM_ASSERT(vd->Hwnd != 0);
  836. DWORD new_style;
  837. DWORD new_ex_style;
  838. ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style);
  839. // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
  840. if (vd->DwStyle != new_style || vd->DwExStyle != new_ex_style)
  841. {
  842. // (Optional) Update TopMost state if it changed _after_ creation
  843. bool top_most_changed = (vd->DwExStyle & WS_EX_TOPMOST) != (new_ex_style & WS_EX_TOPMOST);
  844. HWND insert_after = top_most_changed ? ((viewport->Flags & ImGuiViewportFlags_TopMost) ? HWND_TOPMOST : HWND_NOTOPMOST) : 0;
  845. UINT swp_flag = top_most_changed ? 0 : SWP_NOZORDER;
  846. // Apply flags and position (since it is affected by flags)
  847. vd->DwStyle = new_style;
  848. vd->DwExStyle = new_ex_style;
  849. ::SetWindowLong(vd->Hwnd, GWL_STYLE, vd->DwStyle);
  850. ::SetWindowLong(vd->Hwnd, GWL_EXSTYLE, vd->DwExStyle);
  851. RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
  852. ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen
  853. ::SetWindowPos(vd->Hwnd, insert_after, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, swp_flag | SWP_NOACTIVATE | SWP_FRAMECHANGED);
  854. ::ShowWindow(vd->Hwnd, SW_SHOWNA); // This is necessary when we alter the style
  855. viewport->PlatformRequestMove = viewport->PlatformRequestResize = true;
  856. }
  857. }
  858. static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
  859. {
  860. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  861. IM_ASSERT(vd->Hwnd != 0);
  862. POINT pos = { 0, 0 };
  863. ::ClientToScreen(vd->Hwnd, &pos);
  864. return ImVec2((float)pos.x, (float)pos.y);
  865. }
  866. static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
  867. {
  868. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  869. IM_ASSERT(vd->Hwnd != 0);
  870. RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y };
  871. ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle);
  872. ::SetWindowPos(vd->Hwnd, NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
  873. }
  874. static ImVec2 ImGui_ImplWin32_GetWindowSize(ImGuiViewport* viewport)
  875. {
  876. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  877. IM_ASSERT(vd->Hwnd != 0);
  878. RECT rect;
  879. ::GetClientRect(vd->Hwnd, &rect);
  880. return ImVec2(float(rect.right - rect.left), float(rect.bottom - rect.top));
  881. }
  882. static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
  883. {
  884. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  885. IM_ASSERT(vd->Hwnd != 0);
  886. RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
  887. ::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen
  888. ::SetWindowPos(vd->Hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
  889. }
  890. static void ImGui_ImplWin32_SetWindowFocus(ImGuiViewport* viewport)
  891. {
  892. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  893. IM_ASSERT(vd->Hwnd != 0);
  894. ::BringWindowToTop(vd->Hwnd);
  895. ::SetForegroundWindow(vd->Hwnd);
  896. ::SetFocus(vd->Hwnd);
  897. }
  898. static bool ImGui_ImplWin32_GetWindowFocus(ImGuiViewport* viewport)
  899. {
  900. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  901. IM_ASSERT(vd->Hwnd != 0);
  902. return ::GetForegroundWindow() == vd->Hwnd;
  903. }
  904. static bool ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport* viewport)
  905. {
  906. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  907. IM_ASSERT(vd->Hwnd != 0);
  908. return ::IsIconic(vd->Hwnd) != 0;
  909. }
  910. static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title)
  911. {
  912. // ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string.
  913. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  914. IM_ASSERT(vd->Hwnd != 0);
  915. int n = ::MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
  916. ImVector<wchar_t> title_w;
  917. title_w.resize(n);
  918. ::MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w.Data, n);
  919. ::SetWindowTextW(vd->Hwnd, title_w.Data);
  920. }
  921. static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
  922. {
  923. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  924. IM_ASSERT(vd->Hwnd != 0);
  925. IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
  926. if (alpha < 1.0f)
  927. {
  928. DWORD style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED;
  929. ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, style);
  930. ::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA);
  931. }
  932. else
  933. {
  934. DWORD style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED;
  935. ::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, style);
  936. }
  937. }
  938. static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport)
  939. {
  940. ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
  941. IM_ASSERT(vd->Hwnd != 0);
  942. return ImGui_ImplWin32_GetDpiScaleForHwnd(vd->Hwnd);
  943. }
  944. // FIXME-DPI: Testing DPI related ideas
  945. static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport)
  946. {
  947. (void)viewport;
  948. #if 0
  949. ImGuiStyle default_style;
  950. //default_style.WindowPadding = ImVec2(0, 0);
  951. //default_style.WindowBorderSize = 0.0f;
  952. //default_style.ItemSpacing.y = 3.0f;
  953. //default_style.FramePadding = ImVec2(0, 0);
  954. default_style.ScaleAllSizes(viewport->DpiScale);
  955. ImGuiStyle& style = ImGui::GetStyle();
  956. style = default_style;
  957. #endif
  958. }
  959. static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  960. {
  961. if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
  962. return true;
  963. if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hWnd))
  964. {
  965. switch (msg)
  966. {
  967. case WM_CLOSE:
  968. viewport->PlatformRequestClose = true;
  969. return 0;
  970. case WM_MOVE:
  971. viewport->PlatformRequestMove = true;
  972. break;
  973. case WM_SIZE:
  974. viewport->PlatformRequestResize = true;
  975. break;
  976. case WM_MOUSEACTIVATE:
  977. if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick)
  978. return MA_NOACTIVATE;
  979. break;
  980. case WM_NCHITTEST:
  981. // Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
  982. // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
  983. // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
  984. // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
  985. if (viewport->Flags & ImGuiViewportFlags_NoInputs)
  986. return HTTRANSPARENT;
  987. break;
  988. }
  989. }
  990. return DefWindowProc(hWnd, msg, wParam, lParam);
  991. }
  992. static void ImGui_ImplWin32_InitPlatformInterface()
  993. {
  994. WNDCLASSEX wcex;
  995. wcex.cbSize = sizeof(WNDCLASSEX);
  996. wcex.style = CS_HREDRAW | CS_VREDRAW;
  997. wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow;
  998. wcex.cbClsExtra = 0;
  999. wcex.cbWndExtra = 0;
  1000. wcex.hInstance = ::GetModuleHandle(NULL);
  1001. wcex.hIcon = NULL;
  1002. wcex.hCursor = NULL;
  1003. wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
  1004. wcex.lpszMenuName = NULL;
  1005. wcex.lpszClassName = _T("ImGui Platform");
  1006. wcex.hIconSm = NULL;
  1007. ::RegisterClassEx(&wcex);
  1008. ImGui_ImplWin32_UpdateMonitors();
  1009. // Register platform interface (will be coupled with a renderer interface)
  1010. ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
  1011. platform_io.Platform_CreateWindow = ImGui_ImplWin32_CreateWindow;
  1012. platform_io.Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow;
  1013. platform_io.Platform_ShowWindow = ImGui_ImplWin32_ShowWindow;
  1014. platform_io.Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos;
  1015. platform_io.Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos;
  1016. platform_io.Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize;
  1017. platform_io.Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize;
  1018. platform_io.Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus;
  1019. platform_io.Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus;
  1020. platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized;
  1021. platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle;
  1022. platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha;
  1023. platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
  1024. platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
  1025. platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
  1026. // Register main window handle (which is owned by the main application, not by us)
  1027. // 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.
  1028. ImGuiViewport* main_viewport = ImGui::GetMainViewport();
  1029. ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
  1030. ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
  1031. vd->Hwnd = bd->hWnd;
  1032. vd->HwndOwned = false;
  1033. main_viewport->PlatformUserData = vd;
  1034. main_viewport->PlatformHandle = (void*)bd->hWnd;
  1035. }
  1036. static void ImGui_ImplWin32_ShutdownPlatformInterface()
  1037. {
  1038. ::UnregisterClass(_T("ImGui Platform"), ::GetModuleHandle(NULL));
  1039. ImGui::DestroyPlatformWindows();
  1040. }
  1041. //---------------------------------------------------------------------------------------------------------
  1042. // Transparency related helpers (optional)
  1043. //--------------------------------------------------------------------------------------------------------
  1044. #if defined(_MSC_VER)
  1045. #pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi'
  1046. #endif
  1047. // [experimental]
  1048. // Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c
  1049. // (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
  1050. void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
  1051. {
  1052. if (!_IsWindowsVistaOrGreater())
  1053. return;
  1054. BOOL composition;
  1055. if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
  1056. return;
  1057. BOOL opaque;
  1058. DWORD color;
  1059. if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
  1060. {
  1061. HRGN region = ::CreateRectRgn(0, 0, -1, -1);
  1062. DWM_BLURBEHIND bb = {};
  1063. bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
  1064. bb.hRgnBlur = region;
  1065. bb.fEnable = TRUE;
  1066. ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
  1067. ::DeleteObject(region);
  1068. }
  1069. else
  1070. {
  1071. DWM_BLURBEHIND bb = {};
  1072. bb.dwFlags = DWM_BB_ENABLE;
  1073. ::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
  1074. }
  1075. }
  1076. //---------------------------------------------------------------------------------------------------------