2022-11-20 15:12:12 +01:00
|
|
|
|
using System;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
using System.Collections.Generic;
|
2022-11-19 09:19:57 +01:00
|
|
|
|
using System.Collections.Immutable;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
using System.Diagnostics;
|
2022-11-18 15:20:35 +01:00
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
2022-11-20 15:12:12 +01:00
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using static PowerControl.Helpers.PhysicalMonitorBrightnessController;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
|
|
|
|
|
namespace PowerControl.Helpers
|
|
|
|
|
|
{
|
2022-11-20 15:12:12 +01:00
|
|
|
|
internal class DisplayResolutionController
|
2022-11-14 11:06:03 +01:00
|
|
|
|
{
|
2022-11-19 09:19:57 +01:00
|
|
|
|
public struct DisplayResolution : IComparable<DisplayResolution>
|
2022-11-18 15:20:35 +01:00
|
|
|
|
{
|
|
|
|
|
|
public int Width { get; set; }
|
|
|
|
|
|
public int Height { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public DisplayResolution() { Width = 0; Height = 0; }
|
|
|
|
|
|
|
|
|
|
|
|
public DisplayResolution(int width, int height) { Width = width; Height = height; }
|
|
|
|
|
|
|
|
|
|
|
|
public static bool operator ==(DisplayResolution sz1, DisplayResolution sz2) => sz1.Width == sz2.Width && sz1.Height == sz2.Height;
|
|
|
|
|
|
|
|
|
|
|
|
public static bool operator !=(DisplayResolution sz1, DisplayResolution sz2) => !(sz1 == sz2);
|
|
|
|
|
|
|
|
|
|
|
|
public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is DisplayResolution && Equals((DisplayResolution)obj);
|
|
|
|
|
|
public readonly bool Equals(DisplayResolution other) => this == other;
|
|
|
|
|
|
|
|
|
|
|
|
public override readonly int GetHashCode() => HashCode.Combine(Width, Height);
|
|
|
|
|
|
|
2022-11-19 09:19:57 +01:00
|
|
|
|
public int CompareTo(DisplayResolution other)
|
|
|
|
|
|
{
|
|
|
|
|
|
var index = Width.CompareTo(other.Width);
|
|
|
|
|
|
if (index == 0) index = Height.CompareTo(other.Height);
|
|
|
|
|
|
return index;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-18 15:20:35 +01:00
|
|
|
|
public override string ToString()
|
|
|
|
|
|
{
|
|
|
|
|
|
return String.Format("{0}x{1}", Width, Height);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
private static IEnumerable<DEVMODE> FindAllDisplaySettings()
|
2022-11-18 15:20:35 +01:00
|
|
|
|
{
|
|
|
|
|
|
DEVMODE dm = new DEVMODE();
|
|
|
|
|
|
for (int i = 0; EnumDisplaySettings(null, i, ref dm); i++)
|
|
|
|
|
|
{
|
2022-11-18 15:49:34 +01:00
|
|
|
|
if (dm.dmFields.HasFlag(DM.PelsWidth) && dm.dmFields.HasFlag(DM.PelsHeight) && dm.dmFields.HasFlag(DM.PelsHeight))
|
|
|
|
|
|
yield return dm;
|
2022-11-18 15:20:35 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
dm = new DEVMODE();
|
|
|
|
|
|
}
|
2022-11-18 15:20:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
private static DEVMODE? CurrentDisplaySettings()
|
2022-11-18 15:20:35 +01:00
|
|
|
|
{
|
|
|
|
|
|
DEVMODE dm = new DEVMODE();
|
2022-11-18 15:49:34 +01:00
|
|
|
|
if (EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm))
|
|
|
|
|
|
return dm;
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2022-11-18 15:20:35 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
public static DisplayResolution[] GetAllResolutions()
|
|
|
|
|
|
{
|
|
|
|
|
|
return FindAllDisplaySettings()
|
|
|
|
|
|
.Select((dm) => new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight))
|
2022-11-19 09:19:57 +01:00
|
|
|
|
.ToImmutableSortedSet()
|
2022-11-18 15:49:34 +01:00
|
|
|
|
.ToArray();
|
|
|
|
|
|
}
|
2022-11-18 15:20:35 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
public static DisplayResolution? GetResolution()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dm = CurrentDisplaySettings();
|
|
|
|
|
|
if (dm is not null)
|
|
|
|
|
|
return new DisplayResolution(dm.Value.dmPelsWidth, dm.Value.dmPelsHeight);
|
2022-11-18 15:20:35 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
return null;
|
2022-11-18 15:20:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool SetResolution(DisplayResolution size)
|
|
|
|
|
|
{
|
2022-11-18 15:49:34 +01:00
|
|
|
|
DEVMODE? best = FindAllDisplaySettings()
|
|
|
|
|
|
.Where((dm) => dm.dmPelsWidth == size.Width && dm.dmPelsHeight == size.Height)
|
|
|
|
|
|
.MaxBy((dm) => dm.dmDisplayFrequency);
|
2022-11-18 15:20:35 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
if (best == null)
|
2022-11-18 15:20:35 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
DEVMODE dm = best.Value;
|
2022-11-18 15:20:35 +01:00
|
|
|
|
|
|
|
|
|
|
var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero);
|
|
|
|
|
|
|
|
|
|
|
|
if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
Trace.WriteLine("DispChange: " + dispChange.ToString() + " Size:" + size.ToString() +
|
2022-11-18 15:20:35 +01:00
|
|
|
|
" SetSize:" + new DisplayResolution(dm.dmPelsWidth, dm.dmPelsHeight).ToString());
|
|
|
|
|
|
|
|
|
|
|
|
if (dispChange == DISP_CHANGE.Successful)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static int[] GetRefreshRates(DisplayResolution? size = null)
|
2022-11-14 11:06:03 +01:00
|
|
|
|
{
|
2022-11-18 15:20:35 +01:00
|
|
|
|
if (size is null)
|
|
|
|
|
|
size = GetResolution();
|
|
|
|
|
|
if (size is null)
|
|
|
|
|
|
return new int[0];
|
|
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
return FindAllDisplaySettings()
|
|
|
|
|
|
.Where((dm) => dm.dmPelsWidth == size?.Width && dm.dmPelsHeight == size?.Height)
|
|
|
|
|
|
.Select((dm) => dm.dmDisplayFrequency)
|
|
|
|
|
|
.ToHashSet()
|
|
|
|
|
|
.ToArray();
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static int GetRefreshRate()
|
|
|
|
|
|
{
|
2022-11-18 15:49:34 +01:00
|
|
|
|
var dm = CurrentDisplaySettings();
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
if (dm is not null)
|
|
|
|
|
|
return dm.Value.dmDisplayFrequency;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
return -1;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static bool SetRefreshRate(int hz)
|
|
|
|
|
|
{
|
2022-11-18 15:49:34 +01:00
|
|
|
|
var current = CurrentDisplaySettings();
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
if (current is null)
|
2022-11-18 15:20:35 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
DEVMODE? best = FindAllDisplaySettings()
|
|
|
|
|
|
.Where((dm) => dm.dmPelsWidth == current.Value.dmPelsWidth && dm.dmPelsHeight == current.Value.dmPelsHeight)
|
|
|
|
|
|
.Where((dm) => dm.dmDisplayFrequency == hz)
|
|
|
|
|
|
.First();
|
|
|
|
|
|
|
|
|
|
|
|
if (best is null)
|
2022-11-14 11:06:03 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
2022-11-18 15:49:34 +01:00
|
|
|
|
DEVMODE dm = best.Value;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
|
|
|
|
|
var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero);
|
|
|
|
|
|
|
|
|
|
|
|
if (!EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
Trace.WriteLine("DispChange: " + dispChange.ToString() + " HZ:" + hz.ToString() + " SetHZ:" + dm.dmDisplayFrequency.ToString());
|
|
|
|
|
|
|
|
|
|
|
|
if (dispChange == DISP_CHANGE.Successful)
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
enum DISP_CHANGE : int
|
|
|
|
|
|
{
|
|
|
|
|
|
Successful = 0,
|
|
|
|
|
|
Restart = 1,
|
|
|
|
|
|
Failed = -1,
|
|
|
|
|
|
BadMode = -2,
|
|
|
|
|
|
NotUpdated = -3,
|
|
|
|
|
|
BadFlags = -4,
|
|
|
|
|
|
BadParam = -5,
|
|
|
|
|
|
BadDualView = -6
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[Flags()]
|
|
|
|
|
|
enum DM : int
|
2022-11-14 11:06:03 +01:00
|
|
|
|
{
|
2022-11-20 15:12:12 +01:00
|
|
|
|
Orientation = 0x1,
|
|
|
|
|
|
PaperSize = 0x2,
|
|
|
|
|
|
PaperLength = 0x4,
|
|
|
|
|
|
PaperWidth = 0x8,
|
|
|
|
|
|
Scale = 0x10,
|
|
|
|
|
|
Position = 0x20,
|
|
|
|
|
|
NUP = 0x40,
|
|
|
|
|
|
DisplayOrientation = 0x80,
|
|
|
|
|
|
Copies = 0x100,
|
|
|
|
|
|
DefaultSource = 0x200,
|
|
|
|
|
|
PrintQuality = 0x400,
|
|
|
|
|
|
Color = 0x800,
|
|
|
|
|
|
Duplex = 0x1000,
|
|
|
|
|
|
YResolution = 0x2000,
|
|
|
|
|
|
TTOption = 0x4000,
|
|
|
|
|
|
Collate = 0x8000,
|
|
|
|
|
|
FormName = 0x10000,
|
|
|
|
|
|
LogPixels = 0x20000,
|
|
|
|
|
|
BitsPerPixel = 0x40000,
|
|
|
|
|
|
PelsWidth = 0x80000,
|
|
|
|
|
|
PelsHeight = 0x100000,
|
|
|
|
|
|
DisplayFlags = 0x200000,
|
|
|
|
|
|
DisplayFrequency = 0x400000,
|
|
|
|
|
|
ICMMethod = 0x800000,
|
|
|
|
|
|
ICMIntent = 0x1000000,
|
|
|
|
|
|
MeduaType = 0x2000000,
|
|
|
|
|
|
DitherType = 0x4000000,
|
|
|
|
|
|
PanningWidth = 0x8000000,
|
|
|
|
|
|
PanningHeight = 0x10000000,
|
|
|
|
|
|
DisplayFixedOutput = 0x20000000
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
struct POINTL
|
2022-11-14 11:06:03 +01:00
|
|
|
|
{
|
2022-11-20 15:12:12 +01:00
|
|
|
|
public Int32 x;
|
|
|
|
|
|
public Int32 y;
|
|
|
|
|
|
};
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
|
|
|
|
|
|
struct DEVMODE
|
|
|
|
|
|
{
|
|
|
|
|
|
public const int CCHDEVICENAME = 32;
|
|
|
|
|
|
public const int CCHFORMNAME = 32;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(0)]
|
|
|
|
|
|
public string dmDeviceName;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(32)]
|
|
|
|
|
|
public Int16 dmSpecVersion;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(34)]
|
|
|
|
|
|
public Int16 dmDriverVersion;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(36)]
|
|
|
|
|
|
public Int16 dmSize;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(38)]
|
|
|
|
|
|
public Int16 dmDriverExtra;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(40)]
|
|
|
|
|
|
public DM dmFields;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(44)]
|
|
|
|
|
|
Int16 dmOrientation;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(46)]
|
|
|
|
|
|
Int16 dmPaperSize;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(48)]
|
|
|
|
|
|
Int16 dmPaperLength;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(50)]
|
|
|
|
|
|
Int16 dmPaperWidth;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(52)]
|
|
|
|
|
|
Int16 dmScale;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(54)]
|
|
|
|
|
|
Int16 dmCopies;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(56)]
|
|
|
|
|
|
Int16 dmDefaultSource;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(58)]
|
|
|
|
|
|
Int16 dmPrintQuality;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(44)]
|
|
|
|
|
|
public POINTL dmPosition;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(52)]
|
|
|
|
|
|
public Int32 dmDisplayOrientation;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(56)]
|
|
|
|
|
|
public Int32 dmDisplayFixedOutput;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(60)]
|
|
|
|
|
|
public short dmColor; // See note below!
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(62)]
|
|
|
|
|
|
public short dmDuplex; // See note below!
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(64)]
|
|
|
|
|
|
public short dmYResolution;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(66)]
|
|
|
|
|
|
public short dmTTOption;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(68)]
|
|
|
|
|
|
public short dmCollate; // See note below!
|
|
|
|
|
|
//[System.Runtime.InteropServices.FieldOffset(70)]
|
|
|
|
|
|
//[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
|
|
|
|
|
|
//public string dmFormName;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(102)]
|
|
|
|
|
|
public Int16 dmLogPixels;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(104)]
|
|
|
|
|
|
public Int32 dmBitsPerPel;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(108)]
|
|
|
|
|
|
public Int32 dmPelsWidth;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(112)]
|
|
|
|
|
|
public Int32 dmPelsHeight;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(116)]
|
|
|
|
|
|
public Int32 dmDisplayFlags;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(116)]
|
|
|
|
|
|
public Int32 dmNup;
|
|
|
|
|
|
[System.Runtime.InteropServices.FieldOffset(120)]
|
|
|
|
|
|
public Int32 dmDisplayFrequency;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[Flags()]
|
|
|
|
|
|
public enum ChangeDisplaySettingsFlags : uint
|
2022-11-14 11:06:03 +01:00
|
|
|
|
{
|
2022-11-20 15:12:12 +01:00
|
|
|
|
CDS_NONE = 0,
|
|
|
|
|
|
CDS_UPDATEREGISTRY = 0x00000001,
|
|
|
|
|
|
CDS_TEST = 0x00000002,
|
|
|
|
|
|
CDS_FULLSCREEN = 0x00000004,
|
|
|
|
|
|
CDS_GLOBAL = 0x00000008,
|
|
|
|
|
|
CDS_SET_PRIMARY = 0x00000010,
|
|
|
|
|
|
CDS_VIDEOPARAMETERS = 0x00000020,
|
|
|
|
|
|
CDS_ENABLE_UNSAFE_MODES = 0x00000100,
|
|
|
|
|
|
CDS_DISABLE_UNSAFE_MODES = 0x00000200,
|
|
|
|
|
|
CDS_RESET = 0x40000000,
|
|
|
|
|
|
CDS_RESET_EX = 0x20000000,
|
|
|
|
|
|
CDS_NORESET = 0x10000000
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
const int ENUM_CURRENT_SETTINGS = -1;
|
|
|
|
|
|
const int ENUM_REGISTRY_SETTINGS = -2;
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[DllImport("user32.dll")]
|
|
|
|
|
|
static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);
|
2022-11-14 11:06:03 +01:00
|
|
|
|
|
2022-11-20 15:12:12 +01:00
|
|
|
|
[DllImport("user32.dll")]
|
|
|
|
|
|
static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
|
|
|
|
|
|
}
|
2022-11-14 11:06:03 +01:00
|
|
|
|
}
|