Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/settings-ui/Settings.UI.Library/CmdPalProperties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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.IO;
using System.IO.Abstractions;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Microsoft.PowerToys.Settings.UI.Library
{
public class CmdPalProperties
{
// Default shortcut - Win + Alt + Space
public static readonly HotkeySettings DefaultHotkeyValue = new HotkeySettings(true, false, true, false, 32);

#pragma warning disable SA1401 // Fields should be private
#pragma warning disable CA1051 // Do not declare visible instance fields
public HotkeySettings Hotkey;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay this is my c# knowledge being limited, but is there a reason to do it this way vs just

public HotkeySettings Hotkey { get; private set; }

#pragma warning restore CA1051 // Do not declare visible instance fields
#pragma warning restore SA1401 // Fields should be private

private string _settingsFilePath;

public CmdPalProperties()
{
var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

#if DEBUG
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i mean big picture, this isn't exactly right, but it'll work this week

_settingsFilePath = Path.Combine(localAppDataDir, "Packages", "Microsoft.CommandPalette.Dev_8wekyb3d8bbwe", "LocalState", "settings.json");
#else
_settingsFilePath = Path.Combine(localAppDataDir, "Packages", "Microsoft.CommandPalette_8wekyb3d8bbwe", "LocalState", "settings.json");
#endif

InitializeHotkey();
}

public void InitializeHotkey()
{
try
{
string json = File.ReadAllText(_settingsFilePath); // Read JSON file
using JsonDocument doc = JsonDocument.Parse(json);

if (doc.RootElement.TryGetProperty(nameof(Hotkey), out JsonElement hotkeyElement))
{
Hotkey = JsonSerializer.Deserialize<HotkeySettings>(hotkeyElement.GetRawText());

if (Hotkey == null)
{
Hotkey = DefaultHotkeyValue;
}
}
}
catch (Exception)
{
Hotkey = DefaultHotkeyValue;
}
}
}
}
21 changes: 21 additions & 0 deletions src/settings-ui/Settings.UI.Library/Utilities/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ public static string GetSerializedCustomAction(string moduleName, string actionN
return sendCustomAction.ToJsonString();
}

public static IFileSystemWatcher GetFileWatcher(string path, Action onChangedCallback, IFileSystem fileSystem = null)
{
fileSystem ??= FileSystem;

var dirPath = Path.GetDirectoryName(path);
if (!fileSystem.Directory.Exists(dirPath))
{
return null;
}

var watcher = fileSystem.FileSystemWatcher.New();
watcher.Path = dirPath;
watcher.Filter = Path.GetFileName(path);
watcher.NotifyFilter = NotifyFilters.LastWrite;
watcher.EnableRaisingEvents = true;

watcher.Changed += (o, e) => onChangedCallback();

return watcher;
}

public static IFileSystemWatcher GetFileWatcher(string moduleName, string fileName, Action onChangedCallback, IFileSystem fileSystem = null)
{
fileSystem ??= FileSystem;
Expand Down
10 changes: 10 additions & 0 deletions src/settings-ui/Settings.UI/SettingsXAML/Views/CmdPalPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@
IsOpen="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}"
IsTabStop="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay}"
Severity="Informational" />

<controls:SettingsGroup x:Uid="CmdPal_Activation_GroupSettings" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">

<tkcontrols:SettingsCard x:Uid="CmdPal_ActivationShortcut" HeaderIcon="{ui:FontIcon Glyph=&#xEDA7;}">
<controls:ShortcutControl
MinWidth="{StaticResource SettingActionControlMinWidth}"
HotkeySettings="{x:Bind Path=ViewModel.Hotkey, Mode=OneWay}"
IsEnabled="False" />
</tkcontrols:SettingsCard>
</controls:SettingsGroup>
</StackPanel>
</controls:SettingsPageControl.ModuleContent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public CmdPalPage()
ViewModel = new CmdPalViewModel(
settingsUtils,
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
ShellPage.SendDefaultIPCMessage);
ShellPage.SendDefaultIPCMessage,
DispatcherQueue);
DataContext = ViewModel;
InitializeComponent();
}
Expand Down
9 changes: 9 additions & 0 deletions src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -4990,4 +4990,13 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
<data name="RetryLabel.Text" xml:space="preserve">
<value>Retry</value>
</data>
<data name="CmdPal_Activation_GroupSettings.Header" xml:space="preserve">
<value>Activation</value>
</data>
<data name="CmdPal_ActivationShortcut.Header" xml:space="preserve">
<value>Activation shortcut</value>
</data>
<data name="CmdPal_ActivationShortcut.Description" xml:space="preserve">
<value>Go to Command Palette settings to customize the activation shortcut.</value>
</data>
</root>
43 changes: 42 additions & 1 deletion src/settings-ui/Settings.UI/ViewModels/CmdPalViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@

