Implemented shortcut

Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
This commit is contained in:
Shawn Yuan (from Dev Box)
2025-12-09 14:46:56 +08:00
parent e89d6d8f5a
commit 4a823320c4
13 changed files with 164 additions and 19 deletions

View File

@@ -36,5 +36,6 @@ namespace ManagedCommon
PowerOCR,
Workspaces,
ZoomIt,
GeneralSettings,
}
}

View File

@@ -189,6 +189,12 @@ GeneralSettings get_general_settings()
void apply_general_settings(const json::JsonObject& general_configs, bool save)
{
std::wstring old_settings_json_string;
if (save)
{
old_settings_json_string = get_general_settings().to_json().Stringify().c_str();
}
Logger::info(L"apply_general_settings: {}", std::wstring{ general_configs.ToString() });
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
@@ -355,9 +361,13 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
if (save)
{
GeneralSettings save_settings = get_general_settings();
std::wstring new_settings_json_string = save_settings.to_json().Stringify().c_str();
if (old_settings_json_string != new_settings_json_string)
{
PTSettingsHelper::save_general_settings(save_settings.to_json());
Trace::SettingsChanged(save_settings);
}
}
}
void start_enabled_powertoys()

View File

@@ -190,12 +190,12 @@ void dispatch_received_json(const std::wstring& json_to_parse)
if (name == L"general")
{
apply_general_settings(value.GetObjectW());
const std::wstring settings_string{ get_all_settings().Stringify().c_str() };
{
std::unique_lock lock{ ipc_mutex };
if (current_settings_ipc)
current_settings_ipc->send(settings_string);
}
// const std::wstring settings_string{ get_all_settings().Stringify().c_str() };
// {
// std::unique_lock lock{ ipc_mutex };
// if (current_settings_ipc)
// current_settings_ipc->send(settings_string);
// }
}
else if (name == L"powertoys")
{

View File

@@ -6,6 +6,7 @@
#include "centralized_hotkeys.h"
#include "centralized_kb_hook.h"
#include "quick_access_host.h"
#include "hotkey_conflict_detector.h"
#include <Windows.h>
#include <common/utils/resources.h>
@@ -357,18 +358,31 @@ void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject ho
{
static PowerToysSettings::HotkeyObject current_hotkey;
static bool is_registered = false;
auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance();
if (is_registered)
{
CentralizedHotkeys::UnregisterHotkeysForModule(L"QuickAccess");
CentralizedKeyboardHook::ClearModuleHotkeys(L"QuickAccess");
hkmng.RemoveHotkeyByModule(L"GeneralSettings");
is_registered = false;
}
if (enabled && hotkey.get_code() != 0)
{
CentralizedHotkeys::AddHotkeyAction({ static_cast<WORD>(hotkey.get_modifiers()), static_cast<WORD>(hotkey.get_code()) }, { L"QuickAccess", [](WORD, WORD) {
HotkeyConflictDetector::Hotkey hk = {
hotkey.win_pressed(),
hotkey.ctrl_pressed(),
hotkey.shift_pressed(),
hotkey.alt_pressed(),
static_cast<unsigned char>(hotkey.get_code())
};
hkmng.AddHotkey(hk, L"GeneralSettings", 0, true);
CentralizedKeyboardHook::SetHotkeyAction(L"QuickAccess", hk, []() {
open_quick_access_flyout_window();
}});
return true;
});
current_hotkey = hotkey;
is_registered = true;
}

View File

@@ -8,10 +8,9 @@
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="ms-appx:///Resources/Styles/Button.xaml" />
<ResourceDictionary Source="ms-appx:///Resources/Styles/TextBlock.xaml" />
<ResourceDictionary Source="ms-appx:///Resources/Themes/Colors.xaml" />
<ResourceDictionary Source="ms-appx:///Resources/Themes/Generic.xaml" />
<ResourceDictionary Source="/Resources/Styles/Button.xaml" />
<ResourceDictionary Source="/Resources/Styles/TextBlock.xaml" />
<ResourceDictionary Source="/Resources/Themes/Colors.xaml" />
</ResourceDictionary.MergedDictionaries>
<ResourceDictionary.ThemeDictionaries>
@@ -20,21 +19,29 @@
x:Key="LayerOnAcrylicFillColorDefaultBrush"
Opacity="0.7"
Color="#FFFFFFFF" />
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#0F000000" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#B3FFFFFF" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<SolidColorBrush
x:Key="LayerOnAcrylicFillColorDefaultBrush"
Opacity="0.7"
Color="#FFFFFFFF" />
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#0F000000" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#B3FFFFFF" />
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush
x:Key="LayerOnAcrylicFillColorDefaultBrush"
Opacity="0.6"
Color="#FF000000" />
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#0FFFFFFF" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#0DFFFFFF" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="LayerOnAcrylicFillColorDefaultBrush" Color="{ThemeResource SystemColorWindowColor}" />
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="{ThemeResource SystemColorWindowTextColor}" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="{ThemeResource SystemColorWindowColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

View File

@@ -372,7 +372,7 @@ public sealed partial class MainWindow : WindowEx, IDisposable
_exitEvent?.Dispose();
_exitEvent = null;
if (_hwnd != IntPtr.Zero)
if (_hwnd != IntPtr.Zero && IsWindow(_hwnd))
{
UncloakWindow();
}
@@ -385,6 +385,10 @@ public sealed partial class MainWindow : WindowEx, IDisposable
_disposed = true;
}
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)]
private static extern bool ShowWindowNative(IntPtr hWnd, int nCmdShow);

