diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 68615160..ac03b3c1 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -414,8 +414,6 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) }; bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro)); - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); - #if ALLEGRO_HAS_CLIPBOARD io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText; io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText; diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index ab78faf9..b1964358 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -13,7 +13,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer. diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 4c690722..2f8e808f 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -13,7 +13,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer. diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 31fd48f3..e0e74c88 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -22,7 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer. diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index c27836ca..45be26a5 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -13,7 +13,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-06-25: DirectX9: Explicitly disable texture state stages after >= 1. // 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 2a87b62c..7496aeb3 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -20,7 +20,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback(). // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API. // 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback(). @@ -111,6 +112,7 @@ struct ImGui_ImplGlfw_Data // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. GLFWwindowfocusfun PrevUserCallbackWindowFocus; + GLFWcursorposfun PrevUserCallbackCursorPos; GLFWcursorenterfun PrevUserCallbackCursorEnter; GLFWmousebuttonfun PrevUserCallbackMousebutton; GLFWscrollfun PrevUserCallbackScroll; @@ -336,16 +338,37 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) io.AddFocusEvent(focused != 0); } +void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window) + bd->PrevUserCallbackCursorPos(window, x, y); + + ImGuiIO& io = ImGui::GetIO(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + int window_x, window_y; + glfwGetWindowPos(window, &window_x, &window_y); + x += window_x; + y += window_y; + } + io.MousePos = ImVec2((float)x, (float)y); +} + void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window) bd->PrevUserCallbackCursorEnter(window, entered); + ImGuiIO& io = ImGui::GetIO(); if (entered) bd->MouseWindow = window; if (!entered && bd->MouseWindow == window) + { bd->MouseWindow = NULL; + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + } } void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) @@ -424,6 +447,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->InstalledCallbacks = true; bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); + bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback); bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); @@ -475,6 +499,7 @@ void ImGui_ImplGlfw_Shutdown() { glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus); glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter); + glfwSetCursorPosCallback(bd->Window, bd->PrevUserCallbackCursorPos); glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton); glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll); glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey); @@ -490,61 +515,52 @@ void ImGui_ImplGlfw_Shutdown() IM_DELETE(bd); } -static void ImGui_ImplGlfw_UpdateMousePosAndButtons() +static void ImGui_ImplGlfw_UpdateMouseData() { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - const ImVec2 mouse_pos_prev = io.MousePos; - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); io.MouseHoveredViewport = 0; - // Update mouse buttons - // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame) - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) - { - io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0; - bd->MouseJustPressed[i] = false; - } - + const ImVec2 mouse_pos_prev = io.MousePos; + int mouse_buttons_mask = 0x00; for (int n = 0; n < platform_io.Viewports.Size; n++) { ImGuiViewport* viewport = platform_io.Viewports[n]; GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle; #ifdef __EMSCRIPTEN__ - const bool focused = true; + const bool is_window_focused = true; #else - const bool focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0; + const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0; #endif - GLFWwindow* mouse_window = (bd->MouseWindow == window || focused) ? window : NULL; - - // Update mouse buttons - if (focused) - for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) - io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0; - - // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - // (When multi-viewports are enabled, all Dear ImGui positions are same as OS positions) - if (io.WantSetMousePos && focused) - glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y)); - - // Set Dear ImGui mouse position from OS position - if (mouse_window != NULL) + if (is_window_focused) { - double mouse_x, mouse_y; - glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + // Update mouse button mask (applied below) + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + if (glfwGetMouseButton(window, i) != 0) + mouse_buttons_mask |= (1 << i); + + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. + if (io.WantSetMousePos) + glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y)); + + // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured) + if (bd->MouseWindow == NULL) { - // 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) - int window_x, window_y; - glfwGetWindowPos(window, &window_x, &window_y); - io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y); - } - else - { - // 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) + double mouse_x, mouse_y; + glfwGetCursorPos(window, &mouse_x, &mouse_y); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + // 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) + // 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) + int window_x, window_y; + glfwGetWindowPos(window, &window_x, &window_y); + mouse_x += window_x; + mouse_y += window_y; + } io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); } } @@ -566,6 +582,14 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons() io.MouseHoveredViewport = viewport->ID; #endif } + + // Update mouse buttons + // (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame) + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) + { + io.MouseDown[i] = bd->MouseJustPressed[i] || (mouse_buttons_mask & (1 << i)) != 0; + bd->MouseJustPressed[i] = false; + } } static void ImGui_ImplGlfw_UpdateMouseCursor() @@ -701,10 +725,8 @@ void ImGui_ImplGlfw_NewFrame() io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f); bd->Time = current_time; - // Update key modifiers ImGui_ImplGlfw_UpdateKeyModifiers(); - - ImGui_ImplGlfw_UpdateMousePosAndButtons(); + ImGui_ImplGlfw_UpdateMouseData(); ImGui_ImplGlfw_UpdateMouseCursor(); // Update game controllers (if enabled and available) @@ -800,6 +822,7 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) // Install GLFW callbacks for secondary viewports glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback); glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback); + glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback); glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback); glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback); glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback); diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 18f87e5e..478ca31b 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -37,8 +37,9 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); // GLFW callbacks // - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any. // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks. -IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); -IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); +IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84 +IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84 +IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87 IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 871d9c15..2b6d10ca 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -20,7 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-12-08: OpenGL: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 7e8b066a..8cc7a63c 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -15,7 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers. // 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions. // 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader. diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index b0f8e33f..33485c73 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -7,6 +7,7 @@ // [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 kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: IME support. // Issues: // [ ] Platform: Multi-viewport / platform windows. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index a3f3ec5e..b7d37cc1 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -7,6 +7,7 @@ // [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 kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: IME support. // Issues: // [ ] Platform: Multi-viewport / platform windows. @@ -24,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2022-01-12: Inputs: Added basic Platform IME support, hooking the io.SetPlatformImeDataFn() function. // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2021-12-13: *BREAKING CHANGE* Add NSView parameter to ImGui_ImplOSX_Init(). Generally fix keyboard support. Using kVK_* codes for keyboard keys. // 2021-12-13: Add game controller support. @@ -56,6 +58,7 @@ static bool g_MouseDown[ImGuiMouseButton_COUNT] = {}; static ImGuiKeyModFlags g_KeyModifiers = ImGuiKeyModFlags_None; static ImFocusObserver* g_FocusObserver = nil; static KeyEventResponder* g_KeyEventResponder = nil; +static NSTextInputContext* g_InputContext = nil; // Undocumented methods for creating cursors. @interface NSCursor() @@ -93,6 +96,29 @@ static double GetMachAbsoluteTimeInSeconds() @end @implementation KeyEventResponder +{ + float _posX; + float _posY; + NSRect _imeRect; +} + +#pragma mark - Public + +- (void)setImePosX:(float)posX imePosY:(float)posY +{ + _posX = posX; + _posY = posY; +} + +- (void)updateImePosWithView:(NSView *)view +{ + NSWindow *window = view.window; + if (!window) + return; + NSRect contentRect = [window contentRectForFrameRect:window.frame]; + NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0); + _imeRect = [window convertRectToScreen:rect]; +} - (void)viewDidMoveToWindow { @@ -147,7 +173,7 @@ static double GetMachAbsoluteTimeInSeconds() - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange { - return NSZeroRect; + return _imeRect; } - (BOOL)hasMarkedText @@ -392,6 +418,7 @@ bool ImGui_ImplOSX_Init(NSView* view) // Add the NSTextInputClient to the view hierarchy, // to receive keyboard events and translate them to input text. g_KeyEventResponder = [[KeyEventResponder alloc] initWithFrame:NSZeroRect]; + g_InputContext = [[NSTextInputContext alloc] initWithClient:g_KeyEventResponder]; [view addSubview:g_KeyEventResponder]; // Some events do not raise callbacks of AppView in some circumstances (for example when CMD key is held down). @@ -403,6 +430,21 @@ bool ImGui_ImplOSX_Init(NSView* view) return event; }]; + io.SetPlatformImeDataFn = [](ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void + { + if (data->WantVisible) + { + [g_InputContext activate]; + } + else + { + [g_InputContext discardMarkedText]; + [g_InputContext invalidateCharacterCoordinates]; + [g_InputContext deactivate]; + } + [g_KeyEventResponder setImePosX:data->InputPos.x imePosY:data->InputPos.y + data->InputLineHeight]; + }; + return true; } @@ -501,6 +543,13 @@ static void ImGui_ImplOSX_UpdateKeyModifiers() io.AddKeyModsEvent(g_KeyModifiers); } +static void ImGui_ImplOSX_UpdateImePosWithView(NSView* view) +{ + ImGuiIO& io = ImGui::GetIO(); + if (io.WantTextInput) + [g_KeyEventResponder updateImePosWithView:view]; +} + void ImGui_ImplOSX_NewFrame(NSView* view) { // Setup display size @@ -525,6 +574,7 @@ void ImGui_ImplOSX_NewFrame(NSView* view) ImGui_ImplOSX_UpdateKeyModifiers(); ImGui_ImplOSX_UpdateMouseCursorAndButtons(); ImGui_ImplOSX_UpdateGamepads(); + ImGui_ImplOSX_UpdateImePosWithView(view); } bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) @@ -605,9 +655,10 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) if ([event isARepeat]) return io.WantCaptureKeyboard; + int key_code = (int)[event keyCode]; ImGuiKey key = ImGui_ImplOSX_KeyCodeToImGuiKey(key_code); io.AddKeyEvent(key, event.type == NSEventTypeKeyDown); - io.SetKeyEventNativeData(key, (int)[event keyCode], -1); // To support legacy indexing (<1.87 user code) + io.SetKeyEventNativeData(key, key_code, -1); // To support legacy indexing (<1.87 user code) return io.WantCaptureKeyboard; } diff --git a/backends/imgui_impl_sdl.cpp b/backends/imgui_impl_sdl.cpp index 6711aa5f..c1225ce2 100644 --- a/backends/imgui_impl_sdl.cpp +++ b/backends/imgui_impl_sdl.cpp @@ -20,7 +20,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API. +// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST. // 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+) @@ -85,6 +87,7 @@ struct ImGui_ImplSDL2_Data { SDL_Window* Window; Uint64 Time; + int MouseButtonsDown; bool MousePressed[3]; SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; char* ClipboardTextData; @@ -248,7 +251,20 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) switch (event->type) { - case SDL_MOUSEWHEEL: + case SDL_MOUSEMOTION: + { + ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + int window_x, window_y; + SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y); + mouse_pos.x += window_x; + mouse_pos.y += window_y; + } + io.MousePos = mouse_pos; + return true; + } + case SDL_MOUSEWHEEL: { if (event->wheel.x > 0) io.MouseWheelH += 1; if (event->wheel.x < 0) io.MouseWheelH -= 1; @@ -256,45 +272,55 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) if (event->wheel.y < 0) io.MouseWheel -= 1; return true; } - case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: { - if (event->button.button == SDL_BUTTON_LEFT) { bd->MousePressed[0] = true; } - if (event->button.button == SDL_BUTTON_RIGHT) { bd->MousePressed[1] = true; } - if (event->button.button == SDL_BUTTON_MIDDLE) { bd->MousePressed[2] = true; } + int mouse_button = -1; + if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } + if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; } + if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; } + if (mouse_button != -1) + break; + if (event->type == SDL_MOUSEBUTTONDOWN) + bd->MousePressed[mouse_button] = true; + bd->MouseButtonsDown = (event->type == SDL_MOUSEBUTTONDOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button)); return true; } - case SDL_TEXTINPUT: + case SDL_TEXTINPUT: { io.AddInputCharactersUTF8(event->text.text); return true; } - case SDL_KEYDOWN: - case SDL_KEYUP: + case SDL_KEYDOWN: + case SDL_KEYUP: { ImGuiKey key = ImGui_ImplSDL2_KeycodeToImGuiKey(event->key.keysym.sym); io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. return true; } - // Multi-viewport support - case SDL_WINDOWEVENT: - Uint8 window_event = event->window.event; - if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED || window_event == SDL_WINDOWEVENT_FOCUS_GAINED || window_event == SDL_WINDOWEVENT_FOCUS_LOST) - if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID))) - { - if (window_event == SDL_WINDOWEVENT_CLOSE) - viewport->PlatformRequestClose = true; - if (window_event == SDL_WINDOWEVENT_MOVED) - viewport->PlatformRequestMove = true; - if (window_event == SDL_WINDOWEVENT_RESIZED) - viewport->PlatformRequestResize = true; - if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) - io.AddFocusEvent(true); - else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) - io.AddFocusEvent(false); - return true; - } - break; + case SDL_WINDOWEVENT: + { + Uint8 window_event = event->window.event; + if (window_event == SDL_WINDOWEVENT_LEAVE) + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) + io.AddFocusEvent(true); + else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) + io.AddFocusEvent(false); + if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED) + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID))) + { + if (window_event == SDL_WINDOWEVENT_CLOSE) + viewport->PlatformRequestClose = true; + if (window_event == SDL_WINDOWEVENT_MOVED) + viewport->PlatformRequestMove = true; + if (window_event == SDL_WINDOWEVENT_RESIZED) + viewport->PlatformRequestResize = true; + return true; + } + return true; + } } return false; } @@ -427,77 +453,60 @@ void ImGui_ImplSDL2_Shutdown() } // This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4. -static void ImGui_ImplSDL2_UpdateMousePosAndButtons() +static void ImGui_ImplSDL2_UpdateMouseData() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); - ImVec2 mouse_pos_prev = io.MousePos; - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); + // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below) +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside + SDL_CaptureMouse(bd->MouseButtonsDown != 0 ? SDL_TRUE : SDL_FALSE); + SDL_Window* focused_window = SDL_GetKeyboardFocus(); + const bool is_app_focused = (bd->Window == focused_window); +#else + const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only +#endif + + if (is_app_focused) + { + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) + { +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y); + else +#endif + SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); + } + + // (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured) + if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0) + { + // 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) + // 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) + int mouse_x, mouse_y, window_x, window_y; + SDL_GetGlobalMouseState(&mouse_x, &mouse_y); + if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) + { + SDL_GetWindowPosition(focused_window, &window_x, &window_y); + mouse_x -= window_x; + mouse_y -= window_y; + } + io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); + } + } + + // We don't support ImGuiBackendFlags_HasMouseHoveredViewport io.MouseHoveredViewport = 0; - // Update mouse buttons - int mouse_x_local, mouse_y_local; - Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local); + // Update buttons + Uint32 mouse_buttons = SDL_GetMouseState(NULL, NULL); io.MouseDown[0] = bd->MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. io.MouseDown[1] = bd->MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0; io.MouseDown[2] = bd->MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0; bd->MousePressed[0] = bd->MousePressed[1] = bd->MousePressed[2] = false; - - // Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing) -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - SDL_Window* focused_window = SDL_GetKeyboardFocus(); - SDL_Window* hovered_window = SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH ? SDL_GetMouseFocus() : NULL; // This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH. - SDL_Window* mouse_window = NULL; - if (hovered_window && (bd->Window == hovered_window || ImGui::FindViewportByPlatformHandle((void*)hovered_window))) - mouse_window = hovered_window; - else if (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window))) - mouse_window = focused_window; - - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside - SDL_CaptureMouse(ImGui::IsAnyMouseDown() ? SDL_TRUE : SDL_FALSE); -#else - // SDL 2.0.3 and non-windowed systems: single-viewport only - SDL_Window* mouse_window = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) ? bd->Window : NULL; -#endif - - if (mouse_window == NULL) - return; - - // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - if (io.WantSetMousePos) - { -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - SDL_WarpMouseGlobal((int)mouse_pos_prev.x, (int)mouse_pos_prev.y); - else -#endif - SDL_WarpMouseInWindow(bd->Window, (int)mouse_pos_prev.x, (int)mouse_pos_prev.y); - } - - // Set Dear ImGui mouse position from OS position + get buttons. (this is the common behavior) - if (bd->MouseCanUseGlobalState) - { - int mouse_x_global, mouse_y_global; - SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global); - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - // 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) - io.MousePos = ImVec2((float)mouse_x_global, (float)mouse_y_global); - } - else - { - // 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) - // Unlike local position obtained earlier this will be valid when straying out of bounds. - int window_x, window_y; - SDL_GetWindowPosition(mouse_window, &window_x, &window_y); - io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y)); - } - } - else - { - io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local); - } } static void ImGui_ImplSDL2_UpdateMouseCursor() @@ -625,10 +634,8 @@ void ImGui_ImplSDL2_NewFrame() io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; - // Update key modifiers ImGui_ImplSDL2_UpdateKeyModifiers(); - - ImGui_ImplSDL2_UpdateMousePosAndButtons(); + ImGui_ImplSDL2_UpdateMouseData(); ImGui_ImplSDL2_UpdateMouseCursor(); // Update game controllers (if enabled and available) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index c9de3256..2bb768c9 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -24,7 +24,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-03-22: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize. diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 072f2549..6e12c6f4 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -314,8 +314,8 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1); // Bind shader and vertex buffers - wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize); - wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize); + wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize * sizeof(ImDrawVert)); + wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize * sizeof(ImDrawIdx)); wgpuRenderPassEncoderSetPipeline(ctx, g_pipelineState); wgpuRenderPassEncoderSetBindGroup(ctx, 0, g_resources.CommonBindGroup, 0, NULL); diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 6348e8a4..d5e64fc8 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -19,6 +19,7 @@ #define WIN32_LEAN_AND_MEAN #endif #include +#include // GET_X_LPARAM(), GET_Y_LPARAM() #include #include @@ -34,7 +35,9 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2022-01-12: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API. +// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. // 2021-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness. // 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages. @@ -81,6 +84,7 @@ struct ImGui_ImplWin32_Data HWND hWnd; HWND MouseHwnd; bool MouseTracked; + int MouseButtonsDown; INT64 Time; INT64 TicksPerSecond; ImGuiMouseCursor LastMouseCursor; @@ -256,54 +260,41 @@ static void ImGui_ImplWin32_UpdateKeyModifiers() // This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports) // Because of that, it is a little more complicated than your typical single-viewport binding code! -static void ImGui_ImplWin32_UpdateMousePos() +static void ImGui_ImplWin32_UpdateMouseData() { ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(bd->hWnd != 0); - const ImVec2 mouse_pos_prev = io.MousePos; - io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); - io.MouseHoveredViewport = 0; - - // Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing) - HWND focused_window = ::GetForegroundWindow(); - HWND hovered_window = bd->MouseHwnd; - HWND mouse_window = NULL; - if (hovered_window && (hovered_window == bd->hWnd || ::IsChild(hovered_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)hovered_window))) - mouse_window = hovered_window; - else if (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)focused_window))) - mouse_window = focused_window; - if (mouse_window == NULL) - return; - - // Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) - // (When multi-viewports are enabled, all Dear ImGui positions are same as OS positions) - if (io.WantSetMousePos) - { - POINT pos = { (int)mouse_pos_prev.x, (int)mouse_pos_prev.y }; - if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0) - ::ClientToScreen(mouse_window, &pos); - ::SetCursorPos(pos.x, pos.y); - } - - // Set Dear ImGui mouse position from OS position POINT mouse_screen_pos; - if (!::GetCursorPos(&mouse_screen_pos)) - return; - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0; + + HWND focused_window = ::GetForegroundWindow(); + const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)focused_window))); + if (is_app_focused) { - // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) - // This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same. - io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y); - } - else - { - // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) - // This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE. - POINT mouse_client_pos = mouse_screen_pos; - ::ScreenToClient(bd->hWnd, &mouse_client_pos); - io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y); + // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + // When multi-viewports are enabled, all Dear ImGui positions are same as OS positions. + if (io.WantSetMousePos) + { + POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; + if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0) + ::ClientToScreen(focused_window, &pos); + ::SetCursorPos(pos.x, pos.y); + } + + // (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured) + if (!io.WantSetMousePos && !bd->MouseTracked && has_mouse_screen_pos) + { + // Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) + // (This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.) + // Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor) + // (This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.) + POINT mouse_pos = mouse_screen_pos; + if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) + ::ScreenToClient(bd->hWnd, &mouse_pos); + io.MousePos = ImVec2((float)mouse_pos.x, (float)mouse_pos.y); + } } // (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering. @@ -312,10 +303,12 @@ static void ImGui_ImplWin32_UpdateMousePos() // - This is _regardless_ of whether another viewport is focused or being dragged from. // If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the // 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. - if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) - if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd)) - if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated? - io.MouseHoveredViewport = viewport->ID; + io.MouseHoveredViewport = 0; + if (has_mouse_screen_pos) + if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos)) + if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd)) + if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated? + io.MouseHoveredViewport = viewport->ID; } // Gamepad navigation mapping @@ -415,15 +408,15 @@ void ImGui_ImplWin32_NewFrame() io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond; bd->Time = current_time; + // Update OS mouse position + ImGui_ImplWin32_UpdateMouseData(); + // Process workarounds for known Windows key handling issues ImGui_ImplWin32_ProcessKeyEventsWorkarounds(); // Update key modifiers ImGui_ImplWin32_UpdateKeyModifiers(); - // Update OS mouse position - ImGui_ImplWin32_UpdateMousePos(); - // Update OS mouse cursor with the cursor requested by imgui ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); if (bd->LastMouseCursor != mouse_cursor) @@ -583,6 +576,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA switch (msg) { case WM_MOUSEMOVE: + { // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events bd->MouseHwnd = hwnd; if (!bd->MouseTracked) @@ -591,11 +585,17 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA ::TrackMouseEvent(&tme); bd->MouseTracked = true; } + POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) }; + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ::ClientToScreen(hwnd, &mouse_pos); + io.MousePos = ImVec2((float)mouse_pos.x, (float)mouse_pos.y); break; + } case WM_MOUSELEAVE: if (bd->MouseHwnd == hwnd) bd->MouseHwnd = NULL; bd->MouseTracked = false; + io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); break; case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: @@ -607,8 +607,9 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } - if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) + if (bd->MouseButtonsDown == 0 && ::GetCapture() == NULL) ::SetCapture(hwnd); + bd->MouseButtonsDown |= 1 << button; io.MouseDown[button] = true; return 0; } @@ -622,9 +623,10 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA if (msg == WM_RBUTTONUP) { button = 1; } if (msg == WM_MBUTTONUP) { button = 2; } if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } - io.MouseDown[button] = false; - if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) + bd->MouseButtonsDown &= ~(1 << button); + if (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd) ::ReleaseCapture(); + io.MouseDown[button] = false; return 0; } case WM_MOUSEWHEEL: diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7912640d..dc6ef367 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -133,6 +133,10 @@ Breaking Changes: - io.AddKeyEvent() will later be turned into a trickling IO queue (for all inputs) to handle very low framerate better. (#2525, #2787, #3383) - io.SetKeyEventNativeData() include native keycode/scancode which will later be exposed. (#3141, #2959) - Renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. (#2625) +- Backends: GLFW: backend now uses glfwSetCursorPosCallback(). + - If calling ImGui_ImplGlfw_InitXXX with install_callbacks=true: nothing to do. is already done for you. + - If calling ImGui_ImplGlfw_InitXXX with install_callbacks=false: you WILL NEED to register the GLFW callback + using glfwSetCursorPosCallback() and forward it to the backend function ImGui_ImplGlfw_CursorPosCallback(). - Commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019) - ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen() - ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x @@ -162,7 +166,12 @@ Other Changes: - Backends: GLFW: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. We are now converting GLFW untranslated keycodes back to translated keycodes in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API. (#456, #2625) +- Backends: GLFW: Update mouse position using glfwSetCursorPosCallback() + fallback when focused but not hovered/captured. +- Backends: Win32: Update mouse position using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback when focused but not hovered/captured. +- Backends: Win32: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. - Backends: SDL: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. +- Backends: SDL: Update mouse position using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback when focused but not hovered/captured. +- Backends: SDL: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted. - Backends: Allegro5, GLFW, GLUT, SDL, OSX, Win32, Android: Updated to use io.AddKeyEvent() with full key range. (#2625) [@thedmd] - Backends: OpenGL3: Fixed a buffer overflow in imgui_impl_opengl3_loader.h init (added in 1.86). (#4468, #4830) [@dymk] It would generally not have noticeable side-effect at runtime but would be detected by runtime checkers. @@ -170,6 +179,9 @@ Other Changes: Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file. - Backends: Metal: Ignore ImDrawCmd where ElemCount == 0, which are normally not emitted by the library but can theorically be created by user code manipulating a ImDrawList. (#4857) +- Backends: OSX: Added basic Platform IME support. (#3108, #2598) [@liuliu] +- Backends: WebGPU: Fixed incorrect size parameters in wgpuRenderPassEncoderSetIndexBuffer() and + wgpuRenderPassEncoderSetVertexBuffer() calls. (#4891) [@FeepsDev] Docking+Viewports Branch: diff --git a/imgui.cpp b/imgui.cpp index 8f6d13ea..91c97b6c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8020,6 +8020,8 @@ const char* ImGui::GetKeyName(ImGuiKey key) #endif if (key == ImGuiKey_None) return "None"; + if (!IsNamedKey(key)) + return "Unknown"; return GKeyNames[key - ImGuiKey_NamedKey_BEGIN]; } @@ -8168,6 +8170,7 @@ bool ImGui::IsMousePosValid(const ImVec2* mouse_pos) return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID; } +// [WILL OBSOLETE] This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. bool ImGui::IsAnyMouseDown() { ImGuiContext& g = *GImGui; @@ -8225,6 +8228,13 @@ void ImGui::CaptureMouseFromApp(bool capture) g.WantCaptureMouseNextFrame = capture ? 1 : 0; } +static const char* GetInputSourceName(ImGuiInputSource source) +{ + const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; + IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT); + return input_source_names[source]; +} + //----------------------------------------------------------------------------- // [SECTION] ERROR CHECKING @@ -10357,6 +10367,18 @@ static ImVec2 ImGui::NavCalcPreferredRefPos() } } +const char* ImGui::GetNavInputName(ImGuiNavInput n) +{ + static const char* names[] = + { + "Activate", "Cancel", "Input", "Menu", "DpadLeft", "DpadRight", "DpadUp", "DpadDown", "LStickLeft", "LStickRight", "LStickUp", "LStickDown", + "FocusPrev", "FocusNext", "TweakSlow", "TweakFast", "KeyLeft", "KeyRight", "KeyUp", "KeyDown" + }; + IM_ASSERT(IM_ARRAYSIZE(names) == ImGuiNavInput_COUNT); + IM_ASSERT(n >= 0 && n < ImGuiNavInput_COUNT); + return names[n]; +} + float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) { ImGuiContext& g = *GImGui; @@ -17602,8 +17624,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) // Misc Details if (TreeNode("Internal state")) { - const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT); - Text("WINDOWING"); Indent(); Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL"); @@ -17616,7 +17636,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Text("ITEMS"); Indent(); - Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]); + Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, GetInputSourceName(g.ActiveIdSource)); Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); int active_id_using_key_input_count = 0; @@ -17631,7 +17651,7 @@ void ImGui::ShowMetricsWindow(bool* p_open) Indent(); Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); - Text("NavInputSource: %s", input_source_names[g.NavInputSource]); + Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource)); Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId); Text("NavActivateFlags: %04X", g.NavActivateFlags); diff --git a/imgui.h b/imgui.h index 9529b5ea..f657642e 100644 --- a/imgui.h +++ b/imgui.h @@ -65,7 +65,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.87 WIP" -#define IMGUI_VERSION_NUM 18604 +#define IMGUI_VERSION_NUM 18605 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_HAS_TABLE #define IMGUI_HAS_VIEWPORT // Viewport WIP branch @@ -940,7 +940,7 @@ namespace ImGui IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available - IMGUI_API bool IsAnyMouseDown(); // is any mouse button held? + IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid. IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves) IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold) @@ -1585,8 +1585,7 @@ enum ImGuiNavInput_ ImGuiNavInput_KeyRight_, // Move right ImGuiNavInput_KeyUp_, // Move up ImGuiNavInput_KeyDown_, // Move down - ImGuiNavInput_COUNT, - ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyLeft_ + ImGuiNavInput_COUNT }; // Configuration flags stored in io.ConfigFlags. Set by user/application. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 84ce94cc..09550518 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6091,7 +6091,7 @@ void ImGui::ShowAboutWindow(bool* p_open) namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } // Demo helper function to select among loaded fonts. -// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one. +// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one. void ImGui::ShowFontSelector(const char* label) { ImGuiIO& io = ImGui::GetIO(); diff --git a/imgui_internal.h b/imgui_internal.h index d4d8c60d..30511eec 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -453,7 +453,7 @@ static inline float ImLengthSqr(const ImVec2& lhs) static inline float ImLengthSqr(const ImVec4& lhs) { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return ImRsqrt(d); return fail_value; } static inline float ImFloor(float f) { return (float)(int)(f); } -static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() +static inline float ImFloorSigned(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } static inline int ImModPositive(int a, int b) { return (a + b) % b; } static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } @@ -2811,6 +2811,7 @@ namespace ImGui IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); + IMGUI_API const char* GetNavInputName(ImGuiNavInput n); IMGUI_API float GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode); IMGUI_API ImVec2 GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f); IMGUI_API int CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate);