/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/modules/powerdisplay/PowerDisplay.Lib/Models/Monitor.cs
357 строк
13 KB
moooyo
feat(powerdisplay): add CLI for monitor control (#48632)
16 июл 2026, 18:08
Не верифицирован
16 июл 2026, 18:08
5c9c93d
Код
Авторство
О чём код?
// 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.ComponentModel; using System.Runtime.CompilerServices; using PowerDisplay.Common.Interfaces; using PowerDisplay.Common.Utils; namespace PowerDisplay.Common.Models { /// <summary> /// Monitor model that implements property change notification. /// Implements IMonitorData to provide a common interface for monitor hardware values. /// </summary> /// <remarks> /// <para><see cref="Id"/> is the unique identifier used for all purposes: UI lookups, IPC, persistent storage, and handle management.</para> /// <para> /// Format: the Windows DevicePath with the trailing device-class GUID stripped, e.g. /// <c>\\?\DISPLAY#DELD1A8#5&abc&0&UID12345</c>. The middle segment is the /// PnP instance ID, unique per (physical device × physical port) and stable across /// reboots, sleep/wake, and OS-level monitor reordering. See <see cref="MonitorIdentity.FromDevicePath"/>. /// </para> /// </remarks> public partial class Monitor : INotifyPropertyChanged, IMonitorData { private int _currentBrightness; private int _currentColorTemperature = 0x05; // Default to 6500K preset (VCP 0x14 value) private int _currentInputSource; // VCP 0x60 value private int _currentPowerState = 0x01; // Default to On (VCP 0xD6 value) private int _orientation; /// <summary> /// Gets or sets unique identifier for all purposes: UI lookups, IPC, persistent storage, and handle management. /// </summary> /// <remarks> /// Format: the Windows DevicePath with the trailing device-class GUID stripped, /// e.g. <c>\\?\DISPLAY#DELD1A8#5&abc&0&UID12345</c>. Stable across /// reboots, sleep/wake, and identical-monitor reordering by Windows. /// </remarks> public string Id { get; set; } = string.Empty; /// <summary> /// Gets or sets display name /// </summary> public string Name { get; set; } = string.Empty; /// <summary> /// Gets or sets current brightness as a percentage (0-100). /// </summary> public int CurrentBrightness { get => _currentBrightness; set { var clamped = Math.Clamp(value, 0, 100); if (_currentBrightness != clamped) { _currentBrightness = clamped; OnPropertyChanged(); } } } /// <summary> /// Gets or sets the device-reported raw VCP maximum for brightness (VCP 0x10). /// </summary> /// <remarks> /// <para>This is the value returned in the "max" out-parameter of <c>GetVCPFeatureAndVCPFeatureReply</c>. /// Most monitors report 100, but some (e.g. several Samsung models) report 50 — for those, writing /// the slider percentage as the raw VCP value lops off the upper half of the range. Writers must scale /// percent → raw using this field; readers use it via <see cref="VcpFeatureValue.ToPercentage"/>.</para> /// </remarks> public int BrightnessVcpMax { get; set; } = 100; /// <summary> /// Gets or sets current color temperature VCP preset value (from VCP code 0x14). /// This stores the raw VCP value (e.g., 0x05 for 6500K), not Kelvin temperature. /// Use ColorTemperaturePresetName to get human-readable name. /// </summary> public int CurrentColorTemperature { get => _currentColorTemperature; set { if (_currentColorTemperature != value) { _currentColorTemperature = value; OnPropertyChanged(); OnPropertyChanged(nameof(ColorTemperaturePresetName)); } } } /// <summary> /// Gets human-readable color temperature preset name (e.g., "6500K (0x05)", "sRGB (0x01)") /// </summary> public string ColorTemperaturePresetName => VcpNames.GetFormattedValueName(0x14, CurrentColorTemperature); /// <summary> /// Gets or sets a value indicating whether the monitor supports color temperature adjustment via VCP 0x14 /// </summary> public bool SupportsColorTemperature { get; set; } /// <summary> /// Gets or sets current input source VCP value (from VCP code 0x60). /// This stores the raw VCP value (e.g., 0x11 for HDMI-1). /// Use InputSourceName to get human-readable name. /// </summary> public int CurrentInputSource { get => _currentInputSource; set { if (_currentInputSource != value) { _currentInputSource = value; OnPropertyChanged(); OnPropertyChanged(nameof(InputSourceName)); } } } /// <summary> /// Gets human-readable input source name (e.g., "HDMI-1", "DisplayPort-1") /// Returns just the name without hex value for cleaner UI display. /// </summary> public string InputSourceName => VcpNames.GetValueName(0x60, CurrentInputSource) ?? $"Source 0x{CurrentInputSource:X2}"; /// <summary> /// Gets a value indicating whether the monitor supports input source switching via VCP 0x60 /// </summary> public bool SupportsInputSource => VcpCapabilitiesInfo?.SupportsVcpCode(0x60) ?? false; /// <summary> /// Gets get supported input sources from capabilities (as list of VCP values) /// </summary> public System.Collections.Generic.IReadOnlyList<int>? SupportedInputSources => VcpCapabilitiesInfo?.GetSupportedValues(0x60); /// <summary> /// Gets a value indicating whether the monitor supports power state control via VCP 0xD6 /// </summary> public bool SupportsPowerState => VcpCapabilitiesInfo?.SupportsVcpCode(0xD6) ?? false; /// <summary> /// Gets supported power states from capabilities (as list of VCP values) /// Values: 0x01=On, 0x02=Standby, 0x03=Suspend, 0x04=Off(DPM), 0x05=Off(Hard) /// </summary> public System.Collections.Generic.IReadOnlyList<int>? SupportedPowerStates => VcpCapabilitiesInfo?.GetSupportedValues(0xD6); /// <summary> /// Gets or sets current power state VCP value (from VCP code 0xD6). /// Values: 0x01=On, 0x02=Standby, 0x03=Suspend, 0x04=Off(DPM), 0x05=Off(Hard). /// </summary> public int CurrentPowerState { get => _currentPowerState; set { if (_currentPowerState != value) { _currentPowerState = value; OnPropertyChanged(); } } } /// <summary> /// Gets a value indicating whether the monitor supports brightness adjustment /// </summary> public bool SupportsBrightness => Capabilities.HasFlag(MonitorCapabilities.Brightness); /// <summary> /// Gets a value indicating whether the monitor supports contrast adjustment /// </summary> public bool SupportsContrast => Capabilities.HasFlag(MonitorCapabilities.Contrast); /// <summary> /// Gets a value indicating whether the monitor supports volume adjustment (for audio-capable monitors) /// </summary> public bool SupportsVolume => Capabilities.HasFlag(MonitorCapabilities.Volume); private int _currentContrast = 50; private int _currentVolume = 50; /// <summary> /// Gets or sets current contrast as a percentage (0-100). /// </summary> public int CurrentContrast { get => _currentContrast; set { var clamped = Math.Clamp(value, 0, 100); if (_currentContrast != clamped) { _currentContrast = clamped; OnPropertyChanged(); } } } /// <summary> /// Gets or sets the device-reported raw VCP maximum for contrast (VCP 0x12). /// See <see cref="BrightnessVcpMax"/> for semantics — same story applies to contrast. /// </summary> public int ContrastVcpMax { get; set; } = 100; /// <summary> /// Gets or sets current volume as a percentage (0-100). /// </summary> public int CurrentVolume { get => _currentVolume; set { var clamped = Math.Clamp(value, 0, 100); if (_currentVolume != clamped) { _currentVolume = clamped; OnPropertyChanged(); } } } /// <summary> /// Gets or sets the device-reported raw VCP maximum for volume (VCP 0x62). /// See <see cref="BrightnessVcpMax"/> for semantics — same story applies to volume. /// </summary> public int VolumeVcpMax { get; set; } = 100; /// <summary> /// Gets or sets physical monitor handle (for DDC/CI) /// </summary> public IntPtr Handle { get; set; } = IntPtr.Zero; /// <summary> /// Gets or sets instance name (used by WMI) /// </summary> public string InstanceName { get; set; } = string.Empty; /// <summary> /// Gets or sets communication method (DDC/CI, WMI, HDR API, etc.) /// </summary> public string CommunicationMethod { get; set; } = string.Empty; /// <summary> /// Gets or sets supported control methods /// </summary> public MonitorCapabilities Capabilities { get; set; } = MonitorCapabilities.None; /// <summary> /// Gets or sets the set of current values successfully read from the device during /// discovery. Callers (e.g. the CLI) use this to avoid reporting a default/stale value /// as the live "before" value. The GUI ignores this. /// </summary> public MonitorReadFlags ReadValues { get; set; } = MonitorReadFlags.None; /// <summary> /// Gets or sets raw DDC/CI capabilities string (MCCS format) /// </summary> public string? CapabilitiesRaw { get; set; } /// <summary> /// Gets or sets parsed VCP capabilities information /// </summary> public VcpCapabilities? VcpCapabilitiesInfo { get; set; } public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public override string ToString() { return $"{Name} ({CommunicationMethod}) - {CurrentBrightness}%"; } /// <inheritdoc /> int IMonitorData.Brightness { get => CurrentBrightness; set => CurrentBrightness = value; } /// <inheritdoc /> int IMonitorData.Contrast { get => CurrentContrast; set => CurrentContrast = value; } /// <inheritdoc /> int IMonitorData.Volume { get => CurrentVolume; set => CurrentVolume = value; } /// <inheritdoc /> int IMonitorData.ColorTemperatureVcp { get => CurrentColorTemperature; set => CurrentColorTemperature = value; } /// <summary> /// Gets or sets monitor number (1, 2, 3...) /// </summary> public int MonitorNumber { get; set; } /// <summary> /// Gets or sets the GDI device name (e.g., "\\.\DISPLAY1"). /// This is obtained from QueryDisplayConfig during discovery and should be used /// for display settings APIs (EnumDisplaySettings, ChangeDisplaySettingsEx). /// </summary> public string GdiDeviceName { get; set; } = string.Empty; /// <summary> /// Gets or sets monitor orientation (0=0, 1=90, 2=180, 3=270). /// Fires PropertyChanged when value changes. /// </summary> public int Orientation { get => _orientation; set { if (_orientation != value) { _orientation = value; OnPropertyChanged(); } } } /// <inheritdoc /> int IMonitorData.MonitorNumber { get => MonitorNumber; set => MonitorNumber = value; } /// <inheritdoc /> int IMonitorData.Orientation { get => Orientation; set => Orientation = value; } } }