Main.cs
  1  // Copyright (c) Microsoft Corporation
  2  // The Microsoft Corporation licenses this file to you under the MIT license.
  3  // See the LICENSE file in the project root for more information.
  4  
  5  using System;
  6  using System.Collections.Generic;
  7  using System.Globalization;
  8  using System.Linq;
  9  using System.Windows.Controls;
 10  
 11  using ManagedCommon;
 12  using Microsoft.PowerToys.Run.Plugin.System.Components;
 13  using Microsoft.PowerToys.Run.Plugin.System.Properties;
 14  using Microsoft.PowerToys.Settings.UI.Library;
 15  using Wox.Infrastructure;
 16  using Wox.Plugin;
 17  using Wox.Plugin.Common.Win32;
 18  
 19  namespace Microsoft.PowerToys.Run.Plugin.System
 20  {
 21      public class Main : IPlugin, IPluginI18n, ISettingProvider, IContextMenu, IDelayedExecutionPlugin
 22      {
 23          private PluginInitContext _context;
 24  
 25          private bool _confirmSystemCommands;
 26          private bool _showSuccessOnEmptyRB;
 27          private bool _localizeSystemCommands;
 28          private bool _reduceNetworkResultScore;
 29          private bool _separateEmptyRB;
 30  
 31          public string Name => Resources.Microsoft_plugin_sys_plugin_name;
 32  
 33          public string Description => Resources.Microsoft_plugin_sys_plugin_description;
 34  
 35          public static string PluginID => "CEA08895D2544B019B2E9C5009600DF4";
 36  
 37          public string IconTheme { get; set; }
 38  
 39          public bool IsBootedInUefiMode { get; set; }
 40  
 41          public IEnumerable<PluginAdditionalOption> AdditionalOptions => new List<PluginAdditionalOption>()
 42          {
 43              new PluginAdditionalOption()
 44              {
 45                  Key = "ConfirmSystemCommands",
 46                  DisplayLabel = Resources.confirm_system_commands,
 47                  Value = false,
 48              },
 49              new PluginAdditionalOption()
 50              {
 51                  Key = "ShowSuccessOnEmptyRB",
 52                  DisplayLabel = Resources.Microsoft_plugin_sys_RecycleBin_ShowEmptySuccessMessage,
 53                  Value = false,
 54              },
 55              new PluginAdditionalOption()
 56              {
 57                  Key = "LocalizeSystemCommands",
 58                  DisplayLabel = Resources.Use_localized_system_commands,
 59                  Value = true,
 60              },
 61              new PluginAdditionalOption()
 62              {
 63                  Key = "SeparateResultEmptyRB",
 64                  DisplayLabel = Resources.Microsoft_plugin_sys_RecycleBin_ShowEmptySeparate,
 65                  Value = false,
 66              },
 67              new PluginAdditionalOption()
 68              {
 69                  Key = "ReduceNetworkResultScore",
 70                  DisplayLabel = Resources.Reduce_Network_Result_Score,
 71                  DisplayDescription = Resources.Reduce_Network_Result_Score_Description,
 72                  Value = true,
 73              },
 74          };
 75  
 76          public void Init(PluginInitContext context)
 77          {
 78              _context = context;
 79              _context.API.ThemeChanged += OnThemeChanged;
 80              UpdateIconTheme(_context.API.GetCurrentTheme());
 81              IsBootedInUefiMode = Win32Helpers.GetSystemFirmwareType() == FirmwareType.Uefi;
 82  
 83              // Log info if the system hasn't boot in uefi mode.
 84              // (Because this is only going into the log we can ignore the fact that normally UEFI and BIOS are written upper case. No need to convert the enumeration value to upper case.)
 85              if (!IsBootedInUefiMode)
 86              {
 87                  Wox.Plugin.Logger.Log.Info($"The UEFI command will not show to the user. The system has not booted in UEFI mode or the system does not have an UEFI firmware! (Detected type: {Win32Helpers.GetSystemFirmwareType()})", typeof(Main));
 88              }
 89          }
 90  
 91          public List<Result> Query(Query query)
 92          {
 93              List<Result> results = new List<Result>();
 94              CultureInfo culture = _localizeSystemCommands ? CultureInfo.CurrentUICulture : new CultureInfo("en-US");
 95  
 96              if (query == null)
 97              {
 98                  return results;
 99              }
100  
101              // normal system commands are fast and can be returned immediately
102              var systemCommands = Commands.GetSystemCommands(IsBootedInUefiMode, _separateEmptyRB, _confirmSystemCommands, _showSuccessOnEmptyRB, IconTheme, culture);
103              foreach (var c in systemCommands)
104              {
105                  var resultMatch = StringMatcher.FuzzySearch(query.Search, c.Title);
106                  if (resultMatch.Score > 0)
107                  {
108                      c.Score = resultMatch.Score;
109                      c.TitleHighlightData = resultMatch.MatchData;
110                      results.Add(c);
111                  }
112                  else if (c?.ContextData is SystemPluginContext contextData)
113                  {
114                      var searchTagMatch = StringMatcher.FuzzySearch(query.Search, contextData.SearchTag);
115                      if (searchTagMatch.Score > 0)
116                      {
117                          c.Score = resultMatch.Score;
118                          results.Add(c);
119                      }
120                  }
121              }
122  
123              // The following information result is not returned because delayed queries doesn't clear output if no results are available.
124              // On global queries the first word/part has to be 'ip', 'mac' or 'address' for network results
125              // string[] keywordList = Resources.ResourceManager.GetString("Microsoft_plugin_sys_Search_NetworkKeywordList", culture).Split("; ");
126              // if (!string.IsNullOrEmpty(query.ActionKeyword) || keywordList.Any(x => query.Search.StartsWith(x, StringComparison.CurrentCultureIgnoreCase)))
127              // {
128              //    results.Add(new Result()
129              //    {
130              //        Title = "Getting network information. Please wait ...",
131              //        IcoPath = $"Images\\networkAdapter.{IconTheme}.png",
132              //        Score = StringMatcher.FuzzySearch("address", "ip address").Score,
133              //    });
134              // }
135              return results;
136          }
137  
138          public List<Result> Query(Query query, bool delayedExecution)
139          {
140              List<Result> results = new List<Result>();
141              CultureInfo culture = _localizeSystemCommands ? CultureInfo.CurrentUICulture : new CultureInfo("en-US");
142  
143              if (query == null)
144              {
145                  return results;
146              }
147  
148              // Network (ip and mac) results are slow with many network cards and returned delayed.
149              // On global queries the first word/part has to be 'ip', 'mac' or 'address' for network results
150              string[] keywordList = Resources.ResourceManager.GetString("Microsoft_plugin_sys_Search_NetworkKeywordList", culture).Split("; ");
151              if (!string.IsNullOrEmpty(query.ActionKeyword) || keywordList.Any(x => query.Search.StartsWith(x, StringComparison.CurrentCultureIgnoreCase)))
152              {
153                  var networkConnectionResults = Commands.GetNetworkConnectionResults(IconTheme, culture);
154                  foreach (var r in networkConnectionResults)
155                  {
156                      var resultMatch = StringMatcher.FuzzySearch(query.Search, r.SubTitle);
157                      if (resultMatch.Score > 0)
158                      {
159                          r.Score = _reduceNetworkResultScore ? (int)(resultMatch.Score * 65 / 100) : resultMatch.Score; // Adjust score to improve user experience and priority order
160                          r.SubTitleHighlightData = resultMatch.MatchData;
161                          results.Add(r);
162                      }
163                      else if (r?.ContextData is SystemPluginContext contextData)
164                      {
165                          var searchTagMatch = StringMatcher.FuzzySearch(query.Search, contextData.SearchTag);
166                          if (searchTagMatch.Score > 0)
167                          {
168                              r.Score = resultMatch.Score;
169                              results.Add(r);
170                          }
171                      }
172                  }
173              }
174  
175              return results;
176          }
177  
178          public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
179          {
180              return ResultHelper.GetContextMenuForResult(selectedResult, _showSuccessOnEmptyRB);
181          }
182  
183          private void UpdateIconTheme(Theme theme)
184          {
185              if (theme == Theme.Light || theme == Theme.HighContrastWhite)
186              {
187                  IconTheme = "light";
188              }
189              else
190              {
191                  IconTheme = "dark";
192              }
193          }
194  
195          private void OnThemeChanged(Theme currentTheme, Theme newTheme)
196          {
197              UpdateIconTheme(newTheme);
198          }
199  
200          public string GetTranslatedPluginDescription()
201          {
202              return Resources.Microsoft_plugin_sys_plugin_description;
203          }
204  
205          public string GetTranslatedPluginTitle()
206          {
207              return Resources.Microsoft_plugin_sys_plugin_name;
208          }
209  
210          public Control CreateSettingPanel()
211          {
212              throw new NotImplementedException();
213          }
214  
215          public void UpdateSettings(PowerLauncherPluginSettings settings)
216          {
217              var confirmSystemCommands = false;
218              var showSuccessOnEmptyRB = false;
219              var localizeSystemCommands = true;
220              var reduceNetworkResultScore = true;
221              var separateEmptyRB = false;
222  
223              if (settings != null && settings.AdditionalOptions != null)
224              {
225                  var optionConfirm = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "ConfirmSystemCommands");
226                  confirmSystemCommands = optionConfirm?.Value ?? confirmSystemCommands;
227  
228                  var optionEmptyRBSuccessMsg = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "ShowSuccessOnEmptyRB");
229                  showSuccessOnEmptyRB = optionEmptyRBSuccessMsg?.Value ?? showSuccessOnEmptyRB;
230  
231                  var optionLocalize = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "LocalizeSystemCommands");
232                  localizeSystemCommands = optionLocalize?.Value ?? localizeSystemCommands;
233  
234                  var optionNetworkScore = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "ReduceNetworkResultScore");
235                  reduceNetworkResultScore = optionNetworkScore?.Value ?? reduceNetworkResultScore;
236  
237                  var optionSeparateEmptyRB = settings.AdditionalOptions.FirstOrDefault(x => x.Key == "SeparateResultEmptyRB");
238                  separateEmptyRB = optionSeparateEmptyRB?.Value ?? separateEmptyRB;
239              }
240  
241              _confirmSystemCommands = confirmSystemCommands;
242              _showSuccessOnEmptyRB = showSuccessOnEmptyRB;
243              _localizeSystemCommands = localizeSystemCommands;
244              _reduceNetworkResultScore = reduceNetworkResultScore;
245              _separateEmptyRB = separateEmptyRB;
246          }
247      }
248  }