Refactor logging and VCP naming; simplify capabilities status

Removed excessive debug/info logging and consolidated VCP code/value naming into a single VcpNames utility. Eliminated CapabilitiesStatus property in favor of simpler logic. Cleaned up exception handling and removed non-essential UI and service logs. No changes to core functionality.
This commit is contained in:
Yu Leng
2025-12-12 10:36:46 +08:00
parent 73dca1b598
commit 4557c509e5
25 changed files with 209 additions and 373 deletions

View File

@@ -165,7 +165,6 @@ namespace PowerDisplay.Common.Drivers.DDC
// Check if capabilities are already cached
if (!string.IsNullOrEmpty(monitor.CapabilitiesRaw))
{
Logger.LogDebug($"GetCapabilitiesStringAsync: Using cached capabilities for {monitor.Id} (length: {monitor.CapabilitiesRaw.Length})");
return monitor.CapabilitiesRaw;
}
@@ -202,7 +201,6 @@ namespace PowerDisplay.Common.Drivers.DDC
if (!string.IsNullOrEmpty(capsString))
{
Logger.LogDebug($"Got capabilities string (length: {capsString.Length})");
return capsString;
}
@@ -370,7 +368,6 @@ namespace PowerDisplay.Common.Drivers.DDC
var monitorInfo = matchingInfos[i];
candidates.Add(new CandidateMonitor(physicalMonitor.HPhysicalMonitor, physicalMonitor, monitorInfo));
Logger.LogDebug($"DDC: Candidate {gdiDeviceName} -> DevicePath={monitorInfo.DevicePath}, HardwareId={monitorInfo.HardwareId}");
}
}
@@ -413,7 +410,6 @@ namespace PowerDisplay.Common.Drivers.DDC
{
if (!capResult.IsValid)
{
Logger.LogDebug($"DDC: Handle 0x{candidate.Handle:X} - No DDC/CI brightness support, skipping");
continue;
}
@@ -471,7 +467,6 @@ namespace PowerDisplay.Common.Drivers.DDC
if (GetVCPFeatureAndVCPFeatureReply(handle, VcpCodeInputSource, IntPtr.Zero, out uint current, out uint _))
{
monitor.CurrentInputSource = (int)current;
Logger.LogDebug($"[{monitor.Id}] Input source: {VcpValueNames.GetFormattedName(VcpCodeInputSource, (int)current)}");
}
}
@@ -483,7 +478,6 @@ namespace PowerDisplay.Common.Drivers.DDC
if (GetVCPFeatureAndVCPFeatureReply(handle, VcpCodeSelectColorPreset, IntPtr.Zero, out uint current, out uint _))
{
monitor.CurrentColorTemperature = (int)current;
Logger.LogDebug($"[{monitor.Id}] Color temperature: {VcpValueNames.GetFormattedName(VcpCodeSelectColorPreset, (int)current)}");
}
}
@@ -496,7 +490,6 @@ namespace PowerDisplay.Common.Drivers.DDC
{
var brightnessInfo = new VcpFeatureValue((int)current, 0, (int)max);
monitor.CurrentBrightness = brightnessInfo.ToPercentage();
Logger.LogDebug($"[{monitor.Id}] Brightness: {monitor.CurrentBrightness}%");
}
}
@@ -522,8 +515,6 @@ namespace PowerDisplay.Common.Drivers.DDC
{
monitor.SupportsColorTemperature = true;
}
Logger.LogDebug($"[{monitor.Id}] Capabilities: Contrast={monitor.SupportsContrast}, Volume={monitor.SupportsVolume}, ColorTemp={monitor.SupportsColorTemperature}, InputSource={monitor.SupportsInputSource}");
}
/// <summary>
@@ -599,30 +590,14 @@ namespace PowerDisplay.Common.Drivers.DDC
{
if (monitor.Handle == IntPtr.Zero)
{
if (featureName != null)
{
Logger.LogDebug($"[{monitor.Id}] Invalid handle for {featureName} read");
}
return VcpFeatureValue.Invalid;
}
if (GetVCPFeatureAndVCPFeatureReply(monitor.Handle, vcpCode, IntPtr.Zero, out uint current, out uint max))
{
if (featureName != null)
{
var valueName = VcpValueNames.GetFormattedName(vcpCode, (int)current);
Logger.LogDebug($"[{monitor.Id}] {featureName} via 0x{vcpCode:X2}: {valueName}");
}
return new VcpFeatureValue((int)current, 0, (int)max);
}
if (featureName != null)
{
Logger.LogWarning($"[{monitor.Id}] Failed to read {featureName} (0x{vcpCode:X2} not supported)");
}
return VcpFeatureValue.Invalid;
},
cancellationToken);

View File

