From bb88aff663531a7e2f8f2461aaccaad6dbd6438f Mon Sep 17 00:00:00 2001 From: cyberrex5 <67976161+cyberrex5@users.noreply.github.com> Date: Fri, 24 Dec 2021 04:56:44 +0200 Subject: [PATCH] [PT Run][New Plugin] Web Search (#14882) * [PT Run][New Plugin] Web Search * [PT Run][Web Search] Added plugin files to WXS and YML * [PT Run][Web Search] Added docs * [PT Run][Web Search] Added new option + minor modifications * [PT Run][Web Search] Fixed a bug + minor refactoring * [PT Run][Web Search] Updated docs and changed icons * [PT Run][Web Search] Fixed capitalization for spell check + fixed icons * [PT Run][Web Search] Fixed renaming * adding cyberrex to name * [PT Run][Web Search] Fixed typo in doc screenshot * [PT Run][Web Search] Fixed plugin not working with Opera browser + minor modifications * Fixed merge and typo * [PT Run][Web Search] Removed globalization error suppression + changed action word * [PT Run][Web Search] Added LocProject.json + minor modifications * [PT Run][Web Search] Using plugin icon to not confuse with uri plugin + changed action word because another plugin uses it * Added Firefox to spell-check expect.txt * [PT Run][Web Search] Fixed bug with opera + changed default setting's value to false * Added sourceid to spell-check expect.txt * [PT Run][WebSearch] Changed action word * Making Web plugin a dependency for launcher like other plugins * [PT Run][Web Search] Now using JsonDocument + better way of getting browser name * [PT Run][Web Search] Fixed bug * adding in DLL to signing for release.yml build Co-authored-by: Clint Rutkas --- .github/actions/spell-check/expect.txt | 3 + .pipelines/ESRPSigning_core.json | 1 + .pipelines/pipeline.user.windows.yml | 1 + PowerToys.sln | 10 + .../modules/launcher/plugins/websearch.md | 11 + doc/devdocs/modules/launcher/readme.md | 1 + doc/images/launcher/plugins/WebSearch.png | Bin 0 -> 29791 bytes installer/PowerToysSetup/Product.wxs | 17 +- ...nity.PowerToys.Run.Plugin.WebSearch.csproj | 106 +++++ .../Images/WebSearch.dark.png | Bin 0 -> 1311 bytes .../Images/WebSearch.light.png | Bin 0 -> 1214 bytes .../LocProject.json | 14 + .../Main.cs | 430 ++++++++++++++++++ .../NativeMethods.cs | 21 + .../Properties/Resources.Designer.cs | 126 +++++ .../Properties/Resources.resx | 141 ++++++ .../plugin.json | 13 + 17 files changed, 894 insertions(+), 1 deletion(-) create mode 100644 doc/devdocs/modules/launcher/plugins/websearch.md create mode 100644 doc/images/launcher/plugins/WebSearch.png create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Community.PowerToys.Run.Plugin.WebSearch.csproj create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Images/WebSearch.dark.png create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Images/WebSearch.light.png create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/LocProject.json create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Main.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/NativeMethods.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.Designer.cs create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.resx create mode 100644 src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/plugin.json diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 1e7abbb5b3..3fe8f316ab 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -347,6 +347,7 @@ cxfksword CXSMICON CXVIRTUALSCREEN cxxopts +cyberrex CYSMICON CYVIRTUALSCREEN czf @@ -589,6 +590,7 @@ Filterx finalizer findfast findstr +Firefox FIXEDFILEINFO FLASHZONES FLASHZONESONQUICKSWITCH @@ -1796,6 +1798,7 @@ somil Soref SOURCECLIENTAREAONLY SOURCEHEADER +sourceid sourcesdirectory spamming spdisp diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index 8370f8e07a..6a2fdfee12 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -88,6 +88,7 @@ "modules\\launcher\\Plugins\\VSCodeWorkspaces\\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.dll", "modules\\launcher\\Plugins\\Service\\Microsoft.PowerToys.Run.Plugin.Service.dll", "modules\\launcher\\Plugins\\System\\Microsoft.PowerToys.Run.Plugin.System.dll", + "modules\\launcher\\Plugins\\WebSearch\\Community.PowerToys.Run.Plugin.WebSearch.dll", "modules\\launcher\\Plugins\\WindowsTerminal\\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll", "modules\\MouseUtils\\PowerToys.FindMyMouse.dll", diff --git a/.pipelines/pipeline.user.windows.yml b/.pipelines/pipeline.user.windows.yml index a9e570abb0..683d859203 100644 --- a/.pipelines/pipeline.user.windows.yml +++ b/.pipelines/pipeline.user.windows.yml @@ -161,6 +161,7 @@ build: - 'modules\launcher\Plugins\WindowWalker\PowerToys.ManagedTelemetry.dll' - 'modules\launcher\Plugins\UnitConverter\Community.PowerToys.Run.Plugin.UnitConverter.dll' - 'modules\launcher\Plugins\VSCodeWorkspaces\Community.PowerToys.Run.Plugin.VSCodeWorkspaces.dll' + - 'modules\launcher\Plugins\WebSearch\Community.PowerToys.Run.Plugin.WebSearch.dll' - 'modules\launcher\Plugins\Service\Microsoft.PowerToys.Run.Plugin.Service.dll' - 'modules\launcher\Plugins\System\Microsoft.PowerToys.Run.Plugin.System.dll' - 'modules\launcher\Plugins\WindowsTerminal\Microsoft.PowerToys.Run.Plugin.WindowsTerminal.dll' diff --git a/PowerToys.sln b/PowerToys.sln index 29d7382265..209b6e4af4 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -129,6 +129,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.Launcher", "src\m EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PowerLauncher", "src\modules\launcher\PowerLauncher\PowerLauncher.csproj", "{F97E5003-F263-4D4A-A964-0F1F3C82DEF2}" ProjectSection(ProjectDependencies) = postProject + {9F94B303-5E21-4364-9362-64426F8DB932} = {9F94B303-5E21-4364-9362-64426F8DB932} {FD8EB419-FF9C-4D88-BB6F-BF6CED37747B} = {FD8EB419-FF9C-4D88-BB6F-BF6CED37747B} {03276A39-D4E9-417C-8FFD-200B0EE5E871} = {03276A39-D4E9-417C-8FFD-200B0EE5E871} {4D971245-7A70-41D5-BAA0-DDB5684CAF51} = {4D971245-7A70-41D5-BAA0-DDB5684CAF51} @@ -382,6 +383,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GcodePreviewHandler", "src\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests-GcodePreviewHandler", "src\modules\previewpane\UnitTests-GcodePreviewHandler\UnitTests-GcodePreviewHandler.csproj", "{FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Community.PowerToys.Run.Plugin.WebSearch", "src\modules\launcher\Plugins\Community.PowerToys.Run.Plugin.WebSearch\Community.PowerToys.Run.Plugin.WebSearch.csproj", "{9F94B303-5E21-4364-9362-64426F8DB932}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -1027,6 +1030,12 @@ Global {FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Release|x64.ActiveCfg = Release|x64 {FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Release|x64.Build.0 = Release|x64 {FCF3E52D-B80A-4FC3-98FD-6391354F0EE3}.Release|x86.ActiveCfg = Release|x64 + {9F94B303-5E21-4364-9362-64426F8DB932}.Debug|x64.ActiveCfg = Debug|x64 + {9F94B303-5E21-4364-9362-64426F8DB932}.Debug|x64.Build.0 = Debug|x64 + {9F94B303-5E21-4364-9362-64426F8DB932}.Debug|x86.ActiveCfg = Debug|x64 + {9F94B303-5E21-4364-9362-64426F8DB932}.Release|x64.ActiveCfg = Release|x64 + {9F94B303-5E21-4364-9362-64426F8DB932}.Release|x64.Build.0 = Release|x64 + {9F94B303-5E21-4364-9362-64426F8DB932}.Release|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1151,6 +1160,7 @@ Global {133281D8-1BCE-4D07-B31E-796612A9609E} = {2F305555-C296-497E-AC20-5FA1B237996A} {805306FF-A562-4415-8DEF-E493BDC45918} = {2F305555-C296-497E-AC20-5FA1B237996A} {FCF3E52D-B80A-4FC3-98FD-6391354F0EE3} = {2F305555-C296-497E-AC20-5FA1B237996A} + {9F94B303-5E21-4364-9362-64426F8DB932} = {4AFC9975-2456-4C70-94A4-84073C1CED93} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/doc/devdocs/modules/launcher/plugins/websearch.md b/doc/devdocs/modules/launcher/plugins/websearch.md new file mode 100644 index 0000000000..a011bdfb71 --- /dev/null +++ b/doc/devdocs/modules/launcher/plugins/websearch.md @@ -0,0 +1,11 @@ +## Web Search Plugin +The Web Search Plugin, as the name suggests, is used to perform a web search - in the default search engine in the default browser - on the query that has been entered by the user. + +![Image of Web Search plugin](/doc/images/launcher/plugins/WebSearch.png) + +## Default Browser Icon +- The icon for each web search result is that of the default browser set by the user. +- It, and the browser path, are obtained from the user registry and updated each time the theme of PT Run is changed. + +## Score +- The web search result always has a score of 0 which indicates that it would show up after each of the other plugins, other than the indexer plugin and possibly the uri plugin which both have a score of 0. \ No newline at end of file diff --git a/doc/devdocs/modules/launcher/readme.md b/doc/devdocs/modules/launcher/readme.md index 69af0edc46..9ca90366c3 100644 --- a/doc/devdocs/modules/launcher/readme.md +++ b/doc/devdocs/modules/launcher/readme.md @@ -14,3 +14,4 @@ - [Sys](/doc/devdocs/modules/launcher/plugins/sys.md) - [Uri](/doc/devdocs/modules/launcher/plugins/uri.md) - [Window Walker](/doc/devdocs/modules/launcher/plugins/windowwalker.md) + - [Web Search](/doc/devdocs/modules/launcher/plugins/WebSearch.md) diff --git a/doc/images/launcher/plugins/WebSearch.png b/doc/images/launcher/plugins/WebSearch.png new file mode 100644 index 0000000000000000000000000000000000000000..da94fd71ceaf279b40fef988aa0e269761e44880 GIT binary patch literal 29791 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 + + + + @@ -1008,7 +1012,7 @@ - + @@ -1278,6 +1282,17 @@ + + + + + + + + + + + diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Community.PowerToys.Run.Plugin.WebSearch.csproj b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Community.PowerToys.Run.Plugin.WebSearch.csproj new file mode 100644 index 0000000000..94f6e67606 --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Community.PowerToys.Run.Plugin.WebSearch.csproj @@ -0,0 +1,106 @@ + + + + + netcoreapp3.1 + {9F94B303-5E21-4364-9362-64426F8DB932} + Properties + Community.PowerToys.Run.Plugin.WebSearch + Community.PowerToys.Run.Plugin.WebSearch + $(Version).0 + true + false + false + x64 + en-US + + + + true + ..\..\..\..\..\x64\Debug\modules\launcher\Plugins\WebSearch\ + DEBUG;TRACE + full + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + 4 + false + true + + + + ..\..\..\..\..\x64\Release\modules\launcher\Plugins\WebSearch\ + TRACE + true + pdbonly + x64 + 7.3 + prompt + MinimumRecommendedRules.ruleset + 4 + true + + + + + GlobalSuppressions.cs + + + StyleCop.json + + + + + + false + + + false + + + + + + PreserveNewest + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + True + True + Resources.resx + + + + + + PublicResXFileCodeGenerator + Resources.Designer.cs + + + + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Images/WebSearch.dark.png b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Images/WebSearch.dark.png new file mode 100644 index 0000000000000000000000000000000000000000..9f8f033814ee09d005bc644343b19ff5db4f4331 GIT binary patch literal 1311 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 true, dont show global result on queries that are URIs + private bool _notGlobalIfUri; + + private PluginInitContext _context; + + private string _searchEngineUrl; + + private string _browserName = Properties.Resources.plugin_browser; + private string _browserIconPath; + private string _browserPath; + private string _defaultIconPath; + + private bool _disposed; + + public string Name => Properties.Resources.plugin_name; + + public string Description => Properties.Resources.plugin_description; + + public IEnumerable AdditionalOptions => new List() + { + new PluginAdditionalOption() + { + Key = NotGlobalIfUri, + DisplayLabel = Properties.Resources.plugin_global_if_uri, + Value = false, + }, + }; + + public List LoadContextMenus(Result selectedResult) + { + return new List(0); + } + + public List Query(Query query) + { + if (query is null) + { + throw new ArgumentNullException(nameof(query)); + } + + var results = new List(); + + if (!AreResultsGlobal() + && query.ActionKeyword == query.RawQuery + && IsDefaultBrowserSet()) + { + string arguments = "\"? \""; + results.Add(new Result + { + Title = Properties.Resources.plugin_description.Remove(Description.Length - 1, 1), + SubTitle = Properties.Resources.plugin_in_browser, + QueryTextDisplay = string.Empty, + IcoPath = _defaultIconPath, + ProgramArguments = arguments, + Action = action => + { + if (!Helper.OpenInShell(_browserPath, arguments)) + { + _context.API.ShowMsg( + $"Plugin: {Properties.Resources.plugin_name}", + $"{Properties.Resources.plugin_search_failed}: "); + return false; + } + + return true; + }, + }); + return results; + } + + if (!string.IsNullOrEmpty(query.Search)) + { + string searchTerm = query.Search; + + // Don't include in global results if the query is a URI (and if the option NotGlobalIfUri is enabled) + if (_notGlobalIfUri + && AreResultsGlobal() + && IsURI(searchTerm)) + { + return results; + } + + var result = new Result + { + Title = searchTerm, + SubTitle = string.Format(System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.plugin_open, _browserName), + QueryTextDisplay = searchTerm, + IcoPath = _defaultIconPath, + }; + + if (_searchEngineUrl is null) + { + string arguments = $"\"? {searchTerm}\""; + + result.ProgramArguments = arguments; + result.Action = action => + { + if (!Helper.OpenInShell(_browserPath, arguments)) + { + _context.API.ShowMsg( + $"Plugin: {Properties.Resources.plugin_name}", + $"{Properties.Resources.plugin_search_failed}: "); + return false; + } + + return true; + }; + } + else + { + string url = string.Format(System.Globalization.CultureInfo.InvariantCulture, _searchEngineUrl, searchTerm); + + result.Action = action => + { + if (!Helper.OpenInShell(url)) + { + _context.API.ShowMsg( + $"Plugin: {Properties.Resources.plugin_name}", + $"{Properties.Resources.plugin_search_failed}: "); + return false; + } + + return true; + }; + } + + results.Add(result); + } + + return results; + + bool AreResultsGlobal() + { + return string.IsNullOrEmpty(query.ActionKeyword); + } + + // Checks if input is a URI the same way Microsoft.Plugin.Uri.UriHelper.ExtendedUriParser does + bool IsURI(string input) + { + if (input.EndsWith(":", StringComparison.OrdinalIgnoreCase) + && !input.StartsWith("http", StringComparison.OrdinalIgnoreCase) + && !input.Contains("/", StringComparison.OrdinalIgnoreCase) + && !input.All(char.IsDigit)) + { + return true; + } + + if (input.EndsWith(":", StringComparison.CurrentCulture) + || input.EndsWith(".", StringComparison.CurrentCulture) + || input.EndsWith(":/", StringComparison.CurrentCulture) + || input.EndsWith("://", StringComparison.CurrentCulture) + || input.All(char.IsDigit)) + { + return false; + } + + try + { + _ = new UriBuilder(input); + } + catch (UriFormatException) + { + return false; + } + + return true; + } + } + + private bool IsDefaultBrowserSet() + { + return !string.IsNullOrEmpty(_browserPath); + } + + public void Init(PluginInitContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _context.API.ThemeChanged += OnThemeChanged; + UpdateIconPath(_context.API.GetCurrentTheme()); + UpdateBrowserIconPath(_context.API.GetCurrentTheme()); + } + + public string GetTranslatedPluginTitle() + { + return Properties.Resources.plugin_name; + } + + public string GetTranslatedPluginDescription() + { + return Properties.Resources.plugin_description; + } + + private void OnThemeChanged(Theme oldtheme, Theme newTheme) + { + UpdateIconPath(newTheme); + UpdateBrowserIconPath(newTheme); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "Design", + "CA1031:Do not catch general exception types", + Justification = "We want to keep the process alive but will log the exception")] + private void UpdateBrowserIconPath(Theme newTheme) + { + try + { + string progId = GetRegistryValue( + "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice", + "ProgId"); + + // The `?` argument doesn't work on opera, so we get the user's default search engine: + if (progId.StartsWith("Opera", StringComparison.OrdinalIgnoreCase)) + { + // Opera user preferences file: + string prefFile; + + if (progId.Contains("GX", StringComparison.OrdinalIgnoreCase)) + { + _browserName = "Opera GX"; + prefFile = System.IO.File.ReadAllText($"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\Opera Software\\Opera GX Stable\\Preferences"); + } + else + { + _browserName = "Opera"; + prefFile = System.IO.File.ReadAllText($"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\Opera Software\\Opera Stable\\Preferences"); + } + + // "default_search_provider_data" doesn't exist if the user hasn't searched for the first time, + // therefore we set `url` to opera's default search engine: + string url = "https://www.google.com/search?client=opera&q={0}&sourceid=opera"; + + using (System.Text.Json.JsonDocument doc = System.Text.Json.JsonDocument.Parse(prefFile)) + { + if (doc.RootElement.TryGetProperty("default_search_provider_data", out var element)) + { + if (element.TryGetProperty("template_url_data", out element)) + { + if (element.TryGetProperty("url", out element)) + { + url = element.GetString(); + } + } + } + } + + url = url + .Replace("{searchTerms}", "{0}", StringComparison.Ordinal) + .Replace("{inputEncoding}", "UTF-8", StringComparison.Ordinal) + .Replace("{outputEncoding}", "UTF-8", StringComparison.Ordinal); + + int startIndex = url.IndexOf('}', StringComparison.Ordinal) + 1; + + // In case there are other url parameters (e.g. `&foo={bar}`), remove them: + for (int i = url.IndexOf("}", startIndex, StringComparison.Ordinal); + i != -1; + i = url.IndexOf("}", startIndex, StringComparison.Ordinal)) + { + for (int j = i - 1; j > 0; --j) + { + if (url[j] == '&') + { + url = url.Remove(j, i - j + 1); + break; + } + } + } + + _searchEngineUrl = url; + } + else + { + string appName = GetRegistryValue($"HKEY_CLASSES_ROOT\\{progId}\\Application", "ApplicationName") + ?? GetRegistryValue($"HKEY_CLASSES_ROOT\\{progId}", "FriendlyTypeName"); + + if (appName is null) + { + appName = Properties.Resources.plugin_browser; + } + else + { + // Handle indirect strings: + if (appName.StartsWith("@", StringComparison.Ordinal)) + { + appName = GetIndirectString(appName); + } + + appName = appName + .Replace("URL", null, StringComparison.OrdinalIgnoreCase) + .Replace("HTML", null, StringComparison.OrdinalIgnoreCase) + .Replace("Document", null, StringComparison.OrdinalIgnoreCase) + .TrimEnd(); + } + + _browserName = appName; + + _searchEngineUrl = null; + } + + var programLocation = + + // Resolve App Icon (UWP) + GetRegistryValue( + "HKEY_CLASSES_ROOT\\" + progId + "\\Application", + "ApplicationIcon") + + // Resolves default file association icon (UWP + Normal) + ?? GetRegistryValue("HKEY_CLASSES_ROOT\\" + progId + "\\DefaultIcon", null); + + // "Handles 'Indirect Strings' (UWP programs)" + // Using Ordinal since this is internal and used with a symbol + if (programLocation.StartsWith("@", StringComparison.Ordinal)) + { + // Check if there's a postfix with contract-white/contrast-black icon is available and use that instead + string directProgramLocation = GetIndirectString(programLocation); + var themeIcon = newTheme == Theme.Light || newTheme == Theme.HighContrastWhite + ? "contrast-white" + : "contrast-black"; + var extension = Path.GetExtension(directProgramLocation); + var themedProgLocation = + $"{directProgramLocation.Substring(0, directProgramLocation.Length - extension.Length)}_{themeIcon}{extension}"; + _browserIconPath = File.Exists(themedProgLocation) + ? themedProgLocation + : directProgramLocation; + } + else + { + // Using Ordinal since this is internal and used with a symbol + var indexOfComma = programLocation.IndexOf(',', StringComparison.Ordinal); + _browserIconPath = indexOfComma > 0 + ? programLocation.Substring(0, indexOfComma) + : programLocation; + _browserPath = _browserIconPath; + } + } + catch (Exception e) + { + _browserIconPath = _defaultIconPath; + Log.Exception("Exception when retrieving icon", e, GetType()); + } + + string GetRegistryValue(string registryLocation, string valueName) + { + return Microsoft.Win32.Registry.GetValue(registryLocation, valueName, null) as string; + } + + string GetIndirectString(string str) + { + var stringBuilder = new StringBuilder(128); + if (NativeMethods.SHLoadIndirectString( + str, + stringBuilder, + (uint)stringBuilder.Capacity, + IntPtr.Zero) + == NativeMethods.Hresult.Ok) + { + return stringBuilder.ToString(); + } + + throw new Exception("Could not load indirect string."); + } + } + + private void UpdateIconPath(Theme theme) + { + if (theme == Theme.Light || theme == Theme.HighContrastWhite) + { + _defaultIconPath = "Images/WebSearch.light.png"; + } + else + { + _defaultIconPath = "Images/WebSearch.dark.png"; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed && disposing) + { + if (_context != null && _context.API != null) + { + _context.API.ThemeChanged -= OnThemeChanged; + } + + _disposed = true; + } + } + + public Control CreateSettingPanel() + { + throw new NotImplementedException(); + } + + public void UpdateSettings(PowerLauncherPluginSettings settings) + { + _notGlobalIfUri = settings?.AdditionalOptions?.FirstOrDefault(x => x.Key == NotGlobalIfUri)?.Value ?? false; + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/NativeMethods.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/NativeMethods.cs new file mode 100644 index 0000000000..2faa79df9d --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/NativeMethods.cs @@ -0,0 +1,21 @@ +// 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. + +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Community.PowerToys.Run.Plugin.WebSearch +{ + internal static class NativeMethods + { + internal enum Hresult : uint + { + Ok = 0x0000, + } + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] + internal static extern Hresult SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, IntPtr ppvReserved); + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.Designer.cs b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..6e48115836 --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.Designer.cs @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Community.PowerToys.Run.Plugin.WebSearch.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Community.PowerToys.Run.Plugin.WebSearch.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to the default browser. + /// + public static string plugin_browser { + get { + return ResourceManager.GetString("plugin_browser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Search the web.. + /// + public static string plugin_description { + get { + return ResourceManager.GetString("plugin_description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Don't include in global results on queries that are URIs. + /// + public static string plugin_global_if_uri { + get { + return ResourceManager.GetString("plugin_global_if_uri", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In the default browser. + /// + public static string plugin_in_browser { + get { + return ResourceManager.GetString("plugin_in_browser", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Web Search. + /// + public static string plugin_name { + get { + return ResourceManager.GetString("plugin_name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Search the web in {0}. + /// + public static string plugin_open { + get { + return ResourceManager.GetString("plugin_open", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to open the default browser. + /// + public static string plugin_search_failed { + get { + return ResourceManager.GetString("plugin_search_failed", resourceCulture); + } + } + } +} diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.resx b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.resx new file mode 100644 index 0000000000..5899780264 --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/Properties/Resources.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + the default browser + + + Search the web. + + + Don't include in global results on queries that are URIs + + + In the default browser + + + Web Search + + + Search the web in {0} + + + Failed to open the default browser + + \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/plugin.json b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/plugin.json new file mode 100644 index 0000000000..6a751c6071 --- /dev/null +++ b/src/modules/launcher/Plugins/Community.PowerToys.Run.Plugin.WebSearch/plugin.json @@ -0,0 +1,13 @@ +{ + "ID": "9F1B49201C3F4BF781CAAD5CD88EA4DC", + "ActionKeyword": "??", + "IsGlobal": true, + "Name": "Web Search", + "Author": "cyberrex5", + "Version": "1.0.0", + "Language": "csharp", + "Website": "https://aka.ms/powertoys", + "ExecuteFileName": "Community.PowerToys.Run.Plugin.WebSearch.dll", + "IcoPathDark": "Images\\WebSearch.dark.png", + "IcoPathLight": "Images\\WebSearch.light.png" +} \ No newline at end of file