Helper.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.Diagnostics;
  7  using System.IO;
  8  using System.IO.Abstractions;
  9  using System.Linq;
 10  using System.Security.Principal;
 11  
 12  using Microsoft.PowerToys.Settings.UI.Library.CustomAction;
 13  
 14  namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
 15  {
 16      public static class Helper
 17      {
 18          public static readonly IFileSystem FileSystem = new FileSystem();
 19  
 20          public static string UserLocalAppDataPath { get; set; } = string.Empty;
 21  
 22          public static bool AllowRunnerToForeground()
 23          {
 24              var result = false;
 25              var processes = Process.GetProcessesByName("PowerToys");
 26              if (processes.Length > 0)
 27              {
 28                  var pid = processes[0].Id;
 29                  result = NativeMethods.AllowSetForegroundWindow(pid);
 30              }
 31  
 32              return result;
 33          }
 34  
 35          public static string GetSerializedCustomAction(string moduleName, string actionName, string actionValue)
 36          {
 37              var customAction = new CustomActionDataModel
 38              {
 39                  Name = actionName,
 40                  Value = actionValue,
 41              };
 42  
 43              var moduleCustomAction = new ModuleCustomAction
 44              {
 45                  ModuleAction = customAction,
 46              };
 47  
 48              var sendCustomAction = new SendCustomAction(moduleName)
 49              {
 50                  Action = moduleCustomAction,
 51              };
 52  
 53              return sendCustomAction.ToJsonString();
 54          }
 55  
 56          public static IFileSystemWatcher GetFileWatcher(string path, Action onChangedCallback, IFileSystem fileSystem = null)
 57          {
 58              fileSystem ??= FileSystem;
 59  
 60              var dirPath = Path.GetDirectoryName(path);
 61              if (!fileSystem.Directory.Exists(dirPath))
 62              {
 63                  return null;
 64              }
 65  
 66              var watcher = fileSystem.FileSystemWatcher.New();
 67              watcher.Path = dirPath;
 68              watcher.Filter = Path.GetFileName(path);
 69              watcher.NotifyFilter = NotifyFilters.LastWrite;
 70              watcher.EnableRaisingEvents = true;
 71  
 72              watcher.Changed += (o, e) => onChangedCallback();
 73  
 74              return watcher;
 75          }
 76  
 77          public static IFileSystemWatcher GetFileWatcher(string moduleName, string fileName, Action onChangedCallback, IFileSystem fileSystem = null)
 78          {
 79              fileSystem ??= FileSystem;
 80  
 81              var path = fileSystem.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{moduleName}");
 82  
 83              if (!fileSystem.Directory.Exists(path))
 84              {
 85                  fileSystem.Directory.CreateDirectory(path);
 86              }
 87  
 88              var watcher = fileSystem.FileSystemWatcher.New();
 89              watcher.Path = path;
 90              watcher.Filter = fileName;
 91              watcher.NotifyFilter = NotifyFilters.LastWrite;
 92              watcher.EnableRaisingEvents = true;
 93  
 94              watcher.Changed += (o, e) => onChangedCallback();
 95  
 96              return watcher;
 97          }
 98  
 99          public static string LocalApplicationDataFolder()
100          {
101              WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
102              SecurityIdentifier currentUserSID = currentUser.User;
103  
104              SecurityIdentifier localSystemSID = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
105              if (currentUserSID.Equals(localSystemSID) && UserLocalAppDataPath != string.Empty)
106              {
107                  return UserLocalAppDataPath;
108              }
109              else
110              {
111                  return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
112              }
113          }
114  
115          public static string GetPowerToysInstallationFolder()
116          {
117              // PowerToys.exe is in the parent folder relative to Settings.
118              var settingsPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
119              return Directory.GetParent(settingsPath).FullName;
120          }
121  
122          public static string GetPowerToysInstallationWinUI3AppsAssetsFolder()
123          {
124              // return .\PowerToys\WinUI3Apps\Assets
125              return Path.Combine(GetPowerToysInstallationFolder(), "WinUI3Apps", "Assets");
126          }
127  
128          private static readonly global::PowerToys.Interop.LayoutMapManaged LayoutMap = new global::PowerToys.Interop.LayoutMapManaged();
129  
130          public static string GetKeyName(uint key)
131          {
132              return LayoutMap.GetKeyName(key);
133          }
134  
135          public static uint GetKeyValue(string key)
136          {
137              return LayoutMap.GetKeyValue(key);
138          }
139  
140          public static string GetProductVersion()
141          {
142              return global::PowerToys.Interop.CommonManaged.GetProductVersion();
143          }
144  
145          public static int CompareVersions(string version1, string version2)
146          {
147              try
148              {
149                  // Split up the version strings into int[]
150                  // Example: v10.0.2 -> {10, 0, 2};
151                  ArgumentNullException.ThrowIfNull(version1);
152                  ArgumentNullException.ThrowIfNull(version2);
153  
154                  var v1 = version1.Substring(1).Split('.').Select(int.Parse).ToArray();
155                  var v2 = version2.Substring(1).Split('.').Select(int.Parse).ToArray();
156  
157                  if (v1.Length != 3 || v2.Length != 3)
158                  {
159                      throw new FormatException();
160                  }
161  
162                  if (v1[0] - v2[0] != 0)
163                  {
164                      return v1[0] - v2[0];
165                  }
166  
167                  if (v1[1] - v2[1] != 0)
168                  {
169                      return v1[1] - v2[1];
170                  }
171  
172                  return v1[2] - v2[2];
173              }
174              catch (Exception)
175              {
176                  throw new FormatException("Bad product version format");
177              }
178          }
179  
180          public static void CopyDirectory(string source_directory, string destination_directory, bool copy_recursively)
181          {
182              var current_directory_info = new DirectoryInfo(source_directory);
183  
184              DirectoryInfo[] source_subdirectories = current_directory_info.GetDirectories();
185  
186              Directory.CreateDirectory(destination_directory);
187  
188              foreach (FileInfo file in current_directory_info.GetFiles())
189              {
190                  string destination_file_path = Path.Combine(destination_directory, file.Name);
191                  file.CopyTo(destination_file_path, true);
192              }
193  
194              if (copy_recursively)
195              {
196                  foreach (DirectoryInfo subdirectory in source_subdirectories)
197                  {
198                      string newDestinationDir = Path.Combine(destination_directory, subdirectory.Name);
199                      CopyDirectory(subdirectory.FullName, newDestinationDir, true);
200                  }
201              }
202          }
203  
204          public static readonly uint VirtualKeyWindows = global::PowerToys.Interop.Constants.VK_WIN_BOTH;
205      }
206  }