@@ -93,7 +93,6 @@ namespace PowerDisplay.Common.Drivers.DDC
var capsString = TryGetCapabilitiesString(hPhysicalMonitor);
if (string.IsNullOrEmpty(capsString))
{
Logger.LogDebug($"FetchCapabilities: Failed to get capabilities string for handle 0x{hPhysicalMonitor:X}");
return DdcCiValidationResult.Invalid;
}
@@ -102,19 +101,15 @@ namespace PowerDisplay.Common.Drivers.DDC
var capabilities = parseResult.Capabilities;
if (capabilities == null || capabilities.SupportedVcpCodes.Count == 0)
{
Logger.LogDebug($"FetchCapabilities: Failed to parse capabilities string for handle 0x{hPhysicalMonitor:X}");
return DdcCiValidationResult.Invalid;
}
// Check if brightness (VCP 0x10) is supported - determines DDC/CI validity
bool supportsBrightness = capabilities.SupportsVcpCode(NativeConstants.VcpCodeBrightness);
Logger.LogDebug($"FetchCapabilities: Handle 0x{hPhysicalMonitor:X} - BrightnessSupport={supportsBrightness}, VcpCodes={capabilities.SupportedVcpCodes.Count}");
return new DdcCiValidationResult(supportsBrightness, capsString, capabilities);
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"FetchCapabilities: Exception for handle 0x{hPhysicalMonitor:X}: {ex.Message}");
return DdcCiValidationResult.Invalid;
}
}
@@ -157,7 +152,6 @@ namespace PowerDisplay.Common.Drivers.DDC
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"TryGetCapabilitiesString failed: {ex.Message}");
return null;
}
}
@@ -191,7 +185,6 @@ namespace PowerDisplay.Common.Drivers.DDC
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"GetSourceGdiDeviceName failed: {ex.Message}");
}
return null;
@@ -238,7 +231,6 @@ namespace PowerDisplay.Common.Drivers.DDC
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"GetTargetDeviceInfo failed: {ex.Message}");
}
return (null, null, null);
@@ -308,7 +300,6 @@ namespace PowerDisplay.Common.Drivers.DDC
var gdiDeviceName = GetSourceGdiDeviceName(path.SourceInfo.AdapterId, path.SourceInfo.Id);
if (string.IsNullOrEmpty(gdiDeviceName))
{
Logger.LogDebug($"QueryDisplayConfig path[{i}]: Failed to get GDI device name");
continue;
}
@@ -318,7 +309,6 @@ namespace PowerDisplay.Common.Drivers.DDC
// Use device path as key - unique per target, supports mirror mode
if (string.IsNullOrEmpty(devicePath))
{
Logger.LogDebug($"QueryDisplayConfig path[{i}]: Failed to get device path");
continue;
}
@@ -332,13 +322,10 @@ namespace PowerDisplay.Common.Drivers.DDC
TargetId = path.TargetInfo.Id,
MonitorNumber = i + 1, // 1-based, matches Windows Display Settings
};
Logger.LogDebug($"QueryDisplayConfig path[{i}]: DevicePath={devicePath}, GdiName={gdiDeviceName}, HardwareId={hardwareId}, FriendlyName={friendlyName}");
}
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"GetAllMonitorDisplayInfo failed: {ex.Message}");
}
return monitorInfo;

View File

@@ -34,15 +34,12 @@ namespace PowerDisplay.Common.Drivers.DDC
try
{
Logger.LogDebug($"GetPhysicalMonitors: hMonitor=0x{hMonitor:X}");
if (!GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, out uint numMonitors))
{
Logger.LogWarning($"GetPhysicalMonitors: GetNumberOfPhysicalMonitorsFromHMONITOR failed for 0x{hMonitor:X}");
return null;
}
Logger.LogDebug($"GetPhysicalMonitors: numMonitors={numMonitors}");
if (numMonitors == 0)
{
Logger.LogWarning($"GetPhysicalMonitors: numMonitors is 0");
@@ -59,8 +56,6 @@ namespace PowerDisplay.Common.Drivers.DDC
}
}
Logger.LogDebug($"GetPhysicalMonitors: GetPhysicalMonitorsFromHMONITOR returned {apiResult}");
if (!apiResult)
{
Logger.LogWarning($"GetPhysicalMonitors: GetPhysicalMonitorsFromHMONITOR failed");
@@ -71,7 +66,6 @@ namespace PowerDisplay.Common.Drivers.DDC
var validMonitors = new List<PHYSICAL_MONITOR>();
for (int i = 0; i < numMonitors; i++)
{
string desc = physicalMonitors[i].GetDescription() ?? string.Empty;
IntPtr handle = physicalMonitors[i].HPhysicalMonitor;
if (handle == IntPtr.Zero)
@@ -81,7 +75,6 @@ namespace PowerDisplay.Common.Drivers.DDC
continue;
}
Logger.LogDebug($"GetPhysicalMonitors: [{i}] Handle=0x{handle:X}, Desc='{desc}'");
validMonitors.Add(physicalMonitors[i]);
}
@@ -141,7 +134,6 @@ namespace PowerDisplay.Common.Drivers.DDC
Handle = physicalMonitor.HPhysicalMonitor,
Capabilities = MonitorCapabilities.DdcCi,
CommunicationMethod = "DDC/CI",
CapabilitiesStatus = "unknown",
MonitorNumber = monitorInfo.MonitorNumber,
GdiDeviceName = monitorInfo.GdiDeviceName ?? string.Empty,
Orientation = DmdoDefault, // Orientation will be set separately if needed

View File

@@ -66,11 +66,10 @@ namespace PowerDisplay.Common.Drivers.DDC
try
{
DestroyPhysicalMonitor(handle);
Logger.LogDebug($"DDC: Cleaned up unused handle 0x{handle:X}");
}
catch (Exception ex)
catch
{
Logger.LogWarning($"DDC: Failed to destroy handle 0x{handle:X}: {ex.Message}");
// Silently ignore cleanup failures
}
}
}
@@ -91,11 +90,10 @@ namespace PowerDisplay.Common.Drivers.DDC
try
{
DestroyPhysicalMonitor(handle);
Logger.LogDebug($"Released physical monitor handle 0x{handle:X}");
}
catch (Exception ex)
catch
{
Logger.LogWarning($"Failed to destroy physical monitor handle 0x{handle:X}: {ex.Message}");
// Silently ignore cleanup failures
}
}
}

View File

