Files
PowerToys/src/settings-ui/Settings.UI/ViewModels/DashboardViewModel.cs
Kai Tao 21f06b8bd0 Always On Top: The opacity should be able to configure the hotkey individually (#46410)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
This pull request adds support for customizing the hotkeys used to
increase and decrease the opacity of pinned windows in the Always On Top
module.
Previously, these shortcuts were hardcoded to use the same modifiers as
the main pin hotkey.

With these changes, users can now independently configure the increase
and decrease opacity shortcuts via the settings UI, and the backend has
been updated to respect and store these new settings.

Another change: If window is not Always On Topped, the opacity change
take no effect, so we should not intercept, we should pass through to
minimize the impact.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] Closes: #46391, #46387
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
<img width="1184" height="351" alt="image"
src="https://github.com/user-attachments/assets/5d20ffae-9f0c-4ce3-9d85-2ba1efea6301"
/>

<img width="336" height="244" alt="image"
src="https://github.com/user-attachments/assets/a78cc4a3-9eb3-49f1-bbb9-d6db37554e53"
/>

Verified locally that transparency hotkey will not intercept the normal
hotkey in window if Always on top not enabled

---------

Co-authored-by: Niels Laute <niels.laute@live.nl>
2026-03-24 14:02:36 -04:00

884 lines
43 KiB
C#

