Signed-off-by: Shawn Yuan (from Dev Box) <shuaiyuan@microsoft.com>
This commit is contained in:
Shawn Yuan (from Dev Box)
2025-12-08 16:21:44 +08:00
parent 6ba33b0d91
commit 2ca7531ae7
13 changed files with 210 additions and 3 deletions

View File

@@ -119,6 +119,16 @@ namespace PowerToysSettings
class HotkeyObject
{
public:
HotkeyObject() :
m_json(json::JsonObject())
{
m_json.SetNamedValue(L"win", json::value(false));
m_json.SetNamedValue(L"ctrl", json::value(false));
m_json.SetNamedValue(L"alt", json::value(false));
m_json.SetNamedValue(L"shift", json::value(false));
m_json.SetNamedValue(L"code", json::value(0));
m_json.SetNamedValue(L"key", json::value(L""));
}
static HotkeyObject from_json(json::JsonObject json)
{
return HotkeyObject(std::move(json));

View File

@@ -2,6 +2,7 @@
#include "general_settings.h"
#include "auto_start_helper.h"
#include "tray_icon.h"
#include "quick_access_host.h"
#include "Generated files/resource.h"
#include "hotkey_conflict_detector.h"
@@ -71,6 +72,8 @@ static bool download_updates_automatically = true;
static bool show_whats_new_after_updates = true;
static bool enable_experimentation = true;
static bool enable_warnings_elevated_apps = true;
static bool enable_quick_access = true;
static PowerToysSettings::HotkeyObject quick_access_shortcut;
static DashboardSortOrder dashboard_sort_order = DashboardSortOrder::Alphabetical;
static json::JsonObject ignored_conflict_properties = create_default_ignored_conflict_properties();
@@ -104,6 +107,8 @@ json::JsonObject GeneralSettings::to_json()
result.SetNamedValue(L"dashboard_sort_order", json::value(static_cast<int>(dashboardSortOrder)));
result.SetNamedValue(L"is_admin", json::value(isAdmin));
result.SetNamedValue(L"enable_warnings_elevated_apps", json::value(enableWarningsElevatedApps));
result.SetNamedValue(L"enable_quick_access", json::value(enableQuickAccess));
result.SetNamedValue(L"quick_access_shortcut", quickAccessShortcut.get_json());
result.SetNamedValue(L"theme", json::value(theme));
result.SetNamedValue(L"system_theme", json::value(systemTheme));
result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion));
@@ -126,6 +131,11 @@ json::JsonObject load_general_settings()
show_whats_new_after_updates = loaded.GetNamedBoolean(L"show_whats_new_after_updates", true);
enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation", true);
enable_warnings_elevated_apps = loaded.GetNamedBoolean(L"enable_warnings_elevated_apps", true);
enable_quick_access = loaded.GetNamedBoolean(L"enable_quick_access", true);
if (json::has(loaded, L"quick_access_shortcut", json::JsonValueType::Object))
{
quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(loaded.GetNamedObject(L"quick_access_shortcut"));
}
dashboard_sort_order = parse_dashboard_sort_order(loaded, dashboard_sort_order);
if (json::has(loaded, L"ignored_conflict_properties", json::JsonValueType::Object))
@@ -152,6 +162,8 @@ GeneralSettings get_general_settings()
.isRunElevated = run_as_elevated,
.isAdmin = is_user_admin,
.enableWarningsElevatedApps = enable_warnings_elevated_apps,
.enableQuickAccess = enable_quick_access,
.quickAccessShortcut = quick_access_shortcut,
.showNewUpdatesToastNotification = show_new_updates_toast_notification,
.downloadUpdatesAutomatically = download_updates_automatically && is_user_admin,
.showWhatsNewAfterUpdates = show_whats_new_after_updates,
@@ -182,6 +194,36 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
enable_warnings_elevated_apps = general_configs.GetNamedBoolean(L"enable_warnings_elevated_apps", true);
bool new_enable_quick_access = general_configs.GetNamedBoolean(L"enable_quick_access", true);
Logger::info(L"apply_general_settings: enable_quick_access={}, new_enable_quick_access={}", enable_quick_access, new_enable_quick_access);
PowerToysSettings::HotkeyObject new_quick_access_shortcut;
if (json::has(general_configs, L"quick_access_shortcut", json::JsonValueType::Object))
{
new_quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(general_configs.GetNamedObject(L"quick_access_shortcut"));
}
auto hotkey_equals = [](const PowerToysSettings::HotkeyObject& a, const PowerToysSettings::HotkeyObject& b) {
return a.get_code() == b.get_code() &&
a.get_modifiers() == b.get_modifiers();
};
if (enable_quick_access != new_enable_quick_access || !hotkey_equals(quick_access_shortcut, new_quick_access_shortcut))
{
enable_quick_access = new_enable_quick_access;
quick_access_shortcut = new_quick_access_shortcut;
if (enable_quick_access)
{
QuickAccessHost::start();
}
else
{
QuickAccessHost::stop();
}
update_quick_access_hotkey(enable_quick_access, quick_access_shortcut);
}
show_new_updates_toast_notification = general_configs.GetNamedBoolean(L"show_new_updates_toast_notification", true);
download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true);
@@ -404,3 +446,5 @@ void start_enabled_powertoys()
}
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <common/utils/json.h>
#include <common/SettingsAPI/settings_objects.h>
enum class DashboardSortOrder
{
@@ -18,6 +19,8 @@ struct GeneralSettings
bool isRunElevated;
bool isAdmin;
bool enableWarningsElevatedApps;
bool enableQuickAccess;
PowerToysSettings::HotkeyObject quickAccessShortcut;
bool showNewUpdatesToastNotification;
bool downloadUpdatesAutomatically;
bool showWhatsNewAfterUpdates;

View File

@@ -106,7 +106,11 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
#endif
Trace::RegisterProvider();
start_tray_icon(isProcessElevated);
QuickAccessHost::start();
if (get_general_settings().enableQuickAccess)
{
QuickAccessHost::start();
}
update_quick_access_hotkey(get_general_settings().enableQuickAccess, get_general_settings().quickAccessShortcut);
set_tray_icon_visible(get_general_settings().showSystemTrayIcon);
CentralizedKeyboardHook::Start();

View File

@@ -107,9 +107,11 @@ namespace QuickAccessHost
void start()
{
Logger::info(L"QuickAccessHost::start() called");
std::scoped_lock lock(quick_access_mutex);
if (is_process_active_locked())
{
Logger::info(L"QuickAccessHost::start: process already active");
return;
}
@@ -232,6 +234,7 @@ namespace QuickAccessHost
void stop()
{
Logger::info(L"QuickAccessHost::stop() called");
std::unique_lock lock(quick_access_mutex);
if (exit_event)
{
@@ -241,6 +244,7 @@ namespace QuickAccessHost
if (quick_access_process)
{
const DWORD wait_result = WaitForSingleObject(quick_access_process.get(), 2000);
Logger::info(L"QuickAccessHost::stop: WaitForSingleObject result={}", wait_result);
if (wait_result == WAIT_TIMEOUT)
{
Logger::warn(L"QuickAccessHost: Quick Access process did not exit in time, terminating.");
@@ -250,6 +254,7 @@ namespace QuickAccessHost
}
else
{
Logger::info(L"QuickAccessHost: TerminateProcess succeeded.");
WaitForSingleObject(quick_access_process.get(), 5000);
}
}

View File

@@ -180,6 +180,8 @@ void dispatch_received_json(const std::wstring& json_to_parse)
return;
}
Logger::info(L"dispatch_received_json: {}", json_to_parse);
for (const auto& base_element : j)
{
const auto name = base_element.Key();

View File

@@ -125,7 +125,14 @@ void click_timer_elapsed()
double_click_timer_running = false;
if (!double_clicked)
{
open_quick_access_flyout_window();
if (get_general_settings().enableQuickAccess)
{
open_quick_access_flyout_window();
}
else
{
open_settings_window(std::nullopt);
}
}
}
@@ -345,4 +352,24 @@ void stop_tray_icon()
BugReportManager::instance().clear_callbacks();
SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0);
}
}
}
void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject hotkey)
{
static PowerToysSettings::HotkeyObject current_hotkey;
static bool is_registered = false;
if (is_registered)
{
CentralizedHotkeys::UnregisterHotkeysForModule(L"QuickAccess");
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) {
open_quick_access_flyout_window();
}});
current_hotkey = hotkey;
is_registered = true;
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <optional>
#include <string>
#include <common/SettingsAPI/settings_objects.h>
// Start the Tray Icon
void start_tray_icon(bool isProcessElevated);
@@ -10,6 +11,8 @@ void set_tray_icon_visible(bool shouldIconBeVisible);
void stop_tray_icon();
// Open the Settings Window
void open_settings_window(std::optional<std::wstring> settings_window);
// Update Quick Access Hotkey
void update_quick_access_hotkey(bool enabled, PowerToysSettings::HotkeyObject hotkey);
// Callback type to be called by the tray icon loop
typedef void (*main_loop_callback_function)(PVOID);
// Calls a callback in _callback

