diff --git a/src/modules/powerdisplay/PowerDisplay.Lib/Models/CustomVcpValueMapping.cs b/src/modules/powerdisplay/PowerDisplay.Lib/Models/CustomVcpValueMapping.cs
index fe21f24583..2e464abbb8 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib/Models/CustomVcpValueMapping.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib/Models/CustomVcpValueMapping.cs
@@ -29,5 +29,19 @@ namespace PowerDisplay.Common.Models
///
[JsonPropertyName("customName")]
public string CustomName { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a value indicating whether this mapping applies to all monitors.
+ /// When true, the mapping is applied globally. When false, only applies to TargetMonitorId.
+ ///
+ [JsonPropertyName("applyToAll")]
+ public bool ApplyToAll { get; set; } = true;
+
+ ///
+ /// Gets or sets the target monitor ID when ApplyToAll is false.
+ /// This is the monitor's unique identifier.
+ ///
+ [JsonPropertyName("targetMonitorId")]
+ public string TargetMonitorId { get; set; } = string.Empty;
}
}
diff --git a/src/modules/powerdisplay/PowerDisplay.Lib/Utils/VcpNames.cs b/src/modules/powerdisplay/PowerDisplay.Lib/Utils/VcpNames.cs
index 504c49c9ca..78e5e6ba13 100644
--- a/src/modules/powerdisplay/PowerDisplay.Lib/Utils/VcpNames.cs
+++ b/src/modules/powerdisplay/PowerDisplay.Lib/Utils/VcpNames.cs
@@ -391,6 +391,16 @@ namespace PowerDisplay.Common.Utils
},
};
+ ///
+ /// Get all known values for a VCP code
+ ///
+ /// VCP code (e.g., 0x14)
+ /// Dictionary of value to name mappings, or null if no mappings exist
+ public static IReadOnlyDictionary? GetValueMappings(byte vcpCode)
+ {
+ return ValueNames.TryGetValue(vcpCode, out var values) ? values : null;
+ }
+
///
/// Get human-readable name for a VCP value
///
@@ -430,18 +440,26 @@ namespace PowerDisplay.Common.Utils
///
/// Get human-readable name for a VCP value with custom mapping support.
/// Custom mappings take priority over built-in mappings.
+ /// Monitor ID is required to properly filter monitor-specific mappings.
///
/// VCP code (e.g., 0x14)
/// Value to translate
/// Optional custom mappings that take priority
+ /// Monitor ID to filter mappings
/// Name string like "sRGB" or null if unknown
- public static string? GetValueName(byte vcpCode, int value, IEnumerable? customMappings)
+ public static string? GetValueName(byte vcpCode, int value, IEnumerable? customMappings, string monitorId)
{
// 1. Priority: Check custom mappings first
if (customMappings != null)
{
+ // Find a matching custom mapping:
+ // - ApplyToAll = true (global), OR
+ // - ApplyToAll = false AND TargetMonitorId matches the given monitorId
var custom = customMappings.FirstOrDefault(m =>
- m.VcpCode == vcpCode && m.Value == value);
+ m.VcpCode == vcpCode &&
+ m.Value == value &&
+ (m.ApplyToAll || (!m.ApplyToAll && m.TargetMonitorId == monitorId)));
+
if (custom != null && !string.IsNullOrEmpty(custom.CustomName))
{
return custom.CustomName;
@@ -455,14 +473,16 @@ namespace PowerDisplay.Common.Utils
///
/// Get formatted display name for a VCP value with custom mapping support.
/// Custom mappings take priority over built-in mappings.
+ /// Monitor ID is required to properly filter monitor-specific mappings.
///
/// VCP code (e.g., 0x14)
/// Value to translate
/// Optional custom mappings that take priority
+ /// Monitor ID to filter mappings
/// Formatted string like "sRGB (0x01)" or "0x01" if unknown
- public static string GetFormattedValueName(byte vcpCode, int value, IEnumerable? customMappings)
+ public static string GetFormattedValueName(byte vcpCode, int value, IEnumerable? customMappings, string monitorId)
{
- var name = GetValueName(vcpCode, value, customMappings);
+ var name = GetValueName(vcpCode, value, customMappings, monitorId);
if (name != null)
{
return $"{name} (0x{value:X2})";
diff --git a/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.Settings.cs b/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.Settings.cs
index 8c9dfb0cde..d01af35c6c 100644
--- a/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.Settings.cs
+++ b/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.Settings.cs
@@ -43,6 +43,10 @@ public partial class MainViewModel
// UpdateMonitorList already handles filtering hidden monitors
UpdateMonitorList(_monitorManager.Monitors, isInitialLoad: false);
+ // Reload UI display settings first (includes custom VCP mappings)
+ // Must be loaded before ApplyUIConfiguration so names are available for UI refresh
+ LoadUIDisplaySettings();
+
// Apply UI configuration changes only (feature visibility toggles, etc.)
// Hardware parameters (brightness, color temperature) are applied via custom actions
var settings = _settingsUtils.GetSettingsOrDefault("PowerDisplay");
@@ -51,8 +55,11 @@ public partial class MainViewModel
// Reload profiles in case they were added/updated/deleted in Settings UI
LoadProfiles();
- // Reload UI display settings (profile switcher, identify button, color temp switcher)
- LoadUIDisplaySettings();
+ // Notify MonitorViewModels to refresh their custom VCP name displays
+ foreach (var monitor in Monitors)
+ {
+ monitor.RefreshCustomVcpNames();
+ }
}
catch (Exception ex)
{
diff --git a/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.cs b/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.cs
index 858a2fbca3..26e05623ed 100644
--- a/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.cs
+++ b/src/modules/powerdisplay/PowerDisplay/ViewModels/MainViewModel.cs
@@ -416,6 +416,8 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
VcpCode = m.VcpCode,
Value = m.Value,
CustomName = m.CustomName,
+ ApplyToAll = m.ApplyToAll,
+ TargetMonitorId = m.TargetMonitorId,
}).ToList();
Logger.LogInfo($"[Settings] Loaded {CustomVcpMappings.Count} custom VCP mappings");
}
diff --git a/src/modules/powerdisplay/PowerDisplay/ViewModels/MonitorViewModel.cs b/src/modules/powerdisplay/PowerDisplay/ViewModels/MonitorViewModel.cs
index 5a5ea766cb..c03e606eff 100644
--- a/src/modules/powerdisplay/PowerDisplay/ViewModels/MonitorViewModel.cs
+++ b/src/modules/powerdisplay/PowerDisplay/ViewModels/MonitorViewModel.cs
@@ -469,7 +469,7 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
/// Uses custom mappings if available, otherwise falls back to built-in names.
///
public string ColorTemperaturePresetName =>
- Common.Utils.VcpNames.GetFormattedValueName(0x14, _monitor.CurrentColorTemperature, _mainViewModel?.CustomVcpMappings);
+ Common.Utils.VcpNames.GetFormattedValueName(0x14, _monitor.CurrentColorTemperature, _mainViewModel?.CustomVcpMappings, _monitor.Id);
///
/// Gets a value indicating whether this monitor supports color temperature via VCP 0x14
@@ -549,7 +549,7 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
_availableColorPresets = presetValues.Select(value => new ColorTemperatureItem
{
VcpValue = value,
- DisplayName = Common.Utils.VcpNames.GetFormattedValueName(0x14, value, _mainViewModel?.CustomVcpMappings),
+ DisplayName = Common.Utils.VcpNames.GetFormattedValueName(0x14, value, _mainViewModel?.CustomVcpMappings, _monitor.Id),
IsSelected = value == _monitor.CurrentColorTemperature,
MonitorId = _monitor.Id,
}).ToList();
@@ -572,7 +572,7 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
/// Uses custom mappings if available, otherwise falls back to built-in names.
///
public string CurrentInputSourceName =>
- Common.Utils.VcpNames.GetValueName(0x60, _monitor.CurrentInputSource, _mainViewModel?.CustomVcpMappings)
+ Common.Utils.VcpNames.GetValueName(0x60, _monitor.CurrentInputSource, _mainViewModel?.CustomVcpMappings, _monitor.Id)
?? $"Source 0x{_monitor.CurrentInputSource:X2}";
private List? _availableInputSources;
@@ -608,7 +608,7 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
_availableInputSources = supportedSources.Select(value => new InputSourceItem
{
Value = value,
- Name = Common.Utils.VcpNames.GetValueName(0x60, value, _mainViewModel?.CustomVcpMappings) ?? $"Source 0x{value:X2}",
+ Name = Common.Utils.VcpNames.GetValueName(0x60, value, _mainViewModel?.CustomVcpMappings, _monitor.Id) ?? $"Source 0x{value:X2}",
SelectionVisibility = value == _monitor.CurrentInputSource ? Visibility.Visible : Visibility.Collapsed,
MonitorId = _monitor.Id,
}).ToList();
@@ -616,6 +616,23 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
OnPropertyChanged(nameof(AvailableInputSources));
}
+ ///
+ /// Refresh custom VCP name displays after settings change.
+ /// Called when CustomVcpMappings is updated from Settings UI.
+ ///
+ public void RefreshCustomVcpNames()
+ {
+ // Refresh color temperature names
+ OnPropertyChanged(nameof(ColorTemperaturePresetName));
+ _availableColorPresets = null; // Force rebuild with new custom names
+ OnPropertyChanged(nameof(AvailableColorPresets));
+
+ // Refresh input source names
+ OnPropertyChanged(nameof(CurrentInputSourceName));
+ _availableInputSources = null; // Force rebuild with new custom names
+ OnPropertyChanged(nameof(AvailableInputSources));
+ }
+
///
/// Set input source for this monitor
///
diff --git a/src/settings-ui/Settings.UI.Library/CustomVcpValueMapping.cs b/src/settings-ui/Settings.UI.Library/CustomVcpValueMapping.cs
index 680cc148cc..3f10afc28c 100644
--- a/src/settings-ui/Settings.UI.Library/CustomVcpValueMapping.cs
+++ b/src/settings-ui/Settings.UI.Library/CustomVcpValueMapping.cs
@@ -31,6 +31,26 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[JsonPropertyName("customName")]
public string CustomName { get; set; } = string.Empty;
+ ///
+ /// Gets or sets a value indicating whether this mapping applies to all monitors.
+ /// When true, the mapping is applied globally. When false, only applies to TargetMonitorId.
+ ///
+ [JsonPropertyName("applyToAll")]
+ public bool ApplyToAll { get; set; } = true;
+
+ ///
+ /// Gets or sets the target monitor ID when ApplyToAll is false.
+ /// This is the monitor's unique identifier.
+ ///
+ [JsonPropertyName("targetMonitorId")]
+ public string TargetMonitorId { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the target monitor display name (for UI display only, not serialized).
+ ///
+ [JsonIgnore]
+ public string TargetMonitorName { get; set; } = string.Empty;
+
///
/// Gets the display name for the VCP code (for UI display).
///
@@ -50,9 +70,21 @@ namespace Microsoft.PowerToys.Settings.UI.Library
///
/// Gets a summary string for display in the UI list.
- /// Format: "VcpCodeName: OriginalValue → CustomName"
+ /// Format: "OriginalValue → CustomName" or "OriginalValue → CustomName (MonitorName)"
///
[JsonIgnore]
- public string DisplaySummary => $"{VcpNames.GetValueName(VcpCode, Value) ?? $"0x{Value:X2}"} → {CustomName}";
+ public string DisplaySummary
+ {
+ get
+ {
+ var baseSummary = $"{VcpNames.GetValueName(VcpCode, Value) ?? $"0x{Value:X2}"} → {CustomName}";
+ if (!ApplyToAll && !string.IsNullOrEmpty(TargetMonitorName))
+ {
+ return $"{baseSummary} ({TargetMonitorName})";
+ }
+
+ return baseSummary;
+ }
+ }
}
}
diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml
index 1e2750c23e..efbecb8223 100644
--- a/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml
+++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml
@@ -6,7 +6,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="400"
MinWidth="400"
- CloseButtonClick="ContentDialog_CloseButtonClick"
DefaultButton="Primary"
IsPrimaryButtonEnabled="{x:Bind CanSave, Mode=OneWay}"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
@@ -52,5 +51,25 @@
HorizontalAlignment="Stretch"
MaxLength="50"
TextChanged="CustomNameTextBox_TextChanged" />
+
+
+
+
+
+
+
+
diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml.cs
index 19ae87d773..a5f8c22d1a 100644
--- a/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml.cs
+++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/CustomVcpMappingEditorDialog.xaml.cs
@@ -41,19 +41,29 @@ namespace Microsoft.PowerToys.Settings.UI.Views
public bool IsCustomOption => Value == CustomValueMarker;
}
+ ///
+ /// Represents a selectable monitor item in the Monitor ComboBox
+ ///
+ public class MonitorItem
+ {
+ public string Id { get; set; } = string.Empty;
+
+ public string DisplayName { get; set; } = string.Empty;
+ }
+
private readonly IEnumerable? _monitors;
private ObservableCollection _availableValues = new();
+ private ObservableCollection _availableMonitors = new();
private byte _selectedVcpCode;
private int _selectedValue;
private string _customName = string.Empty;
private bool _canSave;
private bool _showCustomValueInput;
+ private bool _showMonitorSelector;
private int _customValueParsed;
-
- public CustomVcpMappingEditorDialog()
- : this(null)
- {
- }
+ private bool _applyToAll = true;
+ private string _selectedMonitorId = string.Empty;
+ private string _selectedMonitorName = string.Empty;
public CustomVcpMappingEditorDialog(IEnumerable? monitors)
{
@@ -66,6 +76,9 @@ namespace Microsoft.PowerToys.Settings.UI.Views
PrimaryButtonText = resourceLoader.GetString("PowerDisplay_Dialog_Save");
CloseButtonText = resourceLoader.GetString("PowerDisplay_Dialog_Cancel");
+ // Populate monitor list
+ PopulateMonitorList();
+
// Default to Color Temperature (0x14)
VcpCodeComboBox.SelectedIndex = 0;
}
@@ -88,6 +101,19 @@ namespace Microsoft.PowerToys.Settings.UI.Views
}
}
+ ///
+ /// Gets the available monitors for selection
+ ///
+ public ObservableCollection AvailableMonitors
+ {
+ get => _availableMonitors;
+ private set
+ {
+ _availableMonitors = value;
+ OnPropertyChanged();
+ }
+ }
+
///
/// Gets a value indicating whether the dialog can be saved
///
@@ -107,17 +133,40 @@ namespace Microsoft.PowerToys.Settings.UI.Views
///
/// Gets a value indicating whether to show the custom value input TextBox
///
- public Visibility ShowCustomValueInput
+ public Visibility ShowCustomValueInput => _showCustomValueInput ? Visibility.Visible : Visibility.Collapsed;
+
+ ///
+ /// Gets a value indicating whether to show the monitor selector ComboBox
+ ///
+ public Visibility ShowMonitorSelector => _showMonitorSelector ? Visibility.Visible : Visibility.Collapsed;
+
+ private void SetShowCustomValueInput(bool value)
{
- get => _showCustomValueInput ? Visibility.Visible : Visibility.Collapsed;
- private set
+ if (_showCustomValueInput != value)
{
- var newValue = value == Visibility.Visible;
- if (_showCustomValueInput != newValue)
- {
- _showCustomValueInput = newValue;
- OnPropertyChanged();
- }
+ _showCustomValueInput = value;
+ OnPropertyChanged(nameof(ShowCustomValueInput));
+ }
+ }
+
+ private void SetShowMonitorSelector(bool value)
+ {
+ if (_showMonitorSelector != value)
+ {
+ _showMonitorSelector = value;
+ OnPropertyChanged(nameof(ShowMonitorSelector));
+ }
+ }
+
+ private void PopulateMonitorList()
+ {
+ AvailableMonitors = new ObservableCollection(
+ _monitors?.Select(m => new MonitorItem { Id = m.Id, DisplayName = m.DisplayName })
+ ?? Enumerable.Empty());
+
+ if (AvailableMonitors.Count > 0)
+ {
+ MonitorComboBox.SelectedIndex = 0;
}
}
@@ -138,27 +187,15 @@ namespace Microsoft.PowerToys.Settings.UI.Views
PopulateValuesForVcpCode(mapping.VcpCode);
// Try to select the value in the ComboBox
- bool foundInList = false;
- foreach (var item in AvailableValues)
+ var matchingItem = AvailableValues.FirstOrDefault(v => !v.IsCustomOption && v.Value == mapping.Value);
+ if (matchingItem != null)
{
- if (!item.IsCustomOption && item.Value == mapping.Value)
- {
- ValueComboBox.SelectedItem = item;
- foundInList = true;
- break;
- }
+ ValueComboBox.SelectedItem = matchingItem;
}
-
- // If value not found in list, select "Custom value" option and fill the TextBox
- if (!foundInList)
+ else
{
- // Select the "Custom value" option (last item)
- var customOption = AvailableValues.FirstOrDefault(v => v.IsCustomOption);
- if (customOption != null)
- {
- ValueComboBox.SelectedItem = customOption;
- }
-
+ // Value not found in list, select "Custom value" option and fill the TextBox
+ ValueComboBox.SelectedItem = AvailableValues.FirstOrDefault(v => v.IsCustomOption);
CustomValueTextBox.Text = $"0x{mapping.Value:X2}";
_customValueParsed = mapping.Value;
}
@@ -167,6 +204,23 @@ namespace Microsoft.PowerToys.Settings.UI.Views
CustomNameTextBox.Text = mapping.CustomName;
_customName = mapping.CustomName;
+ // Set apply scope
+ _applyToAll = mapping.ApplyToAll;
+ ApplyToAllToggle.IsOn = mapping.ApplyToAll;
+ SetShowMonitorSelector(!mapping.ApplyToAll);
+
+ // Select the target monitor if not applying to all
+ if (!mapping.ApplyToAll && !string.IsNullOrEmpty(mapping.TargetMonitorId))
+ {
+ var targetMonitor = AvailableMonitors.FirstOrDefault(m => m.Id == mapping.TargetMonitorId);
+ if (targetMonitor != null)
+ {
+ MonitorComboBox.SelectedItem = targetMonitor;
+ _selectedMonitorId = targetMonitor.Id;
+ _selectedMonitorName = targetMonitor.DisplayName;
+ }
+ }
+
UpdateCanSave();
}
@@ -227,23 +281,20 @@ namespace Microsoft.PowerToys.Settings.UI.Views
}
}
- // If no values found from monitors, fall back to built-in values
+ // If no values found from monitors, fall back to built-in values from VcpNames
if (values.Count == 0)
{
- Dictionary builtInValues = vcpCode switch
+ var builtInValues = VcpNames.GetValueMappings(vcpCode);
+ if (builtInValues != null)
{
- 0x14 => GetColorTemperatureValues(),
- 0x60 => GetInputSourceValues(),
- _ => new Dictionary(),
- };
-
- foreach (var kvp in builtInValues)
- {
- values.Add(new VcpValueItem
+ foreach (var kvp in builtInValues)
{
- Value = kvp.Key,
- DisplayName = $"{kvp.Value} (0x{kvp.Key:X2})",
- });
+ values.Add(new VcpValueItem
+ {
+ Value = kvp.Key,
+ DisplayName = $"{kvp.Value} (0x{kvp.Key:X2})",
+ });
+ }
}
}
@@ -279,85 +330,19 @@ namespace Microsoft.PowerToys.Settings.UI.Views
return int.TryParse(cleanHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result);
}
- private static Dictionary GetColorTemperatureValues()
- {
- return new Dictionary
- {
- { 0x01, "sRGB" },
- { 0x02, "Display Native" },
- { 0x03, "4000K" },
- { 0x04, "5000K" },
- { 0x05, "6500K" },
- { 0x06, "7500K" },
- { 0x07, "8200K" },
- { 0x08, "9300K" },
- { 0x09, "10000K" },
- { 0x0A, "11500K" },
- { 0x0B, "User 1" },
- { 0x0C, "User 2" },
- { 0x0D, "User 3" },
- };
- }
-
- private static Dictionary GetInputSourceValues()
- {
- return new Dictionary
- {
- { 0x01, "VGA-1" },
- { 0x02, "VGA-2" },
- { 0x03, "DVI-1" },
- { 0x04, "DVI-2" },
- { 0x05, "Composite Video 1" },
- { 0x06, "Composite Video 2" },
- { 0x07, "S-Video-1" },
- { 0x08, "S-Video-2" },
- { 0x09, "Tuner-1" },
- { 0x0A, "Tuner-2" },
- { 0x0B, "Tuner-3" },
- { 0x0C, "Component Video 1" },
- { 0x0D, "Component Video 2" },
- { 0x0E, "Component Video 3" },
- { 0x0F, "DisplayPort-1" },
- { 0x10, "DisplayPort-2" },
- { 0x11, "HDMI-1" },
- { 0x12, "HDMI-2" },
- { 0x1B, "USB-C" },
- };
- }
-
private void ValueComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ValueComboBox.SelectedItem is VcpValueItem selectedItem)
{
- if (selectedItem.IsCustomOption)
- {
- // Show custom value input
- ShowCustomValueInput = Visibility.Visible;
- _selectedValue = 0; // Will be set from TextBox
- }
- else
- {
- // Hide custom value input and use selected value
- ShowCustomValueInput = Visibility.Collapsed;
- _selectedValue = selectedItem.Value;
- }
-
+ SetShowCustomValueInput(selectedItem.IsCustomOption);
+ _selectedValue = selectedItem.IsCustomOption ? 0 : selectedItem.Value;
UpdateCanSave();
}
}
private void CustomValueTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
- var text = CustomValueTextBox.Text?.Trim() ?? string.Empty;
- if (TryParseHexCode(text, out int parsed))
- {
- _customValueParsed = parsed;
- }
- else
- {
- _customValueParsed = 0;
- }
-
+ _customValueParsed = TryParseHexCode(CustomValueTextBox.Text?.Trim(), out int parsed) ? parsed : 0;
UpdateCanSave();
}
@@ -367,21 +352,33 @@ namespace Microsoft.PowerToys.Settings.UI.Views
UpdateCanSave();
}
+ private void ApplyToAllToggle_Toggled(object sender, RoutedEventArgs e)
+ {
+ _applyToAll = ApplyToAllToggle.IsOn;
+ SetShowMonitorSelector(!_applyToAll);
+ UpdateCanSave();
+ }
+
+ private void MonitorComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (MonitorComboBox.SelectedItem is MonitorItem selectedMonitor)
+ {
+ _selectedMonitorId = selectedMonitor.Id;
+ _selectedMonitorName = selectedMonitor.DisplayName;
+ UpdateCanSave();
+ }
+ }
+
private void UpdateCanSave()
{
- bool hasValidValue;
- if (_showCustomValueInput)
- {
- hasValidValue = _customValueParsed > 0;
- }
- else
- {
- hasValidValue = ValueComboBox.SelectedItem is VcpValueItem item && !item.IsCustomOption;
- }
+ var hasValidValue = _showCustomValueInput
+ ? _customValueParsed > 0
+ : ValueComboBox.SelectedItem is VcpValueItem item && !item.IsCustomOption;
CanSave = _selectedVcpCode > 0 &&
hasValidValue &&
- !string.IsNullOrWhiteSpace(_customName);
+ !string.IsNullOrWhiteSpace(_customName) &&
+ (_applyToAll || !string.IsNullOrEmpty(_selectedMonitorId));
}
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
@@ -394,15 +391,13 @@ namespace Microsoft.PowerToys.Settings.UI.Views
VcpCode = _selectedVcpCode,
Value = finalValue,
CustomName = _customName,
+ ApplyToAll = _applyToAll,
+ TargetMonitorId = _applyToAll ? string.Empty : _selectedMonitorId,
+ TargetMonitorName = _applyToAll ? string.Empty : _selectedMonitorName,
};
}
}
- private void ContentDialog_CloseButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
- {
- ResultMapping = null;
- }
-
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/PowerDisplayPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/PowerDisplayPage.xaml
index 6b7a850826..fcead09717 100644
--- a/src/settings-ui/Settings.UI/SettingsXAML/Views/PowerDisplayPage.xaml
+++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/PowerDisplayPage.xaml
@@ -68,7 +68,7 @@
@@ -107,7 +107,7 @@
diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
index 7fe3b01095..4eea892140 100644
--- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
+++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
@@ -6037,6 +6037,18 @@ The break timer font matches the text font.
e.g., 0x11 or 17
+
+ Apply to all monitors
+
+
+ On
+
+
+ Off
+
+
+ Select monitor
+
Delete custom mapping?
diff --git a/src/settings-ui/Settings.UI/ViewModels/PowerDisplayViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/PowerDisplayViewModel.cs
index 8db82b95cc..7e923bf2a2 100644
--- a/src/settings-ui/Settings.UI/ViewModels/PowerDisplayViewModel.cs
+++ b/src/settings-ui/Settings.UI/ViewModels/PowerDisplayViewModel.cs
@@ -56,6 +56,9 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
// set the callback functions value to handle outgoing IPC message.
SendConfigMSG = ipcMSGCallBackFunc;
+ // Subscribe to collection changes for HasProfiles binding
+ _profiles.CollectionChanged += (s, e) => OnPropertyChanged(nameof(HasProfiles));
+
// Load profiles
LoadProfiles();
@@ -450,39 +453,27 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private ObservableCollection _profiles = new ObservableCollection();
// Custom VCP mapping fields
- private ObservableCollection _customVcpMappings = new ObservableCollection();
+ private ObservableCollection _customVcpMappings;
///
- /// Gets or sets collection of custom VCP value name mappings
+ /// Gets collection of custom VCP value name mappings
///
- public ObservableCollection CustomVcpMappings
- {
- get => _customVcpMappings;
- set
- {
- if (_customVcpMappings != value)
- {
- _customVcpMappings = value;
- OnPropertyChanged();
- }
- }
- }
+ public ObservableCollection CustomVcpMappings => _customVcpMappings;
///
- /// Gets or sets collection of available profiles (for button display)
+ /// Gets whether there are any custom VCP mappings (for UI binding)
///
- public ObservableCollection Profiles
- {
- get => _profiles;
- set
- {
- if (_profiles != value)
- {
- _profiles = value;
- OnPropertyChanged();
- }
- }
- }
+ public bool HasCustomVcpMappings => _customVcpMappings?.Count > 0;
+
+ ///
+ /// Gets collection of available profiles (for button display)
+ ///
+ public ObservableCollection Profiles => _profiles;
+
+ ///
+ /// Gets whether there are any profiles (for UI binding)
+ ///
+ public bool HasProfiles => _profiles?.Count > 0;
public void RefreshEnabledState()
{
@@ -676,18 +667,25 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
try
{
var mappings = _settings.Properties.CustomVcpMappings ?? new List();
- CustomVcpMappings = new ObservableCollection(mappings);
+ _customVcpMappings = new ObservableCollection(mappings);
+ _customVcpMappings.CollectionChanged += (s, e) => OnPropertyChanged(nameof(HasCustomVcpMappings));
+ OnPropertyChanged(nameof(CustomVcpMappings));
+ OnPropertyChanged(nameof(HasCustomVcpMappings));
Logger.LogInfo($"Loaded {CustomVcpMappings.Count} custom VCP mappings");
}
catch (Exception ex)
{
Logger.LogError($"Failed to load custom VCP mappings: {ex.Message}");
- CustomVcpMappings = new ObservableCollection();
+ _customVcpMappings = new ObservableCollection();
+ _customVcpMappings.CollectionChanged += (s, e) => OnPropertyChanged(nameof(HasCustomVcpMappings));
+ OnPropertyChanged(nameof(CustomVcpMappings));
+ OnPropertyChanged(nameof(HasCustomVcpMappings));
}
}
///
- /// Add a new custom VCP mapping
+ /// Add a new custom VCP mapping.
+ /// No duplicate checking - mappings are resolved by order (first match wins in VcpNames).
///
public void AddCustomVcpMapping(Library.CustomVcpValueMapping mapping)
{
@@ -696,23 +694,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
return;
}
- // Check if a mapping for the same VcpCode+Value already exists
- var existing = CustomVcpMappings.FirstOrDefault(m =>
- m.VcpCode == mapping.VcpCode && m.Value == mapping.Value);
-
- if (existing != null)
- {
- // Update the existing mapping's custom name
- existing.CustomName = mapping.CustomName;
- Logger.LogInfo($"Updated existing custom VCP mapping: VCP=0x{mapping.VcpCode:X2}, Value=0x{mapping.Value:X2}");
- }
- else
- {
- // Add new mapping
- CustomVcpMappings.Add(mapping);
- Logger.LogInfo($"Added custom VCP mapping: VCP=0x{mapping.VcpCode:X2}, Value=0x{mapping.Value:X2} -> {mapping.CustomName}");
- }
-
+ CustomVcpMappings.Add(mapping);
+ Logger.LogInfo($"Added custom VCP mapping: VCP=0x{mapping.VcpCode:X2}, Value=0x{mapping.Value:X2} -> {mapping.CustomName}");
SaveCustomVcpMappings();
}