diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index eb844dd7ca0..085a6b3e148 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -86,4 +86,13 @@ EVENT_OBJECT_HIDE EVENT_SYSTEM_DIALOGEND WM_POWERBROADCAST -PBT_APMRESUMEAUTOMATIC \ No newline at end of file +PBT_APMRESUMEAUTOMATIC + +SetForegroundWindow +GetForegroundWindow +GetCurrentThreadId +GetWindowThreadProcessId +AttachThreadInput +SetWindowPos +SetFocus +SetActiveWindow \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 8117339254d..18de790c5b1 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -151,6 +151,40 @@ internal static bool IsForegroundWindow(HWND handle) return handle.Equals(PInvoke.GetForegroundWindow()); } + /// + /// Brings the window to foreground if window is visible. From https://github.com/files-community/Files. + /// + /// + /// For more information, visit + ///
+ /// - + ///
+ /// -
+ ///
+ /// The window to bring. + public static unsafe void BringToForegroundEx(Window window) + { + var hWnd = GetWindowHandle(window); + var topMost = window.Topmost; + var hCurWnd = PInvoke.GetForegroundWindow(); + var dwMyID = PInvoke.GetCurrentThreadId(); + var dwCurID = PInvoke.GetWindowThreadProcessId(hCurWnd); + + PInvoke.AttachThreadInput(dwCurID, dwMyID, true); + + // Set the window to be the topmost window + PInvoke.SetWindowPos(hWnd, (HWND)(-1), 0, 0, 0, 0, SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE); + if (!topMost) + { + // Restore the window to its original position + PInvoke.SetWindowPos(hWnd, (HWND)(-2), 0, 0, 0, 0, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE); + } + PInvoke.SetForegroundWindow(hWnd); + PInvoke.SetFocus(hWnd); + PInvoke.SetActiveWindow(hWnd); + PInvoke.AttachThreadInput(dwCurID, dwMyID, false); + } + #endregion #region Task Switching diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d492f28c58c..2ba1e8a7223 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -2249,6 +2249,7 @@ public void FocusQueryTextBox() // When application is exiting, the Application.Current will be null if (Application.Current?.MainWindow is MainWindow window) { + Win32Helper.BringToForegroundEx(window); window.QueryTextBox.Focus(); Keyboard.Focus(window.QueryTextBox); } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index a86b96800c2..4bb87424bee 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -412,11 +412,11 @@ private void OnWinRPressed() _ = Task.Run(async () => { Context.API.ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}"); - + // Win+R is a system-reserved shortcut, and though the plugin intercepts the keyboard event and // shows the main window, Windows continues to process the Win key and briefly reclaims focus. // So we need to wait until the keyboard event processing is completed and then set focus - await Task.Delay(50); + await Task.Delay(1000); Context.API.FocusQueryTextBox(); }); }