diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml index cfcb43089d..58bcf7beaf 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/de.xaml @@ -34,4 +34,9 @@ Programm Suche Programme mit Wox - \ No newline at end of file + + Win32-Anwendung + Weblink-Anwendung + Web-Anwendung + + diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml index b7202d590f..2caa14067c 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/en.xaml @@ -45,4 +45,8 @@ Success Successfully disabled this program from displaying in your query + + Win32 application + Internet shortcut application + Web application \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml index 07630a1cda..364dc4e9b2 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/ja.xaml @@ -35,4 +35,9 @@ Program Search programs in Wox + + Win32 application + Internet shortcut application + Web application + \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml index bb82ee8d2e..b739a1d551 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/pl.xaml @@ -34,4 +34,9 @@ Programy Szukaj i uruchamiaj programy z poziomu Woxa + + Win32 application + Internet shortcut application + Web application + \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml index ef01e29fd1..e659da4876 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/tr.xaml @@ -36,4 +36,9 @@ Geçersiz Konum + + Win32 application + Internet shortcut application + Web application + \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml index f41193095b..83acbe6148 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-cn.xaml @@ -36,4 +36,9 @@ 无效路径 + + Win32 application + Internet shortcut application + Web application + \ No newline at end of file diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml index d3c0f18cca..c424b7347a 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Languages/zh-tw.xaml @@ -33,4 +33,9 @@ 程式 在 Wox 中搜尋程式 + + + Win32 application + Internet shortcut application + Web application diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/ShellLinkHelper.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/ShellLinkHelper.cs index 6d829d741c..5842a386de 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/ShellLinkHelper.cs +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/ShellLinkHelper.cs @@ -103,6 +103,7 @@ namespace Microsoft.Plugin.Program.Programs public String description = String.Empty; // Sets to true if the program takes in arguments + public String Arguments = String.Empty; public bool hasArguments = false; // Retrieve the target path using Shell Link @@ -130,6 +131,7 @@ namespace Microsoft.Plugin.Program.Programs StringBuilder argumentBuffer = new StringBuilder(MAX_PATH); ((IShellLinkW)link).GetArguments(argumentBuffer, argumentBuffer.Capacity); + Arguments = argumentBuffer.ToString(); // Set variable to true if the program takes in any arguments if (argumentBuffer.Length != 0) diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs index a2875eb8a9..75f6ee46c4 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program/Programs/Win32.cs @@ -31,16 +31,24 @@ namespace Microsoft.Plugin.Program.Programs public bool Valid { get; set; } public bool Enabled { get; set; } public bool hasArguments { get; set; } = false; + public string Arguments { get; set; } = String.Empty; public string Location => ParentDirectory; - public string AppType { get; set; } + public uint AppType { get; set; } private const string ShortcutExtension = "lnk"; private const string ApplicationReferenceExtension = "appref-ms"; private const string ExeExtension = "exe"; private const string InternetShortcutExtension = "url"; - - private const string InternetShortcutApplication = "Internet shortcut application"; - private const string Win32Application = "Win32 application"; + + private const string proxyWebApp = "_proxy.exe"; + private const string appIdArgument = "--app-id"; + + private enum ApplicationTypes + { + WEB_APPLICATION = 0, + INTERNET_SHORTCUT_APPLICATION = 1, + WIN32_APPLICATION = 2 + } private int Score(string query) { @@ -51,6 +59,68 @@ namespace Microsoft.Plugin.Program.Programs return score; } + public bool IsWebApplication() + { + // To Filter PWAs when the user searches for the main application + // All Chromium based applications contain the --app-id argument + // Reference : https://codereview.chromium.org/399045/show + bool isWebApplication = FullPath.Contains(proxyWebApp) && Arguments.Contains(appIdArgument); + return isWebApplication; + } + + // Condition to Filter pinned Web Applications or PWAs when searching for the main application + public bool FilterWebApplication(string query) + { + // If the app is not a web application, then do not filter it + if(!IsWebApplication()) + { + return false; + } + + // Set the subtitle to 'Web Application' + AppType = (uint)ApplicationTypes.WEB_APPLICATION; + + string[] subqueries = query.Split(); + bool nameContainsQuery = false; + bool pathContainsQuery = false; + + // check if any space separated query is a part of the app name or path name + foreach (var subquery in subqueries) + { + if (FullPath.Contains(subquery, StringComparison.OrdinalIgnoreCase)) + { + pathContainsQuery = true; + } + + if(Name.Contains(subquery, StringComparison.OrdinalIgnoreCase)) + { + nameContainsQuery = true; + } + } + return pathContainsQuery && !nameContainsQuery; + } + + // Function to set the subtitle based on the Type of application + public string SetSubtitle(uint AppType, IPublicAPI api) + { + if(AppType == (uint)ApplicationTypes.WIN32_APPLICATION) + { + return api.GetTranslation("powertoys_run_plugin_program_win32_application"); + } + else if(AppType == (uint)ApplicationTypes.INTERNET_SHORTCUT_APPLICATION) + { + return api.GetTranslation("powertoys_run_plugin_program_internet_shortcut_application"); + } + else if(AppType == (uint)ApplicationTypes.WEB_APPLICATION) + { + return api.GetTranslation("powertoys_run_plugin_program_web_application"); + } + else + { + return String.Empty; + } + } + public Result Result(string query, IPublicAPI api) { var score = Score(query); @@ -64,10 +134,18 @@ namespace Microsoft.Plugin.Program.Programs var noArgumentScoreModifier = 5; score += noArgumentScoreModifier; } + else + { + // Filter Web Applications when searching for the main application + if (FilterWebApplication(query)) + { + return null; + } + } var result = new Result { - SubTitle = AppType, + SubTitle = SetSubtitle(AppType, api), IcoPath = IcoPath, Score = score, ContextData = this, @@ -105,7 +183,7 @@ namespace Microsoft.Plugin.Program.Programs public List ContextMenus(IPublicAPI api) { // To add a context menu only to open file location as Internet shortcut applications do not have the functionality to run as admin - if(AppType.Equals(InternetShortcutApplication)) + if(AppType == (uint)ApplicationTypes.INTERNET_SHORTCUT_APPLICATION) { var contextMenuItems = new List { @@ -195,7 +273,7 @@ namespace Microsoft.Plugin.Program.Programs Description = string.Empty, Valid = true, Enabled = true, - AppType = Win32Application + AppType = (uint)ApplicationTypes.WIN32_APPLICATION }; return p; } @@ -260,10 +338,9 @@ namespace Microsoft.Plugin.Program.Programs FullPath = path.ToLower(), UniqueIdentifier = path, ParentDirectory = Directory.GetParent(path).FullName, - Description = InternetShortcutApplication, Valid = true, Enabled = true, - AppType = InternetShortcutApplication + AppType = (uint)ApplicationTypes.INTERNET_SHORTCUT_APPLICATION }; return p; } @@ -295,6 +372,7 @@ namespace Microsoft.Plugin.Program.Programs program.FullPath = Path.GetFullPath(target).ToLower(); program.ExecutableName = Path.GetFileName(target); program.hasArguments = _helper.hasArguments; + program.Arguments = _helper.Arguments; var description = _helper.description; if (!string.IsNullOrEmpty(description)) diff --git a/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs b/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs index 54b8b95fc0..abf45b7888 100644 --- a/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs +++ b/src/modules/launcher/Wox.Test/Plugins/ProgramPluginTest.cs @@ -78,6 +78,53 @@ namespace Wox.Test.Plugins LnkResolvedPath = null }; + Win32 twitter_pwa = new Win32 + { + Name = "Twitter", + FullPath = "c:\\program files (x86)\\google\\chrome\\application\\chrome_proxy.exe", + LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\chrome apps\\twitter.lnk", + Arguments = " --profile-directory=Default --app-id=jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi" + }; + + Win32 pinned_webpage = new Win32 + { + Name = "Web page", + FullPath = "c:\\program files (x86)\\microsoft\\edge\\application\\msedge_proxy.exe", + LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\web page.lnk", + Arguments = "--profile-directory=Default --app-id=homljgmgpmcbpjbnjpfijnhipfkiclkd" + }; + + Win32 edge_named_pinned_webpage = new Win32 + { + Name = "edge - Bing", + FullPath = "c:\\program files (x86)\\microsoft\\edge\\application\\msedge_proxy.exe", + LnkResolvedPath = "c:\\users\\powertoys\\appdata\\roaming\\microsoft\\windows\\start menu\\programs\\edge - bing.lnk", + Arguments = " --profile-directory=Default --app-id=aocfnapldcnfbofgmbbllojgocaelgdd" + }; + + Win32 msedge = new Win32 + { + Name = "Microsoft Edge", + ExecutableName = "msedge.exe", + FullPath = "c:\\program files (x86)\\microsoft\\edge\\application\\msedge.exe", + LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\microsoft edge.lnk" + }; + + Win32 chrome = new Win32 + { + Name = "Google Chrome", + ExecutableName = "chrome.exe", + FullPath = "c:\\program files (x86)\\google\\chrome\\application\\chrome.exe", + LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\google chrome.lnk" + }; + + Win32 dummy_proxy_app = new Win32 + { + Name = "Proxy App", + ExecutableName = "test_proxy.exe", + FullPath = "c:\\program files (x86)\\microsoft\\edge\\application\\test_proxy.exe", + LnkResolvedPath = "c:\\programdata\\microsoft\\windows\\start menu\\programs\\test proxy.lnk" + }; [Test] public void DedupFunction_whenCalled_mustRemoveDuplicateNotepads() @@ -139,5 +186,79 @@ namespace Wox.Test.Plugins // Assert Assert.AreEqual(apps.Length, 3); } + + [Test] + public void FunctionIsWebApplication_ShouldReturnTrue_ForWebApplications() + { + // The IsWebApplication(() function must return true for all PWAs and pinned web pages + Assert.IsTrue(twitter_pwa.IsWebApplication()); + Assert.IsTrue(pinned_webpage.IsWebApplication()); + Assert.IsTrue(edge_named_pinned_webpage.IsWebApplication()); + + // Should not filter apps whose executable name ends with proxy.exe + Assert.IsFalse(dummy_proxy_app.IsWebApplication()); + } + + [TestCase("ignore")] + public void FunctionFilterWebApplication_ShouldReturnFalse_WhenSearchingForTheMainApp(string query) + { + // Irrespective of the query, the FilterWebApplication() Function must not filter main apps such as edge and chrome + Assert.IsFalse(msedge.FilterWebApplication(query)); + Assert.IsFalse(chrome.FilterWebApplication(query)); + } + + [TestCase("edge", ExpectedResult = true)] + [TestCase("EDGE", ExpectedResult = true)] + [TestCase("msedge", ExpectedResult = true)] + [TestCase("Microsoft", ExpectedResult = true)] + [TestCase("edg", ExpectedResult = true)] + [TestCase("Edge page", ExpectedResult = false)] + [TestCase("Edge Web page", ExpectedResult = false)] + public bool EdgeWebSites_ShouldBeFiltered_WhenSearchingForEdge(string query) + { + return pinned_webpage.FilterWebApplication(query); + } + + [TestCase("chrome", ExpectedResult = true)] + [TestCase("CHROME", ExpectedResult = true)] + [TestCase("Google", ExpectedResult = true)] + [TestCase("Google Chrome", ExpectedResult = true)] + [TestCase("Google Chrome twitter", ExpectedResult = false)] + public bool ChromeWebSites_ShouldBeFiltered_WhenSearchingForChrome(string query) + { + return twitter_pwa.FilterWebApplication(query); + } + + [TestCase("twitter", 0, ExpectedResult = false)] + [TestCase("Twit", 0, ExpectedResult = false)] + [TestCase("TWITTER", 0, ExpectedResult = false)] + [TestCase("web", 1, ExpectedResult = false)] + [TestCase("Page", 1, ExpectedResult = false)] + [TestCase("WEB PAGE", 1, ExpectedResult = false)] + [TestCase("edge", 2, ExpectedResult = false)] + [TestCase("EDGE", 2, ExpectedResult = false)] + public bool PinnedWebPages_ShouldNotBeFiltered_WhenSearchingForThem(string query, int Case) + { + const uint CASE_TWITTER = 0; + const uint CASE_WEB_PAGE = 1; + const uint CASE_EDGE_NAMED_WEBPAGE = 2; + + // If the query is a part of the name of the web application, it should not be filtered, + // even if the name is the same as that of the main application, eg: case 2 - edge + if (Case == CASE_TWITTER) + { + return twitter_pwa.FilterWebApplication(query); + } + else if(Case == CASE_WEB_PAGE) + { + return pinned_webpage.FilterWebApplication(query); + } + else if(Case == CASE_EDGE_NAMED_WEBPAGE) + { + return edge_named_pinned_webpage.FilterWebApplication(query); + } + // unreachable code + return true; + } } }