View File

@@ -48,6 +48,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("enable_warnings_elevated_apps")]
public bool EnableWarningsElevatedApps { get; set; }
// Gets or sets a value indicating whether Quick Access is enabled.
[JsonPropertyName("enable_quick_access")]
public bool EnableQuickAccess { get; set; }
// Gets or sets Quick Access shortcut.
[JsonPropertyName("quick_access_shortcut")]
public HotkeySettings QuickAccessShortcut { get; set; }
// Gets or sets theme Name.
[JsonPropertyName("theme")]
public string Theme { get; set; }
@@ -94,6 +102,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
ShowSysTrayIcon = true;
IsAdmin = false;
EnableWarningsElevatedApps = true;
EnableQuickAccess = true;
QuickAccessShortcut = new HotkeySettings();
IsElevated = false;
ShowNewUpdatesToastNotification = true;
AutoDownloadUpdates = false;

View File

@@ -40,6 +40,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
// Main Settings Classes
[JsonSerializable(typeof(GeneralSettings))]
[JsonSerializable(typeof(OutGoingGeneralSettings))]
[JsonSerializable(typeof(AdvancedPasteSettings))]
[JsonSerializable(typeof(AlwaysOnTopSettings))]
[JsonSerializable(typeof(AwakeSettings))]

View File

