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