diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 6b1e81f7ac1a..b46d1985cf85 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -390,6 +390,19 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev) if (ev->keyboard.display == bd->Display) io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN); return true; + case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT: + if (ev->display.source == bd->Display) + io.AddFocusEvent(false); + return false; // don't consume event + case ALLEGRO_EVENT_DISPLAY_SWITCH_IN: + if (ev->display.source == bd->Display) + { + io.AddFocusEvent(true); +#if defined(ALLEGRO_UNSTABLE) + al_clear_keyboard_state(bd->Display); +#endif + } + return false; // don't consume event } return false; } diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index dfc81e09f424..f60100e1fa77 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -80,6 +80,7 @@ struct ImGui_ImplGlfw_Data bool InstalledCallbacks; // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + GLFWwindowfocusfun PrevUserCallbackWindowFocus; GLFWcursorenterfun PrevUserCallbackCursorEnter; GLFWmousebuttonfun PrevUserCallbackMousebutton; GLFWscrollfun PrevUserCallbackScroll; @@ -160,6 +161,16 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int a #endif } +void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + if (bd->PrevUserCallbackWindowFocus != NULL) + bd->PrevUserCallbackWindowFocus(window, focused); + + ImGuiIO& io = ImGui::GetIO(); + io.AddFocusEvent(focused != 0); +} + void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); @@ -256,6 +267,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw glfwSetErrorCallback(prev_error_callback); // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. + bd->PrevUserCallbackWindowFocus = NULL; bd->PrevUserCallbackMousebutton = NULL; bd->PrevUserCallbackScroll = NULL; bd->PrevUserCallbackKey = NULL; @@ -264,6 +276,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw if (install_callbacks) { bd->InstalledCallbacks = true; + bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback); bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback); bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); @@ -298,6 +311,7 @@ void ImGui_ImplGlfw_Shutdown() if (bd->InstalledCallbacks) { + glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus); glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter); glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton); glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll); diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 4d718f0acc7e..5e1fb06df29c 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -32,6 +32,7 @@ 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_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 2fcb7124140d..5745390629e9 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -60,14 +60,24 @@ static void resetKeys() @interface ImFocusObserver : NSObject +- (void)onApplicationBecomeActive:(NSNotification*)aNotification; - (void)onApplicationBecomeInactive:(NSNotification*)aNotification; @end @implementation ImFocusObserver +- (void)onApplicationBecomeActive:(NSNotification*)aNotification +{ + ImGuiIO& io = ImGui::GetIO(); + io.AddFocusEvent(true); +} + - (void)onApplicationBecomeInactive:(NSNotification*)aNotification { + ImGuiIO& io = ImGui::GetIO(); + io.AddFocusEvent(false); + // Unfocused applications do not receive input events, therefore we must manually // release any pressed keys when application loses focus, otherwise they would remain // stuck in a pressed state. https://github.com/ocornut/imgui/issues/3832 @@ -155,6 +165,10 @@ bool ImGui_ImplOSX_Init() }; g_FocusObserver = [[ImFocusObserver alloc] init]; + [[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver + selector:@selector(onApplicationBecomeActive:) + name:NSApplicationDidBecomeActiveNotification + object:nil]; [[NSNotificationCenter defaultCenter] addObserver:g_FocusObserver selector:@selector(onApplicationBecomeInactive:) name:NSApplicationDidResignActiveNotification diff --git a/backends/imgui_impl_sdl.cpp b/backends/imgui_impl_sdl.cpp index 09e6acb6c964..f7c9de28b829 100644 --- a/backends/imgui_impl_sdl.cpp +++ b/backends/imgui_impl_sdl.cpp @@ -148,6 +148,15 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) #endif return true; } + case SDL_WINDOWEVENT: + { + if (event->window.event == SDL_WINDOWEVENT_FOCUS_GAINED) + io.AddFocusEvent(true); + else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST) + io.AddFocusEvent(false); + + return false; // don't consume event + } } return false; } diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 984171a58e8e..f7285a7604ae 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -431,9 +431,11 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA io.KeyAlt = down; return 0; } + case WM_SETFOCUS: + io.AddFocusEvent(true); + return 0; case WM_KILLFOCUS: - memset(io.KeysDown, 0, sizeof(io.KeysDown)); - io.KeyCtrl = io.KeyShift = io.KeyAlt = io.KeySuper = false; + io.AddFocusEvent(false); return 0; case WM_CHAR: // You can also use ToAscii()+GetKeyboardState() to retrieve characters. diff --git a/imgui.cpp b/imgui.cpp index 7bab8ca31038..7918a9df3ad7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1180,6 +1180,21 @@ void ImGuiIO::ClearInputCharacters() InputQueueCharacters.resize(0); } +void ImGuiIO::AddFocusEvent(bool gain) +{ + if (!gain) + { + // Reset pressed buttons when focus is lost + memset(KeysDown, 0, sizeof(KeysDown)); + for (int n = 0; n < IM_ARRAYSIZE(KeysDownDuration); n++) + KeysDownDuration[n] = KeysDownDurationPrev[n] = -1.0f; + KeyCtrl = KeyShift = KeyAlt = KeySuper = false; + KeyMods = 0; + for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++) + NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f; + } +} + //----------------------------------------------------------------------------- // [SECTION] MISC HELPERS/UTILITIES (Geometry functions) //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 182c46a556ea..51a14abdf21e 100644 --- a/imgui.h +++ b/imgui.h @@ -1869,6 +1869,7 @@ struct ImGuiIO IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue new character input from an UTF-16 character, it can be a surrogate IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually + IMGUI_API void AddFocusEvent(bool gain); // Notifies ImGui when underlying windows lose or gain input focus //------------------------------------------------------------------ // Output - Updated by NewFrame() or EndFrame()/Render()