diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index d4eb02a909e..cb60251ed95 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -88,6 +88,11 @@ public interface IPublicAPI /// Show the MainWindow when hiding /// void ShowMainWindow(); + + /// + /// Focus the query text box in the main window + /// + void FocusQueryTextBox(); /// /// Hide MainWindow diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index a0614d90fd5..66e11f88130 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Specialized; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -10,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Input; using System.Windows.Media; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core; @@ -32,7 +34,6 @@ using JetBrains.Annotations; using Squirrel; using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch; -using System.ComponentModel; namespace Flow.Launcher { @@ -93,6 +94,8 @@ public async void RestartApp() public void ShowMainWindow() => _mainVM.Show(); + public void FocusQueryTextBox() => _mainVM.FocusQueryTextBox(); + public void HideMainWindow() => _mainVM.Hide(); public bool IsMainWindowVisible() => _mainVM.MainWindowVisibilityStatus; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 807275fcbd5..6e1b0dd9379 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1926,6 +1926,21 @@ public void UpdateResultView(ICollection resultsForUpdates) Results.AddResults(resultsForUpdates, token, reSelect); } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "")] + public void FocusQueryTextBox() + { + // When application is exiting, the Application.Current will be null + Application.Current?.Dispatcher.Invoke(() => + { + // When application is exiting, the Application.Current will be null + if (Application.Current?.MainWindow is MainWindow window) + { + window.QueryTextBox.Focus(); + Keyboard.Focus(window.QueryTextBox); + } + }); + } + #endregion #region IDisposable diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs index 0d395c0537a..2613c770b35 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs @@ -378,11 +378,17 @@ bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state) private void OnWinRPressed() { + Context.API.ShowMainWindow(); // show the main window and set focus to the query box - _ = Task.Run(() => + _ = Task.Run(async () => { - Context.API.ShowMainWindow(); 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); + Context.API.FocusQueryTextBox(); }); }