// 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.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Abstractions;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.WinUI.Controls;
using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Controls;
using Microsoft.PowerToys.Settings.UI.Helpers;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.PowerToys.Settings.UI.Views;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Settings.UI.Library;
namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
public partial class DashboardViewModel : PageViewModelBase
{
private readonly object _sortLock = new object();
protected override string ModuleName => "Dashboard";
private DispatcherQueue dispatcher;
public Func<string, int> SendConfigMSG { get; }
public ObservableCollection<DashboardListItem> AllModules { get; set; } = new ObservableCollection<DashboardListItem>();
public ObservableCollection<DashboardListItem> ShortcutModules { get; set; } = new ObservableCollection<DashboardListItem>();
public ObservableCollection<DashboardListItem> ActionModules { get; set; } = new ObservableCollection<DashboardListItem>();
public ObservableCollection<QuickAccessItem> QuickAccessItems => _quickAccessViewModel.Items;
private readonly QuickAccessViewModel _quickAccessViewModel;
// Master list of module items that is sorted and projected into AllModules.
private List<DashboardListItem> _moduleItems = new List<DashboardListItem>();
// Flag to prevent circular updates when a UI toggle triggers settings changes.
private bool _isUpdatingFromUI;
// Flag to prevent toggle operations during sorting to avoid race conditions.
private bool _isSorting;
private bool _isDisposed;
private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData();
public AllHotkeyConflictsData AllHotkeyConflictsData
{
get => _allHotkeyConflictsData;
set
{
if (Set(ref _allHotkeyConflictsData, value))
{
OnPropertyChanged();
}
}
}
public string PowerToysVersion
{
get
{
return Helper.GetProductVersion();
}
}
private DashboardSortOrder _dashboardSortOrder = DashboardSortOrder.Alphabetical;
public DashboardSortOrder DashboardSortOrder
{
get => generalSettingsConfig.DashboardSortOrder;
set
{
if (_dashboardSortOrder != value)
{
_dashboardSortOrder = value;
generalSettingsConfig.DashboardSortOrder = value;
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
SendConfigMSG(outgoing.ToString());
// Notify UI before sorting so menu updates its checked state
OnPropertyChanged(nameof(DashboardSortOrder));
SortModuleList();
}
}
}
private ISettingsRepository<GeneralSettings> _settingsRepository;
private GeneralSettings generalSettingsConfig;
private Windows.ApplicationModel.Resources.ResourceLoader resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
public DashboardViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
{
dispatcher = DispatcherQueue.GetForCurrentThread();
_settingsRepository = settingsRepository;
generalSettingsConfig = settingsRepository.SettingsConfig;
_settingsRepository.SettingsChanged += OnSettingsChanged;
// Initialize dashboard sort order from settings
_dashboardSortOrder = generalSettingsConfig.DashboardSortOrder;
// set the callback functions value to handle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
_quickAccessViewModel = new QuickAccessViewModel(
_settingsRepository,
new Microsoft.PowerToys.Settings.UI.Controls.QuickAccessLauncher(App.IsElevated),
moduleType => Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType) == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled,
moduleType => Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType) == global::PowerToys.GPOWrapper.GpoRuleConfigured.Enabled,
resourceLoader);
BuildModuleList();
SortModuleList();
RefreshShortcutModules();
}
private void OnSettingsChanged(GeneralSettings newSettings)
{
if (_isDisposed)
{
return;
}
dispatcher.TryEnqueue(() =>
{
if (_isDisposed)
{
return;
}
generalSettingsConfig = newSettings;
// Update local field and notify UI if sort order changed
if (_dashboardSortOrder != generalSettingsConfig.DashboardSortOrder)
{
_dashboardSortOrder = generalSettingsConfig.DashboardSortOrder;
OnPropertyChanged(nameof(DashboardSortOrder));
}
ModuleEnabledChangedOnSettingsPage();
});
}
protected override void OnConflictsUpdated(object sender, AllHotkeyConflictsEventArgs e)
{
if (_isDisposed)
{
return;
}
dispatcher.TryEnqueue(() =>
{
if (_isDisposed)
{
return;
}
var allConflictData = e.Conflicts;
foreach (var inAppConflict in allConflictData.InAppConflicts)
{
var hotkey = inAppConflict.Hotkey;
var hotkeySetting = new HotkeySettings(hotkey.Win, hotkey.Ctrl, hotkey.Alt, hotkey.Shift, hotkey.Key);
inAppConflict.ConflictIgnored = HotkeyConflictIgnoreHelper.IsIgnoringConflicts(hotkeySetting);
}
foreach (var systemConflict in allConflictData.SystemConflicts)
{
var hotkey = systemConflict.Hotkey;
var hotkeySetting = new HotkeySettings(hotkey.Win, hotkey.Ctrl, hotkey.Alt, hotkey.Shift, hotkey.Key);
systemConflict.ConflictIgnored = HotkeyConflictIgnoreHelper.IsIgnoringConflicts(hotkeySetting);
}
AllHotkeyConflictsData = e.Conflicts ?? new AllHotkeyConflictsData();
});
}
private void RequestConflictData()
{
// Request current conflicts data
GlobalHotkeyConflictManager.Instance?.RequestAllConflicts();
}
/// <summary>
/// Builds the master list of module items. Called once during initialization.
/// Each module item contains its configuration, enabled state, and GPO lock status.
/// </summary>
private void BuildModuleList()
{
_moduleItems.Clear();
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
{
if (moduleType == ModuleType.GeneralSettings)
{
continue;
}
// TEMPORARILY_DISABLED: PowerDisplay
if (moduleType == ModuleType.PowerDisplay)
{
continue;
}
GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(moduleType);
var newItem = new DashboardListItem()
{
Tag = moduleType,
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
IsNew = false,
DashboardModuleItems = GetModuleItems(moduleType),
ClickCommand = new RelayCommand<object>(DashboardListItemClick),
};
newItem.EnabledChangedCallback = EnabledChangedOnUI;
_moduleItems.Add(newItem);
}
}
/// <summary>
/// Sorts the module list according to the current sort order and updates the AllModules collection.
/// On first call, populates AllModules. On subsequent calls, uses Move() to reorder items in-place
/// to avoid destroying and recreating UI elements.
/// Temporarily disables interaction on all items during sorting to prevent race conditions.
/// </summary>
private void SortModuleList()
{
if (_isSorting)
{
return;
}
lock (_sortLock)
{
_isSorting = true;
try
{
var sortedItems = (DashboardSortOrder switch
{
DashboardSortOrder.ByStatus => _moduleItems.OrderByDescending(x => x.IsEnabled).ThenBy(x => x.Label),
_ => _moduleItems.OrderBy(x => x.Label), // Default alphabetical
}).ToList();
// If AllModules is empty (first load), just populate it.
if (AllModules.Count == 0)
{
foreach (var item in sortedItems)
{
AllModules.Add(item);
}
return;
}
// Otherwise, update the collection in place using Move to avoid UI glitches.
for (int i = 0; i < sortedItems.Count; i++)
{
var currentItem = sortedItems[i];
var currentIndex = AllModules.IndexOf(currentItem);
if (currentIndex != -1 && currentIndex != i)
{
AllModules.Move(currentIndex, i);
}
}
}
finally
{
// Use dispatcher to reset flag after UI updates complete
dispatcher.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
_isSorting = false;
});
}
}
}
/// <summary>
/// Refreshes module enabled/locked states by re-reading GPO configuration. Only
/// updates properties that have actually changed to minimize UI notifications
/// then re-sorts the list according to the current sort order.
/// </summary>
private void RefreshModuleList()
{
foreach (var item in _moduleItems)
{
GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(item.Tag);
// GPO can force-enable (Enabled) or force-disable (Disabled) a module.
// If Enabled: module is on and the user cannot disable it.
// If Disabled: module is off and the user cannot enable it.
// Otherwise, the setting is unlocked and the user can enable/disable it.
bool newEnabledState = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag));
// Lock the toggle when GPO is controlling the module.
bool newLockedState = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled;
// Only update if there's an actual change to minimize UI notifications.
if (item.IsEnabled != newEnabledState)
{
item.UpdateStatus(newEnabledState);
}
if (item.IsLocked != newLockedState)
{
item.IsLocked = newLockedState;
}
}
SortModuleList();
}
/// <summary>
/// Callback invoked when a user toggles a module's enabled state in the UI.
/// Sets the _isUpdatingFromUI flag to prevent circular updates, then updates
/// settings, re-sorts if needed, and refreshes dependent collections.
/// </summary>
private void EnabledChangedOnUI(ModuleListItem item)
{
var dashboardListItem = (DashboardListItem)item;
var isEnabled = dashboardListItem.IsEnabled;
// Ignore toggle operations during sorting to prevent race conditions.
// Revert the toggle state since UI already changed due to TwoWay binding.
if (_isSorting)
{
dashboardListItem.UpdateStatus(!isEnabled);
return;
}
_isUpdatingFromUI = true;
try
{
// Send optimized IPC message with only the module status update
// Format: {"module_status": {"ModuleName": true/false}}
string moduleKey = ModuleHelper.GetModuleKey(dashboardListItem.Tag);
string moduleStatusJson = $"{{\"module_status\": {{\"{moduleKey}\": {isEnabled.ToString().ToLowerInvariant()}}}}}";
SendConfigMSG(moduleStatusJson);
// Update local settings config to keep UI in sync
ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, dashboardListItem.Tag, isEnabled);
if (dashboardListItem.Tag == ModuleType.NewPlus && isEnabled == true)
{
var settingsUtils = SettingsUtils.Default;
var settings = NewPlusViewModel.LoadSettings(settingsUtils);
NewPlusViewModel.CopyTemplateExamples(settings.Properties.TemplateLocation.Value);
}
// Re-sort only required if sorting by enabled status.
if (DashboardSortOrder == DashboardSortOrder.ByStatus)
{
SortModuleList();
}
// Always refresh shortcuts/actions to reflect enabled state changes.
RefreshShortcutModules();
// Request updated conflicts after module state change.
RequestConflictData();
}
finally
{
_isUpdatingFromUI = false;
}
}
/// <summary>
/// Callback invoked when module enabled state changes from other parts of the
/// settings UI. Ignores the notification if it was triggered by a UI toggle
/// we're already handling, to prevent circular updates.
/// </summary>
public void ModuleEnabledChangedOnSettingsPage()
{
if (_isDisposed)
{
return;
}
// Ignore if this was triggered by a UI change that we're already handling.
if (_isUpdatingFromUI)
{
return;
}
try
{
RefreshModuleList();
RefreshShortcutModules();
OnPropertyChanged(nameof(ShortcutModules));
// Request updated conflicts after module state change.
RequestConflictData();
}
catch (Exception ex)
{
Logger.LogError($"Updating active/disabled modules list failed: {ex.Message}");
}
}
/// <summary>
/// Rebuilds ShortcutModules and ActionModules collections by filtering AllModules
/// to only include enabled modules and their respective shortcut/action items.
/// </summary>
private void RefreshShortcutModules()
{
if (_isDisposed)
{
return;
}
if (!dispatcher.HasThreadAccess)
{
_ = dispatcher.TryEnqueue(DispatcherQueuePriority.Normal, RefreshShortcutModules);
return;
}
ShortcutModules.Clear();
ActionModules.Clear();
foreach (var x in AllModules.Where(x => x.IsEnabled))
{
var filteredItems = x.DashboardModuleItems
.Where(m => m is DashboardModuleShortcutItem || m is DashboardModuleActivationItem)
.ToList();
if (filteredItems.Count != 0)
{
var newItem = new DashboardListItem
{
Icon = x.Icon,
IsLocked = x.IsLocked,
Label = x.Label,
Tag = x.Tag,
IsEnabled = x.IsEnabled,
DashboardModuleItems = new ObservableCollection<DashboardModuleItem>(filteredItems),
};
ShortcutModules.Add(newItem);
newItem.EnabledChangedCallback = x.EnabledChangedCallback;
}
}
foreach (var x in AllModules.Where(x => x.IsEnabled))
{
var filteredItems = x.DashboardModuleItems
.Where(m => m is DashboardModuleButtonItem)
.ToList();
if (filteredItems.Count != 0)
{
var newItem = new DashboardListItem
{
Icon = x.Icon,
IsLocked = x.IsLocked,
Label = x.Label,
Tag = x.Tag,
IsEnabled = x.IsEnabled,
DashboardModuleItems = new ObservableCollection<DashboardModuleItem>(filteredItems),
};
ActionModules.Add(newItem);
newItem.EnabledChangedCallback = x.EnabledChangedCallback;
}
}
}
private ObservableCollection<DashboardModuleItem> GetModuleItems(ModuleType moduleType)
{
return moduleType switch
{
ModuleType.AdvancedPaste => GetModuleItemsAdvancedPaste(),
ModuleType.AlwaysOnTop => GetModuleItemsAlwaysOnTop(),
ModuleType.CmdPal => GetModuleItemsCmdPal(),
ModuleType.ColorPicker => GetModuleItemsColorPicker(),
ModuleType.CropAndLock => GetModuleItemsCropAndLock(),
ModuleType.EnvironmentVariables => GetModuleItemsEnvironmentVariables(),
ModuleType.FancyZones => GetModuleItemsFancyZones(),
ModuleType.FindMyMouse => GetModuleItemsFindMyMouse(),
ModuleType.Hosts => GetModuleItemsHosts(),
ModuleType.KeyboardManager => GetModuleItemsKeyboardManager(),
ModuleType.LightSwitch => GetModuleItemsLightSwitch(),
ModuleType.MouseHighlighter => GetModuleItemsMouseHighlighter(),
ModuleType.MouseJump => GetModuleItemsMouseJump(),
ModuleType.MousePointerCrosshairs => GetModuleItemsMousePointerCrosshairs(),
ModuleType.Peek => GetModuleItemsPeek(),
ModuleType.PowerDisplay => GetModuleItemsPowerDisplay(),
ModuleType.PowerLauncher => GetModuleItemsPowerLauncher(),
ModuleType.PowerAccent => GetModuleItemsPowerAccent(),
ModuleType.Workspaces => GetModuleItemsWorkspaces(),
ModuleType.RegistryPreview => GetModuleItemsRegistryPreview(),
ModuleType.MeasureTool => GetModuleItemsMeasureTool(),
ModuleType.ShortcutGuide => GetModuleItemsShortcutGuide(),
ModuleType.PowerOCR => GetModuleItemsPowerOCR(),
_ => new ObservableCollection<DashboardModuleItem>(), // never called, all values listed above
};
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsAlwaysOnTop()
{
ISettingsRepository<AlwaysOnTopSettings> moduleSettingsRepository = SettingsRepository<AlwaysOnTopSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AlwaysOnTop_ActivationShortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.Hotkey.Value.GetKeysList() },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AlwaysOnTop_IncreaseOpacityShortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.IncreaseOpacityHotkey.Value.GetKeysList() },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AlwaysOnTop_DecreaseOpacityShortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.DecreaseOpacityHotkey.Value.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsCmdPal()
{
var hotkey = new CmdPalProperties().Hotkey;
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CmdPal_ActivationDescription"), Shortcut = hotkey.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsColorPicker()
{
ISettingsRepository<ColorPickerSettings> moduleSettingsRepository = SettingsRepository<ColorPickerSettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
var hotkey = settings.Properties.ActivationShortcut;
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ColorPicker_ShortDescription"), Shortcut = hotkey.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsLightSwitch()
{
ISettingsRepository<LightSwitchSettings> moduleSettingsRepository = SettingsRepository<LightSwitchSettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("LightSwitch_ForceDarkMode"), Shortcut = settings.Properties.ToggleThemeHotkey.Value.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsCropAndLock()
{
ISettingsRepository<CropAndLockSettings> moduleSettingsRepository = SettingsRepository<CropAndLockSettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Thumbnail"), Shortcut = settings.Properties.ThumbnailHotkey.Value.GetKeysList() },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Reparent"), Shortcut = settings.Properties.ReparentHotkey.Value.GetKeysList() },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Screenshot"), Shortcut = settings.Properties.ScreenshotHotkey.Value.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsEnvironmentVariables()
{
var list = new List<DashboardModuleItem>
{
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("EnvironmentVariables_LaunchButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("EnvironmentVariables_LaunchButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/EnvironmentVariables.png", ButtonClickHandler = EnvironmentVariablesLaunchClicked },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsFancyZones()
{
ISettingsRepository<FancyZonesSettings> moduleSettingsRepository = SettingsRepository<FancyZonesSettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
string activationMode = $"{resourceLoader.GetString(settings.Properties.FancyzonesShiftDrag.Value ? "FancyZones_ActivationShiftDrag" : "FancyZones_ActivationNoShiftDrag")}.";
var list = new List<DashboardModuleItem>
{
new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Activate_Zones"), Activation = activationMode },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("FancyZones_OpenEditor"), Shortcut = settings.Properties.FancyzonesEditorHotkey.Value.GetKeysList() },
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("FancyZones_LaunchEditorButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("FancyZones_LaunchEditorButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/FancyZones.png", ButtonClickHandler = FancyZoneLaunchClicked },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsFindMyMouse()
{
ISettingsRepository<FindMyMouseSettings> moduleSettingsRepository = SettingsRepository<FindMyMouseSettings>.GetInstance(SettingsUtils.Default);
string shortDescription = resourceLoader.GetString("FindMyMouse_ShortDescription");
var settings = moduleSettingsRepository.SettingsConfig;
var activationMethod = settings.Properties.ActivationMethod.Value;
var list = new List<DashboardModuleItem>();
if (activationMethod == 3)
{
var hotkey = settings.Properties.ActivationShortcut;
list.Add(new DashboardModuleShortcutItem() { Label = shortDescription, Shortcut = hotkey.GetKeysList() });
}
else
{
string activation = string.Empty;
switch (activationMethod)
{
case 2: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationShakeMouse/Content"); break;
case 1: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationDoubleRightControlPress/Content"); break;
case 0:
default: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationDoubleControlPress/Content"); break;
}
list.Add(new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Dashboard_Activation"), Activation = activation });
}
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsHosts()
{
var list = new List<DashboardModuleItem>
{
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("Hosts_LaunchButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("Hosts_LaunchButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/Hosts.png", ButtonClickHandler = HostLaunchClicked },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsKeyboardManager()
{
ISettingsRepository<KeyboardManagerSettings> moduleSettingsRepository = SettingsRepository<KeyboardManagerSettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
var list = new List<DashboardModuleItem>();
if (settings.Properties.UseNewEditor)
{
list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Dashboard_KeyboardManager_OpenEditor"), Shortcut = settings.Properties.EditorShortcut.GetKeysList() });
}
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseHighlighter()
{
ISettingsRepository<MouseHighlighterSettings> moduleSettingsRepository = SettingsRepository<MouseHighlighterSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseHighlighter_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseJump()
{
ISettingsRepository<MouseJumpSettings> moduleSettingsRepository = SettingsRepository<MouseJumpSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseJump_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsMousePointerCrosshairs()
{
ISettingsRepository<MousePointerCrosshairsSettings> moduleSettingsRepository = SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseCrosshairs_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsAdvancedPaste()
{
ISettingsRepository<AdvancedPasteSettings> moduleSettingsRepository = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AdvancedPasteUI_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.AdvancedPasteUIShortcut.GetKeysList() },
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsPlainText_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsPlainTextShortcut.GetKeysList() },
};
if (moduleSettingsRepository.SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList().Count > 0)
{
list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsMarkdown_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList() });
}
if (moduleSettingsRepository.SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList().Count > 0)
{
list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsJson_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList() });
}
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsPeek()
{
ISettingsRepository<PeekSettings> moduleSettingsRepository = SettingsRepository<PeekSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Peek_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerLauncher()
{
ISettingsRepository<PowerLauncherSettings> moduleSettingsRepository = SettingsRepository<PowerLauncherSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Run_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.OpenPowerLauncher.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerAccent()
{
var settingsUtils = SettingsUtils.Default;
PowerAccentSettings moduleSettings = settingsUtils.GetSettingsOrDefault<PowerAccentSettings>(PowerAccentSettings.ModuleName);
var activationMethod = moduleSettings.Properties.ActivationKey;
string activation = string.Empty;
switch (activationMethod)
{
case Library.Enumerations.PowerAccentActivationKey.LeftRightArrow: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Arrows/Content"); break;
case Library.Enumerations.PowerAccentActivationKey.Space: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Space/Content"); break;
case Library.Enumerations.PowerAccentActivationKey.Both: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Either/Content"); break;
}
var list = new List<DashboardModuleItem>
{
new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Dashboard_Activation"), Activation = activation },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsWorkspaces()
{
ISettingsRepository<WorkspacesSettings> moduleSettingsRepository = SettingsRepository<WorkspacesSettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Workspaces_ShortDescription"), Shortcut = settings.Properties.Hotkey.Value.GetKeysList() },
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("Workspaces_LaunchEditorButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("FancyZones_LaunchEditorButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/Workspaces.png", ButtonClickHandler = WorkspacesLaunchClicked },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsRegistryPreview()
{
var list = new List<DashboardModuleItem>
{
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("RegistryPreview_LaunchButtonControl/Header"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/RegistryPreview.png", ButtonClickHandler = RegistryPreviewLaunchClicked },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsMeasureTool()
{
ISettingsRepository<MeasureToolSettings> moduleSettingsRepository = SettingsRepository<MeasureToolSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ScreenRuler_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsShortcutGuide()
{
ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository = SettingsRepository<ShortcutGuideSettings>.GetInstance(SettingsUtils.Default);
var shortcut = moduleSettingsRepository.SettingsConfig.Properties.UseLegacyPressWinKeyBehavior.Value
? new List<object> { 92 } // Right Windows key code
: moduleSettingsRepository.SettingsConfig.Properties.OpenShortcutGuide.GetKeysList();
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ShortcutGuide_ShortDescription"), Shortcut = shortcut },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerOCR()
{
ISettingsRepository<PowerOcrSettings> moduleSettingsRepository = SettingsRepository<PowerOcrSettings>.GetInstance(SettingsUtils.Default);
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PowerOcr_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerDisplay()
{
ISettingsRepository<PowerDisplaySettings> moduleSettingsRepository = SettingsRepository<PowerDisplaySettings>.GetInstance(SettingsUtils.Default);
var settings = moduleSettingsRepository.SettingsConfig;
var list = new List<DashboardModuleItem>
{
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PowerDisplay_ToggleWindow"), Shortcut = settings.Properties.ActivationShortcut.GetKeysList() },
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("PowerDisplay_LaunchButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("PowerDisplay_LaunchButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/PowerDisplay.png", ButtonClickHandler = PowerDisplayLaunchClicked },
};
return new ObservableCollection<DashboardModuleItem>(list);
}
internal void SWVersionButtonClicked()
{
NavigationService.Navigate(typeof(GeneralPage));
}
private void EnvironmentVariablesLaunchClicked(object sender, RoutedEventArgs e)
{
var settingsUtils = SettingsUtils.Default;
var environmentVariablesViewModel = new EnvironmentVariablesViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<EnvironmentVariablesSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
environmentVariablesViewModel.Launch();
}
private void HostLaunchClicked(object sender, RoutedEventArgs e)
{
var settingsUtils = SettingsUtils.Default;
var hostsViewModel = new HostsViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<HostsSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
hostsViewModel.Launch();
}
private void FancyZoneLaunchClicked(object sender, RoutedEventArgs e)
{
// send message to launch the zones editor;
SendConfigMSG("{\"action\":{\"FancyZones\":{\"action_name\":\"ToggledFZEditor\", \"value\":\"\"}}}");
}
private void WorkspacesLaunchClicked(object sender, RoutedEventArgs e)
{
// send message to launch the Workspaces editor;
SendConfigMSG("{\"action\":{\"Workspaces\":{\"action_name\":\"LaunchEditor\", \"value\":\"\"}}}");
}
private void RegistryPreviewLaunchClicked(object sender, RoutedEventArgs e)
{
var actionName = "Launch";
SendConfigMSG("{\"action\":{\"RegistryPreview\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
}
private void PowerDisplayLaunchClicked(object sender, RoutedEventArgs e)
{
var actionName = "Launch";
SendConfigMSG("{\"action\":{\"PowerDisplay\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
}
internal void DashboardListItemClick(object sender)
{
if (sender is ModuleType moduleType)
{
NavigationService.Navigate(ModuleGpoHelper.GetModulePageType(moduleType));
}
}
public override void Dispose()
{
if (_isDisposed)
{
return;
}
_isDisposed = true;
base.Dispose();
if (_settingsRepository != null)
{
_settingsRepository.SettingsChanged -= OnSettingsChanged;
}
GC.SuppressFinalize(this);
}
}
}