View File

@@ -86,6 +86,11 @@ public sealed class AllAppsViewModel : Observable
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
{
if (moduleType == ModuleType.GeneralSettings)
{
continue;
}
var gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
var isLocked = gpo is GpoRuleConfigured.Enabled or GpoRuleConfigured.Disabled;
var isEnabled = gpo == GpoRuleConfigured.Enabled || (!isLocked && ModuleHelper.GetIsModuleEnabled(_generalSettings, moduleType));

View File

@@ -7,6 +7,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Settings.UI.Library.Attributes;
@@ -19,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
ByStatus,
}
public class GeneralSettings : ISettingsConfig
public class GeneralSettings : ISettingsConfig, IHotkeyConfig
{
// Gets or sets a value indicating whether run powertoys on start-up.
[JsonPropertyName("startup")]
@@ -126,6 +127,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
IgnoredConflictProperties = new ShortcutConflictProperties();
}
public HotkeyAccessor[] GetAllHotkeyAccessors()
{
return new HotkeyAccessor[]
{
new HotkeyAccessor(
() => QuickAccessShortcut,
(hotkey) => { QuickAccessShortcut = hotkey; },
"GeneralPage_QuickAccessShortcut"),
};
}
public ModuleType GetModuleType()
{
return ModuleType.GeneralSettings;
}
// converts the current to a json string.
public string ToJsonString()
{

View File

@@ -68,6 +68,11 @@ namespace Microsoft.PowerToys.Settings.UI.Services
if (settingsInstance != null)
{
var moduleName = settingsInstance.GetModuleName();
if (string.IsNullOrEmpty(moduleName) && type == typeof(GeneralSettings))
{
moduleName = "GeneralSettings";
}
if (!string.IsNullOrEmpty(moduleName))
{
settingsTypes[moduleName] = type;
@@ -104,7 +109,13 @@ namespace Microsoft.PowerToys.Settings.UI.Services
var genericMethod = getSettingsMethod?.MakeGenericMethod(settingsType);
// Call GetSettingsOrDefault<T>(moduleKey) to get fresh settings from file
var freshSettings = genericMethod?.Invoke(_settingsUtils, new object[] { moduleKey, "settings.json" });
string actualModuleKey = moduleKey;
if (moduleKey == "GeneralSettings")
{
actualModuleKey = string.Empty;
}
var freshSettings = genericMethod?.Invoke(_settingsUtils, new object[] { actualModuleKey, "settings.json" });
return freshSettings as IHotkeyConfig;
}

View File

@@ -24,6 +24,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
case ModuleType.MouseJump:
case ModuleType.MousePointerCrosshairs:
case ModuleType.CursorWrap: return $"MouseUtils_{moduleType}/Header";
case ModuleType.GeneralSettings: return "QuickAccessTitle/Title";
default: return $"{moduleType}/ModuleTitle";
}
}
@@ -39,6 +40,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
case ModuleType.MousePointerCrosshairs: return "ms-appx:///Assets/Settings/Icons/MouseCrosshairs.png";
case ModuleType.MeasureTool: return "ms-appx:///Assets/Settings/Icons/ScreenRuler.png";
case ModuleType.PowerLauncher: return $"ms-appx:///Assets/Settings/Icons/PowerToysRun.png";
case ModuleType.GeneralSettings: return "ms-appx:///Assets/Settings/Icons/PowerToys.png";
default: return $"ms-appx:///Assets/Settings/Icons/{moduleType}.png";
}
}
@@ -77,6 +79,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
case ModuleType.ShortcutGuide: return generalSettingsConfig.Enabled.ShortcutGuide;
case ModuleType.PowerOCR: return generalSettingsConfig.Enabled.PowerOcr;
case ModuleType.ZoomIt: return generalSettingsConfig.Enabled.ZoomIt;
case ModuleType.GeneralSettings: return generalSettingsConfig.EnableQuickAccess;
default: return false;
}
}
@@ -115,6 +118,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
case ModuleType.ShortcutGuide: generalSettingsConfig.Enabled.ShortcutGuide = isEnabled; break;
case ModuleType.PowerOCR: generalSettingsConfig.Enabled.PowerOcr = isEnabled; break;
case ModuleType.ZoomIt: generalSettingsConfig.Enabled.ZoomIt = isEnabled; break;
case ModuleType.GeneralSettings: generalSettingsConfig.EnableQuickAccess = isEnabled; break;
}
}
@@ -171,6 +175,7 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers
ModuleType.FancyZones => typeof(FancyZonesPage),
ModuleType.FileLocksmith => typeof(FileLocksmithPage),
ModuleType.FindMyMouse => typeof(MouseUtilsPage),
ModuleType.GeneralSettings => typeof(GeneralPage),
ModuleType.Hosts => typeof(HostsPage),
ModuleType.ImageResizer => typeof(ImageResizerPage),
ModuleType.KeyboardManager => typeof(KeyboardManagerPage),

