// 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.Linq; using ManagedCommon; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Views; namespace Microsoft.PowerToys.Settings.UI.Helpers { /// /// Static helper class to manage and check hotkey conflict ignore settings /// public static class HotkeyConflictIgnoreHelper { private static readonly ISettingsRepository _generalSettingsRepository; private static readonly SettingsUtils _settingsUtils; static HotkeyConflictIgnoreHelper() { _settingsUtils = SettingsUtils.Default; _generalSettingsRepository = SettingsRepository.GetInstance(_settingsUtils); } /// /// Ensures ignored conflict properties are initialized /// private static void EnsureInitialized() { var settings = _generalSettingsRepository.SettingsConfig; if (settings.IgnoredConflictProperties == null) { settings.IgnoredConflictProperties = new ShortcutConflictProperties(); SaveSettings(); } } /// /// Checks if a specific hotkey setting is configured to ignore conflicts /// /// The hotkey settings to check /// True if the hotkey is set to ignore conflicts, false otherwise public static bool IsIgnoringConflicts(HotkeySettings hotkeySettings) { if (hotkeySettings == null) { return false; } try { EnsureInitialized(); var settings = _generalSettingsRepository.SettingsConfig; return settings.IgnoredConflictProperties.IgnoredShortcuts .Any(h => AreHotkeySettingsEqual(h, hotkeySettings)); } catch (Exception ex) { Logger.LogError($"Error checking if hotkey is ignoring conflicts: {ex.Message}"); return false; } } /// /// Adds a hotkey setting to the ignored shortcuts list /// /// The hotkey settings to add to the ignored list /// True if successfully added, false if it was already ignored or on error public static bool AddToIgnoredList(HotkeySettings hotkeySettings) { if (hotkeySettings == null) { return false; } try { EnsureInitialized(); var settings = _generalSettingsRepository.SettingsConfig; // Check if already ignored (avoid duplicates) if (IsIgnoringConflicts(hotkeySettings)) { Logger.LogInfo($"Hotkey already in ignored list: {hotkeySettings}"); return false; } // Add to ignored list settings.IgnoredConflictProperties.IgnoredShortcuts.Add(hotkeySettings); SaveSettings(); Logger.LogInfo($"Added hotkey to ignored list: {hotkeySettings}"); return true; } catch (Exception ex) { Logger.LogError($"Error adding hotkey to ignored list: {ex.Message}"); return false; } } /// /// Removes a hotkey setting from the ignored shortcuts list /// /// The hotkey settings to remove from the ignored list /// True if successfully removed, false if it wasn't in the list or on error public static bool RemoveFromIgnoredList(HotkeySettings hotkeySettings) { if (hotkeySettings == null) { return false; } try { EnsureInitialized(); var settings = _generalSettingsRepository.SettingsConfig; var ignoredShortcut = settings.IgnoredConflictProperties.IgnoredShortcuts .FirstOrDefault(h => AreHotkeySettingsEqual(h, hotkeySettings)); if (ignoredShortcut != null) { settings.IgnoredConflictProperties.IgnoredShortcuts.Remove(ignoredShortcut); SaveSettings(); Logger.LogInfo($"Removed hotkey from ignored list: {ignoredShortcut}"); return true; } Logger.LogInfo($"Hotkey not found in ignored list: {hotkeySettings}"); return false; } catch (Exception ex) { Logger.LogError($"Error removing hotkey from ignored list: {ex.Message}"); return false; } } /// /// Gets all hotkey settings that are currently being ignored /// /// List of ignored hotkey settings public static List GetAllIgnoredShortcuts() { try { EnsureInitialized(); var settings = _generalSettingsRepository.SettingsConfig; return new List(settings.IgnoredConflictProperties.IgnoredShortcuts); } catch (Exception ex) { Logger.LogError($"Error getting ignored shortcuts: {ex.Message}"); return new List(); } } /// /// Clears all ignored shortcuts from the list /// /// True if successfully cleared, false on error public static bool ClearAllIgnoredShortcuts() { try { EnsureInitialized(); var settings = _generalSettingsRepository.SettingsConfig; var count = settings.IgnoredConflictProperties.IgnoredShortcuts.Count; settings.IgnoredConflictProperties.IgnoredShortcuts.Clear(); SaveSettings(); Logger.LogInfo($"Cleared all {count} ignored shortcuts"); return true; } catch (Exception ex) { Logger.LogError($"Error clearing ignored shortcuts: {ex.Message}"); return false; } } /// /// Compares two HotkeySettings for equality /// /// First hotkey settings /// Second hotkey settings /// True if they represent the same shortcut, false otherwise private static bool AreHotkeySettingsEqual(HotkeySettings hotkey1, HotkeySettings hotkey2) { if (hotkey1 == null || hotkey2 == null) { return false; } return hotkey1.Win == hotkey2.Win && hotkey1.Ctrl == hotkey2.Ctrl && hotkey1.Alt == hotkey2.Alt && hotkey1.Shift == hotkey2.Shift && hotkey1.Code == hotkey2.Code; } /// /// Saves the general settings using PowerToys standard settings persistence /// private static void SaveSettings() { try { var settings = _generalSettingsRepository.SettingsConfig; // Send IPC message to notify runner of changes (this is thread-safe) var outgoing = new OutGoingGeneralSettings(settings); ShellPage.SendDefaultIPCMessage(outgoing.ToString()); ShellPage.ShellHandler?.SignalGeneralDataUpdate(); } catch (Exception ex) { Logger.LogError($"Error saving shortcut conflict settings: {ex.Message}"); Logger.LogError($"Stack trace: {ex.StackTrace}"); throw; } } } }