diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherProperties.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherProperties.cs index 01887c516f..5f61705afb 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherProperties.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherProperties.cs @@ -6,8 +6,6 @@ namespace Microsoft.PowerToys.Settings.UI.Lib { public class PowerLauncherProperties { - public bool enable_powerlauncher { get; set; } - public string search_result_preference { get; set; } public string search_type_preference { get; set; } diff --git a/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherSettings.cs b/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherSettings.cs index 2ce14acefa..6934f79ee7 100644 --- a/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherSettings.cs +++ b/src/core/Microsoft.PowerToys.Settings.UI.Lib/PowerLauncherSettings.cs @@ -8,7 +8,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib { public class PowerLauncherSettings : BasePTModuleSettings { - public const string POWERTOYNAME = "PowerLauncher"; + public const string POWERTOYNAME = "Launcher"; public PowerLauncherProperties properties { get; set; } diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Main.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Main.cs index 5dd790ed8d..4ee38e52fc 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Main.cs +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Main.cs @@ -88,6 +88,13 @@ namespace Microsoft.Plugin.Indexer return hide; }; r.ContextData = searchResult; + + //If the result is a directory, then it's display should show a directory. + if(Directory.Exists(path)) + { + r.QueryTextDisplay = path; + } + results.Add(r); } } diff --git a/src/modules/launcher/Plugins/Wox.Plugin.Folder/Main.cs b/src/modules/launcher/Plugins/Wox.Plugin.Folder/Main.cs index 2bde1a9245..9734d356a2 100644 --- a/src/modules/launcher/Plugins/Wox.Plugin.Folder/Main.cs +++ b/src/modules/launcher/Plugins/Wox.Plugin.Folder/Main.cs @@ -94,30 +94,14 @@ namespace Wox.Plugin.Folder Title = title, IcoPath = path, SubTitle = subtitle, + QueryTextDisplay = path, TitleHighlightData = StringMatcher.FuzzySearch(query.Search, title).MatchData, + ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path }, Action = c => { - if (c.SpecialKeyState.CtrlPressed) - { - try - { - Process.Start(_fileExplorerProgramName, path); - return true; - } - catch (Exception ex) - { - MessageBox.Show(ex.Message, "Could not start " + path); - return false; - } - } - - string changeTo = path.EndsWith("\\") ? path : path + "\\"; - _context.API.ChangeQuery(string.IsNullOrEmpty(query.ActionKeyword) ? - changeTo : - query.ActionKeyword + " " + changeTo); - return false; - }, - ContextData = new SearchResult { Type = ResultType.Folder, FullPath = path } + Process.Start(_fileExplorerProgramName, path); + return true; + } }; } @@ -273,6 +257,7 @@ namespace Wox.Plugin.Folder return new Result { Title = firstResult, + QueryTextDisplay = search, SubTitle = $"Use > to search within the directory. Use * to search for file extensions. Or use both >*.", IcoPath = search, Score = 500, diff --git a/src/modules/launcher/Plugins/Wox.Plugin.Program/Main.cs b/src/modules/launcher/Plugins/Wox.Plugin.Program/Main.cs index b635b8f46a..444e6525e8 100644 --- a/src/modules/launcher/Plugins/Wox.Plugin.Program/Main.cs +++ b/src/modules/launcher/Plugins/Wox.Plugin.Program/Main.cs @@ -1,9 +1,11 @@ -using Microsoft.PowerToys.Settings.UI.Lib; +using Microsoft.PowerToys.Settings.UI.Lib; using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading.Tasks; +using System.Timers; using System.Windows.Controls; using Wox.Infrastructure.Logger; using Wox.Infrastructure.Storage; @@ -20,6 +22,9 @@ namespace Wox.Plugin.Program internal static UWP.Application[] _uwps { get; set; } internal static Settings _settings { get; set; } + FileSystemWatcher _watcher = null; + System.Timers.Timer _timer = null; + private static bool IsStartupIndexProgramsRequired => _settings.LastIndexTime.AddDays(3) < DateTime.Today; private static PluginInitContext _context; @@ -58,6 +63,9 @@ namespace Wox.Plugin.Program Task.WaitAll(a, b); _settings.LastIndexTime = DateTime.Today; + + InitializeFileWatchers(); + InitializeTimer(); } public void Save() @@ -73,7 +81,7 @@ namespace Wox.Plugin.Program UWP.Application[] uwps; lock (IndexLock) - { + { // just take the reference inside the lock to eliminate query time issues. win32 = _win32s; uwps = _uwps; @@ -173,8 +181,55 @@ namespace Wox.Plugin.Program IndexPrograms(); } - public void UpdateSettings(PowerLauncherSettings settings) - { + public void UpdateSettings(PowerLauncherSettings settings) + { + } + void InitializeFileWatchers() + { + // Create a new FileSystemWatcher and set its properties. + _watcher = new FileSystemWatcher(); + var resolvedPath = Environment.ExpandEnvironmentVariables("%ProgramFiles%"); + _watcher.Path = resolvedPath; + + //Filter to create and deletes of 'microsoft.system.package.metadata' directories. + _watcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName; + _watcher.IncludeSubdirectories = true; + + // Add event handlers. + _watcher.Created += OnChanged; + _watcher.Deleted += OnChanged; + + // Begin watching. + _watcher.EnableRaisingEvents = true; + } + + void InitializeTimer() + { + //multiple file writes occur on install / unistall. Adding a delay before actually indexing. + var delayInterval = 5000; + _timer = new System.Timers.Timer(delayInterval); + _timer.Enabled = true; + _timer.AutoReset = false; + _timer.Elapsed += FileWatchElapsedTimer; + _timer.Stop(); + } + + //When a watched directory changes then reset the timer. + private void OnChanged(object source, FileSystemEventArgs e) + { + Log.Debug($"|Wox.Plugin.Program.Main|Directory Changed: {e.FullPath} {e.ChangeType} - Resetting timer."); + _timer.Stop(); + _timer.Start(); + } + + private void FileWatchElapsedTimer(object sender, ElapsedEventArgs e) + { + Task.Run(() => + { + Log.Debug($"|Wox.Plugin.Program.Main| ReIndexing UWP Programs"); + IndexUWPPrograms(); + Log.Debug($"|Wox.Plugin.Program.Main| Done ReIndexing"); + }); } } } \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Wox.Plugin.Shell/Main.cs b/src/modules/launcher/Plugins/Wox.Plugin.Shell/Main.cs index 5580ed8b6e..5f72492c25 100644 --- a/src/modules/launcher/Plugins/Wox.Plugin.Shell/Main.cs +++ b/src/modules/launcher/Plugins/Wox.Plugin.Shell/Main.cs @@ -291,6 +291,9 @@ namespace Wox.Plugin.Shell bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state) { + // not overriding Win+R + // crutkas we need to earn the right for Win+R override + if (_settings.ReplaceWinR) { if (keyevent == (int)KeyEvent.WM_KEYDOWN && vkcode == (int)Keys.R && state.WinPressed) diff --git a/src/modules/launcher/Plugins/Wox.Plugin.Shell/Settings.cs b/src/modules/launcher/Plugins/Wox.Plugin.Shell/Settings.cs index 616f28cad5..e4e1cd43fc 100644 --- a/src/modules/launcher/Plugins/Wox.Plugin.Shell/Settings.cs +++ b/src/modules/launcher/Plugins/Wox.Plugin.Shell/Settings.cs @@ -5,7 +5,10 @@ namespace Wox.Plugin.Shell public class Settings { public Shell Shell { get; set; } = Shell.RunCommand; - public bool ReplaceWinR { get; set; } = true; + + // not overriding Win+R + // crutkas we need to earn the right for Win+R override + public bool ReplaceWinR { get; set; } = false; public bool LeaveShellOpen { get; set; } public bool RunAsAdministrator { get; set; } = false; diff --git a/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml b/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml index 2784345c4c..6db4be5db7 100644 --- a/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml +++ b/src/modules/launcher/PowerLauncher.UI/LauncherControl.xaml @@ -375,7 +375,6 @@ x:FieldModifier="public" Style="{StaticResource CustomAutoSuggestBoxTextBoxStyle}" PlaceholderText="Start typing" - Text="{Binding QueryText}" Height="60" ScrollViewer.BringIntoViewOnFocusChange="False" Canvas.ZIndex="0" diff --git a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs index 7c7cc62477..f264514e12 100644 --- a/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs +++ b/src/modules/launcher/PowerLauncher/MainWindow.xaml.cs @@ -22,6 +22,7 @@ using System.Threading.Tasks; using Windows.UI.Xaml; using Windows.UI.Core; using System.Windows.Media; +using Windows.UI.Xaml.Data; namespace PowerLauncher { @@ -33,11 +34,10 @@ namespace PowerLauncher private readonly Storyboard _progressBarStoryboard = new Storyboard(); private Settings _settings; private MainViewModel _viewModel; - + private bool _isTextSetProgramatically; const int ROW_COUNT = 4; const int ROW_HEIGHT = 75; const int MAX_LIST_HEIGHT = 300; - #endregion public MainWindow(Settings settings, MainViewModel mainVM) @@ -60,6 +60,7 @@ namespace PowerLauncher private void OnInitialized(object sender, EventArgs e) { + } private void OnLoaded(object sender, System.Windows.RoutedEventArgs _) @@ -153,7 +154,7 @@ namespace PowerLauncher _launcher = (PowerLauncher.UI.LauncherControl)host.Child; _launcher.DataContext = _viewModel; _launcher.KeyDown += _launcher_KeyDown; - _launcher.TextBox.TextChanged += QueryTextBox_TextChanged; + _launcher.TextBox.TextChanging += QueryTextBox_TextChanging; _launcher.TextBox.Loaded += TextBox_Loaded; _launcher.PropertyChanged += UserControl_PropertyChanged; _viewModel.PropertyChanged += (o, e) => @@ -177,9 +178,16 @@ namespace PowerLauncher } } } + else if(e.PropertyName == nameof(MainViewModel.SystemQueryText)) + { + this._isTextSetProgramatically = true; + _launcher.TextBox.Text = _viewModel.SystemQueryText; + } }; } + + private void UserControl_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == "SolidBorderBrush") @@ -210,10 +218,16 @@ namespace PowerLauncher _resultList = (UI.ResultList)host.Child; _resultList.DataContext = _viewModel; _resultList.Tapped += SuggestionsList_Tapped; + _resultList.SuggestionsList.Loaded += SuggestionsList_Loaded; _resultList.SuggestionsList.SelectionChanged += SuggestionsList_SelectionChanged; _resultList.SuggestionsList.ContainerContentChanging += SuggestionList_UpdateListSize; } + private void SuggestionsList_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + _viewModel.ColdStartFix(); + } + private bool IsKeyDown(VirtualKey key) { var keyState = CoreWindow.GetForCurrentThread().GetKeyState(key); @@ -225,21 +239,25 @@ namespace PowerLauncher if (e.Key == VirtualKey.Tab && IsKeyDown(VirtualKey.Shift)) { _viewModel.SelectPrevTabItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); e.Handled = true; } else if (e.Key == VirtualKey.Tab) { - _viewModel.SelectNextTabItemCommand.Execute(null); + _viewModel.SelectNextTabItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); e.Handled = true; } else if (e.Key == VirtualKey.Down) { _viewModel.SelectNextItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); e.Handled = true; } else if (e.Key == VirtualKey.Up) { _viewModel.SelectPrevItemCommand.Execute(null); + UpdateTextBoxToSelectedItem(); e.Handled = true; } else if (e.Key == VirtualKey.PageDown) @@ -254,6 +272,15 @@ namespace PowerLauncher } } + private void UpdateTextBoxToSelectedItem() + { + var itemText = _viewModel?.Results?.SelectedItem?.ToString() ?? null; + if (!String.IsNullOrEmpty(itemText)) + { + _viewModel.ChangeQueryText(itemText); + } + } + private void SuggestionsList_Tapped(object sender, TappedRoutedEventArgs e) { var result = ((Windows.UI.Xaml.FrameworkElement)e.OriginalSource).DataContext; @@ -324,8 +351,7 @@ namespace PowerLauncher private string ListView_FirstItem(String input) { - string s = input; - if (s.Length > 0) + if (!String.IsNullOrEmpty(input)) { String selectedItem = _viewModel.Results?.SelectedItem?.ToString(); int selectedIndex = _viewModel.Results.SelectedIndex; @@ -341,25 +367,49 @@ namespace PowerLauncher return String.Empty; } - - private void QueryTextBox_TextChanged(object sender, Windows.UI.Xaml.Controls.TextChangedEventArgs e) + private void QueryTextBox_TextChanging(TextBox sender, TextBoxTextChangingEventArgs args) { - var latestTimeOfTyping = DateTime.Now; - var text = ((Windows.UI.Xaml.Controls.TextBox)sender).Text; - Task.Run(() => DelayedCheck(latestTimeOfTyping, text)); - s_lastTimeOfTyping = latestTimeOfTyping; + ClearAllQueryTextChangedHanlders(); + + if(this._isTextSetProgramatically) + { + this._launcher.TextBox.TextChanged += QueryTextBox_TextChangedProgramatically; + } + else + { + this._launcher.TextBox.TextChanged += QueryTextBox_TextChangedByUserInput; + } + } + private void ClearAllQueryTextChangedHanlders() + { + this._launcher.TextBox.TextChanged -= QueryTextBox_TextChangedProgramatically; + this._launcher.TextBox.TextChanged -= QueryTextBox_TextChangedByUserInput; + } + + private void QueryTextBox_TextChangedProgramatically(object sender, Windows.UI.Xaml.Controls.TextChangedEventArgs e) + { + var textBox = ((Windows.UI.Xaml.Controls.TextBox)sender); + textBox.SelectionStart = textBox.Text.Length; + + this._isTextSetProgramatically = false; + } + + + private void QueryTextBox_TextChangedByUserInput(object sender, Windows.UI.Xaml.Controls.TextChangedEventArgs e) + { + var text = ((Windows.UI.Xaml.Controls.TextBox)sender).Text; //To clear the auto-suggest immediately instead of waiting for selection changed - if(text == String.Empty) + if (text == String.Empty) { _launcher.AutoCompleteTextBox.PlaceholderText = String.Empty; } - if (_viewModel.QueryTextCursorMovedToEnd) - { - _launcher.TextBox.SelectionStart = _launcher.TextBox.Text.Length; - _viewModel.QueryTextCursorMovedToEnd = false; - } + _viewModel.QueryText = text; + var latestTimeOfTyping = DateTime.Now; + + Task.Run(() => DelayedCheck(latestTimeOfTyping, text)); + s_lastTimeOfTyping = latestTimeOfTyping; } private async Task DelayedCheck(DateTime latestTimeOfTyping, string text) @@ -368,13 +418,13 @@ namespace PowerLauncher if (latestTimeOfTyping.Equals(s_lastTimeOfTyping)) { await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => - { - _viewModel.QueryText = text; - })); + { + _viewModel.Query(); + })); } } - private void WindowsXamlHost_PreviewMouseDown(object sender, MouseButtonEventArgs e) +private void WindowsXamlHost_PreviewMouseDown(object sender, MouseButtonEventArgs e) { // if (sender != null && e.OriginalSource != null) // { diff --git a/src/modules/launcher/Wox.Plugin/Result.cs b/src/modules/launcher/Wox.Plugin/Result.cs index 7631655015..d1f49b142e 100644 --- a/src/modules/launcher/Wox.Plugin/Result.cs +++ b/src/modules/launcher/Wox.Plugin/Result.cs @@ -18,6 +18,11 @@ namespace Wox.Plugin public string FontFamily { get; set; } + /// + /// The text that will get displayed in the Search text box, when this item is selected in the result list. + /// + public string QueryTextDisplay { get; set; } + public string IcoPath { get { return _icoPath; } diff --git a/src/modules/launcher/Wox/MainWindow.xaml.cs b/src/modules/launcher/Wox/MainWindow.xaml.cs index e0ee4ef3f5..ed15aef699 100644 --- a/src/modules/launcher/Wox/MainWindow.xaml.cs +++ b/src/modules/launcher/Wox/MainWindow.xaml.cs @@ -235,16 +235,9 @@ namespace Wox e.Handled = true; } } - private void OnTextChanged(object sender, TextChangedEventArgs e) { - if (_viewModel.QueryTextCursorMovedToEnd) - { - QueryTextBox.CaretIndex = QueryTextBox.Text.Length; - _viewModel.QueryTextCursorMovedToEnd = false; - } + } - - } } \ No newline at end of file diff --git a/src/modules/launcher/Wox/PublicAPIInstance.cs b/src/modules/launcher/Wox/PublicAPIInstance.cs index 10c33b3b36..689f6b8c46 100644 --- a/src/modules/launcher/Wox/PublicAPIInstance.cs +++ b/src/modules/launcher/Wox/PublicAPIInstance.cs @@ -38,12 +38,12 @@ namespace Wox public void ChangeQuery(string query, bool requery = false) { - _mainVM.ChangeQueryText(query); + _mainVM.ChangeQueryText(query, requery); } public void ChangeQueryText(string query, bool selectAll = false) { - _mainVM.ChangeQueryText(query); + _mainVM.ChangeQueryText(query, false); } [Obsolete] diff --git a/src/modules/launcher/Wox/ViewModel/MainViewModel.cs b/src/modules/launcher/Wox/ViewModel/MainViewModel.cs index 348dd57f4e..0d9039bb9c 100644 --- a/src/modules/launcher/Wox/ViewModel/MainViewModel.cs +++ b/src/modules/launcher/Wox/ViewModel/MainViewModel.cs @@ -51,7 +51,6 @@ namespace Wox.ViewModel { _saved = false; _queryTextBeforeLeaveResults = ""; - _queryText = ""; _lastQuery = new Query(); _settings = settings; @@ -179,17 +178,17 @@ namespace Wox.ViewModel if (!didExecuteContextButton) { var result = results.SelectedItem.Result; - if (result != null) // SelectedItem returns null if selection is empty. + if (result != null && result.Action != null) // SelectedItem returns null if selection is empty. { - bool hideWindow = result.Action != null && result.Action(new ActionContext - { - SpecialKeyState = GlobalHotkey.Instance.CheckModifiers() - }); + MainWindowVisibility = Visibility.Collapsed; - if (hideWindow) + Task.Run(() => { - MainWindowVisibility = Visibility.Collapsed; - } + result.Action(new ActionContext + { + SpecialKeyState = GlobalHotkey.Instance.CheckModifiers() + }); + }); if (SelectedIsFromQueryResults()) { @@ -242,29 +241,29 @@ namespace Wox.ViewModel public ResultsViewModel ContextMenu { get; private set; } public ResultsViewModel History { get; private set; } - private string _queryText; - public string QueryText - { - get { return _queryText; } - set - { - _queryText = value; - Query(); - } - } + public string SystemQueryText { get; set; } = String.Empty; + + public string QueryText { get; set; } = String.Empty; + /// /// we need move cursor to end when we manually changed query - /// but we don't want to move cursor to end when query is updated from TextBox + /// but we don't want to move cursor to end when query is updated from TextBox. + /// Also we don't want to force the results to change unless explicity told to. /// /// - public void ChangeQueryText(string queryText) + /// Optional Parameter that if true, will automatically execute a query against the updated text + public void ChangeQueryText(string queryText, bool requery=false) { - QueryTextCursorMovedToEnd = true; - QueryText = queryText; + SystemQueryText = queryText; + + if(requery) + { + QueryText = queryText; + Query(); + } } public bool LastQuerySelected { get; set; } - public bool QueryTextCursorMovedToEnd { get; set; } private ResultsViewModel _selectedResults; private ResultsViewModel SelectedResults @@ -632,6 +631,32 @@ namespace Wox.ViewModel } } + public void ColdStartFix() + { + // Fix Cold start for List view xaml island + List list = new List(); + Result r = new Result + { + Title = "hello" + }; + list.Add(r); + Results.AddResults(list, "0"); + Results.Clear(); + MainWindowVisibility = System.Windows.Visibility.Collapsed; + + // Fix Cold start for plugins + string s = "m"; + var query = QueryBuilder.Build(s.Trim(), PluginManager.NonGlobalPlugins); + var plugins = PluginManager.ValidPluginsForQuery(query); + foreach (PluginPair plugin in plugins) + { + if (!plugin.Metadata.Disabled && plugin.Metadata.Name != "Window Walker") + { + var _ = PluginManager.QueryForPlugin(plugin, query); + } + }; + } + #endregion } } \ No newline at end of file diff --git a/src/modules/launcher/Wox/ViewModel/ResultViewModel.cs b/src/modules/launcher/Wox/ViewModel/ResultViewModel.cs index cab7fec113..9127850371 100644 --- a/src/modules/launcher/Wox/ViewModel/ResultViewModel.cs +++ b/src/modules/launcher/Wox/ViewModel/ResultViewModel.cs @@ -255,7 +255,8 @@ namespace Wox.ViewModel public override string ToString() { - return Result.Title.ToString(); + var display = String.IsNullOrEmpty(Result.QueryTextDisplay) ? Result.Title : Result.QueryTextDisplay; + return display; } } }