@@ -273,6 +273,32 @@
</ComboBox>
</tkcontrols:SettingsCard>
<tkcontrols:SettingsExpander
Name="GeneralPageEnableQuickAccess"
x:Uid="GeneralPage_EnableQuickAccess"
HeaderIcon="{ui:FontIcon Glyph=&#xE71D;}"
IsExpanded="True">
<ToggleSwitch
x:Uid="ToggleSwitch"
AutomationProperties.Name="{Binding ElementName=GeneralPageEnableQuickAccess, Path=Header}"
IsOn="{x:Bind ViewModel.EnableQuickAccess, Mode=TwoWay}" />
<tkcontrols:SettingsExpander.Items>
<!-- HACK: For some weird reason, a ShortcutControl does not work correctly if it's the first or last item in the expander, so we add an invisible card. -->
<tkcontrols:SettingsCard Visibility="Collapsed" />
<tkcontrols:SettingsCard
Name="QuickAccessShortcut"
x:Uid="GeneralPage_QuickAccessShortcut"
IsEnabled="{x:Bind ViewModel.EnableQuickAccess, Mode=OneWay}">
<tkcontrols:SettingsCard.Description>
<TextBlock x:Uid="GeneralPage_QuickAccessShortcut_Description" />
</tkcontrols:SettingsCard.Description>
<controls:ShortcutControl
HotkeySettings="{x:Bind ViewModel.QuickAccessShortcut, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard Visibility="Collapsed" />
</tkcontrols:SettingsExpander.Items>
</tkcontrols:SettingsExpander>
<tkcontrols:SettingsCard
Name="GeneralPageRunAtStartUp"
x:Uid="GeneralPage_RunAtStartUp"

View File

@@ -5763,4 +5763,17 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
<value>A modern UI built with Fluent Design</value>
<comment>Fluent Design is a product name, do not loc</comment>
</data>
<data name="GeneralPage_EnableQuickAccess.Header" xml:space="preserve">
<value>Enable Quick Access flyout</value>
</data>
<data name="GeneralPage_EnableQuickAccess.Description" xml:space="preserve">
<value>Keep the Quick Access process in memory for easy access to your favorite tools</value>
</data>
<data name="GeneralPage_QuickAccessShortcut.Header" xml:space="preserve">
<value>Activation Shortcut</value>
</data>
<data name="GeneralPage_QuickAccessShortcut_Description.Text" xml:space="preserve">
<value>Change the activation shortcut for Quick Access</value>
</data>
</root>

View File

@@ -155,6 +155,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_isElevated = isElevated;
_runElevated = GeneralSettingsConfig.RunElevated;
_enableWarningsElevatedApps = GeneralSettingsConfig.EnableWarningsElevatedApps;
_enableQuickAccess = GeneralSettingsConfig.EnableQuickAccess;
_quickAccessShortcut = GeneralSettingsConfig.QuickAccessShortcut;
if (_quickAccessShortcut != null)
{
_quickAccessShortcut.PropertyChanged += QuickAccessShortcut_PropertyChanged;
}
RunningAsUserDefaultText = runAsUserText;
RunningAsAdminDefaultText = runAsAdminText;
@@ -236,6 +242,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private bool _runElevated;
private bool _isAdmin;
private bool _enableWarningsElevatedApps;
private bool _enableQuickAccess;
private HotkeySettings _quickAccessShortcut;
private int _themeIndex;
private bool _showNewUpdatesToastNotification;
@@ -480,6 +488,57 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool EnableQuickAccess
{
get
{
return _enableQuickAccess;
}
set
{
if (_enableQuickAccess != value)
{
_enableQuickAccess = value;
GeneralSettingsConfig.EnableQuickAccess = value;
NotifyPropertyChanged();
}
}
}
public HotkeySettings QuickAccessShortcut
{
get
{
return _quickAccessShortcut;
}
set
{
if (_quickAccessShortcut != value)
{
if (_quickAccessShortcut != null)
{
_quickAccessShortcut.PropertyChanged -= QuickAccessShortcut_PropertyChanged;
}
_quickAccessShortcut = value;
if (_quickAccessShortcut != null)
{
_quickAccessShortcut.PropertyChanged += QuickAccessShortcut_PropertyChanged;
}
GeneralSettingsConfig.QuickAccessShortcut = value;
NotifyPropertyChanged();
}
}
}
private void QuickAccessShortcut_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
NotifyPropertyChanged(nameof(QuickAccessShortcut));
}
public bool SomeUpdateSettingsAreGpoManaged
{
get