@@ -129,7 +129,6 @@ namespace PowerDisplay.Common.Drivers.WMI
// Check if match was found (struct default has null/empty HardwareId)
if (!string.IsNullOrEmpty(match.HardwareId))
{
Logger.LogDebug($"WMI: Matched HardwareId '{hardwareId}' to MonitorNumber {match.MonitorNumber}, GdiDeviceName={match.GdiDeviceName}");
return match;
}
@@ -162,7 +161,6 @@ namespace PowerDisplay.Common.Drivers.WMI
}
// No match found - monitor may have been disconnected
Logger.LogDebug($"WMI GetBrightness: No monitor found with InstanceName '{monitor.InstanceName}'");
}
catch (WmiException ex)
{
@@ -296,7 +294,6 @@ namespace PowerDisplay.Common.Drivers.WMI
// Get display name from PnP manufacturer ID (e.g., "Lenovo Built-in Display")
var displayName = PnpIdHelper.GetBuiltInDisplayName(hardwareId);
Logger.LogDebug($"WMI: Found internal display '{hardwareId}' -> '{displayName}'");
var monitor = new Monitor
{

View File

@@ -91,7 +91,7 @@ namespace PowerDisplay.Common.Models
/// Gets human-readable color temperature preset name (e.g., "6500K (0x05)", "sRGB (0x01)")
/// </summary>
public string ColorTemperaturePresetName =>
VcpValueNames.GetFormattedName(0x14, CurrentColorTemperature);
VcpNames.GetFormattedValueName(0x14, CurrentColorTemperature);
/// <summary>
/// Gets or sets a value indicating whether the monitor supports color temperature adjustment via VCP 0x14
@@ -122,7 +122,7 @@ namespace PowerDisplay.Common.Models
/// Returns just the name without hex value for cleaner UI display.
/// </summary>
public string InputSourceName =>
VcpValueNames.GetName(0x60, CurrentInputSource) ?? $"Source 0x{CurrentInputSource:X2}";
VcpNames.GetValueName(0x60, CurrentInputSource) ?? $"Source 0x{CurrentInputSource:X2}";
/// <summary>
/// Gets a value indicating whether the monitor supports input source switching via VCP 0x60
@@ -135,11 +135,6 @@ namespace PowerDisplay.Common.Models
public System.Collections.Generic.IReadOnlyList<int>? SupportedInputSources =>
VcpCapabilitiesInfo?.GetSupportedValues(0x60);
/// <summary>
/// Gets or sets capabilities detection status: "available", "unavailable", or "unknown"
/// </summary>
public string CapabilitiesStatus { get; set; } = "unknown";
/// <summary>
/// Gets a value indicating whether the monitor supports contrast adjustment
/// </summary>

View File

@@ -71,12 +71,10 @@ namespace PowerDisplay.Common.Services
}
int currentOrientation = devMode.DmDisplayOrientation;
Logger.LogDebug($"SetRotation: Current orientation={currentOrientation}, target={newOrientation}");
// If already at target orientation, return success
if (currentOrientation == newOrientation)
{
Logger.LogDebug($"SetRotation: Already at target orientation {newOrientation}");
return MonitorOperationResult.Success();
}
@@ -91,7 +89,6 @@ namespace PowerDisplay.Common.Services
int temp = devMode.DmPelsWidth;
devMode.DmPelsWidth = devMode.DmPelsHeight;
devMode.DmPelsHeight = temp;
Logger.LogDebug($"SetRotation: Swapped dimensions to {devMode.DmPelsWidth}x{devMode.DmPelsHeight}");
}
// 3. Set new orientation
@@ -107,8 +104,6 @@ namespace PowerDisplay.Common.Services
return MonitorOperationResult.Failure($"Display settings test failed: {errorMsg}", testResult);
}
Logger.LogDebug($"SetRotation: Test passed, applying settings...");
// 5. Apply the settings (without CDS_UPDATEREGISTRY to make it temporary)
int result = ChangeDisplaySettingsEx(gdiDeviceName, &devMode, IntPtr.Zero, 0, IntPtr.Zero);
if (result != DispChangeSuccessful)
@@ -147,15 +142,13 @@ namespace PowerDisplay.Common.Services
if (!EnumDisplaySettings(gdiDeviceName, EnumCurrentSettings, &devMode))
{
Logger.LogDebug($"GetCurrentOrientation: EnumDisplaySettings failed for {gdiDeviceName}");
return -1;
}
return devMode.DmDisplayOrientation;
}
catch (Exception ex)
catch
{
Logger.LogDebug($"GetCurrentOrientation: Exception for {gdiDeviceName}: {ex.Message}");
return -1;
}
}

View File

@@ -210,8 +210,6 @@ namespace PowerDisplay.Common.Services
// Clear dirty flag after successful save
_isDirty = false;
Logger.LogDebug($"[State] Saved state for {monitorCount} monitors");
}
catch (Exception ex)
{
@@ -231,8 +229,6 @@ namespace PowerDisplay.Common.Services
// Write to disk synchronously - safe for Dispose
File.WriteAllText(_stateFilePath, json);
Logger.LogDebug($"[State] Saved state for {monitorCount} monitors (sync)");
}
catch (Exception ex)
{

View File

@@ -46,12 +46,7 @@ namespace PowerDisplay.Common.Services
{
lock (_lock)
{
var (profiles, message) = LoadProfilesInternal();
if (!string.IsNullOrEmpty(message))
{
Logger.LogInfo($"{LogPrefix} {message}");
}
var (profiles, _) = LoadProfilesInternal();
return profiles;
}
}
@@ -72,12 +67,7 @@ namespace PowerDisplay.Common.Services
return false;
}
var (success, message) = SaveProfilesInternal(profiles);
if (!string.IsNullOrEmpty(message))
{
Logger.LogInfo($"{LogPrefix} {message}");
}
var (success, _) = SaveProfilesInternal(profiles);
return success;
}
}

