mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
[KBM] Migrate Engine and Editor into separate processes (#10774)
* Move KBM engine into separate process (#10672) * [KBM] Migrate KBM UI out of the runner (#10709) * Clean up keyboard hook handles (#10817) * [C++ common] Unhandled exception handler (#10821) * [KBM] Use icon in the KeyboardManagerEditor (#10845) * [KBM] Move resources from the Common project to the Editor. (#10844) * KBM Editor tests (#10858) * Rename engine executable (#10868) * clean up (#10870) * [KBM] Changed Editor and libraries output folders (#10871) * [KBM] New logs structure (#10872) * Add unhandled exception handling to the editor (#10874) * [KBM] Trace for edit keyboard window * Logging for XamlBridge message loop * [KBM] Added Editor and Engine to the installer (#10876) * Fix spelling * Interprocess communication logs, remove unnecessary windows message logs * [KBM] Separated telemetry for the engine and editor. (#10889) * [KBM] Editor test project (#10891) * Versions for the engine and the editor (#10897) * Add the editor's and the engine's executables to signing process (#10900) * [KBM editor] Run only one instance, exit when parent process exits (#10890) * [KBM] Force kill editor process to avoid XAML crash (#10907) * [KBM] Force kill editor process to avoid XAML crash * Fix event releasing Co-authored-by: mykhailopylyp <17161067+mykhailopylyp@users.noreply.github.com> * Make the editor dpi aware (#10908) * [KBM] KeyboardManagerCommon refactoring (#10909) * Do not start the process if it is already started (#10910) * logs * Update src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp * Update src/modules/keyboardmanager/KeyboardManagerEditorLibrary/EditKeyboardWindow.cpp * [KBM] Rename InitUnhandledExceptionHandler to make it explicit that is for x64 only. We will fix it properly when adding support for ARM64 and add a header with the proper conditional building. * [KBM] rename file/class/variables using camel case * [KBM] Rename "event_locker" -> "EventLocker" * [KBM] rename process_waiter Add a TODO comment * [KBM] rename methods Add TODO comment * [KBM] use uppercase for function names * [KBM] use uppercase for methos, lowercase for properties * [KBM] rename method, make methods private, formatting * [KBM] rename private variables * [KBM] use uppercase for function names * [KBM] Added support to run the editor stand-alone when built in debug mode * Update src/modules/keyboardmanager/KeyboardManagerEditor/KeyboardManagerEditor.cpp * Check success of event creation, comment (#10947) * [KBM] code formatting (#10951) * [KBM] code formatting * Update src/modules/keyboardmanager/KeyboardManagerEditorLibrary/BufferValidationHelpers.cpp * [KBM] tracing * [KBM] Remappings not showing fix. (#10954) * removed mutex * retry loop for reading * retry on reading config once * log error Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com> Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com> Co-authored-by: Seraphima Zykova <zykovas91@gmail.com> Co-authored-by: Enrico Giordani <enricogior@users.noreply.github.com> Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -24,15 +26,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
private readonly ISettingsUtils _settingsUtils;
|
||||
|
||||
private const string PowerToyName = KeyboardManagerSettings.ModuleName;
|
||||
private const string RemapKeyboardActionName = "RemapKeyboard";
|
||||
private const string RemapKeyboardActionValue = "Open Remap Keyboard Window";
|
||||
private const string EditShortcutActionName = "EditShortcut";
|
||||
private const string EditShortcutActionValue = "Open Edit Shortcut Window";
|
||||
private const string JsonFileType = ".json";
|
||||
|
||||
private static string ConfigFileMutexName => interop.Constants.KeyboardManagerConfigFileMutexName();
|
||||
private const string KeyboardManagerEditorPath = "modules\\KeyboardManager\\KeyboardManagerEditor\\PowerToys.KeyboardManagerEditor.exe";
|
||||
private Process editor;
|
||||
|
||||
private const int ConfigFileMutexWaitTimeoutMilliseconds = 1000;
|
||||
private enum KeyboardManagerEditorType
|
||||
{
|
||||
KeyEditor = 0,
|
||||
ShortcutEditor,
|
||||
}
|
||||
|
||||
public KeyboardManagerSettings Settings { get; set; }
|
||||
|
||||
@@ -103,6 +106,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
{
|
||||
GeneralSettingsConfig.Enabled.KeyboardManager = value;
|
||||
OnPropertyChanged(nameof(Enabled));
|
||||
|
||||
if (!Enabled && editor != null)
|
||||
{
|
||||
editor.CloseMainWindow();
|
||||
}
|
||||
|
||||
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
|
||||
SendConfigMSG(outgoing.ToString());
|
||||
@@ -165,31 +174,73 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
|
||||
public ICommand EditShortcutCommand => _editShortcutCommand ?? (_editShortcutCommand = new RelayCommand(OnEditShortcut));
|
||||
|
||||
// Note: FxCop suggests calling ConfigureAwait() for the following methods,
|
||||
// and calling ConfigureAwait(true) has the same behavior as not explicitly
|
||||
// calling it (continuations are scheduled on the task-creating thread)
|
||||
private async void OnRemapKeyboard()
|
||||
private void OnRemapKeyboard()
|
||||
{
|
||||
await Task.Run(() => OnRemapKeyboardBackground()).ConfigureAwait(true);
|
||||
OpenEditor((int)KeyboardManagerEditorType.KeyEditor);
|
||||
}
|
||||
|
||||
private async void OnEditShortcut()
|
||||
private void OnEditShortcut()
|
||||
{
|
||||
await Task.Run(() => OnEditShortcutBackground()).ConfigureAwait(true);
|
||||
OpenEditor((int)KeyboardManagerEditorType.ShortcutEditor);
|
||||
}
|
||||
|
||||
private async Task OnRemapKeyboardBackground()
|
||||
private static void BringProcessToFront(Process process)
|
||||
{
|
||||
Helper.AllowRunnerToForeground();
|
||||
SendConfigMSG(Helper.GetSerializedCustomAction(PowerToyName, RemapKeyboardActionName, RemapKeyboardActionValue));
|
||||
await Task.CompletedTask.ConfigureAwait(true);
|
||||
if (process == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr handle = process.MainWindowHandle;
|
||||
if (IsIconic(handle))
|
||||
{
|
||||
ShowWindow(handle, SWRESTORE);
|
||||
}
|
||||
|
||||
SetForegroundWindow(handle);
|
||||
}
|
||||
|
||||
private async Task OnEditShortcutBackground()
|
||||
private const int SWRESTORE = 9;
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("User32.dll")]
|
||||
private static extern bool SetForegroundWindow(IntPtr handle);
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("User32.dll")]
|
||||
|
||||
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("User32.dll")]
|
||||
|
||||
private static extern bool IsIconic(IntPtr handle);
|
||||
|
||||
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exceptions here (especially mutex errors) should not halt app execution, but they will be logged.")]
|
||||
private void OpenEditor(int type)
|
||||
{
|
||||
Helper.AllowRunnerToForeground();
|
||||
SendConfigMSG(Helper.GetSerializedCustomAction(PowerToyName, EditShortcutActionName, EditShortcutActionValue));
|
||||
await Task.CompletedTask.ConfigureAwait(true);
|
||||
try
|
||||
{
|
||||
if (editor != null && editor.HasExited)
|
||||
{
|
||||
Logger.LogInfo($"Previous instance of {PowerToyName} editor exited");
|
||||
editor = null;
|
||||
}
|
||||
|
||||
if (editor != null)
|
||||
{
|
||||
Logger.LogInfo($"The {PowerToyName} editor instance {editor.Id} exists. Bringing the process to the front");
|
||||
BringProcessToFront(editor);
|
||||
return;
|
||||
}
|
||||
|
||||
string path = Path.Combine(Environment.CurrentDirectory, KeyboardManagerEditorPath);
|
||||
Logger.LogInfo($"Starting {PowerToyName} editor from {path}");
|
||||
|
||||
// InvariantCulture: type represents the KeyboardManagerEditorType enum value
|
||||
editor = Process.Start(path, $"{type.ToString(CultureInfo.InvariantCulture)} {Process.GetCurrentProcess().Id}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception encountered when opening an {PowerToyName} editor", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyFileChanged()
|
||||
@@ -201,42 +252,50 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Exceptions here (especially mutex errors) should not halt app execution, but they will be logged.")]
|
||||
public bool LoadProfile()
|
||||
{
|
||||
// The KBM process out of runner creates the default.json file if it does not exist.
|
||||
var success = true;
|
||||
var readSuccessfully = false;
|
||||
|
||||
string fileName = Settings.Properties.ActiveConfiguration.Value + JsonFileType;
|
||||
|
||||
try
|
||||
{
|
||||
using (var profileFileMutex = Mutex.OpenExisting(ConfigFileMutexName))
|
||||
// retry loop for reading
|
||||
CancellationTokenSource ts = new CancellationTokenSource();
|
||||
Task t = Task.Run(() =>
|
||||
{
|
||||
if (profileFileMutex.WaitOne(ConfigFileMutexWaitTimeoutMilliseconds))
|
||||
while (!readSuccessfully && !ts.IsCancellationRequested)
|
||||
{
|
||||
// update the UI element here.
|
||||
try
|
||||
if (_settingsUtils.SettingsExists(PowerToyName, fileName))
|
||||
{
|
||||
string fileName = Settings.Properties.ActiveConfiguration.Value + JsonFileType;
|
||||
|
||||
if (_settingsUtils.SettingsExists(PowerToyName, fileName))
|
||||
try
|
||||
{
|
||||
_profile = _settingsUtils.GetSettingsOrDefault<KeyboardManagerProfile>(PowerToyName, fileName);
|
||||
readSuccessfully = true;
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
// The KBM process out of runner creates the default.json file if it does not exist.
|
||||
success = false;
|
||||
Logger.LogError($"Exception encountered when reading {PowerToyName} settings", e);
|
||||
}
|
||||
}
|
||||
|
||||
FilterRemapKeysList(_profile?.RemapKeys?.InProcessRemapKeys);
|
||||
}
|
||||
finally
|
||||
if (!readSuccessfully)
|
||||
{
|
||||
// Make sure to release the mutex.
|
||||
profileFileMutex.ReleaseMutex();
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
});
|
||||
|
||||
t.Wait(1000, ts.Token);
|
||||
ts.Cancel();
|
||||
ts.Dispose();
|
||||
|
||||
if (!readSuccessfully)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
FilterRemapKeysList(_profile?.RemapKeys?.InProcessRemapKeys);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user