mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
[Shortcut Guide] Move into separate process (#11359)
This commit is contained in:
@@ -14,8 +14,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
PressTime = new IntProperty(900);
|
||||
Theme = new StringProperty("system");
|
||||
DisabledApps = new StringProperty();
|
||||
OpenShortcutGuide = new HotkeySettings(true, false, false, true, 0xBF);
|
||||
}
|
||||
|
||||
[JsonPropertyName("open_shortcutguide")]
|
||||
public HotkeySettings OpenShortcutGuide { get; set; }
|
||||
|
||||
[JsonPropertyName("overlay_opacity")]
|
||||
public IntProperty OverlayOpacity { get; set; }
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
{
|
||||
public class ShortcutGuideViewModel : Observable
|
||||
{
|
||||
private ISettingsUtils SettingsUtils { get; set; }
|
||||
|
||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||
|
||||
private ShortcutGuideSettings Settings { get; set; }
|
||||
@@ -22,8 +24,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
private string _settingsConfigFileFolder = string.Empty;
|
||||
private string _disabledApps;
|
||||
|
||||
public ShortcutGuideViewModel(ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
|
||||
public ShortcutGuideViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc, string configFileSubfolder = "")
|
||||
{
|
||||
SettingsUtils = settingsUtils;
|
||||
|
||||
// Update Settings file folder:
|
||||
_settingsConfigFileFolder = configFileSubfolder;
|
||||
|
||||
@@ -98,6 +102,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public HotkeySettings OpenShortcutGuide
|
||||
{
|
||||
get
|
||||
{
|
||||
return Settings.Properties.OpenShortcutGuide;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (Settings.Properties.OpenShortcutGuide != value)
|
||||
{
|
||||
Settings.Properties.OpenShortcutGuide = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ThemeIndex
|
||||
{
|
||||
get
|
||||
@@ -136,24 +157,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public int PressTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return _pressTime;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_pressTime != value)
|
||||
{
|
||||
_pressTime = value;
|
||||
Settings.Properties.PressTime.Value = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int OverlayOpacity
|
||||
{
|
||||
get
|
||||
@@ -198,9 +201,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
OnPropertyChanged(propertyName);
|
||||
|
||||
SndShortcutGuideSettings outsettings = new SndShortcutGuideSettings(Settings);
|
||||
SndModuleSettings<SndShortcutGuideSettings> ipcMessage = new SndModuleSettings<SndShortcutGuideSettings>(outsettings);
|
||||
SendConfigMSG(ipcMessage.ToJsonString());
|
||||
SettingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,11 @@ namespace ViewModelTests
|
||||
|
||||
// Initialise View Model with test Config files
|
||||
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(generalSettingsRepository, shortcutSettingsRepository, sendMockIPCConfigMSG);
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(mockSettingsUtils, generalSettingsRepository, shortcutSettingsRepository, sendMockIPCConfigMSG);
|
||||
|
||||
// Verify that the old settings persisted
|
||||
Assert.AreEqual(originalGeneralSettings.Enabled.ShortcutGuide, viewModel.IsEnabled);
|
||||
Assert.AreEqual(originalSettings.Properties.OverlayOpacity.Value, viewModel.OverlayOpacity);
|
||||
Assert.AreEqual(originalSettings.Properties.PressTime.Value, viewModel.PressTime);
|
||||
|
||||
// Verify that the stub file was used
|
||||
var expectedCallCount = 2; // once via the view model, and once by the test (GetSettings<T>)
|
||||
@@ -69,6 +68,8 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void IsEnabledShouldEnableModuleWhenSuccessful()
|
||||
{
|
||||
var settingsUtilsMock = new Mock<SettingsUtils>();
|
||||
|
||||
// Assert
|
||||
// Initialize mock function of sending IPC message.
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
@@ -79,7 +80,7 @@ namespace ViewModelTests
|
||||
};
|
||||
|
||||
// Arrange
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), sendMockIPCConfigMSG, ShortCutGuideTestFolderName);
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(settingsUtilsMock.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), sendMockIPCConfigMSG, ShortCutGuideTestFolderName);
|
||||
|
||||
// Act
|
||||
viewModel.IsEnabled = true;
|
||||
@@ -88,65 +89,35 @@ namespace ViewModelTests
|
||||
[TestMethod]
|
||||
public void ThemeIndexShouldSetThemeToDarkWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
// Initialize mock function of sending IPC message.
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
ShortcutGuideSettingsIPCMessage snd = JsonSerializer.Deserialize<ShortcutGuideSettingsIPCMessage>(msg);
|
||||
Assert.AreEqual("dark", snd.Powertoys.ShortcutGuide.Properties.Theme.Value);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Arrange
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), sendMockIPCConfigMSG, ShortCutGuideTestFolderName);
|
||||
var settingsUtilsMock = new Mock<ISettingsUtils>();
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(settingsUtilsMock.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), msg => { return 0; }, ShortCutGuideTestFolderName);
|
||||
|
||||
// Initialize shortcut guide settings theme to 'system' to be in sync with shortcut_guide.h.
|
||||
Assert.AreEqual(2, viewModel.ThemeIndex);
|
||||
|
||||
// Act
|
||||
viewModel.ThemeIndex = 0;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void PressTimeShouldSetPressTimeToOneHundredWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
// Initialize mock function of sending IPC message.
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
ShortcutGuideSettingsIPCMessage snd = JsonSerializer.Deserialize<ShortcutGuideSettingsIPCMessage>(msg);
|
||||
Assert.AreEqual(100, snd.Powertoys.ShortcutGuide.Properties.PressTime.Value);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Arrange
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), sendMockIPCConfigMSG, ShortCutGuideTestFolderName);
|
||||
Assert.AreEqual(900, viewModel.PressTime);
|
||||
|
||||
// Act
|
||||
viewModel.PressTime = 100;
|
||||
Func<string, bool> isDark = s => JsonSerializer.Deserialize<ShortcutGuideSettings>(s).Properties.Theme.Value == "dark";
|
||||
settingsUtilsMock.Verify(x => x.SaveSettings(It.Is<string>(y => isDark(y)), It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OverlayOpacityShouldSeOverlayOpacityToOneHundredWhenSuccessful()
|
||||
{
|
||||
// Assert
|
||||
// Initialize mock function of sending IPC message.
|
||||
Func<string, int> sendMockIPCConfigMSG = msg =>
|
||||
{
|
||||
ShortcutGuideSettingsIPCMessage snd = JsonSerializer.Deserialize<ShortcutGuideSettingsIPCMessage>(msg);
|
||||
|
||||
// Serialisation not working as expected in the test project:
|
||||
Assert.AreEqual(100, snd.Powertoys.ShortcutGuide.Properties.OverlayOpacity.Value);
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Arrange
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), sendMockIPCConfigMSG, ShortCutGuideTestFolderName);
|
||||
var settingsUtilsMock = new Mock<ISettingsUtils>();
|
||||
ShortcutGuideViewModel viewModel = new ShortcutGuideViewModel(settingsUtilsMock.Object, SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), SettingsRepository<ShortcutGuideSettings>.GetInstance(mockShortcutGuideSettingsUtils.Object), msg => { return 0; }, ShortCutGuideTestFolderName);
|
||||
Assert.AreEqual(90, viewModel.OverlayOpacity);
|
||||
|
||||
// Act
|
||||
viewModel.OverlayOpacity = 100;
|
||||
|
||||
// Assert
|
||||
Func<string, bool> equal100 = s => JsonSerializer.Deserialize<ShortcutGuideSettings>(s).Properties.OverlayOpacity.Value == 100;
|
||||
settingsUtilsMock.Verify(x => x.SaveSettings(It.Is<string>(y => equal100(y)), It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,6 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
ColorPickerSharedEventCallback = implementation;
|
||||
}
|
||||
|
||||
public static Func<string> ShortcutGuideSharedEventCallback { get; set; }
|
||||
|
||||
public static void SetShortcutGuideSharedEventCallback(Func<string> implementation)
|
||||
{
|
||||
ShortcutGuideSharedEventCallback = implementation;
|
||||
}
|
||||
|
||||
public static Action<Type> OpenMainWindowCallback { get; set; }
|
||||
|
||||
public static void SetOpenMainWindowCallback(Action<Type> implementation)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
// 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.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
|
||||
using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
|
||||
@@ -27,12 +30,12 @@ namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
|
||||
|
||||
private void Start_ShortcutGuide_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (OobeShellPage.ShortcutGuideSharedEventCallback != null)
|
||||
var executablePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, @"..\modules\ShortcutGuide\ShortcutGuide\PowerToys.ShortcutGuide.exe");
|
||||
var id = Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture);
|
||||
var p = Process.Start(executablePath, id);
|
||||
if (p != null)
|
||||
{
|
||||
using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, OobeShellPage.ShortcutGuideSharedEventCallback()))
|
||||
{
|
||||
eventHandle.Set();
|
||||
}
|
||||
p.Close();
|
||||
}
|
||||
|
||||
ViewModel.LogRunningModuleEvent();
|
||||
|
||||
@@ -477,10 +477,6 @@
|
||||
<data name="ShortcutGuide_Description.Text" xml:space="preserve">
|
||||
<value>Shows a help overlay with Windows shortcuts when the Windows key is pressed.</value>
|
||||
</data>
|
||||
<data name="ShortcutGuide_PressTime.Header" xml:space="preserve">
|
||||
<value>Press duration before showing (ms)</value>
|
||||
<comment>pressing a key in milliseconds</comment>
|
||||
</data>
|
||||
<data name="ShortcutGuide_Appearance_Behavior.Text" xml:space="preserve">
|
||||
<value>Appearance & behavior</value>
|
||||
</data>
|
||||
@@ -1097,7 +1093,7 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
|
||||
<value>PowerToys Run supports various action keys to funnel search queries for a specific subset of results. Typing {<} searches for running processes only, {?} will search only for file, or {.} for installed applications! See PowerToys documentation for the complete set of 'Action Keys' available.</value>
|
||||
</data>
|
||||
<data name="Oobe_ShortcutGuide_HowToLaunch.Text" xml:space="preserve">
|
||||
<value>{Win} + {?} to open Shortcut Guide, press it again to close or press {Esc}. You can also launch it by holding the {Win} key for one second!</value>
|
||||
<value>{Shift} + {Win} + {/} to open Shortcut Guide, press it again to close or press {Esc}.</value>
|
||||
</data>
|
||||
<data name="Oobe_TipsAndTricks.Text" xml:space="preserve">
|
||||
<value>Tips & tricks</value>
|
||||
@@ -1195,4 +1191,7 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
|
||||
<data name="FancyZones_QuickLayoutSwitch_GroupSettings.Text" xml:space="preserve">
|
||||
<value>Quick layout switch</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
|
||||
<value>Open Shortcut Guide</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -2,12 +2,11 @@
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.ShortcutGuidePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Views"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModel="using:Microsoft.PowerToys.Settings.UI.ViewModels"
|
||||
xmlns:CustomControls="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls" xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
AutomationProperties.LandmarkType="Main">
|
||||
@@ -58,21 +57,22 @@
|
||||
<ToggleSwitch x:Uid="ShortcutGuide_Enable"
|
||||
IsOn="{x:Bind Mode=TwoWay, Path=ViewModel.IsEnabled}"/>
|
||||
|
||||
<TextBlock x:Uid="Shortcuts"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"
|
||||
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
|
||||
<CustomControls:HotkeySettingsControl x:Uid="ShortcutGuide_OpenShortcutGuide"
|
||||
HorizontalAlignment="Left"
|
||||
MinWidth="240"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
HotkeySettings="{x:Bind Path=ViewModel.OpenShortcutGuide, Mode=TwoWay}"
|
||||
Keys="Win, Ctrl, Alt, Shift"
|
||||
Enabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"/>
|
||||
|
||||
<TextBlock x:Uid="ShortcutGuide_Appearance_Behavior"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"
|
||||
Foreground="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
|
||||
<muxc:NumberBox x:Uid="ShortcutGuide_PressTime"
|
||||
Minimum="100"
|
||||
SpinButtonPlacementMode="Compact"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
MinWidth="240"
|
||||
Value="{x:Bind Mode=TwoWay, Path=ViewModel.PressTime}"
|
||||
IsEnabled="{x:Bind Mode=OneWay, Path=ViewModel.IsEnabled}"
|
||||
SmallChange="50"
|
||||
LargeChange="100"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="{StaticResource MediumTopMargin}" Spacing="12">
|
||||
<Slider x:Uid="ShortcutGuide_OverlayOpacity"
|
||||
Minimum="0"
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
InitializeComponent();
|
||||
|
||||
var settingsUtils = new SettingsUtils();
|
||||
ViewModel = new ShortcutGuideViewModel(SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<ShortcutGuideSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
ViewModel = new ShortcutGuideViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<ShortcutGuideSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage);
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,12 +78,6 @@ namespace PowerToys.Settings
|
||||
return Constants.ShowColorPickerSharedEvent();
|
||||
});
|
||||
|
||||
OobeShellPage.SetShortcutGuideSharedEventCallback(() =>
|
||||
{
|
||||
NativeMethods.AllowSetForegroundWindow(PowerToys.Settings.Program.PowerToysPID);
|
||||
return Constants.ShowShortcutGuideSharedEvent();
|
||||
});
|
||||
|
||||
OobeShellPage.SetOpenMainWindowCallback((Type type) =>
|
||||
{
|
||||
((App)Application.Current).OpenSettingsWindow(type);
|
||||
|
||||
Reference in New Issue
Block a user