View File

@@ -44,7 +44,7 @@ namespace PowerDisplay.Common.Utils
/// <summary>
/// Formats a color temperature display name.
/// Uses VcpValueNames for standard VCP value mappings if no custom name is provided.
/// Uses VcpNames for standard VCP value mappings if no custom name is provided.
/// </summary>
/// <param name="vcpValue">The VCP value.</param>
/// <param name="customName">Optional custom name from capabilities string.</param>
@@ -60,7 +60,7 @@ namespace PowerDisplay.Common.Utils
}
// Fall back to standard VCP value name from shared library
var standardName = VcpValueNames.GetName(NativeConstants.VcpCodeSelectColorPreset, vcpValue);
var standardName = VcpNames.GetValueName(NativeConstants.VcpCodeSelectColorPreset, vcpValue);
if (standardName != null)
{
return $"{standardName} ({hexValue})";
@@ -78,7 +78,7 @@ namespace PowerDisplay.Common.Utils
/// <returns>Formatted display name with "Custom" indicator.</returns>
public static string FormatCustomColorTemperatureDisplayName(int vcpValue)
{
var standardName = VcpValueNames.GetName(NativeConstants.VcpCodeSelectColorPreset, vcpValue);
var standardName = VcpNames.GetValueName(NativeConstants.VcpCodeSelectColorPreset, vcpValue);
return string.IsNullOrEmpty(standardName)
? $"Custom (0x{vcpValue:X2})"
: $"{standardName} (0x{vcpValue:X2}) - Custom";

View File

@@ -34,7 +34,6 @@ namespace PowerDisplay.Common.Utils
EventResetMode.AutoReset,
eventName);
eventHandle.Set();
Logger.LogDebug($"[EventHelper] Signaled event: {eventName}");
return true;
}
catch (Exception ex)

View File

@@ -254,8 +254,7 @@ namespace PowerDisplay.Common.Utils
}
else
{
// Store unknown segments for potential future use
Logger.LogDebug($"Unknown capabilities segment: {segment.Name}({segment.Content})");
// Unknown segments are silently ignored
}
break;
@@ -273,7 +272,7 @@ namespace PowerDisplay.Common.Utils
while (parser.TryParseEntry(out var entry))
{
var name = VcpCodeNames.GetName(entry.Code);
var name = VcpNames.GetCodeName(entry.Code);
vcpCodes[entry.Code] = new VcpCodeInfo(entry.Code, name, entry.Values);
}

View File

@@ -30,8 +30,6 @@ namespace PowerDisplay.Common.Utils
public bool SupportsInputSource { get; init; }
public string CapabilitiesStatus { get; init; }
public static FeatureSupportResult Unavailable => new()
{
SupportsBrightness = false,
@@ -39,7 +37,6 @@ namespace PowerDisplay.Common.Utils
SupportsColorTemperature = false,
SupportsVolume = false,
SupportsInputSource = false,
CapabilitiesStatus = "unavailable",
};
}
@@ -69,7 +66,6 @@ namespace PowerDisplay.Common.Utils
SupportsColorTemperature = vcpCodeInts.Contains(NativeConstants.VcpCodeSelectColorPreset),
SupportsVolume = vcpCodeInts.Contains(NativeConstants.VcpCodeVolume),
SupportsInputSource = vcpCodeInts.Contains(NativeConstants.VcpCodeInputSource),
CapabilitiesStatus = "available",
};
}

View File

