mirror of
https://github.com/jkocon/g-helper.git
synced 2026-02-23 13:00:52 +01:00
Gamma Init
This commit is contained in:
481
app/WindowsDisplayAPI/DisplayConfig/PathDisplayTarget.cs
Normal file
481
app/WindowsDisplayAPI/DisplayConfig/PathDisplayTarget.cs
Normal file
@@ -0,0 +1,481 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using WindowsDisplayAPI.Exceptions;
|
||||
using WindowsDisplayAPI.Native;
|
||||
using WindowsDisplayAPI.Native.DisplayConfig;
|
||||
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||
using WindowsDisplayAPI.Native.Structures;
|
||||
|
||||
namespace WindowsDisplayAPI.DisplayConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a display path target (Display Device)
|
||||
/// </summary>
|
||||
public class PathDisplayTarget : IEquatable<PathDisplayTarget>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new PathDisplayTarget
|
||||
/// </summary>
|
||||
/// <param name="adapter">Display adapter</param>
|
||||
/// <param name="targetId">Display target identification</param>
|
||||
public PathDisplayTarget(PathDisplayAdapter adapter, uint targetId) : this(adapter, targetId, false)
|
||||
{
|
||||
IsAvailable = GetDisplayTargets().Any(target => target == this);
|
||||
}
|
||||
|
||||
internal PathDisplayTarget(PathDisplayAdapter adapter, uint targetId, bool isAvailable)
|
||||
{
|
||||
Adapter = adapter;
|
||||
TargetId = targetId;
|
||||
IsAvailable = isAvailable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path display adapter
|
||||
/// </summary>
|
||||
public PathDisplayAdapter Adapter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the display boot persistence for the target display device
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException"></exception>
|
||||
/// <exception cref="Win32Exception"></exception>
|
||||
public bool BootPersistence
|
||||
{
|
||||
set
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetPersistence = new DisplayConfigSetTargetPersistence(Adapter.AdapterId, TargetId, value);
|
||||
var result = DisplayConfigApi.DisplayConfigSetDeviceInfo(ref targetPersistence);
|
||||
|
||||
if (result != Win32Status.Success)
|
||||
{
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the one-based instance number of this particular target only when the adapter has multiple targets of this
|
||||
/// type. The connector instance is a consecutive one-based number that is unique within each adapter. If this is the
|
||||
/// only target of this type on the adapter, this value is zero.
|
||||
/// </summary>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
public int ConnectorInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetName = new DisplayConfigTargetDeviceName(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetName);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
return (int) targetName.ConnectorInstance;
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display device path
|
||||
/// </summary>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
public string DevicePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetName = new DisplayConfigTargetDeviceName(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetName);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
return targetName.MonitorDevicePath;
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display manufacture 3 character code from the display EDID manufacture identification
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
/// <exception cref="InvalidEDIDInformation">The EDID information does not contain this value</exception>
|
||||
public string EDIDManufactureCode
|
||||
{
|
||||
get
|
||||
{
|
||||
var edidCode = EDIDManufactureId;
|
||||
edidCode = ((edidCode & 0xff00) >> 8) | ((edidCode & 0x00ff) << 8);
|
||||
var byte1 = (byte) 'A' + (edidCode & 0x1f) - 1;
|
||||
var byte2 = (byte) 'A' + ((edidCode >> 5) & 0x1f) - 1;
|
||||
var byte3 = (byte) 'A' + ((edidCode >> 10) & 0x1f) - 1;
|
||||
|
||||
return $"{Convert.ToChar(byte3)}{Convert.ToChar(byte2)}{Convert.ToChar(byte1)}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display manufacture identification from the display EDID information
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
/// <exception cref="InvalidEDIDInformation">The EDID information does not contain this value</exception>
|
||||
public int EDIDManufactureId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetName = new DisplayConfigTargetDeviceName(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetName);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
if (targetName.Flags.HasFlag(DisplayConfigTargetDeviceNameFlags.EDIDIdsValid))
|
||||
{
|
||||
return targetName.EDIDManufactureId;
|
||||
}
|
||||
|
||||
throw new InvalidEDIDInformation("EDID does not contain necessary information.");
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display product identification from the display EDID information
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
/// <exception cref="InvalidEDIDInformation">The EDID information does not contain this value</exception>
|
||||
public int EDIDProductCode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetName = new DisplayConfigTargetDeviceName(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetName);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
if (targetName.Flags.HasFlag(DisplayConfigTargetDeviceNameFlags.EDIDIdsValid))
|
||||
{
|
||||
return targetName.EDIDProductCodeId;
|
||||
}
|
||||
|
||||
throw new InvalidEDIDInformation("EDID does not contain necessary information.");
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display friendly name from the display EDID information
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
public string FriendlyName
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetName = new DisplayConfigTargetDeviceName(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetName);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
return targetName.MonitorFriendlyDeviceName;
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean value indicating the device availability
|
||||
/// </summary>
|
||||
public bool IsAvailable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display device preferred resolution
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
public Size PreferredResolution
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetPreferredMode = new DisplayConfigTargetPreferredMode(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetPreferredMode);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
return new Size((int) targetPreferredMode.Width, (int) targetPreferredMode.Height);
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display device preferred signal information
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
public PathTargetSignalInfo PreferredSignalMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetPreferredMode = new DisplayConfigTargetPreferredMode(Adapter.AdapterId, TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetPreferredMode);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
return new PathTargetSignalInfo(targetPreferredMode.TargetMode.TargetVideoSignalInfo);
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target identification
|
||||
/// </summary>
|
||||
public uint TargetId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the device virtual resolution support
|
||||
/// </summary>
|
||||
/// <exception cref="TargetNotAvailableException">The target is not available</exception>
|
||||
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||
public bool VirtualResolutionSupport
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetSupportVirtualResolution = new DisplayConfigSupportVirtualResolution(Adapter.AdapterId,
|
||||
TargetId);
|
||||
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref targetSupportVirtualResolution);
|
||||
|
||||
if (result == Win32Status.Success)
|
||||
{
|
||||
return !targetSupportVirtualResolution.DisableMonitorVirtualResolution;
|
||||
}
|
||||
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!IsAvailable)
|
||||
{
|
||||
throw new TargetNotAvailableException("Extra information about the target is not available.",
|
||||
Adapter.AdapterId, TargetId);
|
||||
}
|
||||
|
||||
var targetSupportVirtualResolution = new DisplayConfigSupportVirtualResolution(Adapter.AdapterId,
|
||||
TargetId, !value);
|
||||
var result = DisplayConfigApi.DisplayConfigSetDeviceInfo(ref targetSupportVirtualResolution);
|
||||
|
||||
if (result != Win32Status.Success)
|
||||
{
|
||||
throw new Win32Exception((int) result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(PathDisplayTarget other)
|
||||
{
|
||||
if (ReferenceEquals(null, other))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, other))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Adapter == other.Adapter && TargetId == other.TargetId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieving a list of all display targets from the currently active and inactive paths
|
||||
/// </summary>
|
||||
/// <returns>An array of PathDisplayTarget instances</returns>
|
||||
public static PathDisplayTarget[] GetDisplayTargets()
|
||||
{
|
||||
var targets = new Dictionary<Tuple<LUID, uint>, PathDisplayTarget>();
|
||||
|
||||
foreach (var pathInfo in PathInfo.GetAllPaths())
|
||||
foreach (var pathTargetInfo in pathInfo.TargetsInfo.Where(info => info.DisplayTarget.IsAvailable))
|
||||
{
|
||||
var key = Tuple.Create(
|
||||
pathTargetInfo.DisplayTarget.Adapter.AdapterId,
|
||||
pathTargetInfo.DisplayTarget.TargetId
|
||||
);
|
||||
|
||||
if (!pathTargetInfo.DisplayTarget.Adapter.IsInvalid && !targets.ContainsKey(key))
|
||||
{
|
||||
targets.Add(key, pathTargetInfo.DisplayTarget);
|
||||
}
|
||||
}
|
||||
|
||||
return targets.Values.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for equality of two PathDisplayTarget instances
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance</param>
|
||||
/// <param name="right">The second instance</param>
|
||||
/// <returns>true if both instances are equal, otherwise false</returns>
|
||||
public static bool operator ==(PathDisplayTarget left, PathDisplayTarget right)
|
||||
{
|
||||
return Equals(left, right) || left?.Equals(right) == true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for inequality of two PathDisplayTarget instances
|
||||
/// </summary>
|
||||
/// <param name="left">The first instance</param>
|
||||
/// <param name="right">The second instance</param>
|
||||
/// <returns>true if both instances are not equal, otherwise false</returns>
|
||||
public static bool operator !=(PathDisplayTarget left, PathDisplayTarget right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return obj.GetType() == GetType() && Equals((PathDisplayTarget) obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return ((Adapter != null ? Adapter.GetHashCode() : 0) * 397) ^ (int) TargetId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return FriendlyName;
|
||||
}
|
||||
|
||||
#if !NETSTANDARD
|
||||
/// <summary>
|
||||
/// Opens the registry key of the Windows PnP manager for this display target
|
||||
/// </summary>
|
||||
/// <returns>A RegistryKey instance for successful call, otherwise null</returns>
|
||||
public Microsoft.Win32.RegistryKey OpenDevicePnPKey()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(DevicePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var path = DevicePath;
|
||||
if (path.StartsWith("\\\\?\\"))
|
||||
{
|
||||
path = path.Substring(4).Replace("#", "\\");
|
||||
if (path.EndsWith("}"))
|
||||
{
|
||||
var guidIndex = path.LastIndexOf("{", StringComparison.InvariantCulture);
|
||||
if (guidIndex > 0) {
|
||||
path = path.Substring(0, guidIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
|
||||
"SYSTEM\\CurrentControlSet\\Enum\\" + path,
|
||||
Microsoft.Win32.RegistryKeyPermissionCheck.ReadSubTree
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Returns the corresponding <see cref="DisplayDevice"/> instance
|
||||
/// </summary>
|
||||
/// <returns>An instance of <see cref="DisplayDevice"/>, or null</returns>
|
||||
public DisplayDevice ToDisplayDevice()
|
||||
{
|
||||
return
|
||||
DisplayAdapter.GetDisplayAdapters()
|
||||
.SelectMany(adapter => adapter.GetDisplayDevices())
|
||||
.FirstOrDefault(device => device.DevicePath.Equals(DevicePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user