1 // dear imgui: Platform Binding 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 
4 // Implemented features:
5 //  [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
6 //  [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
7 //  [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
8 //  [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
9 //  [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
10 
11 #ifdef _WIN32 /* [Bruno Levy] */
12 
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 
21 // Using XInput library for gamepad (with recent Windows SDK this may leads to executables which won't run on Windows 7)
22 #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
23 #include <XInput.h>
24 #else
25 #define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
26 #endif
27 #if defined(_MSC_VER) && !defined(IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT)
28 #pragma comment(lib, "xinput")
29 //#pragma comment(lib, "Xinput9_1_0")
30 #endif
31 
32 // CHANGELOG
33 // (minor and older changes stripped away, please see git history for details)
34 //  2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
35 //  2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
36 //  2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
37 //  2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
38 //  2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
39 //  2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
40 //  2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
41 //  2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
42 //  2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
43 //  2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
44 //  2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
45 //  2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
46 //  2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
47 //  2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
48 //  2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
49 //  2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
50 //  2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
51 //  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
52 //  2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
53 //  2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
54 //  2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
55 //  2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
56 //  2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
57 //  2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
58 
59 // Win32 Data
60 static HWND                 g_hWnd = NULL;
61 static INT64                g_Time = 0;
62 static INT64                g_TicksPerSecond = 0;
63 static ImGuiMouseCursor     g_LastMouseCursor = ImGuiMouseCursor_COUNT;
64 static bool                 g_HasGamepad = false;
65 static bool                 g_WantUpdateHasGamepad = true;
66 static bool                 g_WantUpdateMonitors = true;
67 
68 // Forward Declarations
69 static void ImGui_ImplWin32_InitPlatformInterface();
70 static void ImGui_ImplWin32_ShutdownPlatformInterface();
71 static void ImGui_ImplWin32_UpdateMonitors();
72 
73 // Functions
ImGui_ImplWin32_Init(void * hwnd)74 bool    ImGui_ImplWin32_Init(void* hwnd)
75 {
76     if (!::QueryPerformanceFrequency((LARGE_INTEGER*)&g_TicksPerSecond))
77         return false;
78     if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time))
79         return false;
80 
81     // Setup back-end capabilities flags
82     ImGuiIO& io = ImGui::GetIO();
83     io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;         // We can honor GetMouseCursor() values (optional)
84     io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;          // We can honor io.WantSetMousePos requests (optional, rarely used)
85     io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports;    // We can create multi-viewports on the Platform side (optional)
86     io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
87     io.BackendPlatformName = "imgui_impl_win32";
88 
89     // Our mouse update function expect PlatformHandle to be filled for the main viewport
90     g_hWnd = (HWND)hwnd;
91     ImGuiViewport* main_viewport = ImGui::GetMainViewport();
92     main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)g_hWnd;
93     if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
94         ImGui_ImplWin32_InitPlatformInterface();
95 
96     // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
97     io.KeyMap[ImGuiKey_Tab] = VK_TAB;
98     io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
99     io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
100     io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
101     io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
102     io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
103     io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
104     io.KeyMap[ImGuiKey_Home] = VK_HOME;
105     io.KeyMap[ImGuiKey_End] = VK_END;
106     io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
107     io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
108     io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
109     io.KeyMap[ImGuiKey_Space] = VK_SPACE;
110     io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
111     io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
112     io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
113     io.KeyMap[ImGuiKey_A] = 'A';
114     io.KeyMap[ImGuiKey_C] = 'C';
115     io.KeyMap[ImGuiKey_V] = 'V';
116     io.KeyMap[ImGuiKey_X] = 'X';
117     io.KeyMap[ImGuiKey_Y] = 'Y';
118     io.KeyMap[ImGuiKey_Z] = 'Z';
119 
120     return true;
121 }
122 
ImGui_ImplWin32_Shutdown()123 void    ImGui_ImplWin32_Shutdown()
124 {
125     ImGui_ImplWin32_ShutdownPlatformInterface();
126     g_hWnd = (HWND)0;
127 }
128 
ImGui_ImplWin32_UpdateMouseCursor()129 static bool ImGui_ImplWin32_UpdateMouseCursor()
130 {
131     ImGuiIO& io = ImGui::GetIO();
132     if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
133         return false;
134 
135     ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
136     if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
137     {
138         // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
139         ::SetCursor(NULL);
140     }
141     else
142     {
143         // Show OS mouse cursor
144         LPTSTR win32_cursor = IDC_ARROW;
145         switch (imgui_cursor)
146         {
147         case ImGuiMouseCursor_Arrow:        win32_cursor = IDC_ARROW; break;
148         case ImGuiMouseCursor_TextInput:    win32_cursor = IDC_IBEAM; break;
149         case ImGuiMouseCursor_ResizeAll:    win32_cursor = IDC_SIZEALL; break;
150         case ImGuiMouseCursor_ResizeEW:     win32_cursor = IDC_SIZEWE; break;
151         case ImGuiMouseCursor_ResizeNS:     win32_cursor = IDC_SIZENS; break;
152         case ImGuiMouseCursor_ResizeNESW:   win32_cursor = IDC_SIZENESW; break;
153         case ImGuiMouseCursor_ResizeNWSE:   win32_cursor = IDC_SIZENWSE; break;
154         case ImGuiMouseCursor_Hand:         win32_cursor = IDC_HAND; break;
155         case ImGuiMouseCursor_NotAllowed:   win32_cursor = IDC_NO; break;
156         }
157         ::SetCursor(::LoadCursor(NULL, win32_cursor));
158     }
159     return true;
160 }
161 
162 // This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
163 // Because of that, it is a little more complicated than your typical single-viewport binding code!
ImGui_ImplWin32_UpdateMousePos()164 static void ImGui_ImplWin32_UpdateMousePos()
165 {
166     ImGuiIO& io = ImGui::GetIO();
167 
168     // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
169     // (When multi-viewports are enabled, all imgui positions are same as OS positions)
170     if (io.WantSetMousePos)
171     {
172         POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
173         if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
174             ::ClientToScreen(g_hWnd, &pos);
175         ::SetCursorPos(pos.x, pos.y);
176     }
177 
178     io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
179     io.MouseHoveredViewport = 0;
180 
181     // Set imgui mouse position
182     POINT mouse_screen_pos;
183     if (!::GetCursorPos(&mouse_screen_pos))
184         return;
185     if (HWND focused_hwnd = ::GetForegroundWindow())
186     {
187         if (::IsChild(focused_hwnd, g_hWnd))
188             focused_hwnd = g_hWnd;
189         if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
190         {
191             // 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)
192             // This is the position you can get with GetCursorPos(). In theory adding viewport->Pos is also the reverse operation of doing ScreenToClient().
193             if (ImGui::FindViewportByPlatformHandle((void*)focused_hwnd) != NULL)
194                 io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y);
195         }
196         else
197         {
198             // 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.)
199             // This is the position you can get with GetCursorPos() + ScreenToClient() or from WM_MOUSEMOVE.
200             if (focused_hwnd == g_hWnd)
201             {
202                 POINT mouse_client_pos = mouse_screen_pos;
203                 ::ScreenToClient(focused_hwnd, &mouse_client_pos);
204                 io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y);
205             }
206         }
207     }
208 
209     // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
210     // Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
211     // - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
212     // - This is _regardless_ of whether another viewport is focused or being dragged from.
213     // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the back-end, imgui will ignore this field and infer the information by relying on the
214     // 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.
215     if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
216         if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd))
217             if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated?
218                 io.MouseHoveredViewport = viewport->ID;
219 }
220 
221 // Gamepad navigation mapping
ImGui_ImplWin32_UpdateGamepads()222 static void ImGui_ImplWin32_UpdateGamepads()
223 {
224 #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
225     ImGuiIO& io = ImGui::GetIO();
226     memset(io.NavInputs, 0, sizeof(io.NavInputs));
227     if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
228         return;
229 
230     // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
231     // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
232     if (g_WantUpdateHasGamepad)
233     {
234         XINPUT_CAPABILITIES caps;
235         g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS);
236         g_WantUpdateHasGamepad = false;
237     }
238 
239     XINPUT_STATE xinput_state;
240     io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
241     if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
242     {
243         const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
244         io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
245 
246         #define MAP_BUTTON(NAV_NO, BUTTON_ENUM)     { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
247         #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; }
248         MAP_BUTTON(ImGuiNavInput_Activate,      XINPUT_GAMEPAD_A);              // Cross / A
249         MAP_BUTTON(ImGuiNavInput_Cancel,        XINPUT_GAMEPAD_B);              // Circle / B
250         MAP_BUTTON(ImGuiNavInput_Menu,          XINPUT_GAMEPAD_X);              // Square / X
251         MAP_BUTTON(ImGuiNavInput_Input,         XINPUT_GAMEPAD_Y);              // Triangle / Y
252         MAP_BUTTON(ImGuiNavInput_DpadLeft,      XINPUT_GAMEPAD_DPAD_LEFT);      // D-Pad Left
253         MAP_BUTTON(ImGuiNavInput_DpadRight,     XINPUT_GAMEPAD_DPAD_RIGHT);     // D-Pad Right
254         MAP_BUTTON(ImGuiNavInput_DpadUp,        XINPUT_GAMEPAD_DPAD_UP);        // D-Pad Up
255         MAP_BUTTON(ImGuiNavInput_DpadDown,      XINPUT_GAMEPAD_DPAD_DOWN);      // D-Pad Down
256         MAP_BUTTON(ImGuiNavInput_FocusPrev,     XINPUT_GAMEPAD_LEFT_SHOULDER);  // L1 / LB
257         MAP_BUTTON(ImGuiNavInput_FocusNext,     XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
258         MAP_BUTTON(ImGuiNavInput_TweakSlow,     XINPUT_GAMEPAD_LEFT_SHOULDER);  // L1 / LB
259         MAP_BUTTON(ImGuiNavInput_TweakFast,     XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
260         MAP_ANALOG(ImGuiNavInput_LStickLeft,    gamepad.sThumbLX,  -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
261         MAP_ANALOG(ImGuiNavInput_LStickRight,   gamepad.sThumbLX,  +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
262         MAP_ANALOG(ImGuiNavInput_LStickUp,      gamepad.sThumbLY,  +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
263         MAP_ANALOG(ImGuiNavInput_LStickDown,    gamepad.sThumbLY,  -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
264         #undef MAP_BUTTON
265         #undef MAP_ANALOG
266     }
267 #endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
268 }
269 
ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor,HDC,LPRECT,LPARAM)270 static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM)
271 {
272     MONITORINFO info = { 0 };
273     info.cbSize = sizeof(MONITORINFO);
274     if (!::GetMonitorInfo(monitor, &info))
275         return TRUE;
276     ImGuiPlatformMonitor imgui_monitor;
277     imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top);
278     imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top));
279     imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top);
280     imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top));
281     imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
282     ImGuiPlatformIO& io = ImGui::GetPlatformIO();
283     if (info.dwFlags & MONITORINFOF_PRIMARY)
284         io.Monitors.push_front(imgui_monitor);
285     else
286         io.Monitors.push_back(imgui_monitor);
287     return TRUE;
288 }
289 
ImGui_ImplWin32_UpdateMonitors()290 static void ImGui_ImplWin32_UpdateMonitors()
291 {
292     ImGui::GetPlatformIO().Monitors.resize(0);
293     // [Bruno Levy] fourth parameter: NULL -> (LPARAM)(0)
294     ::EnumDisplayMonitors(NULL, NULL, ImGui_ImplWin32_UpdateMonitors_EnumFunc, (LPARAM)(0));
295     g_WantUpdateMonitors = false;
296 }
297 
ImGui_ImplWin32_NewFrame()298 void    ImGui_ImplWin32_NewFrame()
299 {
300     ImGuiIO& io = ImGui::GetIO();
301     IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
302 
303     // Setup display size (every frame to accommodate for window resizing)
304     RECT rect;
305     ::GetClientRect(g_hWnd, &rect);
306     io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
307     if (g_WantUpdateMonitors)
308         ImGui_ImplWin32_UpdateMonitors();
309 
310     // Setup time step
311     INT64 current_time;
312     ::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
313     io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
314     g_Time = current_time;
315 
316     // Read keyboard modifiers inputs
317     io.KeyCtrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;
318     io.KeyShift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;
319     io.KeyAlt = (::GetKeyState(VK_MENU) & 0x8000) != 0;
320     io.KeySuper = false;
321     // io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
322 
323     // Update OS mouse position
324     ImGui_ImplWin32_UpdateMousePos();
325 
326     // Update OS mouse cursor with the cursor requested by imgui
327     ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
328     if (g_LastMouseCursor != mouse_cursor)
329     {
330         g_LastMouseCursor = mouse_cursor;
331         ImGui_ImplWin32_UpdateMouseCursor();
332     }
333 
334     // Update game controllers (if enabled and available)
335     ImGui_ImplWin32_UpdateGamepads();
336 }
337 
338 // Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
339 #ifndef WM_MOUSEHWHEEL
340 #define WM_MOUSEHWHEEL 0x020E
341 #endif
342 #ifndef DBT_DEVNODES_CHANGED
343 #define DBT_DEVNODES_CHANGED 0x0007
344 #endif
345 
346 // Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
347 // Call from your application's message handler.
348 // When implementing your own back-end, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
349 // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
350 // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
351 // Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
352 // 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.
353 // 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.
354 #if 0
355 // Copy this line into your .cpp file to forward declare the function.
356 extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
357 #endif
ImGui_ImplWin32_WndProcHandler(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)358 IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
359 {
360     if (ImGui::GetCurrentContext() == NULL)
361         return 0;
362 
363     ImGuiIO& io = ImGui::GetIO();
364     switch (msg)
365     {
366     case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
367     case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
368     case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK:
369     case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK:
370     {
371         int button = 0;
372         if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; }
373         if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
374         if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
375         if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
376         if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
377             ::SetCapture(hwnd);
378         io.MouseDown[button] = true;
379         return 0;
380     }
381     case WM_LBUTTONUP:
382     case WM_RBUTTONUP:
383     case WM_MBUTTONUP:
384     case WM_XBUTTONUP:
385     {
386         int button = 0;
387         if (msg == WM_LBUTTONUP) { button = 0; }
388         if (msg == WM_RBUTTONUP) { button = 1; }
389         if (msg == WM_MBUTTONUP) { button = 2; }
390         if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
391         io.MouseDown[button] = false;
392         if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
393             ::ReleaseCapture();
394         return 0;
395     }
396     case WM_MOUSEWHEEL:
397         io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
398         return 0;
399     case WM_MOUSEHWHEEL:
400         io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
401         return 0;
402     case WM_KEYDOWN:
403     case WM_SYSKEYDOWN:
404         if (wParam < 256)
405             io.KeysDown[wParam] = 1;
406         return 0;
407     case WM_KEYUP:
408     case WM_SYSKEYUP:
409         if (wParam < 256)
410             io.KeysDown[wParam] = 0;
411         return 0;
412     case WM_CHAR:
413         // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
414         if (wParam > 0 && wParam < 0x10000)
415             io.AddInputCharacterUTF16((unsigned short)wParam);
416         return 0;
417     case WM_SETCURSOR:
418         if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor())
419             return 1;
420         return 0;
421     case WM_DEVICECHANGE:
422         if ((UINT)wParam == DBT_DEVNODES_CHANGED)
423             g_WantUpdateHasGamepad = true;
424         return 0;
425     case WM_DISPLAYCHANGE:
426         g_WantUpdateMonitors = true;
427         return 0;
428     }
429     return 0;
430 }
431 
432 
433 //--------------------------------------------------------------------------------------------------------
434 // DPI-related helpers (optional)
435 //--------------------------------------------------------------------------------------------------------
436 // - Use to enable DPI awareness without having to create an application manifest.
437 // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
438 // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
439 //   but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
440 //   neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
441 //---------------------------------------------------------------------------------------------------------
442 // This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
443 // ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
444 // If you are trying to implement your own back-end for your own engine, you may ignore that noise.
445 //---------------------------------------------------------------------------------------------------------
446 
447 // Implement some of the functions and types normally declared in recent Windows SDK.
448 #if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
IsWindowsVersionOrGreater(WORD major,WORD minor,WORD sp)449 static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
450 {
451     OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 };
452     DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
453     ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
454     cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
455     cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
456     return ::VerifyVersionInfoW(&osvi, mask, cond);
457 }
458 #define IsWindows8Point1OrGreater()  IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WINBLUE
459 #endif
460 
461 #ifndef DPI_ENUMS_DECLARED
462 typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
463 typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, MDT_RAW_DPI = 2, MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE;
464 #endif
465 #ifndef _DPI_AWARENESS_CONTEXTS_
466 DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
467 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE    (DPI_AWARENESS_CONTEXT)-3
468 #endif
469 #ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
470 #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
471 #endif
472 typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);                     // Shcore.lib + dll, Windows 8.1+
473 typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);        // Shcore.lib + dll, Windows 8.1+
474 typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
475 
476 // Helper function to enable DPI awareness without setting up a manifest
ImGui_ImplWin32_EnableDpiAwareness()477 void ImGui_ImplWin32_EnableDpiAwareness()
478 {
479     // Make sure monitors will be updated with latest correct scaling
480     g_WantUpdateMonitors = true;
481 
482     // if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer!
483     {
484         static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
485         if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
486         {
487             SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
488             return;
489         }
490     }
491     if (IsWindows8Point1OrGreater())
492     {
493         static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
494         if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
495         {
496             SetProcessDpiAwarenessFn(PROCESS_PER_MONITOR_DPI_AWARE);
497             return;
498         }
499     }
500 #if _WIN32_WINNT >= 0x0600
501     ::SetProcessDPIAware();
502 #endif
503 }
504 
505 #if defined(_MSC_VER) && !defined(NOGDI)
506 #pragma comment(lib, "gdi32")   // Link with gdi32.lib for GetDeviceCaps()
507 #endif
508 
ImGui_ImplWin32_GetDpiScaleForMonitor(void * monitor)509 float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
510 {
511     UINT xdpi = 96, ydpi = 96;
512     static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater();
513     if (bIsWindows8Point1OrGreater)
514     {
515         static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
516         if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"))
517             GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
518     }
519 #ifndef NOGDI
520     else
521     {
522         const HDC dc = ::GetDC(NULL);
523         xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
524         ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
525         ::ReleaseDC(NULL, dc);
526     }
527 #endif
528     IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
529     return xdpi / 96.0f;
530 }
531 
ImGui_ImplWin32_GetDpiScaleForHwnd(void * hwnd)532 float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
533 {
534     HMONITOR monitor = ::MonitorFromWindow((HWND)hwnd, MONITOR_DEFAULTTONEAREST);
535     return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
536 }
537 
538 
539 //--------------------------------------------------------------------------------------------------------
540 // IME (Input Method Editor) basic support for e.g. Asian language users
541 //--------------------------------------------------------------------------------------------------------
542 
543 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions
544 #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
545 #endif
546 
547 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(__GNUC__)
548 #define HAS_WIN32_IME   1
549 #include <imm.h>
550 #ifdef _MSC_VER
551 #pragma comment(lib, "imm32")
552 #endif
ImGui_ImplWin32_SetImeInputPos(ImGuiViewport * viewport,ImVec2 pos)553 static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos)
554 {
555     COMPOSITIONFORM cf = { CFS_FORCE_POSITION,{ (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) },{ 0, 0, 0, 0 } };
556     if (HWND hwnd = (HWND)viewport->PlatformHandle)
557         if (HIMC himc = ::ImmGetContext(hwnd))
558         {
559             ::ImmSetCompositionWindow(himc, &cf);
560             ::ImmReleaseContext(hwnd, himc);
561         }
562 }
563 #else
564 #define HAS_WIN32_IME   0
565 #endif
566 
567 //--------------------------------------------------------------------------------------------------------
568 // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
569 // This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
570 // 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..
571 //--------------------------------------------------------------------------------------------------------
572 
573 // Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
574 struct ImGuiViewportDataWin32
575 {
576     HWND    Hwnd;
577     bool    HwndOwned;
578     DWORD   DwStyle;
579     DWORD   DwExStyle;
580 
ImGuiViewportDataWin32ImGuiViewportDataWin32581     ImGuiViewportDataWin32() { Hwnd = NULL; HwndOwned = false;  DwStyle = DwExStyle = 0; }
~ImGuiViewportDataWin32ImGuiViewportDataWin32582     ~ImGuiViewportDataWin32() { IM_ASSERT(Hwnd == NULL); }
583 };
584 
ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags,DWORD * out_style,DWORD * out_ex_style)585 static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style)
586 {
587     if (flags & ImGuiViewportFlags_NoDecoration)
588         *out_style = WS_POPUP;
589     else
590         *out_style = WS_OVERLAPPEDWINDOW;
591 
592     if (flags & ImGuiViewportFlags_NoTaskBarIcon)
593         *out_ex_style = WS_EX_TOOLWINDOW;
594     else
595         *out_ex_style = WS_EX_APPWINDOW;
596 
597     if (flags & ImGuiViewportFlags_TopMost)
598         *out_ex_style |= WS_EX_TOPMOST;
599 }
600 
ImGui_ImplWin32_CreateWindow(ImGuiViewport * viewport)601 static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
602 {
603     ImGuiViewportDataWin32* data = IM_NEW(ImGuiViewportDataWin32)();
604     viewport->PlatformUserData = data;
605 
606     // Select style and parent window
607     ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &data->DwStyle, &data->DwExStyle);
608     HWND parent_window = NULL;
609     if (viewport->ParentViewportId != 0)
610         if (ImGuiViewport* parent_viewport = ImGui::FindViewportByID(viewport->ParentViewportId))
611             parent_window = (HWND)parent_viewport->PlatformHandle;
612 
613     // Create window
614     RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
615     ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle);
616     data->Hwnd = ::CreateWindowEx(
617         data->DwExStyle, _T("ImGui Platform"), _T("Untitled"), data->DwStyle,   // Style, class name, window name
618         rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,    // Window area
619         parent_window, NULL, ::GetModuleHandle(NULL), NULL);                    // Parent window, Menu, Instance, Param
620     data->HwndOwned = true;
621     viewport->PlatformRequestResize = false;
622     viewport->PlatformHandle = viewport->PlatformHandleRaw = data->Hwnd;
623 }
624 
ImGui_ImplWin32_DestroyWindow(ImGuiViewport * viewport)625 static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)
626 {
627     if (ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData)
628     {
629         if (::GetCapture() == data->Hwnd)
630         {
631             // Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
632             ::ReleaseCapture();
633             ::SetCapture(g_hWnd);
634         }
635         if (data->Hwnd && data->HwndOwned)
636             ::DestroyWindow(data->Hwnd);
637         data->Hwnd = NULL;
638         IM_DELETE(data);
639     }
640     viewport->PlatformUserData = viewport->PlatformHandle = NULL;
641 }
642 
ImGui_ImplWin32_ShowWindow(ImGuiViewport * viewport)643 static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
644 {
645     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
646     IM_ASSERT(data->Hwnd != 0);
647     if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
648         ::ShowWindow(data->Hwnd, SW_SHOWNA);
649     else
650         ::ShowWindow(data->Hwnd, SW_SHOW);
651 }
652 
ImGui_ImplWin32_UpdateWindow(ImGuiViewport * viewport)653 static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport)
654 {
655     // (Optional) Update Win32 style if it changed _after_ creation.
656     // Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
657     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
658     IM_ASSERT(data->Hwnd != 0);
659     DWORD new_style;
660     DWORD new_ex_style;
661     ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style);
662 
663     // Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
664     if (data->DwStyle != new_style || data->DwExStyle != new_ex_style)
665     {
666         data->DwStyle = new_style;
667         data->DwExStyle = new_ex_style;
668         ::SetWindowLong(data->Hwnd, GWL_STYLE, data->DwStyle);
669         ::SetWindowLong(data->Hwnd, GWL_EXSTYLE, data->DwExStyle);
670         RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
671         ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen
672         ::SetWindowPos(data->Hwnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
673         ::ShowWindow(data->Hwnd, SW_SHOWNA); // This is necessary when we alter the style
674         viewport->PlatformRequestMove = viewport->PlatformRequestResize = true;
675     }
676 }
677 
ImGui_ImplWin32_GetWindowPos(ImGuiViewport * viewport)678 static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
679 {
680     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
681     IM_ASSERT(data->Hwnd != 0);
682     POINT pos = { 0, 0 };
683     ::ClientToScreen(data->Hwnd, &pos);
684     return ImVec2((float)pos.x, (float)pos.y);
685 }
686 
ImGui_ImplWin32_SetWindowPos(ImGuiViewport * viewport,ImVec2 pos)687 static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
688 {
689     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
690     IM_ASSERT(data->Hwnd != 0);
691     RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y };
692     ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle);
693     ::SetWindowPos(data->Hwnd, NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
694 }
695 
ImGui_ImplWin32_GetWindowSize(ImGuiViewport * viewport)696 static ImVec2 ImGui_ImplWin32_GetWindowSize(ImGuiViewport* viewport)
697 {
698     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
699     IM_ASSERT(data->Hwnd != 0);
700     RECT rect;
701     ::GetClientRect(data->Hwnd, &rect);
702     return ImVec2(float(rect.right - rect.left), float(rect.bottom - rect.top));
703 }
704 
ImGui_ImplWin32_SetWindowSize(ImGuiViewport * viewport,ImVec2 size)705 static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
706 {
707     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
708     IM_ASSERT(data->Hwnd != 0);
709     RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
710     ::AdjustWindowRectEx(&rect, data->DwStyle, FALSE, data->DwExStyle); // Client to Screen
711     ::SetWindowPos(data->Hwnd, NULL, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
712 }
713 
ImGui_ImplWin32_SetWindowFocus(ImGuiViewport * viewport)714 static void ImGui_ImplWin32_SetWindowFocus(ImGuiViewport* viewport)
715 {
716     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
717     IM_ASSERT(data->Hwnd != 0);
718     ::BringWindowToTop(data->Hwnd);
719     ::SetForegroundWindow(data->Hwnd);
720     ::SetFocus(data->Hwnd);
721 }
722 
ImGui_ImplWin32_GetWindowFocus(ImGuiViewport * viewport)723 static bool ImGui_ImplWin32_GetWindowFocus(ImGuiViewport* viewport)
724 {
725     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
726     IM_ASSERT(data->Hwnd != 0);
727     return ::GetForegroundWindow() == data->Hwnd;
728 }
729 
ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport * viewport)730 static bool ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport* viewport)
731 {
732     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
733     IM_ASSERT(data->Hwnd != 0);
734     return ::IsIconic(data->Hwnd) != 0;
735 }
736 
ImGui_ImplWin32_SetWindowTitle(ImGuiViewport * viewport,const char * title)737 static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title)
738 {
739     // ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string.
740     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
741     IM_ASSERT(data->Hwnd != 0);
742     int n = ::MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
743     ImVector<wchar_t> title_w;
744     title_w.resize(n);
745     ::MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w.Data, n);
746     ::SetWindowTextW(data->Hwnd, title_w.Data);
747 }
748 
ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport * viewport,float alpha)749 static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
750 {
751     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
752     IM_ASSERT(data->Hwnd != 0);
753     IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
754     if (alpha < 1.0f)
755     {
756         DWORD style = ::GetWindowLongW(data->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED;
757         ::SetWindowLongW(data->Hwnd, GWL_EXSTYLE, style);
758         ::SetLayeredWindowAttributes(data->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA);
759     }
760     else
761     {
762         DWORD style = ::GetWindowLongW(data->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED;
763         ::SetWindowLongW(data->Hwnd, GWL_EXSTYLE, style);
764     }
765 }
766 
ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport * viewport)767 static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport)
768 {
769     ImGuiViewportDataWin32* data = (ImGuiViewportDataWin32*)viewport->PlatformUserData;
770     IM_ASSERT(data->Hwnd != 0);
771     return ImGui_ImplWin32_GetDpiScaleForHwnd(data->Hwnd);
772 }
773 
774 // FIXME-DPI: Testing DPI related ideas
ImGui_ImplWin32_OnChangedViewport(ImGuiViewport * viewport)775 static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport)
776 {
777     (void)viewport;
778 #if 0
779     ImGuiStyle default_style;
780     //default_style.WindowPadding = ImVec2(0, 0);
781     //default_style.WindowBorderSize = 0.0f;
782     //default_style.ItemSpacing.y = 3.0f;
783     //default_style.FramePadding = ImVec2(0, 0);
784     default_style.ScaleAllSizes(viewport->DpiScale);
785     ImGuiStyle& style = ImGui::GetStyle();
786     style = default_style;
787 #endif
788 }
789 
ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)790 static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
791 {
792     if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
793         return true;
794 
795     if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hWnd))
796     {
797         switch (msg)
798         {
799         case WM_CLOSE:
800             viewport->PlatformRequestClose = true;
801             return 0;
802         case WM_MOVE:
803             viewport->PlatformRequestMove = true;
804             break;
805         case WM_SIZE:
806             viewport->PlatformRequestResize = true;
807             break;
808         case WM_MOUSEACTIVATE:
809             if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick)
810                 return MA_NOACTIVATE;
811             break;
812         case WM_NCHITTEST:
813             // Let mouse pass-through the window. This will allow the back-end to set io.MouseHoveredViewport properly (which is OPTIONAL).
814             // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
815             // If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
816             // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
817             if (viewport->Flags & ImGuiViewportFlags_NoInputs)
818                 return HTTRANSPARENT;
819             break;
820         }
821     }
822 
823     return DefWindowProc(hWnd, msg, wParam, lParam);
824 }
825 
ImGui_ImplWin32_InitPlatformInterface()826 static void ImGui_ImplWin32_InitPlatformInterface()
827 {
828     WNDCLASSEX wcex;
829     wcex.cbSize = sizeof(WNDCLASSEX);
830     wcex.style = CS_HREDRAW | CS_VREDRAW;
831     wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow;
832     wcex.cbClsExtra = 0;
833     wcex.cbWndExtra = 0;
834     wcex.hInstance = ::GetModuleHandle(NULL);
835     wcex.hIcon = NULL;
836     wcex.hCursor = NULL;
837     wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
838     wcex.lpszMenuName = NULL;
839     wcex.lpszClassName = _T("ImGui Platform");
840     wcex.hIconSm = NULL;
841     ::RegisterClassEx(&wcex);
842 
843     ImGui_ImplWin32_UpdateMonitors();
844 
845     // Register platform interface (will be coupled with a renderer interface)
846     ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
847     platform_io.Platform_CreateWindow = ImGui_ImplWin32_CreateWindow;
848     platform_io.Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow;
849     platform_io.Platform_ShowWindow = ImGui_ImplWin32_ShowWindow;
850     platform_io.Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos;
851     platform_io.Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos;
852     platform_io.Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize;
853     platform_io.Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize;
854     platform_io.Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus;
855     platform_io.Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus;
856     platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized;
857     platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle;
858     platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha;
859     platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
860     platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
861     platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
862 #if HAS_WIN32_IME
863     platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
864 #endif
865 
866     // Register main window handle (which is owned by the main application, not by us)
867     // 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.
868     ImGuiViewport* main_viewport = ImGui::GetMainViewport();
869     ImGuiViewportDataWin32* data = IM_NEW(ImGuiViewportDataWin32)();
870     data->Hwnd = g_hWnd;
871     data->HwndOwned = false;
872     main_viewport->PlatformUserData = data;
873     main_viewport->PlatformHandle = (void*)g_hWnd;
874 }
875 
ImGui_ImplWin32_ShutdownPlatformInterface()876 static void ImGui_ImplWin32_ShutdownPlatformInterface()
877 {
878     ::UnregisterClass(_T("ImGui Platform"), ::GetModuleHandle(NULL));
879 }
880 
881 //---------------------------------------------------------------------------------------------------------
882 
883 #endif /* [Bruno Levy] */
884