diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml b/src/modules/launcher/PowerLauncher/MainWindow.xaml index 942c07cd09..e6a321969d 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml @@ -74,8 +74,10 @@ Margin="16,0,0,0" ItemContainerStyle="{StaticResource PluginsListViewItemStyle}" ItemsSource="{Binding Plugins}" + PreviewMouseLeftButtonUp="PluginsHintsList_PreviewMouseLeftButtonUp" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" + SelectedItem="{Binding SelectedPlugin, Mode=TwoWay}" SelectionMode="Single"> diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs index c7ae5a5bca..103c2eb59d 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs @@ -364,6 +364,11 @@ namespace PowerLauncher BringProcessToForeground(); _viewModel.SetPluginsOverviewVisibility(); + if (_viewModel.Plugins.Count > 0) + { + _viewModel.SelectedPlugin = null; + pluginsHintsList.ScrollIntoView(pluginsHintsList.Items[0]); + } // HACK: Setting focus here again fixes some focus issues, like on first run or after showing a message box. SearchBox.QueryTextBox.Focus(); @@ -484,66 +489,101 @@ namespace PowerLauncher private void Launcher_KeyDown(object sender, KeyEventArgs e) { - if (e.Key == Key.Tab && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) + if (_viewModel.PluginsOverviewVisibility == Visibility.Visible) { - _viewModel.SelectPrevTabItemCommand.Execute(null); - UpdateTextBoxToSelectedItem(); - e.Handled = true; - } - else if (e.Key == Key.Tab) - { - _viewModel.SelectNextTabItemCommand.Execute(null); - UpdateTextBoxToSelectedItem(); - e.Handled = true; - } - else if (e.Key == Key.Down) - { - _viewModel.SelectNextItemCommand.Execute(null); - UpdateTextBoxToSelectedItem(); - e.Handled = true; - } - else if (e.Key == Key.Up) - { - _viewModel.SelectPrevItemCommand.Execute(null); - UpdateTextBoxToSelectedItem(); - e.Handled = true; - } - else if (e.Key == Key.Right) - { - if (SearchBox.QueryTextBox.CaretIndex == SearchBox.QueryTextBox.Text.Length) + if (e.Key == Key.Up) { - _viewModel.SelectNextContextMenuItemCommand.Execute(null); + _viewModel.SelectPrevOverviewPluginCommand.Execute(null); + pluginsHintsList.ScrollIntoView(_viewModel.SelectedPlugin); + e.Handled = true; + } + else if (e.Key == Key.Down) + { + _viewModel.SelectNextOverviewPluginCommand.Execute(null); + pluginsHintsList.ScrollIntoView(_viewModel.SelectedPlugin); + e.Handled = true; + } + else if (e.Key == Key.Tab && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) + { + _viewModel.SelectPrevOverviewPluginCommand.Execute(null); + pluginsHintsList.ScrollIntoView(_viewModel.SelectedPlugin); + e.Handled = true; + } + else if (e.Key == Key.Tab) + { + _viewModel.SelectNextOverviewPluginCommand.Execute(null); + pluginsHintsList.ScrollIntoView(_viewModel.SelectedPlugin); + e.Handled = true; + } + else if (e.Key == Key.Enter) + { + QueryForSelectedPlugin(); e.Handled = true; } } - else if (e.Key == Key.Left) + else { - if (SearchBox.QueryTextBox.CaretIndex == SearchBox.QueryTextBox.Text.Length) + if (e.Key == Key.Tab && (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))) { - if (_viewModel.Results != null && _viewModel.Results.IsContextMenuItemSelected()) + _viewModel.SelectPrevTabItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); + e.Handled = true; + } + else if (e.Key == Key.Tab) + { + _viewModel.SelectNextTabItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); + e.Handled = true; + } + else if (e.Key == Key.Down) + { + _viewModel.SelectNextItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); + e.Handled = true; + } + else if (e.Key == Key.Up) + { + _viewModel.SelectPrevItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); + e.Handled = true; + } + else if (e.Key == Key.Right) + { + if (SearchBox.QueryTextBox.CaretIndex == SearchBox.QueryTextBox.Text.Length) { - _viewModel.SelectPreviousContextMenuItemCommand.Execute(null); + _viewModel.SelectNextContextMenuItemCommand.Execute(null); e.Handled = true; } } - } - else if (e.Key == Key.PageDown) - { - _viewModel.SelectNextPageCommand.Execute(null); - e.Handled = true; - } - else if (e.Key == Key.PageUp) - { - _viewModel.SelectPrevPageCommand.Execute(null); - e.Handled = true; - } - else if (e.Key == Key.Back) - { - _deletePressed = true; - } - else - { - _viewModel.HandleContextMenu(e.Key, Keyboard.Modifiers); + else if (e.Key == Key.Left) + { + if (SearchBox.QueryTextBox.CaretIndex == SearchBox.QueryTextBox.Text.Length) + { + if (_viewModel.Results != null && _viewModel.Results.IsContextMenuItemSelected()) + { + _viewModel.SelectPreviousContextMenuItemCommand.Execute(null); + e.Handled = true; + } + } + } + else if (e.Key == Key.PageDown) + { + _viewModel.SelectNextPageCommand.Execute(null); + e.Handled = true; + } + else if (e.Key == Key.PageUp) + { + _viewModel.SelectPrevPageCommand.Execute(null); + e.Handled = true; + } + else if (e.Key == Key.Back) + { + _deletePressed = true; + } + else + { + _viewModel.HandleContextMenu(e.Key, Keyboard.Modifiers); + } } } @@ -796,5 +836,25 @@ namespace PowerLauncher _hwndSource = null; } + + private void PluginsHintsList_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + QueryForSelectedPlugin(); + } + + private void QueryForSelectedPlugin() + { + if (_viewModel.Plugins.Count > 0 && _viewModel.SelectedPlugin != null) + { + // Needed to update UI in case the user choose the same plugin multiple times + _viewModel.ChangeQueryText(string.Empty); + + _viewModel.ChangeQueryText(_viewModel.SelectedPlugin.Metadata.ActionKeyword, true); + SearchBox.QueryTextBox.Focus(); + + _viewModel.SelectedPlugin = null; + pluginsHintsList.ScrollIntoView(pluginsHintsList.Items[0]); + } + } } } diff --git a/src/modules/launcher/PowerLauncher/Styles/Styles.xaml b/src/modules/launcher/PowerLauncher/Styles/Styles.xaml index 4ed519b5b1..587991d005 100644 --- a/src/modules/launcher/PowerLauncher/Styles/Styles.xaml +++ b/src/modules/launcher/PowerLauncher/Styles/Styles.xaml @@ -41,24 +41,20 @@ - - - - - - - + + - + + + + + + diff --git a/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs b/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs index 363ff61148..1f02ca5d44 100644 --- a/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs +++ b/src/modules/launcher/PowerLauncher/ViewModel/MainViewModel.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation +// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -132,6 +132,10 @@ namespace PowerLauncher.ViewModel } }); } + else if (e.PropertyName == nameof(PowerToysRunSettings.ShowPluginsOverview)) + { + RefreshPluginsOverview(); + } }; SetHotkey(hwnd, _settings.Hotkey, OnHotkey); @@ -299,6 +303,16 @@ namespace PowerLauncher.ViewModel OnPropertyChanged(nameof(SystemQueryText)); } }); + + SelectNextOverviewPluginCommand = new RelayCommand(_ => + { + SelectNextOverviewPlugin(); + }); + + SelectPrevOverviewPluginCommand = new RelayCommand(_ => + { + SelectPrevOverviewPlugin(); + }); } private ResultsViewModel _results; @@ -473,6 +487,10 @@ namespace PowerLauncher.ViewModel public ICommand ClearQueryCommand { get; private set; } + public ICommand SelectNextOverviewPluginCommand { get; private set; } + + public ICommand SelectPrevOverviewPluginCommand { get; private set; } + public class QueryTuningOptions { public int SearchClickedItemWeight { get; set; } @@ -1212,6 +1230,22 @@ namespace PowerLauncher.ViewModel public ObservableCollection Plugins { get; } = new(); + private PluginPair _selectedPlugin; + + public PluginPair SelectedPlugin + { + get => _selectedPlugin; + + set + { + if (_selectedPlugin != value) + { + _selectedPlugin = value; + OnPropertyChanged(nameof(SelectedPlugin)); + } + } + } + private Visibility _pluginsOverviewVisibility = Visibility.Visible; public Visibility PluginsOverviewVisibility @@ -1245,5 +1279,51 @@ namespace PowerLauncher.ViewModel } }); } + + private void SelectNextOverviewPlugin() + { + if (Plugins.Count == 0) + { + return; + } + + var selectedIndex = Plugins.IndexOf(SelectedPlugin); + if (selectedIndex == -1) + { + selectedIndex = 0; + } + else + { + if (++selectedIndex > Plugins.Count - 1) + { + selectedIndex = 0; + } + } + + SelectedPlugin = Plugins[selectedIndex]; + } + + private void SelectPrevOverviewPlugin() + { + if (Plugins.Count == 0) + { + return; + } + + var selectedIndex = Plugins.IndexOf(SelectedPlugin); + if (selectedIndex == -1) + { + selectedIndex = Plugins.Count - 1; + } + else + { + if (--selectedIndex < 0) + { + selectedIndex = Plugins.Count - 1; + } + } + + SelectedPlugin = Plugins[selectedIndex]; + } } } diff --git a/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs b/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs index d063c24218..de5c841ef0 100644 --- a/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs +++ b/src/modules/launcher/Wox.Infrastructure/UserSettings/PowerToysRunSettings.cs @@ -326,7 +326,20 @@ namespace Wox.Infrastructure.UserSettings None, } - public ShowPluginsOverviewMode ShowPluginsOverview { get; set; } = ShowPluginsOverviewMode.All; + private ShowPluginsOverviewMode _showPluginsOverview = ShowPluginsOverviewMode.All; + + public ShowPluginsOverviewMode ShowPluginsOverview + { + get => _showPluginsOverview; + set + { + if (_showPluginsOverview != value) + { + _showPluginsOverview = value; + OnPropertyChanged(nameof(ShowPluginsOverview)); + } + } + } public bool IgnoreHotkeysOnFullscreen { get; set; }