@@ -7,9 +7,10 @@ using System.Collections.Generic;
namespace PowerDisplay.Common.Utils
{
/// <summary>
/// VCP code to friendly name mapping based on MCCS v2.2a specification
/// Provides human-readable names for VCP codes and their values based on MCCS v2.2a specification.
/// Combines VCP code names (e.g., 0x10 = "Brightness") and VCP value names (e.g., 0x14:0x05 = "6500K").
/// </summary>
public static class VcpCodeNames
public static class VcpNames
{
/// <summary>
/// VCP code to name mapping
@@ -240,9 +241,187 @@ namespace PowerDisplay.Common.Utils
/// </summary>
/// <param name="code">VCP code (e.g., 0x10)</param>
/// <returns>Friendly name, or hex representation if unknown</returns>
public static string GetName(byte code)
public static string GetCodeName(byte code)
{
return CodeNames.TryGetValue(code, out var name) ? name : $"Unknown (0x{code:X2})";
}
// Dictionary<VcpCode, Dictionary<Value, Name>>
private static readonly Dictionary<byte, Dictionary<int, string>> ValueNames = new()
{
// 0x14: Select Color Preset
[0x14] = new Dictionary<int, string>
{
[0x01] = "sRGB",
[0x02] = "Display Native",
[0x03] = "4000K",
[0x04] = "5000K",
[0x05] = "6500K",
[0x06] = "7500K",
[0x08] = "9300K",
[0x09] = "10000K",
[0x0A] = "11500K",
[0x0B] = "User 1",
[0x0C] = "User 2",
[0x0D] = "User 3",
},
// 0x60: Input Source
[0x60] = new Dictionary<int, string>
{
[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",
},
// 0xD6: Power Mode
[0xD6] = new Dictionary<int, string>
{
[0x01] = "On",
[0x02] = "Standby",
[0x03] = "Suspend",
[0x04] = "Off (DPM)",
[0x05] = "Off (Hard)",
},
// 0x8D: Audio Mute
[0x8D] = new Dictionary<int, string>
{
[0x01] = "Muted",
[0x02] = "Unmuted",
},
// 0xDC: Display Application
[0xDC] = new Dictionary<int, string>
{
[0x00] = "Standard/Default",
[0x01] = "Productivity",
[0x02] = "Mixed",
[0x03] = "Movie",
[0x04] = "User Defined",
[0x05] = "Games",
[0x06] = "Sports",
[0x07] = "Professional (calibration)",
[0x08] = "Standard/Default with intermediate power consumption",
[0x09] = "Standard/Default with low power consumption",
[0x0A] = "Demonstration",
[0xF0] = "Dynamic Contrast",
},
// 0xCC: OSD Language
[0xCC] = new Dictionary<int, string>
{
[0x01] = "Chinese (traditional, Hantai)",
[0x02] = "English",
[0x03] = "French",
[0x04] = "German",
[0x05] = "Italian",
[0x06] = "Japanese",
[0x07] = "Korean",
[0x08] = "Portuguese (Portugal)",
[0x09] = "Russian",
[0x0A] = "Spanish",
[0x0B] = "Swedish",
[0x0C] = "Turkish",
[0x0D] = "Chinese (simplified, Kantai)",
[0x0E] = "Portuguese (Brazil)",
[0x0F] = "Arabic",
[0x10] = "Bulgarian",
[0x11] = "Croatian",
[0x12] = "Czech",
[0x13] = "Danish",
[0x14] = "Dutch",
[0x15] = "Estonian",
[0x16] = "Finnish",
[0x17] = "Greek",
[0x18] = "Hebrew",
[0x19] = "Hindi",
[0x1A] = "Hungarian",
[0x1B] = "Latvian",
[0x1C] = "Lithuanian",
[0x1D] = "Norwegian",
[0x1E] = "Polish",
[0x1F] = "Romanian",
[0x20] = "Serbian",
[0x21] = "Slovak",
[0x22] = "Slovenian",
[0x23] = "Thai",
[0x24] = "Ukrainian",
[0x25] = "Vietnamese",
},
// 0x62: Audio Speaker Volume
[0x62] = new Dictionary<int, string>
{
[0x00] = "Mute",
// Other values are continuous
},
// 0xDB: Image Mode (Dell monitors)
[0xDB] = new Dictionary<int, string>
{
[0x00] = "Standard",
[0x01] = "Multimedia",
[0x02] = "Movie",
[0x03] = "Game",
[0x04] = "Sports",
[0x05] = "Color Temperature",
[0x06] = "Custom Color",
[0x07] = "ComfortView",
},
};
/// <summary>
/// Get human-readable name for a VCP value
/// </summary>
/// <param name="vcpCode">VCP code (e.g., 0x14)</param>
/// <param name="value">Value to translate</param>
/// <returns>Name string like "sRGB" or null if unknown</returns>
public static string? GetValueName(byte vcpCode, int value)
{
if (ValueNames.TryGetValue(vcpCode, out var codeValues))
{
if (codeValues.TryGetValue(value, out var name))
{
return name;
}
}
return null;
}
/// <summary>
/// Get formatted display name for a VCP value (with hex value in parentheses)
/// </summary>
/// <param name="vcpCode">VCP code (e.g., 0x14)</param>
/// <param name="value">Value to translate</param>
/// <returns>Formatted string like "sRGB (0x01)" or "0x01" if unknown</returns>
public static string GetFormattedValueName(byte vcpCode, int value)
{
var name = GetValueName(vcpCode, value);
if (name != null)
{
return $"{name} (0x{value:X2})";
}
return $"0x{value:X2}";
}
}
}

View File

@@ -1,192 +0,0 @@
// 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.Collections.Generic;
namespace PowerDisplay.Common.Utils
{
/// <summary>
/// Provides human-readable names for VCP code values based on MCCS standard
/// </summary>
public static class VcpValueNames
{
// Dictionary<VcpCode, Dictionary<Value, Name>>
private static readonly Dictionary<byte, Dictionary<int, string>> ValueNames = new()
{
// 0x14: Select Color Preset
[0x14] = new Dictionary<int, string>
{
[0x01] = "sRGB",
[0x02] = "Display Native",
[0x03] = "4000K",
[0x04] = "5000K",
[0x05] = "6500K",
[0x06] = "7500K",
[0x08] = "9300K",
[0x09] = "10000K",
[0x0A] = "11500K",
[0x0B] = "User 1",
[0x0C] = "User 2",
[0x0D] = "User 3",
},
// 0x60: Input Source
[0x60] = new Dictionary<int, string>
{
[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",
},
// 0xD6: Power Mode
[0xD6] = new Dictionary<int, string>
{
[0x01] = "On",
[0x02] = "Standby",
[0x03] = "Suspend",
[0x04] = "Off (DPM)",
[0x05] = "Off (Hard)",
},
// 0x8D: Audio Mute
[0x8D] = new Dictionary<int, string>
{
[0x01] = "Muted",
[0x02] = "Unmuted",
},
// 0xDC: Display Application
[0xDC] = new Dictionary<int, string>
{
[0x00] = "Standard/Default",
[0x01] = "Productivity",
[0x02] = "Mixed",
[0x03] = "Movie",
[0x04] = "User Defined",
[0x05] = "Games",
[0x06] = "Sports",
[0x07] = "Professional (calibration)",
[0x08] = "Standard/Default with intermediate power consumption",
[0x09] = "Standard/Default with low power consumption",
[0x0A] = "Demonstration",
[0xF0] = "Dynamic Contrast",
},
// 0xCC: OSD Language
[0xCC] = new Dictionary<int, string>
{
[0x01] = "Chinese (traditional, Hantai)",
[0x02] = "English",
[0x03] = "French",
[0x04] = "German",
[0x05] = "Italian",
[0x06] = "Japanese",
[0x07] = "Korean",
[0x08] = "Portuguese (Portugal)",
[0x09] = "Russian",
[0x0A] = "Spanish",
[0x0B] = "Swedish",
[0x0C] = "Turkish",
[0x0D] = "Chinese (simplified, Kantai)",
[0x0E] = "Portuguese (Brazil)",
[0x0F] = "Arabic",
[0x10] = "Bulgarian",
[0x11] = "Croatian",
[0x12] = "Czech",
[0x13] = "Danish",
[0x14] = "Dutch",
[0x15] = "Estonian",
[0x16] = "Finnish",
[0x17] = "Greek",
[0x18] = "Hebrew",
[0x19] = "Hindi",
[0x1A] = "Hungarian",
[0x1B] = "Latvian",
[0x1C] = "Lithuanian",
[0x1D] = "Norwegian",
[0x1E] = "Polish",
[0x1F] = "Romanian",
[0x20] = "Serbian",
[0x21] = "Slovak",
[0x22] = "Slovenian",
[0x23] = "Thai",
[0x24] = "Ukrainian",
[0x25] = "Vietnamese",
},
// 0x62: Audio Speaker Volume
[0x62] = new Dictionary<int, string>
{
[0x00] = "Mute",
// Other values are continuous
},
// 0xDB: Image Mode (Dell monitors)
[0xDB] = new Dictionary<int, string>
{
[0x00] = "Standard",
[0x01] = "Multimedia",
[0x02] = "Movie",
[0x03] = "Game",
[0x04] = "Sports",
[0x05] = "Color Temperature",
[0x06] = "Custom Color",
[0x07] = "ComfortView",
},
};
/// <summary>
/// Get human-readable name for a VCP value
/// </summary>
/// <param name="vcpCode">VCP code (e.g., 0x14)</param>
/// <param name="value">Value to translate</param>
/// <returns>Name string like "sRGB" or null if unknown</returns>
public static string? GetName(byte vcpCode, int value)
{
if (ValueNames.TryGetValue(vcpCode, out var codeValues))
{
if (codeValues.TryGetValue(value, out var name))
{
return name;
}
}
return null;
}
/// <summary>
/// Get formatted display name for a VCP value (with hex value in parentheses)
/// </summary>
/// <param name="vcpCode">VCP code (e.g., 0x14)</param>
/// <param name="value">Value to translate</param>
/// <returns>Formatted string like "sRGB (0x01)" or "0x01" if unknown</returns>
public static string GetFormattedName(byte vcpCode, int value)
{
var name = GetName(vcpCode, value);
if (name != null)
{
return $"{name} (0x{value:X2})";
}
return $"0x{value:X2}";
}
}
}

View File

@@ -55,7 +55,6 @@ public sealed partial class DisplayChangeWatcher : IDisposable
if (_isRunning)
{
Logger.LogDebug("[DisplayChangeWatcher] Already running, ignoring Start()");
return;
}
@@ -125,11 +124,10 @@ public sealed partial class DisplayChangeWatcher : IDisposable
// Ignore events during initial enumeration or after disposal
if (_disposed || !_initialEnumerationComplete)
{
Logger.LogDebug($"[DisplayChangeWatcher] Ignoring add: {args.Name} (disposed={_disposed}, enumComplete={_initialEnumerationComplete})");
return;
}
Logger.LogInfo($"[DisplayChangeWatcher] Display added: {args.Name} ({args.Id})");
Logger.LogInfo($"[DisplayChangeWatcher] Display added: {args.Name}");
ScheduleDisplayChanged();
});
}
@@ -142,19 +140,16 @@ public sealed partial class DisplayChangeWatcher : IDisposable
// Ignore events during initial enumeration or after disposal
if (_disposed || !_initialEnumerationComplete)
{
Logger.LogDebug($"[DisplayChangeWatcher] Ignoring remove: {args.Id} (disposed={_disposed}, enumComplete={_initialEnumerationComplete})");
return;
}
Logger.LogInfo($"[DisplayChangeWatcher] Display removed: {args.Id}");
Logger.LogInfo("[DisplayChangeWatcher] Display removed");
ScheduleDisplayChanged();
});
}
private void OnDeviceUpdated(DeviceWatcher sender, DeviceInformationUpdate args)
{
Logger.LogDebug($"[DisplayChangeWatcher] Display updated: {args.Id}");
// Only trigger refresh for significant updates, not every property change.
// For now, we'll skip updates to avoid excessive refreshes.
// The Added and Removed events are the primary triggers for monitor changes.

View File

@@ -238,7 +238,6 @@ namespace PowerDisplay.Helpers
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"GetColorTemperatureAsync failed: {ex.Message}");
return VcpFeatureValue.Invalid;
}
}
@@ -277,7 +276,6 @@ namespace PowerDisplay.Helpers
}
catch (Exception ex) when (ex is not OutOfMemoryException)
{
Logger.LogDebug($"GetInputSourceAsync failed: {ex.Message}");
return VcpFeatureValue.Invalid;
}
}
@@ -348,7 +346,6 @@ namespace PowerDisplay.Helpers
var currentOrientation = _rotationService.GetCurrentOrientation(monitor.GdiDeviceName);
if (currentOrientation >= 0 && currentOrientation != monitor.Orientation)
{
Logger.LogDebug($"[MonitorManager] RefreshAllOrientations: {monitor.Id} orientation updated from {monitor.Orientation} to {currentOrientation}");
monitor.Orientation = currentOrientation;
monitor.LastUpdate = DateTime.Now;
}

