2025-10-20 16:22:47 +08:00
|
|
|
// 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;
|
2025-11-24 21:58:34 +08:00
|
|
|
using PowerDisplay.Common.Interfaces;
|
2025-11-24 18:08:11 +08:00
|
|
|
using PowerDisplay.Common.Utils;
|
2025-10-20 16:22:47 +08:00
|
|
|
|
2025-11-24 18:08:11 +08:00
|
|
|
namespace PowerDisplay.Common.Models
|
2025-10-20 16:22:47 +08:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
2025-11-24 21:58:34 +08:00
|
|
|
/// Monitor model that implements property change notification.
|
|
|
|
|
/// Implements IMonitorData to provide a common interface for monitor hardware values.
|
2025-10-20 16:22:47 +08:00
|
|
|
/// </summary>
|
2025-11-24 21:58:34 +08:00
|
|
|
public partial class Monitor : INotifyPropertyChanged, IMonitorData
|
2025-10-20 16:22:47 +08:00
|
|
|
{
|
|
|
|
|
private int _currentBrightness;
|
2025-11-14 13:17:55 +08:00
|
|
|
private int _currentColorTemperature = 0x05; // Default to 6500K preset (VCP 0x14 value)
|
2025-10-20 16:22:47 +08:00
|
|
|
private bool _isAvailable = true;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Unique identifier (based on hardware ID)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string Id { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Hardware ID (EDID format like GSM5C6D)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string HardwareId { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Display name
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string Name { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Current brightness (0-100)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CurrentBrightness
|
|
|
|
|
{
|
|
|
|
|
get => _currentBrightness;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
var clamped = Math.Clamp(value, MinBrightness, MaxBrightness);
|
|
|
|
|
if (_currentBrightness != clamped)
|
|
|
|
|
{
|
|
|
|
|
_currentBrightness = clamped;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Minimum brightness value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MinBrightness { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Maximum brightness value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MaxBrightness { get; set; } = 100;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-14 13:17:55 +08:00
|
|
|
/// 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.
|
2025-10-20 16:22:47 +08:00
|
|
|
/// </summary>
|
|
|
|
|
public int CurrentColorTemperature
|
|
|
|
|
{
|
|
|
|
|
get => _currentColorTemperature;
|
|
|
|
|
set
|
|
|
|
|
{
|
2025-11-14 13:17:55 +08:00
|
|
|
if (_currentColorTemperature != value)
|
2025-10-20 16:22:47 +08:00
|
|
|
{
|
2025-11-14 13:17:55 +08:00
|
|
|
_currentColorTemperature = value;
|
2025-10-20 16:22:47 +08:00
|
|
|
OnPropertyChanged();
|
2025-11-14 13:17:55 +08:00
|
|
|
OnPropertyChanged(nameof(ColorTemperaturePresetName));
|
2025-10-20 16:22:47 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
Refactor PowerDisplay for dynamic monitor capabilities
Removed reliance on static `MonitorType` enumeration, replacing it with dynamic `CommunicationMethod` for better flexibility. Updated `IMonitorController` and `MonitorManager` to dynamically determine monitor control capabilities.
Refactored `Monitor` model to streamline properties and improve color temperature handling. Enhanced `MonitorViewModel` with unified methods for brightness, contrast, volume, and color temperature updates, improving UI responsiveness and hardware synchronization.
Improved settings handling by adding support for hidden monitors, preserving user preferences, and separating UI configuration from hardware parameter updates. Updated the PowerDisplay Settings UI with warnings, confirmation dialogs, and better VCP capabilities formatting.
Removed legacy IPC code in favor of event-driven settings updates. Conducted general code cleanup, improving logging, error handling, and documentation for maintainability.
2025-11-14 16:45:22 +08:00
|
|
|
/// Human-readable color temperature preset name (e.g., "6500K (0x05)", "sRGB (0x01)")
|
2025-10-20 16:22:47 +08:00
|
|
|
/// </summary>
|
2025-11-14 13:17:55 +08:00
|
|
|
public string ColorTemperaturePresetName =>
|
Refactor PowerDisplay for dynamic monitor capabilities
Removed reliance on static `MonitorType` enumeration, replacing it with dynamic `CommunicationMethod` for better flexibility. Updated `IMonitorController` and `MonitorManager` to dynamically determine monitor control capabilities.
Refactored `Monitor` model to streamline properties and improve color temperature handling. Enhanced `MonitorViewModel` with unified methods for brightness, contrast, volume, and color temperature updates, improving UI responsiveness and hardware synchronization.
Improved settings handling by adding support for hidden monitors, preserving user preferences, and separating UI configuration from hardware parameter updates. Updated the PowerDisplay Settings UI with warnings, confirmation dialogs, and better VCP capabilities formatting.
Removed legacy IPC code in favor of event-driven settings updates. Conducted general code cleanup, improving logging, error handling, and documentation for maintainability.
2025-11-14 16:45:22 +08:00
|
|
|
VcpValueNames.GetFormattedName(0x14, CurrentColorTemperature);
|
2025-10-20 16:22:47 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-14 13:17:55 +08:00
|
|
|
/// Whether supports color temperature adjustment via VCP 0x14
|
2025-10-20 16:22:47 +08:00
|
|
|
/// </summary>
|
2025-11-14 13:17:55 +08:00
|
|
|
public bool SupportsColorTemperature { get; set; }
|
2025-10-20 16:22:47 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-14 13:17:55 +08:00
|
|
|
/// Capabilities detection status: "available", "unavailable", or "unknown"
|
2025-10-20 16:22:47 +08:00
|
|
|
/// </summary>
|
2025-11-14 13:17:55 +08:00
|
|
|
public string CapabilitiesStatus { get; set; } = "unknown";
|
2025-10-20 16:22:47 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether supports contrast adjustment
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool SupportsContrast => Capabilities.HasFlag(MonitorCapabilities.Contrast);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether supports volume adjustment (for audio-capable monitors)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool SupportsVolume => Capabilities.HasFlag(MonitorCapabilities.Volume);
|
|
|
|
|
|
|
|
|
|
private int _currentContrast = 50;
|
|
|
|
|
private int _currentVolume = 50;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Current contrast (0-100)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CurrentContrast
|
|
|
|
|
{
|
|
|
|
|
get => _currentContrast;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
var clamped = Math.Clamp(value, MinContrast, MaxContrast);
|
|
|
|
|
if (_currentContrast != clamped)
|
|
|
|
|
{
|
|
|
|
|
_currentContrast = clamped;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Minimum contrast value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MinContrast { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Maximum contrast value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MaxContrast { get; set; } = 100;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Current volume (0-100)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int CurrentVolume
|
|
|
|
|
{
|
|
|
|
|
get => _currentVolume;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
var clamped = Math.Clamp(value, MinVolume, MaxVolume);
|
|
|
|
|
if (_currentVolume != clamped)
|
|
|
|
|
{
|
|
|
|
|
_currentVolume = clamped;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Minimum volume value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MinVolume { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Maximum volume value
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MaxVolume { get; set; } = 100;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether available/online
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool IsAvailable
|
|
|
|
|
{
|
|
|
|
|
get => _isAvailable;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
if (_isAvailable != value)
|
|
|
|
|
{
|
|
|
|
|
_isAvailable = value;
|
|
|
|
|
OnPropertyChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Physical monitor handle (for DDC/CI)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public IntPtr Handle { get; set; } = IntPtr.Zero;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-11-14 02:51:43 +08:00
|
|
|
/// Device key - unique identifier part of device path
|
2025-10-20 16:22:47 +08:00
|
|
|
/// </summary>
|
|
|
|
|
public string DeviceKey { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Instance name (used by WMI)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string InstanceName { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Manufacturer information
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string Manufacturer { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Connection type (HDMI, DP, VGA, etc.)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string ConnectionType { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Communication method (DDC/CI, WMI, HDR API, etc.)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string CommunicationMethod { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Supported control methods
|
|
|
|
|
/// </summary>
|
|
|
|
|
public MonitorCapabilities Capabilities { get; set; } = MonitorCapabilities.None;
|
|
|
|
|
|
2025-11-14 02:51:43 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// Raw DDC/CI capabilities string (MCCS format)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public string? CapabilitiesRaw { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Parsed VCP capabilities information
|
|
|
|
|
/// </summary>
|
|
|
|
|
public VcpCapabilities? VcpCapabilitiesInfo { get; set; }
|
|
|
|
|
|
2025-10-20 16:22:47 +08:00
|
|
|
/// <summary>
|
|
|
|
|
/// Last update time
|
|
|
|
|
/// </summary>
|
|
|
|
|
public DateTime LastUpdate { get; set; } = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
|
|
|
|
|
|
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
|
|
|
{
|
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
Refactor PowerDisplay for dynamic monitor capabilities
Removed reliance on static `MonitorType` enumeration, replacing it with dynamic `CommunicationMethod` for better flexibility. Updated `IMonitorController` and `MonitorManager` to dynamically determine monitor control capabilities.
Refactored `Monitor` model to streamline properties and improve color temperature handling. Enhanced `MonitorViewModel` with unified methods for brightness, contrast, volume, and color temperature updates, improving UI responsiveness and hardware synchronization.
Improved settings handling by adding support for hidden monitors, preserving user preferences, and separating UI configuration from hardware parameter updates. Updated the PowerDisplay Settings UI with warnings, confirmation dialogs, and better VCP capabilities formatting.
Removed legacy IPC code in favor of event-driven settings updates. Conducted general code cleanup, improving logging, error handling, and documentation for maintainability.
2025-11-14 16:45:22 +08:00
|
|
|
return $"{Name} ({CommunicationMethod}) - {CurrentBrightness}%";
|
2025-10-20 16:22:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Update monitor status
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void UpdateStatus(int brightness, bool isAvailable = true)
|
|
|
|
|
{
|
|
|
|
|
IsAvailable = isAvailable;
|
|
|
|
|
if (isAvailable)
|
|
|
|
|
{
|
|
|
|
|
CurrentBrightness = brightness;
|
|
|
|
|
LastUpdate = DateTime.Now;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-24 21:58:34 +08:00
|
|
|
|
|
|
|
|
/// <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;
|
|
|
|
|
}
|
2025-11-26 05:57:26 +08:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets monitor number (1, 2, 3...)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int MonitorNumber { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets or sets monitor orientation (0=0, 1=90, 2=180, 3=270)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int Orientation { get; set; }
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
int IMonitorData.MonitorNumber
|
|
|
|
|
{
|
|
|
|
|
get => MonitorNumber;
|
|
|
|
|
set => MonitorNumber = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
int IMonitorData.Orientation
|
|
|
|
|
{
|
|
|
|
|
get => Orientation;
|
|
|
|
|
set => Orientation = value;
|
|
|
|
|
}
|
2025-10-20 16:22:47 +08:00
|
|
|
}
|
|
|
|
|
}
|