using System;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Text.RegularExpressions;
using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.ViewModels.Commands;
using Microsoft.UI.Dispatching;
using Windows.Management.Deployment;

namespace Microsoft.PowerToys.Settings.UI.ViewModels
Expand All @@ -21,12 +25,16 @@ public class CmdPalViewModel : Observable
{
private GpoRuleConfigured _enabledGpoRuleConfiguration;
private bool _isEnabled;
private HotkeySettings _hotkey;
private IFileSystemWatcher _watcher;
private DispatcherQueue _uiDispatcherQueue;
private CmdPalProperties _cmdPalProperties;

private GeneralSettings GeneralSettingsConfig { get; set; }

private Func<string, int> SendConfigMSG { get; }

public CmdPalViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
public CmdPalViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, DispatcherQueue uiDispatcherQueue)
{
ArgumentNullException.ThrowIfNull(settingsUtils);

Expand All @@ -35,8 +43,32 @@ public CmdPalViewModel(ISettingsUtils settingsUtils, ISettingsRepository<General

GeneralSettingsConfig = settingsRepository.SettingsConfig;

_uiDispatcherQueue = uiDispatcherQueue;
_cmdPalProperties = new CmdPalProperties();

InitializeEnabledValue();

var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

#if DEBUG
var settingsPath = Path.Combine(localAppDataDir, "Packages", "Microsoft.CommandPalette.Dev_8wekyb3d8bbwe", "LocalState", "settings.json");
#else
var settingsPath = Path.Combine(localAppDataDir, "Packages", "Microsoft.CommandPalette_8wekyb3d8bbwe", "LocalState", "settings.json");
#endif

_hotkey = _cmdPalProperties.Hotkey;

_watcher = Helper.GetFileWatcher(settingsPath, () =>
{
_cmdPalProperties.InitializeHotkey();
_hotkey = _cmdPalProperties.Hotkey;

_uiDispatcherQueue.TryEnqueue(() =>
{
OnPropertyChanged(nameof(Hotkey));
});
});

// set the callback functions value to handle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
}
Expand Down Expand Up @@ -82,6 +114,15 @@ public bool IsEnabled
}
}

public HotkeySettings Hotkey
Copy link

Copilot AI Mar 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setter for the Hotkey property is empty and does not store any value, which can lead to unexpected behavior if the property is ever set. Consider either implementing the setter to update _hotkey or removing it to make the property read-only.

Copilot uses AI. Check for mistakes.
{
get => _hotkey;

private set
{
}
}

public bool IsEnabledGpoConfigured { get; private set; }

public void RefreshEnabledState()
Expand Down
4 changes: 3 additions & 1 deletion src/settings-ui/Settings.UI/ViewModels/DashboardViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,11 @@ private ObservableCollection<DashboardModuleItem> GetModuleItemsAwake()

private ObservableCollection<DashboardModuleItem> GetModuleItemsCmdPal()
{
var hotkey = new CmdPalProperties().Hotkey;

var list = new List<DashboardModuleItem>
{
new DashboardModuleTextItem() { Label = resourceLoader.GetString("CmdPal_ShortDescription") },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CmdPal_ShortDescription"), Shortcut = hotkey.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
Expand Down
Loading