View File

@@ -24,26 +24,21 @@ namespace PowerDisplay.Helpers
public static void WaitForEventLoop(string eventName, Action callback, CancellationToken cancellationToken)
{
var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
Logger.LogInfo($"[NativeEventWaiter] Setting up listener for event: {eventName}");
var t = new Thread(() =>
{
try
{
using var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
Logger.LogInfo($"[NativeEventWaiter] Thread started, waiting on event: {eventName}");
while (!cancellationToken.IsCancellationRequested)
{
// Use infinite wait like Peek.UI for more reliable event reception
if (eventHandle.WaitOne(500))
{
Logger.LogInfo($"[NativeEventWaiter] Event signaled: {eventName}");
dispatcherQueue.TryEnqueue(() => callback());
}
}
Logger.LogInfo($"[NativeEventWaiter] Cancellation requested, exiting loop for: {eventName}");
}
catch (Exception ex)
{

View File

@@ -265,21 +265,14 @@ namespace PowerDisplay
{
try
{
bool isVisible = IsWindowVisible();
Logger.LogInfo($"[ToggleWindow] IsWindowVisible returned: {isVisible}");
if (isVisible)
if (IsWindowVisible())
{
Logger.LogInfo("[ToggleWindow] Window is visible, calling HideWindow");
HideWindow();
}
else
{
Logger.LogInfo("[ToggleWindow] Window is hidden, calling ShowWindow");
ShowWindow();
}
Logger.LogInfo("[ToggleWindow] Toggle completed");
}
catch (Exception ex)
{
@@ -493,8 +486,6 @@ namespace PowerDisplay
return;
}
Logger.LogDebug($"[AdjustSize] Starting adjustment, current window size: {_appWindow.Size.Width}x{_appWindow.Size.Height}");
// Force layout update to ensure proper measurement
RootGrid.UpdateLayout();
@@ -502,21 +493,13 @@ namespace PowerDisplay
var availableWidth = (double)AppConstants.UI.WindowWidth;
var contentHeight = GetContentHeight(availableWidth);
Logger.LogDebug($"[AdjustSize] Content height from measurement: {contentHeight} DIU");
// Use unified DPI scaling method (consistent with FlyoutWindow pattern)
double dpiScale = WindowHelper.GetDpiScale(this);
Logger.LogDebug($"[AdjustSize] DPI scale: {dpiScale} ({dpiScale * 100}%)");
int scaledHeight = WindowHelper.ScaleToPhysicalPixels((int)Math.Ceiling(contentHeight), dpiScale);
Logger.LogDebug($"[AdjustSize] Scaled height (physical pixels): {scaledHeight}");
// Apply maximum height limit (also needs DPI scaling)
int maxHeight = WindowHelper.ScaleToPhysicalPixels(AppConstants.UI.MaxWindowHeight, dpiScale);
Logger.LogDebug($"[AdjustSize] Max height limit (physical pixels): {maxHeight}");
scaledHeight = Math.Min(scaledHeight, maxHeight);
Logger.LogDebug($"[AdjustSize] Final scaled height after limit: {scaledHeight}");
// Check if resize is needed
// Check if resize is needed
@@ -563,10 +546,9 @@ namespace PowerDisplay
windowSize.Height,
AppConstants.UI.WindowRightMargin);
}
catch (Exception ex)
catch (Exception)
{
// Window positioning failures are non-critical, just log for diagnostics
Logger.LogDebug($"[PositionWindow] Failed to position window: {ex.Message}");
// Window positioning failures are non-critical, silently ignore
}
}
@@ -576,31 +558,23 @@ namespace PowerDisplay
/// </summary>
private void Slider_PointerCaptureLost(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
{
Logger.LogDebug("[UI] Slider_PointerCaptureLost event triggered");
var slider = sender as Slider;
if (slider == null)
{
Logger.LogWarning("[UI] Slider is null in PointerCaptureLost");
return;
}
var propertyName = slider.Tag as string;
var monitorVm = slider.DataContext as MonitorViewModel;
Logger.LogDebug($"[UI] Property: {propertyName}, MonitorVM: {(monitorVm != null ? monitorVm.Name : "NULL")}, Value: {slider.Value}");
if (monitorVm == null || propertyName == null)
{
Logger.LogWarning($"[UI] Null check failed - MonitorVM: {monitorVm == null}, PropertyName: {propertyName == null}");
return;
}
// Get final value after drag completes
int finalValue = (int)slider.Value;
Logger.LogInfo($"[UI] Updating {propertyName} to {finalValue} for monitor {monitorVm.Name}");
// Now update the ViewModel, which will trigger hardware operation
switch (propertyName)
{
@@ -616,8 +590,6 @@ namespace PowerDisplay
monitorVm.Volume = finalValue;
break;
}
Logger.LogDebug($"[UI] ViewModel property {propertyName} updated successfully");
}
/// <summary>

View File

@@ -66,7 +66,6 @@ public partial class MainViewModel
{
if (!skipScanningCheck && IsScanning)
{
Logger.LogDebug("[RefreshMonitorsAsync] Skipping refresh - already scanning");
return;
}

View File

@@ -536,7 +536,7 @@ public partial class MainViewModel
else if (info.HasDiscreteValues)
{
var formattedValues = info.SupportedValues
.Select(v => Common.Utils.VcpValueNames.GetFormattedName(code, v))
.Select(v => Common.Utils.VcpNames.GetFormattedValueName(code, v))
.ToList();
result.Values = $"Values: {string.Join(", ", formattedValues)}";
result.HasValues = true;
@@ -547,7 +547,7 @@ public partial class MainViewModel
.Select(v => new Microsoft.PowerToys.Settings.UI.Library.VcpValueInfo
{
Value = $"0x{v:X2}",
Name = Common.Utils.VcpValueNames.GetName(code, v),
Name = Common.Utils.VcpNames.GetValueName(code, v),
})
.ToList();
}

View File

@@ -168,11 +168,9 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
{
// Get all display areas (virtual desktop regions)
var displayAreas = DisplayArea.FindAll();
Logger.LogDebug($"Found {displayAreas.Count} display areas");
// Get all monitor info from QueryDisplayConfig
var allDisplayInfo = DdcCiNative.GetAllMonitorDisplayInfo().Values.ToList();
Logger.LogDebug($"Found {allDisplayInfo.Count} monitors from QueryDisplayConfig");
// Build GDI name to MonitorNumber(s) mapping
// Note: In mirror mode, multiple monitors may share the same GdiDeviceName
@@ -194,7 +192,6 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
var hMonitor = Win32Interop.GetMonitorFromDisplayId(displayArea.DisplayId);
if (hMonitor == IntPtr.Zero)
{
Logger.LogDebug($"DisplayArea[{i}]: Failed to get HMONITOR");
continue;
}
@@ -202,7 +199,6 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
var monitorInfo = new MonitorInfoEx { CbSize = (uint)sizeof(MonitorInfoEx) };
if (!GetMonitorInfo(hMonitor, ref monitorInfo))
{
Logger.LogDebug($"DisplayArea[{i}]: GetMonitorInfo failed");
continue;
}
@@ -211,13 +207,11 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
// Look up MonitorNumber(s) by GDI device name
if (!gdiToMonitorNumbers.TryGetValue(gdiDeviceName, out var monitorNumbers) || monitorNumbers.Count == 0)
{
Logger.LogDebug($"DisplayArea[{i}]: No MonitorNumber found for GDI device '{gdiDeviceName}'");
continue;
}
// Format display text: single number for normal mode, "1|2" for mirror mode
var displayText = string.Join("|", monitorNumbers);
Logger.LogDebug($"DisplayArea[{i}]: GDI='{gdiDeviceName}' -> MonitorNumbers=[{displayText}]");
// Create and position identify window
var identifyWindow = new IdentifyWindow(displayText);
@@ -283,9 +277,9 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
{
disposable?.Dispose();
}
catch (Exception ex)
catch
{
Logger.LogDebug($"Error disposing {name}: {ex.Message}");
// Silently ignore dispose errors
}
}
@@ -298,9 +292,9 @@ public partial class MainViewModel : INotifyPropertyChanged, IDisposable
{
action();
}
catch (Exception ex)
catch
{
Logger.LogDebug($"Error executing {name}: {ex.Message}");
// Silently ignore execution errors
}
}

View File

@@ -202,8 +202,6 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
{
try
{
Logger.LogDebug($"[{Id}] Applying {propertyName.ToLowerInvariant()}: {value}%");
var result = await setAsyncFunc(Id, value, default);
if (result.IsSuccess)
@@ -518,7 +516,7 @@ public partial class MonitorViewModel : INotifyPropertyChanged, IDisposable
_availableInputSources = supportedSources.Select(value => new InputSourceItem
{
Value = value,
Name = Common.Utils.VcpValueNames.GetName(0x60, value) ?? $"Source 0x{value:X2}",
Name = Common.Utils.VcpNames.GetValueName(0x60, value) ?? $"Source 0x{value:X2}",
SelectionVisibility = value == _monitor.CurrentInputSource ? Visibility.Visible : Visibility.Collapsed,
MonitorId = _monitor.Id,
}).ToList();

View File

@@ -43,7 +43,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
private bool _supportsColorTemperature;
private bool _supportsVolume;
private bool _supportsInputSource;
private string _capabilitiesStatus = "unknown"; // "available", "unavailable", or "unknown"
// Cached color temperature presets (computed from VcpCodesFormatted)
private ObservableCollection<ColorPresetItem> _availableColorPresetsCache;
@@ -609,21 +608,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
[JsonPropertyName("capabilitiesStatus")]
public string CapabilitiesStatus
{
get => _capabilitiesStatus;
set
{
if (_capabilitiesStatus != value)
{
_capabilitiesStatus = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowCapabilitiesWarning));
}
}
}
/// <summary>
/// Available color temperature presets computed from VcpCodesFormatted (VCP code 0x14).
/// This is a computed property that parses the VCP capabilities data on-demand.
@@ -740,7 +724,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
public bool HasCapabilities => !string.IsNullOrEmpty(_capabilitiesRaw);
[JsonIgnore]
public bool ShowCapabilitiesWarning => _capabilitiesStatus == "unavailable";
public bool ShowCapabilitiesWarning => _communicationMethod.Contains("WMI", StringComparison.OrdinalIgnoreCase);
[JsonIgnore]
public string BrightnessTooltip => _supportsBrightness ? string.Empty : "Brightness control not supported by this monitor";
@@ -816,7 +800,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
SupportsColorTemperature = other.SupportsColorTemperature;
SupportsVolume = other.SupportsVolume;
SupportsInputSource = other.SupportsInputSource;
CapabilitiesStatus = other.CapabilitiesStatus;
MonitorNumber = other.MonitorNumber;
}

View File

@@ -306,7 +306,6 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
monitor.VcpCodes,
monitor.CapabilitiesRaw);
monitor.CapabilitiesStatus = result.CapabilitiesStatus;
monitor.SupportsBrightness = result.SupportsBrightness;
monitor.SupportsContrast = result.SupportsContrast;
monitor.SupportsColorTemperature = result.SupportsColorTemperature;