View File

@@ -93,6 +93,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
CheckBugReportStatus();
doRefreshBackupRestoreStatus(100);
this.Loaded += (s, e) => ViewModel.OnPageLoaded();
}
private void OpenColorsSettings_Click(object sender, RoutedEventArgs e)

View File

@@ -48,6 +48,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
// Flag to prevent circular updates when a UI toggle triggers settings changes.
private bool _isUpdatingFromUI;
private bool _isUpdatingFromSettings;
private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData();
@@ -164,6 +165,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
{
if (moduleType == ModuleType.GeneralSettings)
{
continue;
}
GpoRuleConfigured gpo = ModuleHelper.GetModuleGpoConfiguration(moduleType);
var newItem = new DashboardListItem()
{
@@ -263,6 +269,11 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
/// </summary>
private void EnabledChangedOnUI(DashboardListItem dashboardListItem)
{
if (_isUpdatingFromSettings)
{
return;
}
_isUpdatingFromUI = true;
try
{
@@ -306,6 +317,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
return;
}
_isUpdatingFromSettings = true;
try
{
RefreshModuleList();
@@ -320,6 +332,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
Logger.LogError($"Updating active/disabled modules list failed: {ex.Message}");
}
finally
{
_isUpdatingFromSettings = false;
}
}
/// <summary>
@@ -731,5 +747,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
NavigationService.Navigate(ModuleHelper.GetModulePageType(moduleType));
}
}
public override void Dispose()
{
base.Dispose();
if (_settingsRepository != null)
{
_settingsRepository.SettingsChanged -= OnSettingsChanged;
}
GC.SuppressFinalize(this);
}
}
}

View File

@@ -31,7 +31,7 @@ using Windows.System.Profile;
namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
public partial class GeneralViewModel : Observable
public partial class GeneralViewModel : PageViewModelBase
{
public enum InstallScope
{
@@ -39,6 +39,16 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
PerUser,
}
protected override string ModuleName => "GeneralSettings";
public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()
{
return new Dictionary<string, HotkeySettings[]>
{
{ ModuleName, new HotkeySettings[] { QuickAccessShortcut } },
};
}
private GeneralSettings GeneralSettingsConfig { get; set; }
private UpdatingSettings UpdatingSettingsConfig { get; set; }
@@ -75,6 +85,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private string _settingsConfigFileFolder = string.Empty;
private ISettingsRepository<GeneralSettings> _settingsRepository;
private Microsoft.UI.Dispatching.DispatcherQueue _dispatcherQueue;
private IFileSystemWatcher _fileWatcher;
private Func<Task<string>> PickSingleFolderDialog { get; }
@@ -100,6 +113,10 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
ArgumentNullException.ThrowIfNull(settingsRepository);
_settingsRepository = settingsRepository;
_settingsRepository.SettingsChanged += OnSettingsChanged;
_dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
GeneralSettingsConfig = settingsRepository.SettingsConfig;
UpdatingSettingsConfig = UpdatingSettings.LoadSettings();
if (UpdatingSettingsConfig == null)
@@ -1493,5 +1510,30 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
Process.Start("explorer.exe", etwDirPath);
}
}
private void OnSettingsChanged(GeneralSettings newSettings)
{
_dispatcherQueue?.TryEnqueue(() =>
{
GeneralSettingsConfig = newSettings;
if (_enableQuickAccess != newSettings.EnableQuickAccess)
{
_enableQuickAccess = newSettings.EnableQuickAccess;
OnPropertyChanged(nameof(EnableQuickAccess));
}
});
}
public override void Dispose()
{
base.Dispose();
if (_settingsRepository != null)
{
_settingsRepository.SettingsChanged -= OnSettingsChanged;
}
GC.SuppressFinalize(this);
}
}
}