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:
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using WindowsDisplayAPI;
|
||||||
|
|
||||||
namespace GHelper.Display
|
namespace GHelper.Display
|
||||||
{
|
{
|
||||||
@@ -7,6 +7,8 @@ namespace GHelper.Display
|
|||||||
|
|
||||||
public const int MAX_REFRESH = 1000;
|
public const int MAX_REFRESH = 1000;
|
||||||
|
|
||||||
|
public static DisplayGammaRamp? gamma;
|
||||||
|
|
||||||
public void AutoScreen(bool force = false)
|
public void AutoScreen(bool force = false)
|
||||||
{
|
{
|
||||||
if (force || AppConfig.Is("screen_auto"))
|
if (force || AppConfig.Is("screen_auto"))
|
||||||
@@ -22,6 +24,35 @@ namespace GHelper.Display
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SaveGamma()
|
||||||
|
{
|
||||||
|
var display = WindowsDisplayAPI.Display.GetDisplays().Where(x => x.DisplayScreen.IsPrimary).FirstOrDefault();
|
||||||
|
if (display is null) return;
|
||||||
|
|
||||||
|
gamma = display.GammaRamp;
|
||||||
|
|
||||||
|
Logger.WriteLine("R:" + string.Join("-", display.GammaRamp.Red));
|
||||||
|
Logger.WriteLine("G:" + string.Join("-", display.GammaRamp.Green));
|
||||||
|
Logger.WriteLine("B:" + string.Join("-", display.GammaRamp.Blue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RestoreGamma()
|
||||||
|
{
|
||||||
|
var display = WindowsDisplayAPI.Display.GetDisplays().Where(x => x.DisplayScreen.IsPrimary).FirstOrDefault();
|
||||||
|
if (gamma is not null) display!.GammaRamp = gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetGamma(int brightness = 100, int contrast = 100)
|
||||||
|
{
|
||||||
|
var display = WindowsDisplayAPI.Display.GetDisplays().Where(x => x.DisplayScreen.IsPrimary).FirstOrDefault();
|
||||||
|
var bright = (float)(brightness) / 100;
|
||||||
|
|
||||||
|
Logger.WriteLine("Brightness: " + bright.ToString());
|
||||||
|
|
||||||
|
display!.GammaRamp = new DisplayGammaRamp(bright, bright, 1);
|
||||||
|
//ScreenBrightness.Set(60 + (int)(40 * bright));
|
||||||
|
}
|
||||||
|
|
||||||
public void SetScreen(int frequency = -1, int overdrive = -1, int miniled = -1)
|
public void SetScreen(int frequency = -1, int overdrive = -1, int miniled = -1)
|
||||||
{
|
{
|
||||||
var laptopScreen = ScreenNative.FindLaptopScreen(true);
|
var laptopScreen = ScreenNative.FindLaptopScreen(true);
|
||||||
@@ -71,7 +102,8 @@ namespace GHelper.Display
|
|||||||
if (miniled1 >= 0)
|
if (miniled1 >= 0)
|
||||||
{
|
{
|
||||||
miniled = (miniled1 == 1) ? 0 : 1;
|
miniled = (miniled1 == 1) ? 0 : 1;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
switch (miniled2)
|
switch (miniled2)
|
||||||
{
|
{
|
||||||
|
|||||||
10
app/Properties/Resources.Designer.cs
generated
10
app/Properties/Resources.Designer.cs
generated
@@ -210,6 +210,16 @@ namespace GHelper.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap icons8_brightness_32 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("icons8-brightness-32", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -136,6 +136,9 @@
|
|||||||
<data name="icons8-bicycle-48 (1)" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-bicycle-48 (1)" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-bicycle-48 (1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-bicycle-48 (1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="standard" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\standard.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
<data name="eco" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="eco" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\eco.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\eco.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -163,9 +166,15 @@
|
|||||||
<data name="icons8-automation-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-automation-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-automation-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-automation-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="icons8-settings-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\icons8-settings-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
<data name="brightness_up" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="brightness_up" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\brightness-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\brightness-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="brightness_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\brightness-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
<data name="icons8_processor_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_processor_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-processor-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-processor-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -187,15 +196,9 @@
|
|||||||
<data name="icons8-laptop-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-laptop-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-laptop-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-laptop-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ally" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\ally.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="icons8_remove_64" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_remove_64" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-remove-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-remove-64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icons8_share_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\icons8-share-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="icons8_function" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_function" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-function-mac-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-function-mac-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -229,14 +232,11 @@
|
|||||||
<data name="icons8-xbox-rt-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-xbox-rt-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-xbox-rt-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-xbox-rt-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icons8_controller_96" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\icons8-controller-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="icons8-fan-48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-fan-48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-fan-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-fan-48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icons8-settings-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_controller_96" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-settings-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-controller-96.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icons8_maus_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_maus_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-maus-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-maus-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
@@ -250,8 +250,11 @@
|
|||||||
<data name="dot_ultimate" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="dot_ultimate" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\dot-ultimate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\dot-ultimate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="brightness_down" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-heartbeat-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\brightness-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-heartbeat-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
|
<data name="ally" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\ally.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="backlight_up" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="backlight_up" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\backlight-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\backlight-up.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
@@ -319,8 +322,8 @@
|
|||||||
<data name="icons8_software_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_software_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-software-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-software-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="standard" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8_share_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\standard.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-share-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icons8-soonvibes-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-soonvibes-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-soonvibes-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-soonvibes-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
@@ -331,7 +334,7 @@
|
|||||||
<data name="icons8-charging-battery-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-charging-battery-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-charging-battery-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-charging-battery-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="icons8-heartbeat-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="icons8-brightness-32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\icons8-heartbeat-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\icons8-brightness-32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
BIN
app/Resources/icons8-brightness-32.png
Normal file
BIN
app/Resources/icons8-brightness-32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 420 B |
180
app/Settings.Designer.cs
generated
180
app/Settings.Designer.cs
generated
@@ -34,6 +34,7 @@ namespace GHelper
|
|||||||
tableLayoutMatrix = new TableLayoutPanel();
|
tableLayoutMatrix = new TableLayoutPanel();
|
||||||
comboMatrix = new RComboBox();
|
comboMatrix = new RComboBox();
|
||||||
comboMatrixRunning = new RComboBox();
|
comboMatrixRunning = new RComboBox();
|
||||||
|
comboInterval = new RComboBox();
|
||||||
buttonMatrix = new RButton();
|
buttonMatrix = new RButton();
|
||||||
panelMatrixTitle = new Panel();
|
panelMatrixTitle = new Panel();
|
||||||
pictureMatrix = new PictureBox();
|
pictureMatrix = new PictureBox();
|
||||||
@@ -119,7 +120,14 @@ namespace GHelper
|
|||||||
panelAllyTitle = new Panel();
|
panelAllyTitle = new Panel();
|
||||||
pictureAlly = new PictureBox();
|
pictureAlly = new PictureBox();
|
||||||
labelAlly = new Label();
|
labelAlly = new Label();
|
||||||
comboInterval = new RComboBox();
|
panelGamma = new Panel();
|
||||||
|
sliderGamma = new Slider();
|
||||||
|
panelGammaTitle = new Panel();
|
||||||
|
buttonGammaLoad = new RButton();
|
||||||
|
buttonGammaSave = new RButton();
|
||||||
|
labelGamma = new Label();
|
||||||
|
pictureGamma = new PictureBox();
|
||||||
|
labelGammaTitle = new Label();
|
||||||
panelMatrix.SuspendLayout();
|
panelMatrix.SuspendLayout();
|
||||||
tableLayoutMatrix.SuspendLayout();
|
tableLayoutMatrix.SuspendLayout();
|
||||||
panelMatrixTitle.SuspendLayout();
|
panelMatrixTitle.SuspendLayout();
|
||||||
@@ -158,6 +166,9 @@ namespace GHelper
|
|||||||
tableLayoutAlly.SuspendLayout();
|
tableLayoutAlly.SuspendLayout();
|
||||||
panelAllyTitle.SuspendLayout();
|
panelAllyTitle.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)pictureAlly).BeginInit();
|
((System.ComponentModel.ISupportInitialize)pictureAlly).BeginInit();
|
||||||
|
panelGamma.SuspendLayout();
|
||||||
|
panelGammaTitle.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)pictureGamma).BeginInit();
|
||||||
SuspendLayout();
|
SuspendLayout();
|
||||||
//
|
//
|
||||||
// panelMatrix
|
// panelMatrix
|
||||||
@@ -169,7 +180,7 @@ namespace GHelper
|
|||||||
panelMatrix.Controls.Add(panelMatrixTitle);
|
panelMatrix.Controls.Add(panelMatrixTitle);
|
||||||
panelMatrix.Controls.Add(checkMatrix);
|
panelMatrix.Controls.Add(checkMatrix);
|
||||||
panelMatrix.Dock = DockStyle.Top;
|
panelMatrix.Dock = DockStyle.Top;
|
||||||
panelMatrix.Location = new Point(11, 827);
|
panelMatrix.Location = new Point(11, 950);
|
||||||
panelMatrix.Margin = new Padding(0);
|
panelMatrix.Margin = new Padding(0);
|
||||||
panelMatrix.Name = "panelMatrix";
|
panelMatrix.Name = "panelMatrix";
|
||||||
panelMatrix.Padding = new Padding(20, 20, 20, 10);
|
panelMatrix.Padding = new Padding(20, 20, 20, 10);
|
||||||
@@ -230,6 +241,21 @@ namespace GHelper
|
|||||||
comboMatrixRunning.Size = new Size(248, 40);
|
comboMatrixRunning.Size = new Size(248, 40);
|
||||||
comboMatrixRunning.TabIndex = 17;
|
comboMatrixRunning.TabIndex = 17;
|
||||||
//
|
//
|
||||||
|
// comboInterval
|
||||||
|
//
|
||||||
|
comboInterval.BorderColor = Color.White;
|
||||||
|
comboInterval.ButtonColor = Color.FromArgb(255, 255, 255);
|
||||||
|
comboInterval.Dock = DockStyle.Top;
|
||||||
|
comboInterval.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
|
||||||
|
comboInterval.FormattingEnabled = true;
|
||||||
|
comboInterval.ItemHeight = 32;
|
||||||
|
comboInterval.Location = new Point(7, 75);
|
||||||
|
comboInterval.Margin = new Padding(7, 11, 7, 8);
|
||||||
|
comboInterval.Name = "comboInterval";
|
||||||
|
comboInterval.Size = new Size(248, 40);
|
||||||
|
comboInterval.TabIndex = 19;
|
||||||
|
comboInterval.Visible = false;
|
||||||
|
//
|
||||||
// buttonMatrix
|
// buttonMatrix
|
||||||
//
|
//
|
||||||
buttonMatrix.Activated = false;
|
buttonMatrix.Activated = false;
|
||||||
@@ -301,7 +327,7 @@ namespace GHelper
|
|||||||
panelBattery.Controls.Add(sliderBattery);
|
panelBattery.Controls.Add(sliderBattery);
|
||||||
panelBattery.Controls.Add(panelBatteryTitle);
|
panelBattery.Controls.Add(panelBatteryTitle);
|
||||||
panelBattery.Dock = DockStyle.Top;
|
panelBattery.Dock = DockStyle.Top;
|
||||||
panelBattery.Location = new Point(11, 1485);
|
panelBattery.Location = new Point(11, 1608);
|
||||||
panelBattery.Margin = new Padding(0);
|
panelBattery.Margin = new Padding(0);
|
||||||
panelBattery.Name = "panelBattery";
|
panelBattery.Name = "panelBattery";
|
||||||
panelBattery.Padding = new Padding(20, 20, 20, 10);
|
panelBattery.Padding = new Padding(20, 20, 20, 10);
|
||||||
@@ -393,7 +419,7 @@ namespace GHelper
|
|||||||
panelFooter.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
panelFooter.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
panelFooter.Controls.Add(tableButtons);
|
panelFooter.Controls.Add(tableButtons);
|
||||||
panelFooter.Dock = DockStyle.Top;
|
panelFooter.Dock = DockStyle.Top;
|
||||||
panelFooter.Location = new Point(11, 1660);
|
panelFooter.Location = new Point(11, 1783);
|
||||||
panelFooter.Margin = new Padding(0);
|
panelFooter.Margin = new Padding(0);
|
||||||
panelFooter.Name = "panelFooter";
|
panelFooter.Name = "panelFooter";
|
||||||
panelFooter.Padding = new Padding(20);
|
panelFooter.Padding = new Padding(20);
|
||||||
@@ -1140,7 +1166,7 @@ namespace GHelper
|
|||||||
panelKeyboard.Controls.Add(tableLayoutKeyboard);
|
panelKeyboard.Controls.Add(tableLayoutKeyboard);
|
||||||
panelKeyboard.Controls.Add(panelKeyboardTitle);
|
panelKeyboard.Controls.Add(panelKeyboardTitle);
|
||||||
panelKeyboard.Dock = DockStyle.Top;
|
panelKeyboard.Dock = DockStyle.Top;
|
||||||
panelKeyboard.Location = new Point(11, 1143);
|
panelKeyboard.Location = new Point(11, 1266);
|
||||||
panelKeyboard.Margin = new Padding(0);
|
panelKeyboard.Margin = new Padding(0);
|
||||||
panelKeyboard.Name = "panelKeyboard";
|
panelKeyboard.Name = "panelKeyboard";
|
||||||
panelKeyboard.Padding = new Padding(20);
|
panelKeyboard.Padding = new Padding(20);
|
||||||
@@ -1316,7 +1342,7 @@ namespace GHelper
|
|||||||
panelVersion.Controls.Add(labelCharge);
|
panelVersion.Controls.Add(labelCharge);
|
||||||
panelVersion.Controls.Add(checkStartup);
|
panelVersion.Controls.Add(checkStartup);
|
||||||
panelVersion.Dock = DockStyle.Top;
|
panelVersion.Dock = DockStyle.Top;
|
||||||
panelVersion.Location = new Point(11, 1604);
|
panelVersion.Location = new Point(11, 1727);
|
||||||
panelVersion.Margin = new Padding(4);
|
panelVersion.Margin = new Padding(4);
|
||||||
panelVersion.Name = "panelVersion";
|
panelVersion.Name = "panelVersion";
|
||||||
panelVersion.Size = new Size(827, 56);
|
panelVersion.Size = new Size(827, 56);
|
||||||
@@ -1341,7 +1367,7 @@ namespace GHelper
|
|||||||
panelPeripherals.Controls.Add(tableLayoutPeripherals);
|
panelPeripherals.Controls.Add(tableLayoutPeripherals);
|
||||||
panelPeripherals.Controls.Add(panelPeripheralsTile);
|
panelPeripherals.Controls.Add(panelPeripheralsTile);
|
||||||
panelPeripherals.Dock = DockStyle.Top;
|
panelPeripherals.Dock = DockStyle.Top;
|
||||||
panelPeripherals.Location = new Point(11, 1287);
|
panelPeripherals.Location = new Point(11, 1410);
|
||||||
panelPeripherals.Margin = new Padding(0);
|
panelPeripherals.Margin = new Padding(0);
|
||||||
panelPeripherals.Name = "panelPeripherals";
|
panelPeripherals.Name = "panelPeripherals";
|
||||||
panelPeripherals.Padding = new Padding(20, 20, 20, 10);
|
panelPeripherals.Padding = new Padding(20, 20, 20, 10);
|
||||||
@@ -1483,7 +1509,7 @@ namespace GHelper
|
|||||||
panelAlly.Controls.Add(tableLayoutAlly);
|
panelAlly.Controls.Add(tableLayoutAlly);
|
||||||
panelAlly.Controls.Add(panelAllyTitle);
|
panelAlly.Controls.Add(panelAllyTitle);
|
||||||
panelAlly.Dock = DockStyle.Top;
|
panelAlly.Dock = DockStyle.Top;
|
||||||
panelAlly.Location = new Point(11, 1003);
|
panelAlly.Location = new Point(11, 1126);
|
||||||
panelAlly.Margin = new Padding(0);
|
panelAlly.Margin = new Padding(0);
|
||||||
panelAlly.Name = "panelAlly";
|
panelAlly.Name = "panelAlly";
|
||||||
panelAlly.Padding = new Padding(20, 20, 20, 0);
|
panelAlly.Padding = new Padding(20, 20, 20, 0);
|
||||||
@@ -1611,20 +1637,118 @@ namespace GHelper
|
|||||||
labelAlly.TabIndex = 26;
|
labelAlly.TabIndex = 26;
|
||||||
labelAlly.Text = "Ally Controller";
|
labelAlly.Text = "Ally Controller";
|
||||||
//
|
//
|
||||||
// comboInterval
|
// panelGamma
|
||||||
//
|
//
|
||||||
comboInterval.BorderColor = Color.White;
|
panelGamma.AutoSize = true;
|
||||||
comboInterval.ButtonColor = Color.FromArgb(255, 255, 255);
|
panelGamma.AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
comboInterval.Dock = DockStyle.Top;
|
panelGamma.Controls.Add(sliderGamma);
|
||||||
comboInterval.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
|
panelGamma.Controls.Add(panelGammaTitle);
|
||||||
comboInterval.FormattingEnabled = true;
|
panelGamma.Dock = DockStyle.Top;
|
||||||
comboInterval.ItemHeight = 32;
|
panelGamma.Location = new Point(11, 827);
|
||||||
comboInterval.Location = new Point(7, 75);
|
panelGamma.Margin = new Padding(0);
|
||||||
comboInterval.Margin = new Padding(7, 11, 7, 8);
|
panelGamma.Name = "panelGamma";
|
||||||
comboInterval.Name = "comboInterval";
|
panelGamma.Padding = new Padding(20, 20, 20, 10);
|
||||||
comboInterval.Size = new Size(248, 40);
|
panelGamma.Size = new Size(827, 123);
|
||||||
comboInterval.TabIndex = 19;
|
panelGamma.TabIndex = 9;
|
||||||
comboInterval.Visible = false;
|
//
|
||||||
|
// sliderGamma
|
||||||
|
//
|
||||||
|
sliderGamma.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
|
||||||
|
sliderGamma.Location = new Point(40, 69);
|
||||||
|
sliderGamma.Margin = new Padding(4);
|
||||||
|
sliderGamma.Max = 100;
|
||||||
|
sliderGamma.Min = 0;
|
||||||
|
sliderGamma.Name = "sliderGamma";
|
||||||
|
sliderGamma.Size = new Size(752, 40);
|
||||||
|
sliderGamma.Step = 10;
|
||||||
|
sliderGamma.TabIndex = 20;
|
||||||
|
sliderGamma.Text = "sliderGamma";
|
||||||
|
sliderGamma.Value = 100;
|
||||||
|
//
|
||||||
|
// panelGammaTitle
|
||||||
|
//
|
||||||
|
panelGammaTitle.Controls.Add(buttonGammaLoad);
|
||||||
|
panelGammaTitle.Controls.Add(buttonGammaSave);
|
||||||
|
panelGammaTitle.Controls.Add(labelGamma);
|
||||||
|
panelGammaTitle.Controls.Add(pictureGamma);
|
||||||
|
panelGammaTitle.Controls.Add(labelGammaTitle);
|
||||||
|
panelGammaTitle.Dock = DockStyle.Top;
|
||||||
|
panelGammaTitle.Location = new Point(20, 20);
|
||||||
|
panelGammaTitle.Margin = new Padding(4);
|
||||||
|
panelGammaTitle.Name = "panelGammaTitle";
|
||||||
|
panelGammaTitle.Padding = new Padding(0, 0, 0, 4);
|
||||||
|
panelGammaTitle.Size = new Size(787, 44);
|
||||||
|
panelGammaTitle.TabIndex = 40;
|
||||||
|
//
|
||||||
|
// buttonGammaLoad
|
||||||
|
//
|
||||||
|
buttonGammaLoad.Activated = false;
|
||||||
|
buttonGammaLoad.BackColor = SystemColors.ControlLight;
|
||||||
|
buttonGammaLoad.BorderColor = Color.Transparent;
|
||||||
|
buttonGammaLoad.BorderRadius = 2;
|
||||||
|
buttonGammaLoad.FlatAppearance.BorderSize = 0;
|
||||||
|
buttonGammaLoad.FlatStyle = FlatStyle.Flat;
|
||||||
|
buttonGammaLoad.Font = new Font("Segoe UI", 7.125F, FontStyle.Bold, GraphicsUnit.Point);
|
||||||
|
buttonGammaLoad.ForeColor = SystemColors.ControlDark;
|
||||||
|
buttonGammaLoad.Location = new Point(500, 4);
|
||||||
|
buttonGammaLoad.Margin = new Padding(0);
|
||||||
|
buttonGammaLoad.Name = "buttonGammaLoad";
|
||||||
|
buttonGammaLoad.Secondary = true;
|
||||||
|
buttonGammaLoad.Size = new Size(76, 36);
|
||||||
|
buttonGammaLoad.TabIndex = 41;
|
||||||
|
buttonGammaLoad.Text = "Load";
|
||||||
|
buttonGammaLoad.UseVisualStyleBackColor = false;
|
||||||
|
//
|
||||||
|
// buttonGammaSave
|
||||||
|
//
|
||||||
|
buttonGammaSave.Activated = false;
|
||||||
|
buttonGammaSave.BackColor = SystemColors.ControlLight;
|
||||||
|
buttonGammaSave.BorderColor = Color.Transparent;
|
||||||
|
buttonGammaSave.BorderRadius = 2;
|
||||||
|
buttonGammaSave.FlatAppearance.BorderSize = 0;
|
||||||
|
buttonGammaSave.FlatStyle = FlatStyle.Flat;
|
||||||
|
buttonGammaSave.Font = new Font("Segoe UI", 7.125F, FontStyle.Bold, GraphicsUnit.Point);
|
||||||
|
buttonGammaSave.ForeColor = SystemColors.ControlDark;
|
||||||
|
buttonGammaSave.Location = new Point(576, 4);
|
||||||
|
buttonGammaSave.Margin = new Padding(0);
|
||||||
|
buttonGammaSave.Name = "buttonGammaSave";
|
||||||
|
buttonGammaSave.Secondary = true;
|
||||||
|
buttonGammaSave.Size = new Size(75, 36);
|
||||||
|
buttonGammaSave.TabIndex = 40;
|
||||||
|
buttonGammaSave.Text = "Save";
|
||||||
|
buttonGammaSave.UseVisualStyleBackColor = false;
|
||||||
|
//
|
||||||
|
// labelGamma
|
||||||
|
//
|
||||||
|
labelGamma.Anchor = AnchorStyles.Top | AnchorStyles.Right;
|
||||||
|
labelGamma.Location = new Point(675, 4);
|
||||||
|
labelGamma.Margin = new Padding(8, 0, 8, 0);
|
||||||
|
labelGamma.Name = "labelGamma";
|
||||||
|
labelGamma.Size = new Size(107, 36);
|
||||||
|
labelGamma.TabIndex = 39;
|
||||||
|
labelGamma.Text = " ";
|
||||||
|
labelGamma.TextAlign = ContentAlignment.TopRight;
|
||||||
|
//
|
||||||
|
// pictureGamma
|
||||||
|
//
|
||||||
|
pictureGamma.BackgroundImage = Properties.Resources.icons8_brightness_32;
|
||||||
|
pictureGamma.BackgroundImageLayout = ImageLayout.Zoom;
|
||||||
|
pictureGamma.Location = new Point(4, 2);
|
||||||
|
pictureGamma.Margin = new Padding(4);
|
||||||
|
pictureGamma.Name = "pictureGamma";
|
||||||
|
pictureGamma.Size = new Size(32, 32);
|
||||||
|
pictureGamma.TabIndex = 38;
|
||||||
|
pictureGamma.TabStop = false;
|
||||||
|
//
|
||||||
|
// labelGammaTitle
|
||||||
|
//
|
||||||
|
labelGammaTitle.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
|
||||||
|
labelGammaTitle.Location = new Point(43, 0);
|
||||||
|
labelGammaTitle.Margin = new Padding(8, 0, 8, 0);
|
||||||
|
labelGammaTitle.Name = "labelGammaTitle";
|
||||||
|
labelGammaTitle.Size = new Size(307, 32);
|
||||||
|
labelGammaTitle.TabIndex = 37;
|
||||||
|
labelGammaTitle.Text = "Flicker-free Dimming";
|
||||||
//
|
//
|
||||||
// SettingsForm
|
// SettingsForm
|
||||||
//
|
//
|
||||||
@@ -1632,7 +1756,7 @@ namespace GHelper
|
|||||||
AutoScaleMode = AutoScaleMode.Dpi;
|
AutoScaleMode = AutoScaleMode.Dpi;
|
||||||
AutoSize = true;
|
AutoSize = true;
|
||||||
AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
AutoSizeMode = AutoSizeMode.GrowAndShrink;
|
||||||
ClientSize = new Size(849, 1717);
|
ClientSize = new Size(849, 2119);
|
||||||
Controls.Add(panelFooter);
|
Controls.Add(panelFooter);
|
||||||
Controls.Add(panelVersion);
|
Controls.Add(panelVersion);
|
||||||
Controls.Add(panelBattery);
|
Controls.Add(panelBattery);
|
||||||
@@ -1640,6 +1764,7 @@ namespace GHelper
|
|||||||
Controls.Add(panelKeyboard);
|
Controls.Add(panelKeyboard);
|
||||||
Controls.Add(panelAlly);
|
Controls.Add(panelAlly);
|
||||||
Controls.Add(panelMatrix);
|
Controls.Add(panelMatrix);
|
||||||
|
Controls.Add(panelGamma);
|
||||||
Controls.Add(panelScreen);
|
Controls.Add(panelScreen);
|
||||||
Controls.Add(panelGPU);
|
Controls.Add(panelGPU);
|
||||||
Controls.Add(panelPerformance);
|
Controls.Add(panelPerformance);
|
||||||
@@ -1708,6 +1833,9 @@ namespace GHelper
|
|||||||
panelAllyTitle.ResumeLayout(false);
|
panelAllyTitle.ResumeLayout(false);
|
||||||
panelAllyTitle.PerformLayout();
|
panelAllyTitle.PerformLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)pictureAlly).EndInit();
|
((System.ComponentModel.ISupportInitialize)pictureAlly).EndInit();
|
||||||
|
panelGamma.ResumeLayout(false);
|
||||||
|
panelGammaTitle.ResumeLayout(false);
|
||||||
|
((System.ComponentModel.ISupportInitialize)pictureGamma).EndInit();
|
||||||
ResumeLayout(false);
|
ResumeLayout(false);
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
}
|
}
|
||||||
@@ -1803,5 +1931,13 @@ namespace GHelper
|
|||||||
private RButton buttonController;
|
private RButton buttonController;
|
||||||
private RButton buttonOverlay;
|
private RButton buttonOverlay;
|
||||||
private RComboBox comboInterval;
|
private RComboBox comboInterval;
|
||||||
|
private Panel panelGamma;
|
||||||
|
private Slider sliderGamma;
|
||||||
|
private Panel panelGammaTitle;
|
||||||
|
private Label labelGamma;
|
||||||
|
private PictureBox pictureGamma;
|
||||||
|
private Label labelGammaTitle;
|
||||||
|
private RButton buttonGammaLoad;
|
||||||
|
private RButton buttonGammaSave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,9 +253,31 @@ namespace GHelper
|
|||||||
VisualiseFnLock();
|
VisualiseFnLock();
|
||||||
buttonFnLock.Click += ButtonFnLock_Click;
|
buttonFnLock.Click += ButtonFnLock_Click;
|
||||||
|
|
||||||
|
sliderGamma.ValueChanged += SliderGamma_ValueChanged;
|
||||||
|
labelGamma.Text = "100%";
|
||||||
|
|
||||||
|
buttonGammaSave.Click += ButtonGammaSave_Click;
|
||||||
|
buttonGammaLoad.Click += ButtonGammaLoad_Click;
|
||||||
|
|
||||||
panelPerformance.Focus();
|
panelPerformance.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ButtonGammaLoad_Click(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
screenControl.RestoreGamma();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ButtonGammaSave_Click(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
screenControl.SaveGamma();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SliderGamma_ValueChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
screenControl.SetGamma(sliderGamma.Value);
|
||||||
|
labelGamma.Text = sliderGamma.Value + "%";
|
||||||
|
}
|
||||||
|
|
||||||
private void ButtonOverlay_Click(object? sender, EventArgs e)
|
private void ButtonOverlay_Click(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
KeyboardHook.KeyKeyKeyPress(Keys.LControlKey, Keys.LShiftKey, Keys.O);
|
KeyboardHook.KeyKeyKeyPress(Keys.LControlKey, Keys.LShiftKey, Keys.O);
|
||||||
|
|||||||
11
app/WindowsDisplayAPI/ColorDepth.cs
Normal file
11
app/WindowsDisplayAPI/ColorDepth.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
public enum ColorDepth
|
||||||
|
{
|
||||||
|
Depth4Bit = 4,
|
||||||
|
Depth8Bit = 8,
|
||||||
|
Depth16Bit = 16, // 0x00000010
|
||||||
|
Depth24Bit = 24, // 0x00000018
|
||||||
|
Depth32Bit = 32 // 0x00000020
|
||||||
|
}
|
||||||
|
}
|
||||||
104
app/WindowsDisplayAPI/Device.cs
Normal file
104
app/WindowsDisplayAPI/Device.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Windows Video Device including Display Devices and Video Controllers
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Device
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Device
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="devicePath">The device path</param>
|
||||||
|
/// <param name="deviceName">The device name</param>
|
||||||
|
/// <param name="deviceKey">The device driver registry key</param>
|
||||||
|
protected Device(string devicePath, string deviceName, string deviceKey)
|
||||||
|
{
|
||||||
|
DevicePath = devicePath;
|
||||||
|
DeviceName = deviceName;
|
||||||
|
DeviceKey = deviceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the registry address of the device driver and configuration
|
||||||
|
/// </summary>
|
||||||
|
public virtual string DeviceKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Windows device name
|
||||||
|
/// </summary>
|
||||||
|
public virtual string DeviceName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Windows device path
|
||||||
|
/// </summary>
|
||||||
|
public virtual string DevicePath { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{GetType().Name}: {DeviceName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NETSTANDARD
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the registry key at the address specified by the DeviceKey property
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A RegistryKey instance for successful call, otherwise null</returns>
|
||||||
|
/// <exception cref="WindowsDisplayAPI.Exceptions.InvalidRegistryAddressException">Registry address is invalid or unknown.</exception>
|
||||||
|
public Microsoft.Win32.RegistryKey OpenDeviceKey()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(DeviceKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string machineRootName = "\\Registry\\Machine\\";
|
||||||
|
const string userRootName = "\\Registry\\Current\\";
|
||||||
|
|
||||||
|
if (DeviceKey.StartsWith(machineRootName, System.StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
return Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
|
||||||
|
DeviceKey.Substring(machineRootName.Length),
|
||||||
|
Microsoft.Win32.RegistryKeyPermissionCheck.ReadSubTree
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DeviceKey.StartsWith(userRootName, System.StringComparison.InvariantCultureIgnoreCase)) {
|
||||||
|
return Microsoft.Win32.Registry.Users.OpenSubKey(
|
||||||
|
DeviceKey.Substring(userRootName.Length),
|
||||||
|
Microsoft.Win32.RegistryKeyPermissionCheck.ReadSubTree
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exceptions.InvalidRegistryAddressException("Registry address is invalid or unknown.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the registry key of the Windows PnP manager for this device
|
||||||
|
/// </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("{", System.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
|
||||||
|
}
|
||||||
|
}
|
||||||
179
app/WindowsDisplayAPI/Display.cs
Normal file
179
app/WindowsDisplayAPI/Display.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.Exceptions;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Windows Attached Display Device
|
||||||
|
/// </summary>
|
||||||
|
public class Display : DisplayDevice
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Display
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The DisplayDevice instance to copy information from</param>
|
||||||
|
protected Display(DisplayDevice device)
|
||||||
|
: base(
|
||||||
|
device.DevicePath,
|
||||||
|
device.DeviceName,
|
||||||
|
device.DeviceKey,
|
||||||
|
device.Adapter,
|
||||||
|
device.IsAvailable,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display capabilities.
|
||||||
|
/// </summary>
|
||||||
|
public MonitorCapabilities Capabilities
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var handle = DCHandle.CreateFromDevice(ScreenName, DevicePath);
|
||||||
|
|
||||||
|
if (!IsValid || handle?.IsInvalid != false)
|
||||||
|
{
|
||||||
|
throw new InvalidDisplayException(DevicePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MonitorCapabilities(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string DisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsValid)
|
||||||
|
{
|
||||||
|
return DisplayAdapter.GetDisplayAdapters()
|
||||||
|
.SelectMany(adapter => adapter.GetDisplayDevices(base.IsAvailable))
|
||||||
|
.FirstOrDefault(
|
||||||
|
device => device.DevicePath.Equals(DevicePath) && device.DeviceKey.Equals(DeviceKey)
|
||||||
|
)?.DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToUnAttachedDisplay()?.DisplayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the display gamma ramp look up table.
|
||||||
|
/// </summary>
|
||||||
|
public DisplayGammaRamp GammaRamp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var handle = DCHandle.CreateFromDevice(ScreenName, DevicePath);
|
||||||
|
|
||||||
|
if (!IsValid || handle?.IsInvalid != false)
|
||||||
|
{
|
||||||
|
throw new InvalidDisplayException(DevicePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gammaRamp = new GammaRamp();
|
||||||
|
|
||||||
|
return DeviceContextApi.GetDeviceGammaRamp(handle, ref gammaRamp)
|
||||||
|
? new DisplayGammaRamp(gammaRamp)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var handle = DCHandle.CreateFromDevice(ScreenName, DevicePath);
|
||||||
|
|
||||||
|
if (!IsValid || handle?.IsInvalid != false)
|
||||||
|
{
|
||||||
|
throw new InvalidDisplayException(DevicePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gammaRamp = value.AsRamp();
|
||||||
|
|
||||||
|
if (!DeviceContextApi.SetDeviceGammaRamp(handle, ref gammaRamp))
|
||||||
|
{
|
||||||
|
//throw new ArgumentException("Invalid argument or value passed.", nameof(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsAvailable
|
||||||
|
{
|
||||||
|
get => base.IsAvailable && IsValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool IsValid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return DisplayAdapter.GetDisplayAdapters()
|
||||||
|
.SelectMany(adapter => adapter.GetDisplayDevices(base.IsAvailable))
|
||||||
|
.Any(
|
||||||
|
device => device.DevicePath.Equals(DevicePath) && device.DeviceKey.Equals(DeviceKey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ScreenName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IsValid)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
DisplayAdapter.GetDisplayAdapters()
|
||||||
|
.SelectMany(adapter => adapter.GetDisplayDevices(base.IsAvailable))
|
||||||
|
.FirstOrDefault(
|
||||||
|
device => device.DevicePath.Equals(DevicePath) && device.DeviceKey.Equals(DeviceKey)
|
||||||
|
)?.ScreenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToUnAttachedDisplay()?.ScreenName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of all attached displays on this machine
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerable list of Displays</returns>
|
||||||
|
public static IEnumerable<Display> GetDisplays()
|
||||||
|
{
|
||||||
|
return DisplayAdapter.GetDisplayAdapters()
|
||||||
|
.SelectMany(adapter => adapter.GetDisplayDevices(true))
|
||||||
|
.Select(device => new Display(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return IsValid ? $"{GetType().Name}: {DisplayName} ({DeviceName})" : $"{GetType().Name}: Invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the corresponding UnAttachedDisplay device for this display. Only valid when this instance is invalidated
|
||||||
|
/// due to display detachment.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public UnAttachedDisplay ToUnAttachedDisplay()
|
||||||
|
{
|
||||||
|
if (IsValid)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnAttachedDisplay.GetUnAttachedDisplays()
|
||||||
|
.FirstOrDefault(
|
||||||
|
display => display.DevicePath.Equals(DevicePath) && display.DeviceKey.Equals(DeviceKey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
123
app/WindowsDisplayAPI/DisplayAdapter.cs
Normal file
123
app/WindowsDisplayAPI/DisplayAdapter.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Windows Video Controller Display Adapter Device
|
||||||
|
/// </summary>
|
||||||
|
public class DisplayAdapter : Device
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new DisplayAdapter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="devicePath">The device path</param>
|
||||||
|
/// <param name="deviceName">The device name</param>
|
||||||
|
/// <param name="deviceKey">The device driver registry key</param>
|
||||||
|
protected DisplayAdapter(string devicePath, string deviceName, string deviceKey)
|
||||||
|
: base(devicePath, deviceName, deviceKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of all display adapters on this machine
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerable list of DisplayAdapters</returns>
|
||||||
|
public static IEnumerable<DisplayAdapter> GetDisplayAdapters()
|
||||||
|
{
|
||||||
|
var device = Native.DeviceContext.Structures.DisplayDevice.Initialize();
|
||||||
|
var deviceIds = new List<string>();
|
||||||
|
|
||||||
|
for (uint i = 0; DeviceContextApi.EnumDisplayDevices(null, i, ref device, 0); i++)
|
||||||
|
{
|
||||||
|
if (!deviceIds.Contains(device.DeviceId))
|
||||||
|
{
|
||||||
|
deviceIds.Add(device.DeviceId);
|
||||||
|
|
||||||
|
yield return new DisplayAdapter(device.DeviceId, device.DeviceString, device.DeviceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
device = Native.DeviceContext.Structures.DisplayDevice.Initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of all display devices connected to this adapter
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerable list of DisplayDevices</returns>
|
||||||
|
public IEnumerable<DisplayDevice> GetDisplayDevices()
|
||||||
|
{
|
||||||
|
return GetDisplayDevices(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the corresponding PathDisplayAdapter instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An instance of PathDisplayAdapter, or null</returns>
|
||||||
|
public PathDisplayAdapter ToPathDisplayAdapter()
|
||||||
|
{
|
||||||
|
return PathDisplayAdapter.GetAdapters()
|
||||||
|
.FirstOrDefault(adapter =>
|
||||||
|
adapter.DevicePath.StartsWith("\\\\?\\" + DevicePath.Replace("\\", "#"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IEnumerable<DisplayDevice> GetDisplayDevices(bool? filterByAvailability)
|
||||||
|
{
|
||||||
|
var returned = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
var adapterIndex = -1;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
adapterIndex++;
|
||||||
|
var adapter = Native.DeviceContext.Structures.DisplayDevice.Initialize();
|
||||||
|
|
||||||
|
if (!DeviceContextApi.EnumDisplayDevices(null, (uint) adapterIndex, ref adapter, 0))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DevicePath.Equals(adapter.DeviceId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayIndex = -1;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
displayIndex++;
|
||||||
|
var display = Native.DeviceContext.Structures.DisplayDevice.Initialize();
|
||||||
|
|
||||||
|
if (!DeviceContextApi.EnumDisplayDevices(adapter.DeviceName, (uint) displayIndex, ref display, 1))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayDevice = DisplayDevice.FromDeviceInformation(this, adapter, display);
|
||||||
|
|
||||||
|
if (!filterByAvailability.HasValue)
|
||||||
|
{
|
||||||
|
yield return displayDevice;
|
||||||
|
}
|
||||||
|
else if (displayDevice.IsAvailable == filterByAvailability.Value)
|
||||||
|
{
|
||||||
|
if (returned.ContainsKey(display.DeviceId) &&
|
||||||
|
returned[display.DeviceId].Equals(display.DeviceKey)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
returned.Add(display.DeviceId, display.DeviceKey);
|
||||||
|
|
||||||
|
yield return displayDevice;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
269
app/WindowsDisplayAPI/DisplayCapabilities.cs
Normal file
269
app/WindowsDisplayAPI/DisplayCapabilities.cs
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
using System;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information about the device capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MonitorCapabilities : IDisposable
|
||||||
|
{
|
||||||
|
private readonly DCHandle _dcHandle;
|
||||||
|
|
||||||
|
internal MonitorCapabilities(DCHandle dcHandle)
|
||||||
|
{
|
||||||
|
_dcHandle = dcHandle;
|
||||||
|
|
||||||
|
var tech = (DisplayTechnology) DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.Technology);
|
||||||
|
|
||||||
|
if (tech != DisplayTechnology.RasterDisplay)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual color resolution of the device, in bits per pixel.
|
||||||
|
/// </summary>
|
||||||
|
public int ActualColorDepth
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.ColorResolution) * ColorPlanes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if the device is capable of clipping to a rectangle.
|
||||||
|
/// </summary>
|
||||||
|
public bool ClipToRectangleCapability
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.ClipCapabilities) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color management capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayColorManagementCapabilities ColorManagementCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayColorManagementCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.ColorManagementCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of color planes.
|
||||||
|
/// </summary>
|
||||||
|
public int ColorPlanes
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.Planes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the curve capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayCurveCapabilities CurveCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayCurveCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.CurveCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the diagonal width of the device pixel used for line drawing.
|
||||||
|
/// </summary>
|
||||||
|
public int DevicePixelDiagonalWidth
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.HypotenuseAspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the relative height of a device pixel used for line drawing.
|
||||||
|
/// </summary>
|
||||||
|
public int DevicePixelRelativeHeight
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.VerticalAspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the relative width of a device pixel used for line drawing.
|
||||||
|
/// </summary>
|
||||||
|
public int DevicePixelRelativeWidth
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.HorizontalAspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the diagonal length of the physical screen in millimeters.
|
||||||
|
/// </summary>
|
||||||
|
public int DiagonalSizeInMM
|
||||||
|
{
|
||||||
|
get => (int) Math.Round(Math.Pow(Math.Pow(VerticalSizeInMM, 2) + Math.Pow(HorizontalSizeInMM, 2), 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the device driver version.
|
||||||
|
/// </summary>
|
||||||
|
public int DriverVersion
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.DriverVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the effective color resolution of the device, in bits per pixel.
|
||||||
|
/// </summary>
|
||||||
|
public int EffectiveColorDepth
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.BitsPerPixel) * ColorPlanes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of pixels per logical inch along the screen width.
|
||||||
|
/// </summary>
|
||||||
|
public int HorizontalPixelPerInch
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.HorizontalLogicalPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of screen in raster lines.
|
||||||
|
/// </summary>
|
||||||
|
public int HorizontalResolution
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.HorizontalResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width of the physical screen in millimeters.
|
||||||
|
/// </summary>
|
||||||
|
public int HorizontalSizeInMM
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.HorizontalSizeInMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayLineCapabilities LineCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayLineCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.LineCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the polygon capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayPolygonalCapabilities PolygonalCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayPolygonalCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.PolygonalCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the preferred horizontal drawing alignment, expressed as a multiple of pixels. For best drawing performance,
|
||||||
|
/// windows should be horizontally aligned to a multiple of this value. A value of null indicates that the device is
|
||||||
|
/// accelerated, and any alignment may be used.
|
||||||
|
/// </summary>
|
||||||
|
public int? PreferredHorizontalDrawingAlignment
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var value = DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.PreferredBLTAlignment);
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the raster capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayRasterCapabilities RasterCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayRasterCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.RasterCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the shader blending capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayShaderBlendingCapabilities ShaderBlendingCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayShaderBlendingCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.ShadeBlendingCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text capabilities of the device
|
||||||
|
/// </summary>
|
||||||
|
public DisplayTextCapabilities TextCapabilities
|
||||||
|
{
|
||||||
|
get => (DisplayTextCapabilities) DeviceContextApi.GetDeviceCaps(
|
||||||
|
_dcHandle,
|
||||||
|
DeviceCapability.TextCapabilities
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of pixels per logical inch along the screen height.
|
||||||
|
/// </summary>
|
||||||
|
public int VerticalPixelPerInch
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.VerticalLogicalPixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current vertical refresh rate of the device, in cycles per second (Hz) or null for display hardware's
|
||||||
|
/// default refresh rate.
|
||||||
|
/// </summary>
|
||||||
|
public int? VerticalRefreshRateInHz
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var value = DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.VerticalRefreshRateInHz);
|
||||||
|
|
||||||
|
if (value <= 1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width of the screen in pixels.
|
||||||
|
/// </summary>
|
||||||
|
public int VerticalResolution
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.VerticalResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of the physical screen in millimeters.
|
||||||
|
/// </summary>
|
||||||
|
public int VerticalSizeInMM
|
||||||
|
{
|
||||||
|
get => DeviceContextApi.GetDeviceCaps(_dcHandle, DeviceCapability.VerticalSizeInMM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_dcHandle?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
app/WindowsDisplayAPI/DisplayColorManagementCapabilities.cs
Normal file
31
app/WindowsDisplayAPI/DisplayColorManagementCapabilities.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible color management capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayColorManagementCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Device does not support ICM.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can perform ICM on either the device driver or the device itself.
|
||||||
|
/// </summary>
|
||||||
|
DeviceICM = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device supports gamma ramp modification and retrieval
|
||||||
|
/// </summary>
|
||||||
|
GammaRamp = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can accept CMYK color space ICC color profile.
|
||||||
|
/// </summary>
|
||||||
|
CMYKColor = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
190
app/WindowsDisplayAPI/DisplayConfig/PathDisplayAdapter.cs
Normal file
190
app/WindowsDisplayAPI/DisplayConfig/PathDisplayAdapter.cs
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a path display adapter
|
||||||
|
/// </summary>
|
||||||
|
public class PathDisplayAdapter : IEquatable<PathDisplayAdapter>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathDisplayAdapter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="adapterId">The adapter local unique identification</param>
|
||||||
|
public PathDisplayAdapter(LUID adapterId)
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display adapter local identification LUID
|
||||||
|
/// </summary>
|
||||||
|
public LUID AdapterId { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display adapter device path
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||||
|
public string DevicePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var adapterName = new DisplayConfigAdapterName(AdapterId);
|
||||||
|
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref adapterName);
|
||||||
|
|
||||||
|
if (result == Win32Status.Success)
|
||||||
|
{
|
||||||
|
return adapterName.AdapterDevicePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Win32Exception((int) result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating the instance validity
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInvalid
|
||||||
|
{
|
||||||
|
get => AdapterId.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(PathDisplayAdapter other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReferenceEquals(this, other))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AdapterId == other.AdapterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieving a list of all adapters from the currently active and inactive paths
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of PathDisplayAdapter instances</returns>
|
||||||
|
public static PathDisplayAdapter[] GetAdapters()
|
||||||
|
{
|
||||||
|
var adapters = new Dictionary<LUID, PathDisplayAdapter>();
|
||||||
|
|
||||||
|
foreach (var pathInfo in PathInfo.GetAllPaths())
|
||||||
|
{
|
||||||
|
if (!pathInfo.DisplaySource.Adapter.IsInvalid &&
|
||||||
|
!adapters.ContainsKey(pathInfo.DisplaySource.Adapter.AdapterId))
|
||||||
|
{
|
||||||
|
adapters.Add(pathInfo.DisplaySource.Adapter.AdapterId, pathInfo.DisplaySource.Adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pathTargetInfo in pathInfo.TargetsInfo)
|
||||||
|
{
|
||||||
|
if (!pathTargetInfo.DisplayTarget.Adapter.IsInvalid &&
|
||||||
|
!adapters.ContainsKey(pathTargetInfo.DisplayTarget.Adapter.AdapterId))
|
||||||
|
{
|
||||||
|
adapters.Add(pathTargetInfo.DisplayTarget.Adapter.AdapterId, pathTargetInfo.DisplayTarget.Adapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return adapters.Values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for equality of two PathDisplayAdapter 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 ==(PathDisplayAdapter left, PathDisplayAdapter right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left?.Equals(right) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for inequality of two PathDisplayAdapter 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 !=(PathDisplayAdapter left, PathDisplayAdapter 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((PathDisplayAdapter) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return AdapterId.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return DevicePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NETSTANDARD
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the registry key of the Windows PnP manager for this display adapter
|
||||||
|
/// </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>
|
||||||
|
/// Gets the corresponding DisplayAdapter instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An instance of DisplayAdapter, or null</returns>
|
||||||
|
public DisplayAdapter ToDisplayAdapter()
|
||||||
|
{
|
||||||
|
return DisplayAdapter.GetDisplayAdapters()
|
||||||
|
.FirstOrDefault(
|
||||||
|
adapter => DevicePath.StartsWith("\\\\?\\" + adapter.DevicePath.Replace("\\", "#"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
238
app/WindowsDisplayAPI/DisplayConfig/PathDisplaySource.cs
Normal file
238
app/WindowsDisplayAPI/DisplayConfig/PathDisplaySource.cs
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a display path source
|
||||||
|
/// </summary>
|
||||||
|
public class PathDisplaySource : IEquatable<PathDisplaySource>
|
||||||
|
{
|
||||||
|
private static readonly DisplayConfigSourceDPIScale[] DPIScales = Enum
|
||||||
|
.GetValues(typeof(DisplayConfigSourceDPIScale))
|
||||||
|
.Cast<DisplayConfigSourceDPIScale>()
|
||||||
|
.OrderBy(scaling => (uint) scaling)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathDisplaySource
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="adapter">Display adapter</param>
|
||||||
|
/// <param name="sourceId">Display source identification</param>
|
||||||
|
public PathDisplaySource(PathDisplayAdapter adapter, uint sourceId)
|
||||||
|
{
|
||||||
|
Adapter = adapter;
|
||||||
|
SourceId = sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path display adapter
|
||||||
|
/// </summary>
|
||||||
|
public PathDisplayAdapter Adapter { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets and sets the current source DPI scaling
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigSourceDPIScale CurrentDPIScale
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dpiScale = new DisplayConfigGetSourceDPIScale(Adapter.AdapterId, SourceId);
|
||||||
|
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref dpiScale);
|
||||||
|
|
||||||
|
if (result != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new Win32Exception((int) result);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentScaleIndex = Math.Abs(dpiScale.MinimumScaleSteps) + dpiScale.CurrentScaleSteps;
|
||||||
|
|
||||||
|
return DPIScales[currentScaleIndex];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var currentScaleStep = Array.IndexOf(DPIScales, value) - Array.IndexOf(DPIScales, RecommendedDPIScale);
|
||||||
|
|
||||||
|
var dpiScale = new DisplayConfigSetSourceDPIScale(Adapter.AdapterId, SourceId, currentScaleStep);
|
||||||
|
var result = DisplayConfigApi.DisplayConfigSetDeviceInfo(ref dpiScale);
|
||||||
|
|
||||||
|
if (result != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new Win32Exception((int) result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the corresponding <see cref="DisplayScreen"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public DisplayScreen ToScreen()
|
||||||
|
{
|
||||||
|
return DisplayScreen.GetScreens().FirstOrDefault(info => info.ScreenName.Equals(DisplayName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display name
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="Win32Exception">Error code can be retrieved from Win32Exception.NativeErrorCode property</exception>
|
||||||
|
public string DisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var sourceName = new DisplayConfigSourceDeviceName(Adapter.AdapterId, SourceId);
|
||||||
|
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref sourceName);
|
||||||
|
|
||||||
|
if (result == Win32Status.Success)
|
||||||
|
{
|
||||||
|
return sourceName.DeviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Win32Exception((int) result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the maximum DPI scaling for this source
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigSourceDPIScale MaximumDPIScale
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dpiScale = new DisplayConfigGetSourceDPIScale(Adapter.AdapterId, SourceId);
|
||||||
|
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref dpiScale);
|
||||||
|
|
||||||
|
if (result != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new Win32Exception((int) result);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentScaleIndex = Math.Abs(dpiScale.MinimumScaleSteps) + dpiScale.MaximumScaleSteps;
|
||||||
|
|
||||||
|
return DPIScales[currentScaleIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the recommended DPI scaling for this source
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigSourceDPIScale RecommendedDPIScale
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dpiScale = new DisplayConfigGetSourceDPIScale(Adapter.AdapterId, SourceId);
|
||||||
|
var result = DisplayConfigApi.DisplayConfigGetDeviceInfo(ref dpiScale);
|
||||||
|
|
||||||
|
if (result != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new Win32Exception((int) result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DPIScales[Math.Abs(dpiScale.MinimumScaleSteps)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the zero based display identification
|
||||||
|
/// </summary>
|
||||||
|
public uint SourceId { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(PathDisplaySource other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReferenceEquals(this, other))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Adapter == other.Adapter && SourceId == other.SourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieving a list of all display sources from the currently active and inactive paths
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of PathDisplaySource instances</returns>
|
||||||
|
public static PathDisplaySource[] GetDisplaySources()
|
||||||
|
{
|
||||||
|
var sources = new Dictionary<Tuple<LUID, uint>, PathDisplaySource>();
|
||||||
|
|
||||||
|
foreach (var pathInfo in PathInfo.GetAllPaths())
|
||||||
|
{
|
||||||
|
var key = Tuple.Create(
|
||||||
|
pathInfo.DisplaySource.Adapter.AdapterId,
|
||||||
|
pathInfo.DisplaySource.SourceId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!pathInfo.DisplaySource.Adapter.IsInvalid && !sources.ContainsKey(key))
|
||||||
|
{
|
||||||
|
sources.Add(key, pathInfo.DisplaySource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sources.Values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for equality of two PathDisplaySource 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 ==(PathDisplaySource left, PathDisplaySource right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left?.Equals(right) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for inequality of two PathDisplaySource 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 !=(PathDisplaySource left, PathDisplaySource 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((PathDisplaySource) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return ((Adapter != null ? Adapter.GetHashCode() : 0) * 397) ^ (int) SourceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return DisplayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
910
app/WindowsDisplayAPI/DisplayConfig/PathInfo.cs
Normal file
910
app/WindowsDisplayAPI/DisplayConfig/PathInfo.cs
Normal file
@@ -0,0 +1,910 @@
|
|||||||
|
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 path root information
|
||||||
|
/// </summary>
|
||||||
|
public class PathInfo
|
||||||
|
{
|
||||||
|
private readonly uint _cloneGroupId;
|
||||||
|
private readonly DisplayConfigPixelFormat _pixelFormat;
|
||||||
|
private readonly Point _position;
|
||||||
|
private readonly Size _resolution;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="position">The display position in desktop</param>
|
||||||
|
/// <param name="resolution">The display resolution</param>
|
||||||
|
/// <param name="pixelFormat">The display pixel format</param>
|
||||||
|
public PathInfo(
|
||||||
|
PathDisplaySource displaySource,
|
||||||
|
Point position,
|
||||||
|
Size resolution,
|
||||||
|
DisplayConfigPixelFormat pixelFormat
|
||||||
|
) : this(displaySource)
|
||||||
|
{
|
||||||
|
_position = position;
|
||||||
|
_resolution = resolution;
|
||||||
|
_pixelFormat = pixelFormat;
|
||||||
|
IsModeInformationAvailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="position">The display position in desktop</param>
|
||||||
|
/// <param name="resolution">The display resolution</param>
|
||||||
|
/// <param name="pixelFormat">The display pixel format</param>
|
||||||
|
/// <param name="cloneGroup">The display clone group, only valid for virtual aware paths</param>
|
||||||
|
public PathInfo(
|
||||||
|
PathDisplaySource displaySource,
|
||||||
|
Point position,
|
||||||
|
Size resolution,
|
||||||
|
DisplayConfigPixelFormat pixelFormat,
|
||||||
|
uint cloneGroup
|
||||||
|
) : this(displaySource, cloneGroup)
|
||||||
|
{
|
||||||
|
_position = position;
|
||||||
|
_resolution = resolution;
|
||||||
|
_pixelFormat = pixelFormat;
|
||||||
|
IsModeInformationAvailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="position">The display position in desktop</param>
|
||||||
|
/// <param name="resolution">The display resolution</param>
|
||||||
|
/// <param name="pixelFormat">The display pixel format</param>
|
||||||
|
/// <param name="pathTargetInfos">An array of target information</param>
|
||||||
|
public PathInfo(
|
||||||
|
PathDisplaySource displaySource,
|
||||||
|
Point position,
|
||||||
|
Size resolution,
|
||||||
|
DisplayConfigPixelFormat pixelFormat,
|
||||||
|
PathTargetInfo[] pathTargetInfos
|
||||||
|
) : this(displaySource, position, resolution, pixelFormat)
|
||||||
|
{
|
||||||
|
TargetsInfo = pathTargetInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="position">The display position in desktop</param>
|
||||||
|
/// <param name="resolution">The display resolution</param>
|
||||||
|
/// <param name="pixelFormat">The display pixel format</param>
|
||||||
|
/// <param name="pathTargetInfos">An array of target information</param>
|
||||||
|
/// <param name="cloneGroup">The display clone group, only valid for virtual aware paths</param>
|
||||||
|
public PathInfo(
|
||||||
|
PathDisplaySource displaySource,
|
||||||
|
Point position,
|
||||||
|
Size resolution,
|
||||||
|
DisplayConfigPixelFormat pixelFormat,
|
||||||
|
PathTargetInfo[] pathTargetInfos,
|
||||||
|
uint cloneGroup
|
||||||
|
) : this(displaySource, position, resolution, pixelFormat, cloneGroup)
|
||||||
|
{
|
||||||
|
TargetsInfo = pathTargetInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
public PathInfo(PathDisplaySource displaySource)
|
||||||
|
{
|
||||||
|
DisplaySource = displaySource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="cloneGroup">The display clone group, only valid for virtual aware paths</param>
|
||||||
|
public PathInfo(PathDisplaySource displaySource, uint cloneGroup) : this(displaySource)
|
||||||
|
{
|
||||||
|
IsCloneMember = true;
|
||||||
|
_cloneGroupId = cloneGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="pathTargetInfos">An array of target information</param>
|
||||||
|
public PathInfo(
|
||||||
|
PathDisplaySource displaySource,
|
||||||
|
PathTargetInfo[] pathTargetInfos
|
||||||
|
) : this(displaySource)
|
||||||
|
{
|
||||||
|
TargetsInfo = pathTargetInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySource">The display source</param>
|
||||||
|
/// <param name="pathTargetInfos">An array of target information</param>
|
||||||
|
/// <param name="cloneGroup">The display clone group, only valid for virtual aware paths</param>
|
||||||
|
public PathInfo(
|
||||||
|
PathDisplaySource displaySource,
|
||||||
|
PathTargetInfo[] pathTargetInfos,
|
||||||
|
uint cloneGroup
|
||||||
|
) : this(displaySource, cloneGroup)
|
||||||
|
{
|
||||||
|
TargetsInfo = pathTargetInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PathInfo(
|
||||||
|
DisplayConfigPathSourceInfo sourceInfo,
|
||||||
|
DisplayConfigSourceMode? sourceMode,
|
||||||
|
IEnumerable<
|
||||||
|
Tuple<
|
||||||
|
DisplayConfigPathInfoFlags,
|
||||||
|
DisplayConfigPathTargetInfo,
|
||||||
|
DisplayConfigTargetMode?,
|
||||||
|
DisplayConfigDesktopImageInfo?
|
||||||
|
>
|
||||||
|
> targets
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DisplaySource = new PathDisplaySource(new PathDisplayAdapter(sourceInfo.AdapterId), sourceInfo.SourceId);
|
||||||
|
|
||||||
|
IsInUse = sourceInfo.StatusFlags.HasFlag(DisplayConfigPathSourceInfoFlags.InUse);
|
||||||
|
IsModeInformationAvailable = sourceMode.HasValue;
|
||||||
|
|
||||||
|
if (sourceMode.HasValue)
|
||||||
|
{
|
||||||
|
_resolution = new Size((int) sourceMode.Value.Width, (int) sourceMode.Value.Height);
|
||||||
|
_pixelFormat = sourceMode.Value.PixelFormat;
|
||||||
|
_position = new Point(sourceMode.Value.Position.X, sourceMode.Value.Position.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetsInfo = targets.Select(t => new PathTargetInfo(t.Item1, t.Item2, t.Item3, t.Item4)).ToArray();
|
||||||
|
|
||||||
|
if (TargetsInfo.Any(info => info.IsVirtualModeSupportedByPath) &&
|
||||||
|
sourceInfo.CloneGroupId != DisplayConfigPathSourceInfo.InvalidCloneGroupId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_cloneGroupId = sourceInfo.CloneGroupId;
|
||||||
|
IsCloneMember = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a valid identifier used to show which clone group the path is a member of
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="NotACloneMemberException">This path is not a clone member</exception>
|
||||||
|
public uint CloneGroupId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsCloneMember)
|
||||||
|
{
|
||||||
|
throw new NotACloneMemberException(
|
||||||
|
"The display source is not part of a clone group."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cloneGroupId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets extra information about the representing display source
|
||||||
|
/// </summary>
|
||||||
|
public PathDisplaySource DisplaySource { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this path is a member of a clone group
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCloneMember { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this path is the primary GDI path
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingModeException">Source mode information is missing</exception>
|
||||||
|
public bool IsGDIPrimary
|
||||||
|
{
|
||||||
|
get => Position.IsEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if the source is in use by at least one active path
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInUse { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if the source mode information is available
|
||||||
|
/// </summary>
|
||||||
|
public bool IsModeInformationAvailable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating the DisplayConfig (CCD API) availability on this system
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsSupported
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return DisplayConfigApi.GetDisplayConfigBufferSizes(
|
||||||
|
QueryDeviceConfigFlags.AllPaths,
|
||||||
|
out _,
|
||||||
|
out _
|
||||||
|
) == Win32Status.Success;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating the virtual display mode support on this system
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsVirtualModeSupported
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return PathDisplayTarget
|
||||||
|
.GetDisplayTargets()
|
||||||
|
.Any(t => t.VirtualResolutionSupport);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the specifies the pixel format of the source mode
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingModeException">Source mode information is missing</exception>
|
||||||
|
public DisplayConfigPixelFormat PixelFormat
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsModeInformationAvailable)
|
||||||
|
{
|
||||||
|
throw new MissingModeException(
|
||||||
|
"Source mode information is missing or not available.",
|
||||||
|
DisplayConfigModeInfoType.Source
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _pixelFormat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position in the desktop coordinate space of the upper-left corner of this source surface. The source
|
||||||
|
/// surface that is located at (0, 0) is always the primary source surface.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingModeException">Source mode information is missing</exception>
|
||||||
|
public Point Position
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsModeInformationAvailable)
|
||||||
|
{
|
||||||
|
throw new MissingModeException(
|
||||||
|
"Source mode information is missing or not available.",
|
||||||
|
DisplayConfigModeInfoType.Source
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of the source mode
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingModeException">Source mode information is missing</exception>
|
||||||
|
public Size Resolution
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsModeInformationAvailable)
|
||||||
|
{
|
||||||
|
throw new MissingModeException(
|
||||||
|
"Source mode information is missing or not available.",
|
||||||
|
DisplayConfigModeInfoType.Source
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _resolution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of target information
|
||||||
|
/// </summary>
|
||||||
|
public PathTargetInfo[] TargetsInfo { get; } = new PathTargetInfo[0];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies an array of paths
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pathInfos">The array of paths</param>
|
||||||
|
/// <param name="allowChanges">true to allow changes and reordering of the provided paths, otherwise false</param>
|
||||||
|
/// <param name="saveToDatabase">true to save the paths to the persistence database if call succeed, otherwise false</param>
|
||||||
|
/// <param name="forceModeEnumeration">true to force driver mode enumeration before applying the paths</param>
|
||||||
|
/// <exception cref="PathChangeException">Error in changing paths</exception>
|
||||||
|
public static void ApplyPathInfos(
|
||||||
|
IEnumerable<PathInfo> pathInfos,
|
||||||
|
bool allowChanges = true,
|
||||||
|
bool saveToDatabase = false,
|
||||||
|
bool forceModeEnumeration = false
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var pathInfosArray = pathInfos.ToArray();
|
||||||
|
|
||||||
|
if (!ValidatePathInfos(pathInfosArray, allowChanges))
|
||||||
|
{
|
||||||
|
throw new PathChangeException("Invalid paths information.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayConfigPathInfos = GetDisplayConfigPathInfos(pathInfosArray, out var displayConfigModeInfos);
|
||||||
|
|
||||||
|
if (displayConfigPathInfos.Length <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = displayConfigModeInfos.Length == 0
|
||||||
|
? SetDisplayConfigFlags.TopologySupplied
|
||||||
|
: SetDisplayConfigFlags.UseSuppliedDisplayConfig;
|
||||||
|
|
||||||
|
if (allowChanges)
|
||||||
|
{
|
||||||
|
flags |= displayConfigModeInfos.Length == 0
|
||||||
|
? SetDisplayConfigFlags.AllowPathOrderChanges
|
||||||
|
: SetDisplayConfigFlags.AllowChanges;
|
||||||
|
}
|
||||||
|
else if (displayConfigModeInfos.Length > 0)
|
||||||
|
{
|
||||||
|
flags |= SetDisplayConfigFlags.NoOptimization;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (saveToDatabase && displayConfigModeInfos.Length > 0)
|
||||||
|
{
|
||||||
|
flags |= SetDisplayConfigFlags.SaveToDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceModeEnumeration && displayConfigModeInfos.Length > 0)
|
||||||
|
{
|
||||||
|
flags |= SetDisplayConfigFlags.ForceModeEnumeration;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result =
|
||||||
|
DisplayConfigApi.SetDisplayConfig(
|
||||||
|
(uint) displayConfigPathInfos.Length,
|
||||||
|
displayConfigPathInfos,
|
||||||
|
(uint) displayConfigModeInfos.Length,
|
||||||
|
displayConfigModeInfos.Length > 0 ? displayConfigModeInfos : null,
|
||||||
|
SetDisplayConfigFlags.Apply | flags
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new PathChangeException(
|
||||||
|
"An error occurred while applying the paths information.",
|
||||||
|
new Win32Exception((int) result)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies a saved topology
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topology">The topology identification to apply</param>
|
||||||
|
/// <param name="allowPersistence">true to allows persistence of the changes, otherwise false</param>
|
||||||
|
/// <exception cref="PathChangeException">Error in changing paths</exception>
|
||||||
|
public static void ApplyTopology(DisplayConfigTopologyId topology, bool allowPersistence = false)
|
||||||
|
{
|
||||||
|
if (!ValidateTopology(topology))
|
||||||
|
{
|
||||||
|
throw new PathChangeException("Invalid topology request.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = (SetDisplayConfigFlags) topology;
|
||||||
|
|
||||||
|
if (allowPersistence)
|
||||||
|
{
|
||||||
|
flags |= SetDisplayConfigFlags.PathPersistIfRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = DisplayConfigApi.SetDisplayConfig(
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
SetDisplayConfigFlags.Apply | flags
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new PathChangeException(
|
||||||
|
"An error occurred while applying the requested topology.",
|
||||||
|
new Win32Exception((int) result)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the list of active paths
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="virtualModeAware">true if the caller expects virtual mode settings, otherwise false</param>
|
||||||
|
/// <returns>An array of PathInfos</returns>
|
||||||
|
public static PathInfo[] GetActivePaths(bool virtualModeAware = false)
|
||||||
|
{
|
||||||
|
return GetPathInfos(
|
||||||
|
virtualModeAware
|
||||||
|
? QueryDeviceConfigFlags.OnlyActivePaths | QueryDeviceConfigFlags.VirtualModeAware
|
||||||
|
: QueryDeviceConfigFlags.OnlyActivePaths,
|
||||||
|
out _
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the list of all paths, active or inactive
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="virtualModeAware">true if the caller expects virtual mode settings, otherwise false</param>
|
||||||
|
/// <returns>An array of PathInfos</returns>
|
||||||
|
public static PathInfo[] GetAllPaths(bool virtualModeAware = false)
|
||||||
|
{
|
||||||
|
return GetPathInfos(
|
||||||
|
virtualModeAware
|
||||||
|
? QueryDeviceConfigFlags.AllPaths | QueryDeviceConfigFlags.VirtualModeAware
|
||||||
|
: QueryDeviceConfigFlags.AllPaths,
|
||||||
|
out _
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the list of currently active topology paths
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of PathInfos</returns>
|
||||||
|
public static PathInfo[] GetCurrentDatabasePaths()
|
||||||
|
{
|
||||||
|
return GetPathInfos(QueryDeviceConfigFlags.DatabaseCurrent, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current active topology identification
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The topology identification</returns>
|
||||||
|
public static DisplayConfigTopologyId GetCurrentTopology()
|
||||||
|
{
|
||||||
|
GetPathInfos(QueryDeviceConfigFlags.DatabaseCurrent, out var currentDatabaseType);
|
||||||
|
return currentDatabaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates an array of paths before applying
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pathInfos">The array of paths</param>
|
||||||
|
/// <param name="allowChanges">true to allow changes and reordering of the provided paths, otherwise false</param>
|
||||||
|
/// <returns>true if the provided paths are valid, otherwise false</returns>
|
||||||
|
public static bool ValidatePathInfos(IEnumerable<PathInfo> pathInfos, bool allowChanges = true)
|
||||||
|
{
|
||||||
|
var displayConfigPathInfos = GetDisplayConfigPathInfos(pathInfos, out var displayConfigModeInfos);
|
||||||
|
|
||||||
|
if (displayConfigPathInfos.Length <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = displayConfigModeInfos.Length == 0
|
||||||
|
? SetDisplayConfigFlags.TopologySupplied
|
||||||
|
: SetDisplayConfigFlags.UseSuppliedDisplayConfig;
|
||||||
|
|
||||||
|
if (allowChanges)
|
||||||
|
{
|
||||||
|
flags |= displayConfigModeInfos.Length == 0
|
||||||
|
? SetDisplayConfigFlags.AllowPathOrderChanges
|
||||||
|
: SetDisplayConfigFlags.AllowChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
DisplayConfigApi.SetDisplayConfig(
|
||||||
|
(uint) displayConfigPathInfos.Length,
|
||||||
|
displayConfigPathInfos,
|
||||||
|
(uint) displayConfigModeInfos.Length,
|
||||||
|
displayConfigModeInfos.Length > 0 ? displayConfigModeInfos : null,
|
||||||
|
SetDisplayConfigFlags.Validate | flags
|
||||||
|
) ==
|
||||||
|
Win32Status.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates a topology before applying
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topology">The topology identification</param>
|
||||||
|
/// <returns>true if topology is applicable, otherwise false</returns>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||||
|
public static bool ValidateTopology(DisplayConfigTopologyId topology)
|
||||||
|
{
|
||||||
|
if (topology == DisplayConfigTopologyId.None)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(topology), "Topology should not be empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = (SetDisplayConfigFlags) topology;
|
||||||
|
|
||||||
|
return DisplayConfigApi.SetDisplayConfig(
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
SetDisplayConfigFlags.Validate | flags
|
||||||
|
) ==
|
||||||
|
Win32Status.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint AddMode(ref List<DisplayConfigModeInfo> modes, DisplayConfigModeInfo mode)
|
||||||
|
{
|
||||||
|
var existingMode = modes.FindIndex(info =>
|
||||||
|
info.InfoType == mode.InfoType &&
|
||||||
|
info.AdapterId == mode.AdapterId &&
|
||||||
|
info.Id == mode.Id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingMode > 0)
|
||||||
|
{
|
||||||
|
if (modes[existingMode] == mode)
|
||||||
|
{
|
||||||
|
return (uint) existingMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new DuplicateModeException(
|
||||||
|
"Provided list of path information, contains one or more duplicate but not identical modes."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
modes.Add(mode);
|
||||||
|
|
||||||
|
return (uint) modes.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once CyclomaticComplexity
|
||||||
|
private static DisplayConfigPathInfo[] GetDisplayConfigPathInfos(
|
||||||
|
IEnumerable<PathInfo> pathInfos,
|
||||||
|
out DisplayConfigModeInfo[] modeInfos)
|
||||||
|
{
|
||||||
|
var displayConfigPathInfos = new List<DisplayConfigPathInfo>();
|
||||||
|
var displayConfigModeInfos = new List<DisplayConfigModeInfo>();
|
||||||
|
|
||||||
|
foreach (var pathInfo in pathInfos)
|
||||||
|
{
|
||||||
|
var sourceMode = pathInfo.GetDisplayConfigSourceMode();
|
||||||
|
var sourceModeIndex = sourceMode.HasValue
|
||||||
|
? AddMode(
|
||||||
|
ref displayConfigModeInfos,
|
||||||
|
new DisplayConfigModeInfo(
|
||||||
|
pathInfo.DisplaySource.Adapter.AdapterId,
|
||||||
|
pathInfo.DisplaySource.SourceId,
|
||||||
|
sourceMode.Value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: 0u;
|
||||||
|
var sourceInfo = pathInfo.IsCloneMember
|
||||||
|
? new DisplayConfigPathSourceInfo(
|
||||||
|
pathInfo.DisplaySource.Adapter.AdapterId,
|
||||||
|
pathInfo.DisplaySource.SourceId,
|
||||||
|
sourceMode.HasValue ? (ushort) sourceModeIndex : DisplayConfigSourceMode.InvalidSourceModeIndex,
|
||||||
|
(ushort) pathInfo.CloneGroupId
|
||||||
|
)
|
||||||
|
: new DisplayConfigPathSourceInfo(
|
||||||
|
pathInfo.DisplaySource.Adapter.AdapterId,
|
||||||
|
pathInfo.DisplaySource.SourceId,
|
||||||
|
sourceMode.HasValue ? sourceModeIndex : DisplayConfigModeInfo.InvalidModeIndex
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pathInfo.TargetsInfo == null || pathInfo.TargetsInfo.Length == 0)
|
||||||
|
{
|
||||||
|
displayConfigPathInfos.Add(
|
||||||
|
new DisplayConfigPathInfo(sourceInfo,
|
||||||
|
DisplayConfigPathInfoFlags.Active
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var target in pathInfo.TargetsInfo)
|
||||||
|
{
|
||||||
|
var flags = DisplayConfigPathInfoFlags.None;
|
||||||
|
|
||||||
|
if (target.IsPathActive)
|
||||||
|
{
|
||||||
|
flags |= DisplayConfigPathInfoFlags.Active;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.IsVirtualModeSupportedByPath)
|
||||||
|
{
|
||||||
|
flags |= DisplayConfigPathInfoFlags.SupportVirtualMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetMode = target.GetDisplayConfigTargetMode();
|
||||||
|
var targetModeIndex = targetMode.HasValue
|
||||||
|
? AddMode(ref displayConfigModeInfos,
|
||||||
|
new DisplayConfigModeInfo(
|
||||||
|
target.DisplayTarget.Adapter.AdapterId,
|
||||||
|
target.DisplayTarget.TargetId, targetMode.Value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: 0u;
|
||||||
|
DisplayConfigPathTargetInfo targetInfo;
|
||||||
|
|
||||||
|
if (target.IsVirtualModeSupportedByPath)
|
||||||
|
{
|
||||||
|
sourceInfo = new DisplayConfigPathSourceInfo(
|
||||||
|
pathInfo.DisplaySource.Adapter.AdapterId,
|
||||||
|
pathInfo.DisplaySource.SourceId,
|
||||||
|
sourceMode.HasValue
|
||||||
|
? (ushort) sourceModeIndex
|
||||||
|
: DisplayConfigSourceMode.InvalidSourceModeIndex,
|
||||||
|
pathInfo.IsCloneMember
|
||||||
|
? (ushort) pathInfo.CloneGroupId
|
||||||
|
: DisplayConfigPathSourceInfo.InvalidCloneGroupId
|
||||||
|
);
|
||||||
|
var desktopMode = target.GetDisplayConfigDesktopImageInfo();
|
||||||
|
var desktopModeIndex = desktopMode.HasValue
|
||||||
|
? AddMode(ref displayConfigModeInfos,
|
||||||
|
new DisplayConfigModeInfo(
|
||||||
|
target.DisplayTarget.Adapter.AdapterId,
|
||||||
|
target.DisplayTarget.TargetId,
|
||||||
|
desktopMode.Value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: 0u;
|
||||||
|
targetInfo = new DisplayConfigPathTargetInfo(
|
||||||
|
target.DisplayTarget.Adapter.AdapterId,
|
||||||
|
target.DisplayTarget.TargetId,
|
||||||
|
targetMode.HasValue
|
||||||
|
? (ushort) targetModeIndex
|
||||||
|
: DisplayConfigTargetMode.InvalidTargetModeIndex,
|
||||||
|
desktopMode.HasValue
|
||||||
|
? (ushort) desktopModeIndex
|
||||||
|
: DisplayConfigDesktopImageInfo.InvalidDesktopImageModeIndex,
|
||||||
|
target.OutputTechnology,
|
||||||
|
target.Rotation,
|
||||||
|
target.Scaling,
|
||||||
|
target.ScanLineOrdering == DisplayConfigScanLineOrdering.NotSpecified
|
||||||
|
? new DisplayConfigRational()
|
||||||
|
: new DisplayConfigRational(target.FrequencyInMillihertz, 1000, true),
|
||||||
|
target.ScanLineOrdering,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targetInfo = new DisplayConfigPathTargetInfo(
|
||||||
|
target.DisplayTarget.Adapter.AdapterId,
|
||||||
|
target.DisplayTarget.TargetId,
|
||||||
|
targetMode.HasValue ? targetModeIndex : DisplayConfigModeInfo.InvalidModeIndex,
|
||||||
|
target.OutputTechnology,
|
||||||
|
target.Rotation,
|
||||||
|
target.Scaling,
|
||||||
|
target.ScanLineOrdering == DisplayConfigScanLineOrdering.NotSpecified
|
||||||
|
? new DisplayConfigRational()
|
||||||
|
: new DisplayConfigRational(target.FrequencyInMillihertz, 1000, true),
|
||||||
|
target.ScanLineOrdering,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayConfigPathInfos.Add(new DisplayConfigPathInfo(sourceInfo, targetInfo, flags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modeInfos = displayConfigModeInfos.ToArray();
|
||||||
|
|
||||||
|
return displayConfigPathInfos.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PathInfo[] GetPathInfos(QueryDeviceConfigFlags flags, out DisplayConfigTopologyId topologyId)
|
||||||
|
{
|
||||||
|
DisplayConfigPathInfo[] displayPaths;
|
||||||
|
DisplayConfigModeInfo[] displayModes;
|
||||||
|
uint pathCount;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var error = DisplayConfigApi.GetDisplayConfigBufferSizes(flags,
|
||||||
|
out pathCount,
|
||||||
|
out var modeCount);
|
||||||
|
|
||||||
|
if (error != Win32Status.Success)
|
||||||
|
{
|
||||||
|
throw new Win32Exception((int) error);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayPaths = new DisplayConfigPathInfo[pathCount];
|
||||||
|
displayModes = new DisplayConfigModeInfo[modeCount];
|
||||||
|
|
||||||
|
if (flags == QueryDeviceConfigFlags.DatabaseCurrent)
|
||||||
|
{
|
||||||
|
error = DisplayConfigApi.QueryDisplayConfig(
|
||||||
|
flags,
|
||||||
|
ref pathCount,
|
||||||
|
displayPaths,
|
||||||
|
ref modeCount,
|
||||||
|
displayModes,
|
||||||
|
out topologyId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topologyId = DisplayConfigTopologyId.None;
|
||||||
|
error = DisplayConfigApi.QueryDisplayConfig(
|
||||||
|
flags,
|
||||||
|
ref pathCount,
|
||||||
|
displayPaths,
|
||||||
|
ref modeCount,
|
||||||
|
displayModes,
|
||||||
|
IntPtr.Zero
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == Win32Status.Success)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != Win32Status.ErrorInsufficientBuffer)
|
||||||
|
{
|
||||||
|
throw new Win32Exception((int) error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pathInfos =
|
||||||
|
new Dictionary<
|
||||||
|
uint,
|
||||||
|
Tuple<
|
||||||
|
DisplayConfigPathSourceInfo,
|
||||||
|
DisplayConfigSourceMode?,
|
||||||
|
List<
|
||||||
|
Tuple<
|
||||||
|
DisplayConfigPathInfoFlags,
|
||||||
|
DisplayConfigPathTargetInfo,
|
||||||
|
DisplayConfigTargetMode?,
|
||||||
|
DisplayConfigDesktopImageInfo?
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>();
|
||||||
|
|
||||||
|
var sourceId = uint.MaxValue;
|
||||||
|
|
||||||
|
for (var i = 0u; i < pathCount; i++)
|
||||||
|
{
|
||||||
|
var displayPath = displayPaths[i];
|
||||||
|
DisplayConfigSourceMode? sourceMode = null;
|
||||||
|
var key = sourceId;
|
||||||
|
var isVirtualSupported = displayPath.Flags.HasFlag(DisplayConfigPathInfoFlags.SupportVirtualMode);
|
||||||
|
|
||||||
|
if (isVirtualSupported &&
|
||||||
|
displayPath.SourceInfo.SourceModeInfoIndex != DisplayConfigSourceMode.InvalidSourceModeIndex &&
|
||||||
|
displayModes[displayPath.SourceInfo.SourceModeInfoIndex].InfoType ==
|
||||||
|
DisplayConfigModeInfoType.Source)
|
||||||
|
{
|
||||||
|
sourceMode = displayModes[displayPath.SourceInfo.SourceModeInfoIndex].SourceMode;
|
||||||
|
key = displayPath.SourceInfo.SourceModeInfoIndex;
|
||||||
|
}
|
||||||
|
else if (!isVirtualSupported &&
|
||||||
|
displayPath.SourceInfo.ModeInfoIndex != DisplayConfigModeInfo.InvalidModeIndex &&
|
||||||
|
displayModes[displayPath.SourceInfo.ModeInfoIndex].InfoType ==
|
||||||
|
DisplayConfigModeInfoType.Source)
|
||||||
|
{
|
||||||
|
sourceMode = displayModes[displayPath.SourceInfo.ModeInfoIndex].SourceMode;
|
||||||
|
key = displayPath.SourceInfo.ModeInfoIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sourceId--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pathInfos.ContainsKey(key))
|
||||||
|
{
|
||||||
|
pathInfos.Add(
|
||||||
|
key,
|
||||||
|
Tuple.Create(
|
||||||
|
displayPath.SourceInfo,
|
||||||
|
sourceMode,
|
||||||
|
new List<
|
||||||
|
Tuple<
|
||||||
|
DisplayConfigPathInfoFlags,
|
||||||
|
DisplayConfigPathTargetInfo,
|
||||||
|
DisplayConfigTargetMode?,
|
||||||
|
DisplayConfigDesktopImageInfo?
|
||||||
|
>
|
||||||
|
>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayConfigTargetMode? targetMode = null;
|
||||||
|
|
||||||
|
if (isVirtualSupported &&
|
||||||
|
displayPath.TargetInfo.TargetModeInfoIndex != DisplayConfigTargetMode.InvalidTargetModeIndex &&
|
||||||
|
displayModes[displayPath.TargetInfo.TargetModeInfoIndex].InfoType == DisplayConfigModeInfoType.Target
|
||||||
|
)
|
||||||
|
{
|
||||||
|
targetMode = displayModes[displayPath.TargetInfo.TargetModeInfoIndex].TargetMode;
|
||||||
|
}
|
||||||
|
else if (!isVirtualSupported &&
|
||||||
|
displayPath.TargetInfo.ModeInfoIndex != DisplayConfigModeInfo.InvalidModeIndex &&
|
||||||
|
displayModes[displayPath.TargetInfo.ModeInfoIndex].InfoType == DisplayConfigModeInfoType.Target
|
||||||
|
)
|
||||||
|
{
|
||||||
|
targetMode = displayModes[displayPath.TargetInfo.ModeInfoIndex].TargetMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayConfigDesktopImageInfo? desktopImageMode = null;
|
||||||
|
|
||||||
|
if (isVirtualSupported &&
|
||||||
|
displayPath.TargetInfo.DesktopModeInfoIndex !=
|
||||||
|
DisplayConfigDesktopImageInfo.InvalidDesktopImageModeIndex &&
|
||||||
|
displayModes[displayPath.TargetInfo.DesktopModeInfoIndex].InfoType ==
|
||||||
|
DisplayConfigModeInfoType.DesktopImage)
|
||||||
|
{
|
||||||
|
desktopImageMode = displayModes[displayPath.TargetInfo.DesktopModeInfoIndex].DesktopImageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathInfos[key].Item3.Add(
|
||||||
|
Tuple.Create(displayPath.Flags, displayPath.TargetInfo, targetMode, desktopImageMode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathInfos.Select(
|
||||||
|
pair => new PathInfo(pair.Value.Item1, pair.Value.Item2, pair.Value.Item3)
|
||||||
|
).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{DisplaySource}: {Resolution} @ {Position}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private DisplayConfigSourceMode? GetDisplayConfigSourceMode()
|
||||||
|
{
|
||||||
|
if (IsModeInformationAvailable)
|
||||||
|
{
|
||||||
|
return new DisplayConfigSourceMode(
|
||||||
|
(uint) Resolution.Width,
|
||||||
|
(uint) Resolution.Height,
|
||||||
|
PixelFormat,
|
||||||
|
new PointL(Position)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
140
app/WindowsDisplayAPI/DisplayConfig/PathTargetDesktopImage.cs
Normal file
140
app/WindowsDisplayAPI/DisplayConfig/PathTargetDesktopImage.cs
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information about the target desktop image
|
||||||
|
/// </summary>
|
||||||
|
public class PathTargetDesktopImage : IEquatable<PathTargetDesktopImage>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetDesktopImage
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="monitorSurfaceSize">Size of the VidPn source surface that is being displayed on the monitor</param>
|
||||||
|
/// <param name="imageRegion">
|
||||||
|
/// Where the desktop image will be positioned within monitor surface size. Region must be
|
||||||
|
/// completely inside the bounds of the monitor surface size.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="imageClip">
|
||||||
|
/// Which part of the desktop image for this clone group will be displayed on this path. This
|
||||||
|
/// currently must be set to the desktop size.
|
||||||
|
/// </param>
|
||||||
|
public PathTargetDesktopImage(Size monitorSurfaceSize, Rectangle imageRegion, Rectangle imageClip)
|
||||||
|
{
|
||||||
|
ImageClip = imageClip;
|
||||||
|
ImageRegion = imageRegion;
|
||||||
|
MonitorSurfaceSize = monitorSurfaceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal PathTargetDesktopImage(DisplayConfigDesktopImageInfo desktopImage)
|
||||||
|
{
|
||||||
|
MonitorSurfaceSize = desktopImage.PathSourceSize.ToSize();
|
||||||
|
ImageRegion = desktopImage.DesktopImageRegion.ToRectangle();
|
||||||
|
ImageClip = desktopImage.DesktopImageClip.ToRectangle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets part of the desktop image for this clone group that will be displayed on this path. This currently must be set
|
||||||
|
/// to the desktop size.
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle ImageClip { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the part that the desktop image will be positioned within monitor surface size. Region must be completely
|
||||||
|
/// inside the bounds of the monitor surface size.
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle ImageRegion { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of the VidPn source surface that is being displayed on the monitor
|
||||||
|
/// </summary>
|
||||||
|
public Size MonitorSurfaceSize { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(PathTargetDesktopImage other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReferenceEquals(this, other))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImageClip == other.ImageClip &&
|
||||||
|
ImageRegion == other.ImageRegion &&
|
||||||
|
MonitorSurfaceSize == other.MonitorSurfaceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for equality of two PathTargetDesktopImage 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 ==(PathTargetDesktopImage left, PathTargetDesktopImage right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left?.Equals(right) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for inequality of two PathTargetDesktopImage 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 !=(PathTargetDesktopImage left, PathTargetDesktopImage 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((PathTargetDesktopImage) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = ImageClip.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ ImageRegion.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ MonitorSurfaceSize.GetHashCode();
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{ImageClip} => {ImageRegion} @ {MonitorSurfaceSize}";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplayConfigDesktopImageInfo GetDisplayConfigDesktopImageInfo()
|
||||||
|
{
|
||||||
|
return new DisplayConfigDesktopImageInfo(
|
||||||
|
new PointL(MonitorSurfaceSize),
|
||||||
|
new RectangleL(ImageRegion),
|
||||||
|
new RectangleL(ImageClip)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
330
app/WindowsDisplayAPI/DisplayConfig/PathTargetInfo.cs
Normal file
330
app/WindowsDisplayAPI/DisplayConfig/PathTargetInfo.cs
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
using WindowsDisplayAPI.Exceptions;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a path and its target
|
||||||
|
/// </summary>
|
||||||
|
public class PathTargetInfo
|
||||||
|
{
|
||||||
|
private readonly PathTargetDesktopImage _desktopImage;
|
||||||
|
private readonly PathTargetSignalInfo _signalInfo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayTarget">The display target device</param>
|
||||||
|
/// <param name="isVirtualModeSupported">A boolean value indicating the target virtual mode support</param>
|
||||||
|
public PathTargetInfo(PathDisplayTarget displayTarget, bool isVirtualModeSupported = false)
|
||||||
|
{
|
||||||
|
DisplayTarget = displayTarget;
|
||||||
|
IsVirtualModeSupportedByPath = isVirtualModeSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayTarget">The display target device</param>
|
||||||
|
/// <param name="frequencyInMillihertz">Display frequency in millihertz</param>
|
||||||
|
/// <param name="scanLineOrdering">Display scan line ordering</param>
|
||||||
|
/// <param name="rotation">Display rotation</param>
|
||||||
|
/// <param name="scaling">Display scaling</param>
|
||||||
|
/// <param name="isVirtualModeSupported">A boolean value indicating the target virtual mode support</param>
|
||||||
|
public PathTargetInfo(
|
||||||
|
PathDisplayTarget displayTarget,
|
||||||
|
ulong frequencyInMillihertz,
|
||||||
|
DisplayConfigScanLineOrdering scanLineOrdering = DisplayConfigScanLineOrdering.NotSpecified,
|
||||||
|
DisplayConfigRotation rotation = DisplayConfigRotation.NotSpecified,
|
||||||
|
DisplayConfigScaling scaling = DisplayConfigScaling.Preferred,
|
||||||
|
bool isVirtualModeSupported = false
|
||||||
|
) : this(displayTarget, isVirtualModeSupported)
|
||||||
|
{
|
||||||
|
FrequencyInMillihertz = frequencyInMillihertz;
|
||||||
|
ScanLineOrdering = scanLineOrdering;
|
||||||
|
Rotation = rotation;
|
||||||
|
Scaling = scaling;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayTarget">The display target device</param>
|
||||||
|
/// <param name="signalInfo">The display signal information</param>
|
||||||
|
/// <param name="isVirtualModeSupported">A boolean value indicating the target virtual mode support</param>
|
||||||
|
public PathTargetInfo(
|
||||||
|
PathDisplayTarget displayTarget,
|
||||||
|
PathTargetSignalInfo signalInfo,
|
||||||
|
bool isVirtualModeSupported = false
|
||||||
|
) : this(displayTarget, isVirtualModeSupported)
|
||||||
|
{
|
||||||
|
_signalInfo = signalInfo;
|
||||||
|
FrequencyInMillihertz = signalInfo.VerticalSyncFrequencyInMillihertz;
|
||||||
|
ScanLineOrdering = signalInfo.ScanLineOrdering;
|
||||||
|
IsSignalInformationAvailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayTarget">The display target device</param>
|
||||||
|
/// <param name="signalInfo">The display signal information</param>
|
||||||
|
/// <param name="rotation">Display rotation</param>
|
||||||
|
/// <param name="scaling">Display scaling</param>
|
||||||
|
/// <param name="isVirtualModeSupported">A boolean value indicating the target virtual mode support</param>
|
||||||
|
public PathTargetInfo(
|
||||||
|
PathDisplayTarget displayTarget,
|
||||||
|
PathTargetSignalInfo signalInfo,
|
||||||
|
DisplayConfigRotation rotation = DisplayConfigRotation.NotSpecified,
|
||||||
|
DisplayConfigScaling scaling = DisplayConfigScaling.Preferred,
|
||||||
|
bool isVirtualModeSupported = false
|
||||||
|
) : this(
|
||||||
|
displayTarget,
|
||||||
|
0,
|
||||||
|
DisplayConfigScanLineOrdering.NotSpecified,
|
||||||
|
rotation,
|
||||||
|
scaling,
|
||||||
|
isVirtualModeSupported
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_signalInfo = signalInfo;
|
||||||
|
FrequencyInMillihertz = signalInfo.VerticalSyncFrequencyInMillihertz;
|
||||||
|
ScanLineOrdering = signalInfo.ScanLineOrdering;
|
||||||
|
IsSignalInformationAvailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayTarget">The display target device</param>
|
||||||
|
/// <param name="signalInfo">The display signal information</param>
|
||||||
|
/// <param name="desktopImage">The display desktop image information</param>
|
||||||
|
/// <param name="isVirtualModeSupported">A boolean value indicating the target virtual mode support</param>
|
||||||
|
public PathTargetInfo(
|
||||||
|
PathDisplayTarget displayTarget,
|
||||||
|
PathTargetSignalInfo signalInfo,
|
||||||
|
PathTargetDesktopImage desktopImage,
|
||||||
|
bool isVirtualModeSupported = false
|
||||||
|
) : this(displayTarget, signalInfo, isVirtualModeSupported)
|
||||||
|
{
|
||||||
|
_desktopImage = desktopImage;
|
||||||
|
IsDesktopImageInformationAvailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayTarget">The display target device</param>
|
||||||
|
/// <param name="signalInfo">The display signal information</param>
|
||||||
|
/// <param name="desktopImage">The display desktop image information</param>
|
||||||
|
/// <param name="rotation">Display rotation</param>
|
||||||
|
/// <param name="scaling">Display scaling</param>
|
||||||
|
/// <param name="isVirtualModeSupported">A boolean value indicating the target virtual mode support</param>
|
||||||
|
public PathTargetInfo(
|
||||||
|
PathDisplayTarget displayTarget,
|
||||||
|
PathTargetSignalInfo signalInfo,
|
||||||
|
PathTargetDesktopImage desktopImage,
|
||||||
|
DisplayConfigRotation rotation = DisplayConfigRotation.NotSpecified,
|
||||||
|
DisplayConfigScaling scaling = DisplayConfigScaling.Preferred,
|
||||||
|
bool isVirtualModeSupported = false
|
||||||
|
) : this(displayTarget, signalInfo, rotation, scaling, isVirtualModeSupported)
|
||||||
|
{
|
||||||
|
_desktopImage = desktopImage;
|
||||||
|
IsDesktopImageInformationAvailable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal PathTargetInfo(
|
||||||
|
DisplayConfigPathInfoFlags pathFlags,
|
||||||
|
DisplayConfigPathTargetInfo targetInfo,
|
||||||
|
DisplayConfigTargetMode? targetMode,
|
||||||
|
DisplayConfigDesktopImageInfo? desktopImageMode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
IsPathActive = pathFlags.HasFlag(DisplayConfigPathInfoFlags.Active);
|
||||||
|
IsVirtualModeSupportedByPath = pathFlags.HasFlag(DisplayConfigPathInfoFlags.SupportVirtualMode);
|
||||||
|
|
||||||
|
DisplayTarget = new PathDisplayTarget(
|
||||||
|
new PathDisplayAdapter(targetInfo.AdapterId),
|
||||||
|
targetInfo.TargetId,
|
||||||
|
targetInfo.TargetAvailable
|
||||||
|
);
|
||||||
|
|
||||||
|
OutputTechnology = targetInfo.OutputTechnology;
|
||||||
|
Rotation = targetInfo.Rotation;
|
||||||
|
Scaling = targetInfo.Scaling;
|
||||||
|
ScanLineOrdering = targetInfo.ScanLineOrdering;
|
||||||
|
FrequencyInMillihertz = targetInfo.RefreshRate.ToValue(1000);
|
||||||
|
ForcedBootAvailability = targetInfo.StatusFlags.HasFlag(
|
||||||
|
DisplayConfigPathTargetInfoFlags.AvailabilityBoot
|
||||||
|
);
|
||||||
|
ForcedPathAvailability = targetInfo.StatusFlags.HasFlag(
|
||||||
|
DisplayConfigPathTargetInfoFlags.AvailabilityPath
|
||||||
|
);
|
||||||
|
ForcedSystemAvailability = targetInfo.StatusFlags.HasFlag(
|
||||||
|
DisplayConfigPathTargetInfoFlags.AvailabilitySystem
|
||||||
|
);
|
||||||
|
IsCurrentlyInUse = targetInfo.StatusFlags.HasFlag(
|
||||||
|
DisplayConfigPathTargetInfoFlags.InUse
|
||||||
|
);
|
||||||
|
IsForcible = targetInfo.StatusFlags.HasFlag(
|
||||||
|
DisplayConfigPathTargetInfoFlags.Forcible
|
||||||
|
);
|
||||||
|
|
||||||
|
IsSignalInformationAvailable = targetMode.HasValue;
|
||||||
|
|
||||||
|
if (targetMode.HasValue)
|
||||||
|
{
|
||||||
|
_signalInfo = new PathTargetSignalInfo(targetMode.Value.TargetVideoSignalInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
IsDesktopImageInformationAvailable = desktopImageMode.HasValue;
|
||||||
|
|
||||||
|
if (desktopImageMode.HasValue)
|
||||||
|
{
|
||||||
|
_desktopImage = new PathTargetDesktopImage(desktopImageMode.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instance of PathTargetDesktopImage containing information about this target desktop image
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingModeException">Target mode information is missing</exception>
|
||||||
|
public PathTargetDesktopImage DesktopImage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsDesktopImageInformationAvailable)
|
||||||
|
{
|
||||||
|
throw new MissingModeException(
|
||||||
|
"Desktop image information is missing or not available.",
|
||||||
|
DisplayConfigModeInfoType.DesktopImage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _desktopImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets extra information about the representing display target device
|
||||||
|
/// </summary>
|
||||||
|
public PathDisplayTarget DisplayTarget { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating that the output is currently being forced in a boot-persistent manner
|
||||||
|
/// </summary>
|
||||||
|
public bool ForcedBootAvailability { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating that the output is currently being forced in a path-persistent manner
|
||||||
|
/// </summary>
|
||||||
|
public bool ForcedPathAvailability { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating that the output is currently being forced in a non-persistent manner
|
||||||
|
/// </summary>
|
||||||
|
public bool ForcedSystemAvailability { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value that specifies the refresh rate of the target
|
||||||
|
/// </summary>
|
||||||
|
public ulong FrequencyInMillihertz { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if the target is in use on an active path
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCurrentlyInUse { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating the presence of the desktop image information
|
||||||
|
/// </summary>
|
||||||
|
public bool IsDesktopImageInformationAvailable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating that the output can be forced on this target even if a monitor is not detected
|
||||||
|
/// </summary>
|
||||||
|
public bool IsForcible { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this path is or should be active
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPathActive { get; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating the presence of the signal information
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSignalInformationAvailable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value that indicates if the path supports virtual mode
|
||||||
|
/// </summary>
|
||||||
|
public bool IsVirtualModeSupportedByPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of the display device connection
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigVideoOutputTechnology OutputTechnology { get; } = DisplayConfigVideoOutputTechnology.Other;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the rotation of the target
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigRotation Rotation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value that specifies how the source image is scaled to the target
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigScaling Scaling { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value that specifies the scan-line ordering of the output on the target
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigScanLineOrdering ScanLineOrdering { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target device signal information
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="MissingModeException">Target mode information is missing</exception>
|
||||||
|
public PathTargetSignalInfo SignalInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsSignalInformationAvailable)
|
||||||
|
{
|
||||||
|
throw new MissingModeException(
|
||||||
|
"Target mode information is missing or not available.",
|
||||||
|
DisplayConfigModeInfoType.Target
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _signalInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{DisplayTarget}: {FrequencyInMillihertz / 1000}hz{(IsCurrentlyInUse ? " [In Use]" : "")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplayConfigDesktopImageInfo? GetDisplayConfigDesktopImageInfo()
|
||||||
|
{
|
||||||
|
if (IsDesktopImageInformationAvailable)
|
||||||
|
{
|
||||||
|
return DesktopImage.GetDisplayConfigDesktopImageInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplayConfigTargetMode? GetDisplayConfigTargetMode()
|
||||||
|
{
|
||||||
|
if (IsSignalInformationAvailable)
|
||||||
|
{
|
||||||
|
return new DisplayConfigTargetMode(SignalInfo.GetDisplayConfigVideoSignalInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
220
app/WindowsDisplayAPI/DisplayConfig/PathTargetSignalInfo.cs
Normal file
220
app/WindowsDisplayAPI/DisplayConfig/PathTargetSignalInfo.cs
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information about the target signal info
|
||||||
|
/// </summary>
|
||||||
|
public class PathTargetSignalInfo : IEquatable<PathTargetSignalInfo>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetSignalInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="activeSize">Specifies the width and height (in pixels) of the active portion of the video signal.</param>
|
||||||
|
/// <param name="totalSize">Specifies the width and height (in pixels) of the entire video signal.</param>
|
||||||
|
/// <param name="verticalSyncFrequencyInMillihertz">Vertical synchronization frequency.</param>
|
||||||
|
/// <param name="scanLineOrdering">The scan-line ordering (for example, progressive or interlaced) of the video signal.</param>
|
||||||
|
/// <param name="videoStandard">
|
||||||
|
/// The video standard (if any) that defines the video signal. Supported by WDDM 1.3 and later
|
||||||
|
/// display mini-port drivers running on Windows 8.1 and later.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="verticalSyncFrequencyDivider">
|
||||||
|
/// The ratio of the VSync rate of a monitor that displays through a Miracast
|
||||||
|
/// connected session to the VSync rate of the Miracast sink. The ratio of the VSync rate of a monitor that displays
|
||||||
|
/// through a Miracast connected session to the VSync rate of the Miracast sink. Supported by WDDM 1.3 and later
|
||||||
|
/// display mini-port drivers running on Windows 8.1 and later.
|
||||||
|
/// </param>
|
||||||
|
public PathTargetSignalInfo(
|
||||||
|
Size activeSize,
|
||||||
|
Size totalSize,
|
||||||
|
ulong verticalSyncFrequencyInMillihertz,
|
||||||
|
DisplayConfigScanLineOrdering scanLineOrdering,
|
||||||
|
VideoSignalStandard videoStandard = VideoSignalStandard.Uninitialized,
|
||||||
|
ushort verticalSyncFrequencyDivider = 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ActiveSize = activeSize;
|
||||||
|
ScanLineOrdering = scanLineOrdering;
|
||||||
|
TotalSize = totalSize;
|
||||||
|
VerticalSyncFrequencyDivider = verticalSyncFrequencyDivider;
|
||||||
|
VerticalSyncFrequencyInMillihertz = verticalSyncFrequencyInMillihertz;
|
||||||
|
VideoStandard = videoStandard;
|
||||||
|
PixelRate = (ulong) (verticalSyncFrequencyInMillihertz / 1000d * totalSize.Width * totalSize.Height);
|
||||||
|
HorizontalSyncFrequencyInMillihertz = (ulong) totalSize.Height * verticalSyncFrequencyInMillihertz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathTargetSignalInfo
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySetting">A possible display settings</param>
|
||||||
|
/// <param name="totalSignalSize">Total signal size</param>
|
||||||
|
public PathTargetSignalInfo(DisplayPossibleSetting displaySetting, Size totalSignalSize) :
|
||||||
|
this(
|
||||||
|
displaySetting.Resolution, totalSignalSize,
|
||||||
|
(uint) (displaySetting.Frequency * 1000),
|
||||||
|
displaySetting.IsInterlaced
|
||||||
|
? DisplayConfigScanLineOrdering.InterlacedWithUpperFieldFirst
|
||||||
|
: DisplayConfigScanLineOrdering.Progressive
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal PathTargetSignalInfo(DisplayConfigVideoSignalInfo signalInfo)
|
||||||
|
{
|
||||||
|
PixelRate = signalInfo.PixelRate;
|
||||||
|
HorizontalSyncFrequencyInMillihertz = signalInfo.HorizontalSyncFrequency.ToValue(1000);
|
||||||
|
VerticalSyncFrequencyInMillihertz = signalInfo.VerticalSyncFrequency.ToValue(1000);
|
||||||
|
ActiveSize = new Size((int) signalInfo.ActiveSize.Width, (int) signalInfo.ActiveSize.Height);
|
||||||
|
TotalSize = new Size((int) signalInfo.TotalSize.Width, (int) signalInfo.TotalSize.Height);
|
||||||
|
VideoStandard = signalInfo.VideoStandard;
|
||||||
|
VerticalSyncFrequencyDivider = signalInfo.VerticalSyncFrequencyDivider;
|
||||||
|
ScanLineOrdering = signalInfo.ScanLineOrdering;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width and height (in pixels) of the active portion of the video signal
|
||||||
|
/// </summary>
|
||||||
|
public Size ActiveSize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the horizontal synchronization frequency
|
||||||
|
/// </summary>
|
||||||
|
public ulong HorizontalSyncFrequencyInMillihertz { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the pixel clock rate
|
||||||
|
/// </summary>
|
||||||
|
public ulong PixelRate { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scan-line ordering (for example, progressive or interlaced) of the video signal
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigScanLineOrdering ScanLineOrdering { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width and height (in pixels) of the entire video signal
|
||||||
|
/// </summary>
|
||||||
|
public Size TotalSize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the ratio of the VSync rate of a monitor that displays through a Miracast connected session to the VSync rate
|
||||||
|
/// of the Miracast sink. The ratio of the VSync rate of a monitor that displays through a Miracast connected session
|
||||||
|
/// to the VSync rate of the Miracast sink. Supported by WDDM 1.3 and later display mini-port drivers running on Windows
|
||||||
|
/// 8.1 and later
|
||||||
|
/// </summary>
|
||||||
|
public ushort VerticalSyncFrequencyDivider { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the vertical synchronization frequency
|
||||||
|
/// </summary>
|
||||||
|
public ulong VerticalSyncFrequencyInMillihertz { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the video standard (if any) that defines the video signal. Supported by WDDM 1.3 and later display mini-port
|
||||||
|
/// drivers running on Windows 8.1 and later
|
||||||
|
/// </summary>
|
||||||
|
public VideoSignalStandard VideoStandard { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(PathTargetSignalInfo other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, other))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReferenceEquals(this, other))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ActiveSize == other.ActiveSize &&
|
||||||
|
HorizontalSyncFrequencyInMillihertz == other.HorizontalSyncFrequencyInMillihertz &&
|
||||||
|
PixelRate == other.PixelRate &&
|
||||||
|
ScanLineOrdering == other.ScanLineOrdering &&
|
||||||
|
TotalSize == other.TotalSize &&
|
||||||
|
VerticalSyncFrequencyDivider == other.VerticalSyncFrequencyDivider &&
|
||||||
|
VerticalSyncFrequencyInMillihertz == other.VerticalSyncFrequencyInMillihertz &&
|
||||||
|
VideoStandard == other.VideoStandard;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for equality of two PathTargetSignalInfo 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 ==(PathTargetSignalInfo left, PathTargetSignalInfo right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left?.Equals(right) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for inequality of two PathTargetSignalInfo 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 !=(PathTargetSignalInfo left, PathTargetSignalInfo 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((PathTargetSignalInfo) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = ActiveSize.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ (int) HorizontalSyncFrequencyInMillihertz;
|
||||||
|
hashCode = (hashCode * 397) ^ PixelRate.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ (int) ScanLineOrdering;
|
||||||
|
hashCode = (hashCode * 397) ^ TotalSize.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ VerticalSyncFrequencyDivider.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ (int) VerticalSyncFrequencyInMillihertz;
|
||||||
|
hashCode = (hashCode * 397) ^ (int) VideoStandard;
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{ActiveSize} @ {VerticalSyncFrequencyInMillihertz / 1000}hz {VideoStandard}";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplayConfigVideoSignalInfo GetDisplayConfigVideoSignalInfo()
|
||||||
|
{
|
||||||
|
return new DisplayConfigVideoSignalInfo(
|
||||||
|
PixelRate,
|
||||||
|
new DisplayConfigRational(HorizontalSyncFrequencyInMillihertz, 1000, true),
|
||||||
|
new DisplayConfigRational(VerticalSyncFrequencyInMillihertz, 1000, true),
|
||||||
|
new DisplayConfig2DRegion((uint) ActiveSize.Width, (uint) ActiveSize.Height),
|
||||||
|
new DisplayConfig2DRegion((uint) TotalSize.Width, (uint) TotalSize.Height),
|
||||||
|
VideoStandard,
|
||||||
|
VerticalSyncFrequencyDivider,
|
||||||
|
ScanLineOrdering
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
app/WindowsDisplayAPI/DisplayCurveCapabilities.cs
Normal file
61
app/WindowsDisplayAPI/DisplayCurveCapabilities.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible curve drawing capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayCurveCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Device does not support curves.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw circles.
|
||||||
|
/// </summary>
|
||||||
|
Circles = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw pie wedges.
|
||||||
|
/// </summary>
|
||||||
|
Pie = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw chord arcs.
|
||||||
|
/// </summary>
|
||||||
|
Chord = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw ellipses.
|
||||||
|
/// </summary>
|
||||||
|
Ellipses = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw wide borders.
|
||||||
|
/// </summary>
|
||||||
|
Wide = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw styled borders.
|
||||||
|
/// </summary>
|
||||||
|
Styled = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw borders that are wide and styled.
|
||||||
|
/// </summary>
|
||||||
|
WideStyled = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw interiors.
|
||||||
|
/// </summary>
|
||||||
|
Interiors = 128,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw rounded rectangles.
|
||||||
|
/// </summary>
|
||||||
|
RoundRectangle = 256
|
||||||
|
}
|
||||||
|
}
|
||||||
143
app/WindowsDisplayAPI/DisplayDevice.cs
Normal file
143
app/WindowsDisplayAPI/DisplayDevice.cs
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Windows Display Device
|
||||||
|
/// </summary>
|
||||||
|
public class DisplayDevice : Device
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new DisplayDevice
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="devicePath">The device path</param>
|
||||||
|
/// <param name="deviceName">The device name</param>
|
||||||
|
/// <param name="deviceKey">The device driver registry key</param>
|
||||||
|
protected DisplayDevice(string devicePath, string deviceName, string deviceKey)
|
||||||
|
: base(devicePath, deviceName, deviceKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the corresponding <see cref="DisplayScreen" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
public DisplayScreen DisplayScreen
|
||||||
|
{
|
||||||
|
get => DisplayScreen.GetScreens().FirstOrDefault(info => info.ScreenName.Equals(ScreenName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new DisplayDevice
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="devicePath">The device path</param>
|
||||||
|
/// <param name="deviceName">The device name</param>
|
||||||
|
/// <param name="deviceKey">The device driver registry key</param>
|
||||||
|
/// <param name="adapter">The device parent DisplayAdapter</param>
|
||||||
|
/// <param name="isAvailable">true if the device is attached, otherwise false</param>
|
||||||
|
/// <param name="isValid">true if this instance is valid, otherwise false</param>
|
||||||
|
protected DisplayDevice(
|
||||||
|
string devicePath,
|
||||||
|
string deviceName,
|
||||||
|
string deviceKey,
|
||||||
|
DisplayAdapter adapter,
|
||||||
|
bool isAvailable,
|
||||||
|
bool isValid)
|
||||||
|
: this(devicePath, deviceName, deviceKey)
|
||||||
|
{
|
||||||
|
Adapter = adapter;
|
||||||
|
IsAvailable = isAvailable;
|
||||||
|
IsValid = isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new DisplayDevice
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="devicePath">The device path</param>
|
||||||
|
/// <param name="deviceName">The device name</param>
|
||||||
|
/// <param name="deviceKey">The device driver registry key</param>
|
||||||
|
/// <param name="adapter">The device parent DisplayAdapter</param>
|
||||||
|
/// <param name="displayName">The device source display name</param>
|
||||||
|
/// <param name="displayFullName">The device target display name</param>
|
||||||
|
/// <param name="isAvailable">true if the device is attached, otherwise false</param>
|
||||||
|
/// <param name="isValid">true if this instance is valid, otherwise false</param>
|
||||||
|
protected DisplayDevice(
|
||||||
|
string devicePath,
|
||||||
|
string deviceName,
|
||||||
|
string deviceKey,
|
||||||
|
DisplayAdapter adapter,
|
||||||
|
string displayName,
|
||||||
|
string displayFullName,
|
||||||
|
bool isAvailable,
|
||||||
|
bool isValid)
|
||||||
|
: this(devicePath, deviceName, deviceKey, adapter, isAvailable, isValid)
|
||||||
|
{
|
||||||
|
ScreenName = displayName;
|
||||||
|
DisplayName = displayFullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display device driving display adapter instance
|
||||||
|
/// </summary>
|
||||||
|
public virtual DisplayAdapter Adapter { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display device target name
|
||||||
|
/// </summary>
|
||||||
|
public virtual string DisplayName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display device source name
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ScreenName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this display device is currently attached
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsAvailable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this instance is no longer valid, this may happen when display device attached
|
||||||
|
/// status changes
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsValid { get; }
|
||||||
|
|
||||||
|
internal static DisplayDevice FromDeviceInformation(
|
||||||
|
DisplayAdapter adapter,
|
||||||
|
Native.DeviceContext.Structures.DisplayDevice sourceDevice,
|
||||||
|
Native.DeviceContext.Structures.DisplayDevice targetDevice
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return new DisplayDevice(
|
||||||
|
targetDevice.DeviceId,
|
||||||
|
targetDevice.DeviceString,
|
||||||
|
targetDevice.DeviceKey,
|
||||||
|
adapter,
|
||||||
|
sourceDevice.DeviceName,
|
||||||
|
targetDevice.DeviceName,
|
||||||
|
targetDevice.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(DeviceName)
|
||||||
|
? $"{GetType().Name}: {DisplayName} - IsAvailable: {IsAvailable}"
|
||||||
|
: $"{GetType().Name}: {DisplayName} ({DeviceName}) - IsAvailable: {IsAvailable}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the corresponding PathDisplayTarget instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An instance of PathDisplayTarget, or null</returns>
|
||||||
|
public PathDisplayTarget ToPathDisplayTarget()
|
||||||
|
{
|
||||||
|
return PathDisplayTarget
|
||||||
|
.GetDisplayTargets()
|
||||||
|
.FirstOrDefault(target => target.DevicePath.Equals(DevicePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
app/WindowsDisplayAPI/DisplayGammaRamp.cs
Normal file
91
app/WindowsDisplayAPI/DisplayGammaRamp.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
public class DisplayGammaRamp
|
||||||
|
{
|
||||||
|
public DisplayGammaRamp(ushort[] red, ushort[] green, ushort[] blue)
|
||||||
|
{
|
||||||
|
if (red?.Length != GammaRamp.DataPoints)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(red));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (green?.Length != GammaRamp.DataPoints)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(green));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blue?.Length != GammaRamp.DataPoints)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(blue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Red = red;
|
||||||
|
Green = green;
|
||||||
|
Blue = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayGammaRamp(double brightness = 0.5, double contrast = 0.5, double gamma = 1)
|
||||||
|
: this(
|
||||||
|
CalculateLUT(brightness, contrast, gamma),
|
||||||
|
CalculateLUT(brightness, contrast, gamma),
|
||||||
|
CalculateLUT(brightness, contrast, gamma)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayGammaRamp(
|
||||||
|
double redBrightness,
|
||||||
|
double redContrast,
|
||||||
|
double redGamma,
|
||||||
|
double greenBrightness,
|
||||||
|
double greenContrast,
|
||||||
|
double greenGamma,
|
||||||
|
double blueBrightness,
|
||||||
|
double blueContrast,
|
||||||
|
double blueGamma
|
||||||
|
)
|
||||||
|
: this(
|
||||||
|
CalculateLUT(redBrightness, redContrast, redGamma),
|
||||||
|
CalculateLUT(greenBrightness, greenContrast, greenGamma),
|
||||||
|
CalculateLUT(blueBrightness, blueContrast, blueGamma)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplayGammaRamp(GammaRamp ramp) :
|
||||||
|
this(ramp.Red, ramp.Green, ramp.Blue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort[] Blue { get; }
|
||||||
|
public ushort[] Green { get; }
|
||||||
|
public ushort[] Red { get; }
|
||||||
|
private static ushort[] CalculateLUT(double brightness, double contrast, double gamma)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Fill the gamma curve
|
||||||
|
var result = new ushort[GammaRamp.DataPoints];
|
||||||
|
string bits = "";
|
||||||
|
|
||||||
|
for (var i = 0; i < result.Length; i++)
|
||||||
|
{
|
||||||
|
result[i] = (ushort)((0.5 + brightness / 2) * ushort.MaxValue * i / (float)(result.Length - 1));
|
||||||
|
bits += result[i].ToString() + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.WriteLine(bits);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal GammaRamp AsRamp()
|
||||||
|
{
|
||||||
|
return new GammaRamp(Red, Green, Blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
app/WindowsDisplayAPI/DisplayLineCapabilities.cs
Normal file
51
app/WindowsDisplayAPI/DisplayLineCapabilities.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible line drawing capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayLineCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Device does not support lines.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw a poly line.
|
||||||
|
/// </summary>
|
||||||
|
PolyLine = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw a marker.
|
||||||
|
/// </summary>
|
||||||
|
Marker = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw multiple markers.
|
||||||
|
/// </summary>
|
||||||
|
PolyMarker = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw wide lines.
|
||||||
|
/// </summary>
|
||||||
|
Wide = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw styled lines.
|
||||||
|
/// </summary>
|
||||||
|
Styled = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw lines that are wide and styled.
|
||||||
|
/// </summary>
|
||||||
|
WideStyled = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw interiors.
|
||||||
|
/// </summary>
|
||||||
|
Interiors = 128
|
||||||
|
}
|
||||||
|
}
|
||||||
56
app/WindowsDisplayAPI/DisplayPolygonalCapabilities.cs
Normal file
56
app/WindowsDisplayAPI/DisplayPolygonalCapabilities.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible polygon drawing capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayPolygonalCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Device does not support polygons.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw alternate-fill polygons.
|
||||||
|
/// </summary>
|
||||||
|
Polygon = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw rectangles.
|
||||||
|
/// </summary>
|
||||||
|
Rectangle = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw winding-fill polygons.
|
||||||
|
/// </summary>
|
||||||
|
WindingFillPolygon = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw a single scan-line.
|
||||||
|
/// </summary>
|
||||||
|
ScanLine = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw wide borders.
|
||||||
|
/// </summary>
|
||||||
|
Wide = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw styled borders.
|
||||||
|
/// </summary>
|
||||||
|
Styled = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw borders that are wide and styled.
|
||||||
|
/// </summary>
|
||||||
|
WideStyled = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw interiors.
|
||||||
|
/// </summary>
|
||||||
|
Interiors = 128
|
||||||
|
}
|
||||||
|
}
|
||||||
63
app/WindowsDisplayAPI/DisplayPossibleSetting.cs
Normal file
63
app/WindowsDisplayAPI/DisplayPossibleSetting.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a possible display setting
|
||||||
|
/// </summary>
|
||||||
|
public class DisplayPossibleSetting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new DisplayPossibleSetting
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resolution">Display resolution</param>
|
||||||
|
/// <param name="frequency">Display frequency</param>
|
||||||
|
/// <param name="colorDepth">Display color depth</param>
|
||||||
|
/// <param name="isInterlaced">Indicating if display is using interlaces scan out</param>
|
||||||
|
protected DisplayPossibleSetting(Size resolution, int frequency, ColorDepth colorDepth, bool isInterlaced)
|
||||||
|
{
|
||||||
|
ColorDepth = colorDepth;
|
||||||
|
Resolution = resolution;
|
||||||
|
IsInterlaced = isInterlaced;
|
||||||
|
Frequency = frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplayPossibleSetting(DeviceMode deviceMode)
|
||||||
|
: this(
|
||||||
|
new Size((int) deviceMode.PixelsWidth, (int) deviceMode.PixelsHeight),
|
||||||
|
(int) deviceMode.DisplayFrequency,
|
||||||
|
(ColorDepth) deviceMode.BitsPerPixel,
|
||||||
|
deviceMode.DisplayFlags.HasFlag(DisplayFlags.Interlaced)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color depth of the display monitor in bits per pixel
|
||||||
|
/// </summary>
|
||||||
|
public ColorDepth ColorDepth { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the frequency of the display monitor in hz
|
||||||
|
/// </summary>
|
||||||
|
public int Frequency { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if the display uses the interlaced signal
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInterlaced { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size of the display monitor
|
||||||
|
/// </summary>
|
||||||
|
public Size Resolution { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Resolution} {(IsInterlaced ? "Interlaced" : "Progressive")} {Frequency}hz @ {ColorDepth}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
app/WindowsDisplayAPI/DisplayRasterCapabilities.cs
Normal file
91
app/WindowsDisplayAPI/DisplayRasterCapabilities.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible raster capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayRasterCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of transferring bitmaps.
|
||||||
|
/// </summary>
|
||||||
|
BitmapTransfer = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requires banding support.
|
||||||
|
/// </summary>
|
||||||
|
RequiresBanding = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of scaling.
|
||||||
|
/// </summary>
|
||||||
|
Scaling = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of supporting bitmaps larger than 64 KB.
|
||||||
|
/// </summary>
|
||||||
|
Bitmap64K = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies GDI 2.0 compatibility.
|
||||||
|
/// </summary>
|
||||||
|
GDI20Output = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Includes a state block in the device context.
|
||||||
|
/// </summary>
|
||||||
|
GDI20State = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of saving bitmaps locally in shadow memory.
|
||||||
|
/// </summary>
|
||||||
|
SaveBitmap = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of modification and retrieval of display independent bitmap data.
|
||||||
|
/// </summary>
|
||||||
|
DeviceIndependentBitmap = 128,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies a palette-based device.
|
||||||
|
/// </summary>
|
||||||
|
Palette = 256,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of sending display independent bitmap to device.
|
||||||
|
/// </summary>
|
||||||
|
DeviceIndependentBitmapToDevice = 512,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of supporting fonts larger than 64 KB.
|
||||||
|
/// </summary>
|
||||||
|
Font64K = 1024,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of stretching bitmaps.
|
||||||
|
/// </summary>
|
||||||
|
StretchBitmap = 2048,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of performing flood fills.
|
||||||
|
/// </summary>
|
||||||
|
FloodFill = 4096,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of stretching display independent bitmaps.
|
||||||
|
/// </summary>
|
||||||
|
StretchDeviceIndependentBitmap = 8192,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supports transparent bitmap and DirectX arrays.
|
||||||
|
/// </summary>
|
||||||
|
DirectXOutput = 16384,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of working with hardware-dependent bitmaps.
|
||||||
|
/// </summary>
|
||||||
|
DeviceBits = 32768
|
||||||
|
}
|
||||||
|
}
|
||||||
299
app/WindowsDisplayAPI/DisplayScreen.cs
Normal file
299
app/WindowsDisplayAPI/DisplayScreen.cs
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Exceptions;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext.Structures;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information about a display source screen
|
||||||
|
/// </summary>
|
||||||
|
public class DisplayScreen
|
||||||
|
{
|
||||||
|
private readonly IntPtr _monitorHandle;
|
||||||
|
|
||||||
|
private DisplayScreen(IntPtr monitorHandle)
|
||||||
|
{
|
||||||
|
_monitorHandle = monitorHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the source identification number
|
||||||
|
/// </summary>
|
||||||
|
public int SourceId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var name = ScreenName;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = ScreenName.IndexOf("DISPLAY", StringComparison.Ordinal);
|
||||||
|
|
||||||
|
return index < 0 ? 0 : int.Parse(name.Substring(index + 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of all active screens
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of <see cref="DisplayScreen" /> instances.</returns>
|
||||||
|
public static DisplayScreen[] GetScreens()
|
||||||
|
{
|
||||||
|
var result = new List<DisplayScreen>();
|
||||||
|
var callback = new DeviceContextApi.MonitorEnumProcedure(
|
||||||
|
(IntPtr handle, IntPtr dcHandle, ref RectangleL rect, IntPtr callbackObject) =>
|
||||||
|
{
|
||||||
|
result.Add(new DisplayScreen(handle));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return DeviceContextApi.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, IntPtr.Zero)
|
||||||
|
? result.ToArray()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="DisplaySetting"/> instance representing the screen current settings
|
||||||
|
/// </summary>
|
||||||
|
public DisplaySetting CurrentSetting
|
||||||
|
{
|
||||||
|
get => DisplaySetting.GetCurrentFromScreenName(ScreenName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="DisplaySetting"/> instance representing this screen saved settings
|
||||||
|
/// </summary>
|
||||||
|
public DisplaySetting SavedSetting
|
||||||
|
{
|
||||||
|
get => DisplaySetting.GetSavedFromScreenName(ScreenName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disables and detaches all devices connected to this screen
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apply">Indicating if the changes should be applied immediately, recommended value is false</param>
|
||||||
|
public void Disable(bool apply)
|
||||||
|
{
|
||||||
|
SetSettings(new DisplaySetting(), apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables and attach all devices connected to this screen
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySetting">The display settings that should be applied while enabling the display device</param>
|
||||||
|
/// <param name="apply">Indicating if the changes should be applied immediately, recommended value is false</param>
|
||||||
|
public void Enable(DisplaySetting displaySetting, bool apply = false)
|
||||||
|
{
|
||||||
|
SetSettings(displaySetting, apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the display device settings to a new <see cref="DisplaySetting"/> instance
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displaySetting">The display settings that should be applied</param>
|
||||||
|
/// <param name="apply">Indicating if the changes should be applied immediately, recommended value is false</param>
|
||||||
|
public void SetSettings(DisplaySetting displaySetting, bool apply = false)
|
||||||
|
{
|
||||||
|
if (!IsValid)
|
||||||
|
{
|
||||||
|
throw new InvalidDisplayException(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
displaySetting.Save(ScreenName, apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get information about the monitor covering the most of a rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rectangle">The rectangle to get the main monitor information for.</param>
|
||||||
|
/// <returns>An instance of <see cref="DisplayScreen" />.</returns>
|
||||||
|
public static DisplayScreen FromRectangle(Rectangle rectangle)
|
||||||
|
{
|
||||||
|
var monitorHandle = DeviceContextApi.MonitorFromRect(
|
||||||
|
new RectangleL(rectangle),
|
||||||
|
MonitorFromFlag.DefaultToNearest
|
||||||
|
);
|
||||||
|
|
||||||
|
return monitorHandle == IntPtr.Zero ? null : new DisplayScreen(monitorHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get information about the monitor containing or the nearest to a point.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point to get the main monitor information for.</param>
|
||||||
|
/// <returns>An instance of <see cref="DisplayScreen" />.</returns>
|
||||||
|
public static DisplayScreen FromPoint(Point point)
|
||||||
|
{
|
||||||
|
var monitorHandle = DeviceContextApi.MonitorFromPoint(
|
||||||
|
new PointL(point),
|
||||||
|
MonitorFromFlag.DefaultToNearest
|
||||||
|
);
|
||||||
|
|
||||||
|
return monitorHandle == IntPtr.Zero ? null : new DisplayScreen(monitorHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get information about the screen covering the most of a window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hWnd">The window handle to get the main screen information for.</param>
|
||||||
|
/// <returns>An instance of <see cref="DisplayScreen" />.</returns>
|
||||||
|
public static DisplayScreen FromWindow(IntPtr hWnd)
|
||||||
|
{
|
||||||
|
if (hWnd == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid window handle provided.", nameof(hWnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
var monitorHandle = DeviceContextApi.MonitorFromWindow(
|
||||||
|
hWnd,
|
||||||
|
MonitorFromFlag.DefaultToNearest
|
||||||
|
);
|
||||||
|
|
||||||
|
return monitorHandle == IntPtr.Zero ? null : new DisplayScreen(monitorHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NETSTANDARD
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the corresponding <see cref="System.Windows.Forms.Screen" /> instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A instance of Screen object</returns>
|
||||||
|
public System.Windows.Forms.Screen GetWinFormScreen()
|
||||||
|
{
|
||||||
|
if (!IsValid)
|
||||||
|
throw new Exceptions.InvalidDisplayException();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return System.Windows.Forms.Screen.AllScreens.FirstOrDefault(screen => screen.DeviceName.Equals(ScreenName));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the corresponding <see cref="Display" /> instances.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of <see cref="Display" /> instances.</returns>
|
||||||
|
public Display[] GetDisplays()
|
||||||
|
{
|
||||||
|
return Display.GetDisplays().Where(display => display.ScreenName.Equals(ScreenName)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the bounds of the monitor
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle Bounds
|
||||||
|
{
|
||||||
|
get => GetMonitorInfo()?.Bounds.ToRectangle() ?? Rectangle.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the source name of the screen
|
||||||
|
/// </summary>
|
||||||
|
public string ScreenName
|
||||||
|
{
|
||||||
|
get => GetMonitorInfo()?.DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this is the primary display
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPrimary
|
||||||
|
{
|
||||||
|
get => GetMonitorInfo()?.Flags.HasFlag(MonitorInfoFlags.Primary) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this instance contains valid information.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsValid
|
||||||
|
{
|
||||||
|
get => GetMonitorInfo() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the working area of the monitor
|
||||||
|
/// </summary>
|
||||||
|
public Rectangle WorkingArea
|
||||||
|
{
|
||||||
|
get => GetMonitorInfo()?.WorkingArea.ToRectangle() ?? Rectangle.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a list of possible display setting for this screen
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerable list of <see cref="DisplayPossibleSetting"/> instances</returns>
|
||||||
|
public IEnumerable<DisplayPossibleSetting> GetPossibleSettings()
|
||||||
|
{
|
||||||
|
if (!IsValid)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = -1;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
var deviceMode = new DeviceMode(DeviceModeFields.None);
|
||||||
|
if (!DeviceContextApi.EnumDisplaySettings(ScreenName, (DisplaySettingsMode)index, ref deviceMode))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
yield return new DisplayPossibleSetting(deviceMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the best possible display setting for this screen
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="DisplayPossibleSetting"/> instance</returns>
|
||||||
|
public DisplayPossibleSetting GetPreferredSetting()
|
||||||
|
{
|
||||||
|
return IsValid
|
||||||
|
? GetPossibleSettings()
|
||||||
|
.OrderByDescending(setting => (int)setting.ColorDepth)
|
||||||
|
.ThenByDescending(setting => (ulong)setting.Resolution.Width * (ulong)setting.Resolution.Height)
|
||||||
|
.ThenByDescending(setting => setting.Frequency)
|
||||||
|
.FirstOrDefault()
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the corresponding <see cref="PathDisplaySource"/> instance
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An instance of <see cref="PathDisplaySource"/>, or null</returns>
|
||||||
|
public PathDisplaySource ToPathDisplaySource()
|
||||||
|
{
|
||||||
|
return PathDisplaySource
|
||||||
|
.GetDisplaySources()
|
||||||
|
.FirstOrDefault(source => source.DisplayName.Equals(ScreenName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MonitorInfo? GetMonitorInfo()
|
||||||
|
{
|
||||||
|
var monitorInfo = MonitorInfo.Initialize();
|
||||||
|
|
||||||
|
if (DeviceContextApi.GetMonitorInfo(_monitorHandle, ref monitorInfo))
|
||||||
|
{
|
||||||
|
return monitorInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
345
app/WindowsDisplayAPI/DisplaySetting.cs
Normal file
345
app/WindowsDisplayAPI/DisplaySetting.cs
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using WindowsDisplayAPI.Exceptions;
|
||||||
|
using WindowsDisplayAPI.Native;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext.Structures;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds configurations of a windows display
|
||||||
|
/// </summary>
|
||||||
|
public class DisplaySetting : DisplayPossibleSetting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DisplaySetting" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="validSetting">The basic configuration information object</param>
|
||||||
|
/// <param name="position">Display position on desktop</param>
|
||||||
|
public DisplaySetting(DisplayPossibleSetting validSetting, Point position = default)
|
||||||
|
: this(validSetting, position, DisplayOrientation.Identity, DisplayFixedOutput.Default)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DisplaySetting" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="validSetting">The basic configuration information object</param>
|
||||||
|
/// <param name="position">Display position on desktop</param>
|
||||||
|
/// <param name="orientation">Display orientation and rotation</param>
|
||||||
|
/// <param name="outputScalingMode">
|
||||||
|
/// Display output behavior in case of presenting a low-resolution mode on a
|
||||||
|
/// higher-resolution display
|
||||||
|
/// </param>
|
||||||
|
public DisplaySetting(
|
||||||
|
DisplayPossibleSetting validSetting,
|
||||||
|
Point position,
|
||||||
|
DisplayOrientation orientation,
|
||||||
|
DisplayFixedOutput outputScalingMode)
|
||||||
|
: this(
|
||||||
|
validSetting.Resolution, position, validSetting.ColorDepth, validSetting.Frequency,
|
||||||
|
validSetting.IsInterlaced, orientation, outputScalingMode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DisplaySetting" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resolution">Display resolution</param>
|
||||||
|
/// <param name="position">Display position on desktop</param>
|
||||||
|
/// <param name="frequency">Display frequency</param>
|
||||||
|
public DisplaySetting(Size resolution, Point position, int frequency)
|
||||||
|
: this(resolution, position, ColorDepth.Depth32Bit, frequency)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DisplaySetting" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resolution">Display resolution</param>
|
||||||
|
/// <param name="frequency">Display frequency</param>
|
||||||
|
public DisplaySetting(Size resolution, int frequency)
|
||||||
|
: this(resolution, new Point(0, 0), ColorDepth.Depth32Bit, frequency)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="DisplaySetting" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resolution">Display resolution</param>
|
||||||
|
/// <param name="position">Display position on desktop</param>
|
||||||
|
/// <param name="frequency">Display frequency</param>
|
||||||
|
/// <param name="colorDepth">Display color depth</param>
|
||||||
|
/// <param name="isInterlaced">Indicating if display is using interlaces scan out</param>
|
||||||
|
/// <param name="orientation">Display orientation and rotation</param>
|
||||||
|
/// <param name="outputScalingMode">
|
||||||
|
/// Display output behavior in case of presenting a low-resolution mode on a
|
||||||
|
/// higher-resolution display
|
||||||
|
/// </param>
|
||||||
|
public DisplaySetting(
|
||||||
|
Size resolution,
|
||||||
|
Point position,
|
||||||
|
ColorDepth colorDepth,
|
||||||
|
int frequency,
|
||||||
|
bool isInterlaced = false,
|
||||||
|
DisplayOrientation orientation = DisplayOrientation.Identity,
|
||||||
|
DisplayFixedOutput outputScalingMode = DisplayFixedOutput.Default
|
||||||
|
) : base(resolution, frequency, colorDepth, isInterlaced)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
Orientation = orientation;
|
||||||
|
OutputScalingMode = outputScalingMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DisplaySetting() : base(default)
|
||||||
|
{
|
||||||
|
IsEnable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DisplaySetting(DeviceMode deviceMode) : base(deviceMode)
|
||||||
|
{
|
||||||
|
Position = new Point(deviceMode.Position.X, deviceMode.Position.Y);
|
||||||
|
Orientation = deviceMode.DisplayOrientation;
|
||||||
|
OutputScalingMode = deviceMode.DisplayFixedOutput;
|
||||||
|
|
||||||
|
if (Resolution.IsEmpty && Position.IsEmpty)
|
||||||
|
{
|
||||||
|
IsEnable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a boolean value indicating if this instance is currently enable
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnable { get; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the orientation of the display monitor
|
||||||
|
/// </summary>
|
||||||
|
public DisplayOrientation Orientation { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets output behavior in case of presenting a low-resolution mode on a higher-resolution display
|
||||||
|
/// </summary>
|
||||||
|
public DisplayFixedOutput OutputScalingMode { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the position of the display monitor
|
||||||
|
/// </summary>
|
||||||
|
public Point Position { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies settings that are saved using SaveDisplaySettings() or other similar methods but not yet applied
|
||||||
|
/// </summary>
|
||||||
|
public static void ApplySavedSettings()
|
||||||
|
{
|
||||||
|
var result = DeviceContextApi.ChangeDisplaySettingsEx(
|
||||||
|
null,
|
||||||
|
IntPtr.Zero,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ChangeDisplaySettingsFlags.Reset,
|
||||||
|
IntPtr.Zero
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != ChangeDisplaySettingsExResults.Successful)
|
||||||
|
{
|
||||||
|
throw new ModeChangeException($"[{result}]: Applying saved settings failed.", null, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current display settings of a screen
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="screenName">The name of the screen.</param>
|
||||||
|
/// <returns>An instance of <see cref="DisplaySetting" /></returns>
|
||||||
|
public static DisplaySetting GetCurrentFromScreenName(string screenName)
|
||||||
|
{
|
||||||
|
return new DisplaySetting(GetDeviceMode(screenName, DisplaySettingsMode.CurrentSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the saved display settings of a screen
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="screenName">The name of the screen.</param>
|
||||||
|
/// <returns>An instance of <see cref="DisplaySetting" /></returns>
|
||||||
|
public static DisplaySetting GetSavedFromScreenName(string screenName)
|
||||||
|
{
|
||||||
|
return new DisplaySetting(GetDeviceMode(screenName, DisplaySettingsMode.RegistrySettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets and possibility applies a list of display settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newSettingPairs">
|
||||||
|
/// A key value dictionary of <see cref="DisplayDevice" /> and <see cref="DisplaySetting" />
|
||||||
|
/// instances.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="applyNow">Indicating if the changes should be applied immediately, recommended value is false</param>
|
||||||
|
public static void SaveDisplaySettings(
|
||||||
|
Dictionary<DisplayScreen, DisplaySetting> newSettingPairs,
|
||||||
|
bool applyNow)
|
||||||
|
{
|
||||||
|
SaveDisplaySettings(
|
||||||
|
newSettingPairs.ToDictionary(pair => pair.Key.ScreenName, pair => pair.Value),
|
||||||
|
applyNow,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets and possibility applies a list of display settings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newSettingPairs">A key value dictionary of source ids and <see cref="DisplaySetting" /> instance</param>
|
||||||
|
/// <param name="applyNow">Indicating if the changes should be applied immediately, recommended value is false</param>
|
||||||
|
public static void SaveDisplaySettings(
|
||||||
|
Dictionary<int, DisplaySetting> newSettingPairs,
|
||||||
|
bool applyNow)
|
||||||
|
{
|
||||||
|
SaveDisplaySettings(
|
||||||
|
newSettingPairs.ToDictionary(pair => $"\\\\.\\DISPLAY{pair.Key:D}", pair => pair.Value),
|
||||||
|
applyNow,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DeviceMode GetDeviceMode(string screenName, DisplaySettingsMode flags)
|
||||||
|
{
|
||||||
|
var deviceMode = new DeviceMode(DeviceModeFields.None);
|
||||||
|
|
||||||
|
return !string.IsNullOrWhiteSpace(screenName) &&
|
||||||
|
DeviceContextApi.EnumDisplaySettings(
|
||||||
|
screenName,
|
||||||
|
flags,
|
||||||
|
ref deviceMode
|
||||||
|
)
|
||||||
|
? deviceMode
|
||||||
|
: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SaveDisplaySettings(
|
||||||
|
Dictionary<string, DisplaySetting> newSettings,
|
||||||
|
bool applyNow,
|
||||||
|
bool retry
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var screens = DisplayScreen.GetScreens()
|
||||||
|
.Where(screen => screen.IsValid)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var rollbackSettings = screens
|
||||||
|
.ToDictionary(screen => screen.ScreenName, screen => screen.CurrentSetting);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var newSetting in newSettings)
|
||||||
|
{
|
||||||
|
screens.Remove(
|
||||||
|
screens.FirstOrDefault(
|
||||||
|
screen => screen.ScreenName.Equals(newSetting.Key)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
newSetting.Value.Save(newSetting.Key, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable missing monitors
|
||||||
|
foreach (var screen in screens.Where(screen => screen.IsValid))
|
||||||
|
{
|
||||||
|
screen.Disable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applyNow)
|
||||||
|
{
|
||||||
|
ApplySavedSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ModeChangeException)
|
||||||
|
{
|
||||||
|
if (retry)
|
||||||
|
{
|
||||||
|
SaveDisplaySettings(rollbackSettings, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return IsEnable
|
||||||
|
? $"{Resolution} {(IsInterlaced ? "Interlaced" : "Progressive")} {Frequency}hz @ {ColorDepth} @ {Position}"
|
||||||
|
: "Disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Save(string screenName, bool reset)
|
||||||
|
{
|
||||||
|
var deviceMode = GetDeviceMode(screenName);
|
||||||
|
var flags = ChangeDisplaySettingsFlags.UpdateRegistry | ChangeDisplaySettingsFlags.Global;
|
||||||
|
flags |= reset ? ChangeDisplaySettingsFlags.Reset : ChangeDisplaySettingsFlags.NoReset;
|
||||||
|
|
||||||
|
if (IsEnable && Position.X == 0 && Position.Y == 0)
|
||||||
|
{
|
||||||
|
flags |= ChangeDisplaySettingsFlags.SetPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = DeviceContextApi.ChangeDisplaySettingsEx(
|
||||||
|
screenName,
|
||||||
|
ref deviceMode,
|
||||||
|
IntPtr.Zero,
|
||||||
|
flags,
|
||||||
|
IntPtr.Zero
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != ChangeDisplaySettingsExResults.Successful)
|
||||||
|
{
|
||||||
|
throw new ModeChangeException($"[{result}]: Applying saved settings failed.", null, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeviceMode GetDeviceMode(string screenName)
|
||||||
|
{
|
||||||
|
DeviceMode deviceMode;
|
||||||
|
|
||||||
|
if (IsEnable)
|
||||||
|
{
|
||||||
|
var flags = DisplayFlags.None;
|
||||||
|
|
||||||
|
if (IsInterlaced)
|
||||||
|
{
|
||||||
|
flags |= DisplayFlags.Interlaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceMode = new DeviceMode(
|
||||||
|
screenName,
|
||||||
|
new PointL(Position),
|
||||||
|
Orientation,
|
||||||
|
OutputScalingMode,
|
||||||
|
(uint) ColorDepth,
|
||||||
|
(uint) Resolution.Width,
|
||||||
|
(uint) Resolution.Height,
|
||||||
|
flags,
|
||||||
|
(uint) Frequency
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deviceMode = new DeviceMode(
|
||||||
|
screenName,
|
||||||
|
DeviceModeFields.PelsWidth | DeviceModeFields.PelsHeight | DeviceModeFields.Position
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(deviceMode.DeviceName))
|
||||||
|
{
|
||||||
|
throw new MissingDisplayException("Display screen is missing or invalid.", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deviceMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
app/WindowsDisplayAPI/DisplayShaderBlendingCapabilities.cs
Normal file
41
app/WindowsDisplayAPI/DisplayShaderBlendingCapabilities.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible shader blending capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayShaderBlendingCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Device does not support any of these capabilities.
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of handling constant alpha
|
||||||
|
/// </summary>
|
||||||
|
ConstantAlpha = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of handling per-pixel alpha.
|
||||||
|
/// </summary>
|
||||||
|
PerPixelAlpha = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of handling pre-multiplied alpha
|
||||||
|
/// </summary>
|
||||||
|
PreMultipliedAlpha = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of doing gradient fill rectangles.
|
||||||
|
/// </summary>
|
||||||
|
RectangleGradient = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Capable of doing gradient fill triangles.
|
||||||
|
/// </summary>
|
||||||
|
TriangleGradient = 32
|
||||||
|
}
|
||||||
|
}
|
||||||
91
app/WindowsDisplayAPI/DisplayTextCapabilities.cs
Normal file
91
app/WindowsDisplayAPI/DisplayTextCapabilities.cs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible text drawing capabilities of a display device
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayTextCapabilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Device is capable of character output precision.
|
||||||
|
/// </summary>
|
||||||
|
CharacterOutputPrecision = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device is capable of stroke output precision.
|
||||||
|
/// </summary>
|
||||||
|
StrokeOutputPrecision = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device is capable of stroke clip precision.
|
||||||
|
/// </summary>
|
||||||
|
StrokeClipPrecision = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device is capable of 90-degree character rotation.
|
||||||
|
/// </summary>
|
||||||
|
CharacterRotation90 = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device is capable of any character rotation.
|
||||||
|
/// </summary>
|
||||||
|
CharacterRotationAny = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can scale independently in the x-direction and y-direction.
|
||||||
|
/// </summary>
|
||||||
|
IndependentXYScaling = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device is capable of doubled character for scaling.
|
||||||
|
/// </summary>
|
||||||
|
DoubleCharacterScaling = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device uses integer multiples only for character scaling.
|
||||||
|
/// </summary>
|
||||||
|
IntegerCharacterScaling = 128,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device uses any multiples for exact character scaling.
|
||||||
|
/// </summary>
|
||||||
|
ExactCharacterScaling = 256,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw double-weight characters.
|
||||||
|
/// </summary>
|
||||||
|
DoubleWeightCharacter = 512,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can italicize.
|
||||||
|
/// </summary>
|
||||||
|
CanItalicize = 1024,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can underline.
|
||||||
|
/// </summary>
|
||||||
|
CanUnderline = 2048,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw strikeouts.
|
||||||
|
/// </summary>
|
||||||
|
CanStrikeout = 4096,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw raster fonts.
|
||||||
|
/// </summary>
|
||||||
|
RasterFonts = 8192,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device can draw vector fonts.
|
||||||
|
/// </summary>
|
||||||
|
VectorFonts = 16384,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Device cannot scroll using a bit-block transfer. Note that this meaning may be the opposite of what you expect.
|
||||||
|
/// </summary>
|
||||||
|
BitBlockTransferScrollInAbility = 65536
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/WindowsDisplayAPI/Exceptions/DuplicateModeException.cs
Normal file
18
app/WindowsDisplayAPI/Exceptions/DuplicateModeException.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of two similar but not identical path or path target
|
||||||
|
/// </summary>
|
||||||
|
public class DuplicateModeException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new DuplicateModeException exception
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public DuplicateModeException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
app/WindowsDisplayAPI/Exceptions/InvalidDisplayException.cs
Normal file
32
app/WindowsDisplayAPI/Exceptions/InvalidDisplayException.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of an invalid display instance
|
||||||
|
/// </summary>
|
||||||
|
public class InvalidDisplayException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new InvalidDisplayException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayPath">The path of invalidated display device</param>
|
||||||
|
public InvalidDisplayException(string displayPath)
|
||||||
|
{
|
||||||
|
DisplayPath = displayPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new InvalidDisplayException
|
||||||
|
/// </summary>
|
||||||
|
public InvalidDisplayException() : this(null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path of the display device
|
||||||
|
/// </summary>
|
||||||
|
public string DisplayPath { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/WindowsDisplayAPI/Exceptions/InvalidEDIDInformation.cs
Normal file
18
app/WindowsDisplayAPI/Exceptions/InvalidEDIDInformation.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of missing or invalid EDID information
|
||||||
|
/// </summary>
|
||||||
|
public class InvalidEDIDInformation : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new InvalidEDIDInformation exception
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public InvalidEDIDInformation(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of missing or invalid registry address information
|
||||||
|
/// </summary>
|
||||||
|
public class InvalidRegistryAddressException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new InvalidRegistryAddressException exception
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public InvalidRegistryAddressException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
app/WindowsDisplayAPI/Exceptions/MissingDisplayException.cs
Normal file
25
app/WindowsDisplayAPI/Exceptions/MissingDisplayException.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of a missing display
|
||||||
|
/// </summary>
|
||||||
|
public class MissingDisplayException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new MissingDisplayException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayPath">The path of missing display device</param>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public MissingDisplayException(string message, string displayPath) : base(message)
|
||||||
|
{
|
||||||
|
DisplayPath = displayPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path of the display device
|
||||||
|
/// </summary>
|
||||||
|
public string DisplayPath { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/WindowsDisplayAPI/Exceptions/MissingModeException.cs
Normal file
26
app/WindowsDisplayAPI/Exceptions/MissingModeException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of missing mode information
|
||||||
|
/// </summary>
|
||||||
|
public class MissingModeException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new MissingModeException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="missingModeType">The missing mode type</param>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public MissingModeException(string message, DisplayConfigModeInfoType missingModeType) : base(message)
|
||||||
|
{
|
||||||
|
MissingModeType = missingModeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the missing mode type
|
||||||
|
/// </summary>
|
||||||
|
public DisplayConfigModeInfoType MissingModeType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/WindowsDisplayAPI/Exceptions/ModeChangeException.cs
Normal file
37
app/WindowsDisplayAPI/Exceptions/ModeChangeException.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs during a mode change request
|
||||||
|
/// </summary>
|
||||||
|
public class ModeChangeException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new ModeChangeException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The device responsible for the mode change</param>
|
||||||
|
/// <param name="errorCode">The error code</param>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public ModeChangeException(
|
||||||
|
string message,
|
||||||
|
DisplayDevice device,
|
||||||
|
ChangeDisplaySettingsExResults errorCode
|
||||||
|
) : base(message)
|
||||||
|
{
|
||||||
|
Device = device;
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display device responsible for the mode change
|
||||||
|
/// </summary>
|
||||||
|
public DisplayDevice Device { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the error code
|
||||||
|
/// </summary>
|
||||||
|
public ChangeDisplaySettingsExResults ErrorCode { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
app/WindowsDisplayAPI/Exceptions/NotACloneMemberException.cs
Normal file
18
app/WindowsDisplayAPI/Exceptions/NotACloneMemberException.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of not being in a valid clone group
|
||||||
|
/// </summary>
|
||||||
|
public class NotACloneMemberException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new NotACloneMemberException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public NotACloneMemberException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
app/WindowsDisplayAPI/Exceptions/PathChangeException.cs
Normal file
27
app/WindowsDisplayAPI/Exceptions/PathChangeException.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of an invalid path request
|
||||||
|
/// </summary>
|
||||||
|
public class PathChangeException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathChangeException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
public PathChangeException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new PathChangeException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
/// <param name="innerException">The inner causing exception</param>
|
||||||
|
public PathChangeException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occurs because of path target being inavailable
|
||||||
|
/// </summary>
|
||||||
|
public class TargetNotAvailableException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new TargetNotAvailableException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The human readable message of the exception</param>
|
||||||
|
/// <param name="adapterId">The driving adapter's identification</param>
|
||||||
|
/// <param name="targetId">The target identification number</param>
|
||||||
|
public TargetNotAvailableException(string message, LUID adapterId, uint targetId) : base(message)
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
TargetId = targetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the driving adapter's identification
|
||||||
|
/// </summary>
|
||||||
|
public LUID AdapterId { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the target's identification number
|
||||||
|
/// </summary>
|
||||||
|
public uint TargetId { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
app/WindowsDisplayAPI/Icon.png
Normal file
BIN
app/WindowsDisplayAPI/Icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,48 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible values for the result of mode change request
|
||||||
|
/// </summary>
|
||||||
|
public enum ChangeDisplaySettingsExResults
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Completed successfully
|
||||||
|
/// </summary>
|
||||||
|
Successful = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes needs restart
|
||||||
|
/// </summary>
|
||||||
|
Restart = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Failed to change and save setings
|
||||||
|
/// </summary>
|
||||||
|
Failed = -1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid data provide
|
||||||
|
/// </summary>
|
||||||
|
BadMode = -2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes not updated
|
||||||
|
/// </summary>
|
||||||
|
NotUpdated = -3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid flags provided
|
||||||
|
/// </summary>
|
||||||
|
BadFlags = -4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bad parameters provided
|
||||||
|
/// </summary>
|
||||||
|
BadParam = -5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bad Dual View mode used with mode
|
||||||
|
/// </summary>
|
||||||
|
BadDualView = -6
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum ChangeDisplaySettingsFlags : uint
|
||||||
|
{
|
||||||
|
UpdateRegistry = 0x00000001,
|
||||||
|
|
||||||
|
Global = 0x00000008,
|
||||||
|
|
||||||
|
SetPrimary = 0x00000010,
|
||||||
|
|
||||||
|
Reset = 0x40000000,
|
||||||
|
|
||||||
|
NoReset = 0x10000000
|
||||||
|
}
|
||||||
|
}
|
||||||
56
app/WindowsDisplayAPI/Native/DeviceContext/DCHandle.cs
Normal file
56
app/WindowsDisplayAPI/Native/DeviceContext/DCHandle.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
internal class DCHandle : SafeHandle
|
||||||
|
{
|
||||||
|
private readonly bool _created;
|
||||||
|
|
||||||
|
private DCHandle(IntPtr handle, bool created) : base(handle, true)
|
||||||
|
{
|
||||||
|
_created = created;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsInvalid
|
||||||
|
{
|
||||||
|
get => handle == IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DCHandle CreateFromDevice(string screenName, string devicePath)
|
||||||
|
{
|
||||||
|
return new DCHandle(
|
||||||
|
DeviceContextApi.CreateDC(screenName, devicePath, null, IntPtr.Zero),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DCHandle CreateFromScreen(string screenName)
|
||||||
|
{
|
||||||
|
return CreateFromDevice(screenName, screenName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DCHandle CreateFromWindow(IntPtr windowHandle)
|
||||||
|
{
|
||||||
|
return new DCHandle(
|
||||||
|
DeviceContextApi.GetDC(windowHandle),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DCHandle CreateGlobal()
|
||||||
|
{
|
||||||
|
return new DCHandle(
|
||||||
|
DeviceContextApi.CreateDC("DISPLAY", null, null, IntPtr.Zero),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
return _created
|
||||||
|
? DeviceContextApi.DeleteDC(this.handle)
|
||||||
|
: DeviceContextApi.ReleaseDC(IntPtr.Zero, this.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
internal enum DeviceCapability
|
||||||
|
{
|
||||||
|
DriverVersion = 0,
|
||||||
|
Technology = 2,
|
||||||
|
HorizontalSizeInMM = 4,
|
||||||
|
VerticalSizeInMM = 6,
|
||||||
|
HorizontalResolution = 8,
|
||||||
|
VerticalResolution = 10,
|
||||||
|
BitsPerPixel = 12,
|
||||||
|
Planes = 14,
|
||||||
|
NumberOfBrushes = 16,
|
||||||
|
NumberOfPens = 18,
|
||||||
|
NumberOfMarkers = 20,
|
||||||
|
NumberOfFonts = 22,
|
||||||
|
NumberOfColors = 24,
|
||||||
|
DeviceDescriptorSize = 26,
|
||||||
|
CurveCapabilities = 28,
|
||||||
|
LineCapabilities = 30,
|
||||||
|
PolygonalCapabilities = 32,
|
||||||
|
TextCapabilities = 34,
|
||||||
|
ClipCapabilities = 36,
|
||||||
|
RasterCapabilities = 38,
|
||||||
|
HorizontalAspect = 40,
|
||||||
|
VerticalAspect = 42,
|
||||||
|
HypotenuseAspect = 44,
|
||||||
|
//ShadeBlendingCapabilities = 45,
|
||||||
|
HorizontalLogicalPixels = 88,
|
||||||
|
VerticalLogicalPixels = 90,
|
||||||
|
PaletteSize = 104,
|
||||||
|
ReservedPaletteSize = 106,
|
||||||
|
ColorResolution = 108,
|
||||||
|
|
||||||
|
// Printer Only
|
||||||
|
PhysicalWidth = 110,
|
||||||
|
PhysicalHeight = 111,
|
||||||
|
PhysicalHorizontalMargin = 112,
|
||||||
|
PhysicalVerticalMargin = 113,
|
||||||
|
HorizontalScalingFactor = 114,
|
||||||
|
VerticalScalingFactor = 115,
|
||||||
|
|
||||||
|
// Display Only
|
||||||
|
VerticalRefreshRateInHz = 116,
|
||||||
|
DesktopVerticalResolution = 117,
|
||||||
|
DesktopHorizontalResolution = 118,
|
||||||
|
PreferredBLTAlignment = 119,
|
||||||
|
ShadeBlendingCapabilities = 120,
|
||||||
|
ColorManagementCapabilities = 121,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DeviceModeFields : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
Position = 0x20,
|
||||||
|
|
||||||
|
DisplayOrientation = 0x80,
|
||||||
|
|
||||||
|
Color = 0x800,
|
||||||
|
|
||||||
|
Duplex = 0x1000,
|
||||||
|
|
||||||
|
YResolution = 0x2000,
|
||||||
|
|
||||||
|
TtOption = 0x4000,
|
||||||
|
|
||||||
|
Collate = 0x8000,
|
||||||
|
|
||||||
|
FormName = 0x10000,
|
||||||
|
|
||||||
|
LogPixels = 0x20000,
|
||||||
|
|
||||||
|
BitsPerPixel = 0x40000,
|
||||||
|
|
||||||
|
PelsWidth = 0x80000,
|
||||||
|
|
||||||
|
PelsHeight = 0x100000,
|
||||||
|
|
||||||
|
DisplayFlags = 0x200000,
|
||||||
|
|
||||||
|
DisplayFrequency = 0x400000,
|
||||||
|
|
||||||
|
DisplayFixedOutput = 0x20000000,
|
||||||
|
|
||||||
|
AllDisplay = Position |
|
||||||
|
DisplayOrientation |
|
||||||
|
YResolution |
|
||||||
|
BitsPerPixel |
|
||||||
|
PelsWidth |
|
||||||
|
PelsHeight |
|
||||||
|
DisplayFlags |
|
||||||
|
DisplayFrequency |
|
||||||
|
DisplayFixedOutput,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DisplayDeviceStateFlags : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The device is part of the desktop.
|
||||||
|
/// </summary>
|
||||||
|
AttachedToDesktop = 0x1,
|
||||||
|
MultiDriver = 0x2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The device is part of the desktop.
|
||||||
|
/// </summary>
|
||||||
|
PrimaryDevice = 0x4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a pseudo device used to mirror application drawing for remoting or other purposes.
|
||||||
|
/// </summary>
|
||||||
|
MirroringDriver = 0x8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The device is VGA compatible.
|
||||||
|
/// </summary>
|
||||||
|
VGACompatible = 0x10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The device is removable; it cannot be the primary display.
|
||||||
|
/// </summary>
|
||||||
|
Removable = 0x20,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The device has more display modes than its output devices support.
|
||||||
|
/// </summary>
|
||||||
|
ModesPruned = 0x8000000,
|
||||||
|
Remote = 0x4000000,
|
||||||
|
Disconnect = 0x2000000
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible values for the display fixed output
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayFixedOutput : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default behavior
|
||||||
|
/// </summary>
|
||||||
|
Default = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stretches the output to fit to the display
|
||||||
|
/// </summary>
|
||||||
|
Stretch = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Centers the output in the middle of the display
|
||||||
|
/// </summary>
|
||||||
|
Center = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
12
app/WindowsDisplayAPI/Native/DeviceContext/DisplayFlags.cs
Normal file
12
app/WindowsDisplayAPI/Native/DeviceContext/DisplayFlags.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DisplayFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Grayscale = 1,
|
||||||
|
Interlaced = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains possible values for the display orientation
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayOrientation : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No rotation
|
||||||
|
/// </summary>
|
||||||
|
Identity = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 90 degree rotation
|
||||||
|
/// </summary>
|
||||||
|
Rotate90Degree = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 180 degree rotation
|
||||||
|
/// </summary>
|
||||||
|
Rotate180Degree = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 270 degree rotation
|
||||||
|
/// </summary>
|
||||||
|
Rotate270Degree = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
internal enum DisplaySettingsMode
|
||||||
|
{
|
||||||
|
CurrentSettings = -1,
|
||||||
|
|
||||||
|
RegistrySettings = -2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
internal enum DisplayTechnology : int
|
||||||
|
{
|
||||||
|
Plotter = 0,
|
||||||
|
RasterDisplay = 1,
|
||||||
|
RasterPrinter = 2,
|
||||||
|
RasterCamera = 3,
|
||||||
|
CharacterStream = 4,
|
||||||
|
MetaFile = 5,
|
||||||
|
DisplayFile = 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
internal enum MonitorFromFlag : uint
|
||||||
|
{
|
||||||
|
DefaultToNull = 0,
|
||||||
|
DefaultToPrimary = 1,
|
||||||
|
DefaultToNearest = 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum MonitorInfoFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Primary = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd183565(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
|
||||||
|
internal struct DeviceMode
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] [FieldOffset(0)]
|
||||||
|
public readonly string DeviceName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U2)] [FieldOffset(32)]
|
||||||
|
public readonly ushort SpecificationVersion;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U2)] [FieldOffset(34)]
|
||||||
|
public readonly ushort DriverVersion;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U2)] [FieldOffset(36)]
|
||||||
|
public readonly ushort Size;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U2)] [FieldOffset(38)]
|
||||||
|
public readonly ushort DriverExtra;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(40)]
|
||||||
|
public readonly DeviceModeFields Fields;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] [FieldOffset(44)]
|
||||||
|
public readonly PointL Position;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(52)]
|
||||||
|
public readonly DisplayOrientation DisplayOrientation;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(56)]
|
||||||
|
public readonly DisplayFixedOutput DisplayFixedOutput;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I2)] [FieldOffset(60)]
|
||||||
|
public readonly short Color;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I2)] [FieldOffset(62)]
|
||||||
|
public readonly short Duplex;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I2)] [FieldOffset(64)]
|
||||||
|
public readonly short YResolution;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I2)] [FieldOffset(66)]
|
||||||
|
public readonly short TrueTypeOption;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.I2)] [FieldOffset(68)]
|
||||||
|
public readonly short Collate;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] [FieldOffset(72)]
|
||||||
|
private readonly string FormName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U2)] [FieldOffset(102)]
|
||||||
|
public readonly ushort LogicalInchPixels;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(104)]
|
||||||
|
public readonly uint BitsPerPixel;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(108)]
|
||||||
|
public readonly uint PixelsWidth;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(112)]
|
||||||
|
public readonly uint PixelsHeight;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(116)]
|
||||||
|
public readonly DisplayFlags DisplayFlags;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(120)]
|
||||||
|
public readonly uint DisplayFrequency;
|
||||||
|
|
||||||
|
public DeviceMode(DeviceModeFields fields) : this()
|
||||||
|
{
|
||||||
|
SpecificationVersion = 0x0320;
|
||||||
|
Size = (ushort) Marshal.SizeOf(GetType());
|
||||||
|
Fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceMode(string deviceName, DeviceModeFields fields) : this(fields)
|
||||||
|
{
|
||||||
|
DeviceName = deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceMode(
|
||||||
|
string deviceName,
|
||||||
|
PointL position,
|
||||||
|
DisplayOrientation orientation,
|
||||||
|
DisplayFixedOutput fixedOutput,
|
||||||
|
uint bpp,
|
||||||
|
uint width,
|
||||||
|
uint height,
|
||||||
|
DisplayFlags displayFlags,
|
||||||
|
uint displayFrequency) : this(
|
||||||
|
deviceName,
|
||||||
|
DeviceModeFields.Position |
|
||||||
|
DeviceModeFields.DisplayOrientation |
|
||||||
|
DeviceModeFields.DisplayFixedOutput |
|
||||||
|
DeviceModeFields.BitsPerPixel |
|
||||||
|
DeviceModeFields.PelsWidth |
|
||||||
|
DeviceModeFields.PelsHeight |
|
||||||
|
DeviceModeFields.DisplayFlags |
|
||||||
|
DeviceModeFields.DisplayFrequency
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
DisplayOrientation = orientation;
|
||||||
|
DisplayFixedOutput = fixedOutput;
|
||||||
|
BitsPerPixel = bpp;
|
||||||
|
PixelsWidth = width;
|
||||||
|
PixelsHeight = height;
|
||||||
|
DisplayFlags = displayFlags;
|
||||||
|
DisplayFrequency = displayFrequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceMode(string deviceName, PointL position, uint bpp, uint width, uint height, uint displayFrequency)
|
||||||
|
: this(
|
||||||
|
deviceName,
|
||||||
|
DeviceModeFields.Position |
|
||||||
|
DeviceModeFields.BitsPerPixel |
|
||||||
|
DeviceModeFields.PelsWidth |
|
||||||
|
DeviceModeFields.PelsHeight |
|
||||||
|
DeviceModeFields.DisplayFrequency
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
BitsPerPixel = bpp;
|
||||||
|
PixelsWidth = width;
|
||||||
|
PixelsHeight = height;
|
||||||
|
DisplayFrequency = displayFrequency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext.Structures
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
internal struct DisplayDevice
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.U4)] internal uint Size;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public readonly string DeviceName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||||
|
public readonly string DeviceString;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayDeviceStateFlags StateFlags;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||||
|
public readonly string DeviceId;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||||
|
public readonly string DeviceKey;
|
||||||
|
|
||||||
|
public static DisplayDevice Initialize()
|
||||||
|
{
|
||||||
|
return new DisplayDevice
|
||||||
|
{
|
||||||
|
Size = (uint) Marshal.SizeOf(typeof(DisplayDevice))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext.Structures
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct GammaRamp
|
||||||
|
{
|
||||||
|
public const int DataPoints = 256;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DataPoints)]
|
||||||
|
public readonly ushort[] Red;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DataPoints)]
|
||||||
|
public readonly ushort[] Green;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = DataPoints)]
|
||||||
|
public readonly ushort[] Blue;
|
||||||
|
|
||||||
|
public GammaRamp(ushort[] red, ushort[] green, ushort[] blue)
|
||||||
|
{
|
||||||
|
if (red == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(red));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (green == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(green));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blue == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(blue));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (red.Length != DataPoints)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(red));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (green.Length != DataPoints)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(green));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blue.Length != DataPoints)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(blue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Red = red;
|
||||||
|
Green = green;
|
||||||
|
Blue = blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DeviceContext.Structures
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct MonitorInfo
|
||||||
|
{
|
||||||
|
internal uint Size;
|
||||||
|
public readonly RectangleL Bounds;
|
||||||
|
public readonly RectangleL WorkingArea;
|
||||||
|
public readonly MonitorInfoFlags Flags;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public readonly string DisplayName;
|
||||||
|
|
||||||
|
public static MonitorInfo Initialize()
|
||||||
|
{
|
||||||
|
return new MonitorInfo
|
||||||
|
{
|
||||||
|
Size = (uint)Marshal.SizeOf(typeof(MonitorInfo))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
106
app/WindowsDisplayAPI/Native/DeviceContextApi.cs
Normal file
106
app/WindowsDisplayAPI/Native/DeviceContextApi.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext;
|
||||||
|
using WindowsDisplayAPI.Native.DeviceContext.Structures;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native
|
||||||
|
{
|
||||||
|
internal class DeviceContextApi
|
||||||
|
{
|
||||||
|
[DllImport("user32", CharSet = CharSet.Ansi)]
|
||||||
|
public static extern ChangeDisplaySettingsExResults ChangeDisplaySettingsEx(
|
||||||
|
string deviceName,
|
||||||
|
ref DeviceMode devMode,
|
||||||
|
IntPtr handler,
|
||||||
|
ChangeDisplaySettingsFlags flags,
|
||||||
|
IntPtr param
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Ansi)]
|
||||||
|
public static extern ChangeDisplaySettingsExResults ChangeDisplaySettingsEx(
|
||||||
|
string deviceName,
|
||||||
|
IntPtr devModePointer,
|
||||||
|
IntPtr handler,
|
||||||
|
ChangeDisplaySettingsFlags flags,
|
||||||
|
IntPtr param
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Ansi)]
|
||||||
|
public static extern bool EnumDisplaySettings(
|
||||||
|
string deviceName,
|
||||||
|
DisplaySettingsMode mode,
|
||||||
|
ref DeviceMode devMode
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("gdi32", CharSet = CharSet.Unicode)]
|
||||||
|
internal static extern IntPtr CreateDC(string driver, string device, string port, IntPtr deviceMode);
|
||||||
|
|
||||||
|
[DllImport("gdi32")]
|
||||||
|
internal static extern bool DeleteDC(IntPtr dcHandle);
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||||
|
internal static extern bool EnumDisplayDevices(
|
||||||
|
string deviceName,
|
||||||
|
uint deviceNumber,
|
||||||
|
ref DeviceContext.Structures.DisplayDevice displayDevice,
|
||||||
|
uint flags
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern bool EnumDisplayMonitors(
|
||||||
|
[In] IntPtr dcHandle,
|
||||||
|
[In] IntPtr clip,
|
||||||
|
MonitorEnumProcedure callback,
|
||||||
|
IntPtr callbackObject
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern IntPtr GetDC(IntPtr windowHandle);
|
||||||
|
|
||||||
|
[DllImport("gdi32")]
|
||||||
|
internal static extern int GetDeviceCaps(DCHandle dcHandle, DeviceCapability index);
|
||||||
|
|
||||||
|
[DllImport("gdi32")]
|
||||||
|
internal static extern bool GetDeviceGammaRamp(DCHandle dcHandle, ref GammaRamp ramp);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern bool GetMonitorInfo(
|
||||||
|
IntPtr monitorHandle,
|
||||||
|
ref MonitorInfo monitorInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern IntPtr MonitorFromPoint(
|
||||||
|
[In] PointL point,
|
||||||
|
MonitorFromFlag flag
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern IntPtr MonitorFromRect(
|
||||||
|
[In] RectangleL rectangle,
|
||||||
|
MonitorFromFlag flag
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern IntPtr MonitorFromWindow(
|
||||||
|
[In] IntPtr windowHandle,
|
||||||
|
MonitorFromFlag flag
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
internal static extern bool ReleaseDC([In] IntPtr windowHandle, [In] IntPtr dcHandle);
|
||||||
|
|
||||||
|
[DllImport("gdi32")]
|
||||||
|
internal static extern bool SetDeviceGammaRamp(DCHandle dcHandle, ref GammaRamp ramp);
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||||
|
internal delegate int MonitorEnumProcedure(
|
||||||
|
IntPtr monitorHandle,
|
||||||
|
IntPtr dcHandle,
|
||||||
|
ref RectangleL rect,
|
||||||
|
IntPtr callbackObject
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
internal enum DisplayConfigDeviceInfoType
|
||||||
|
{
|
||||||
|
SetSourceDPIScale = -4,
|
||||||
|
GetSourceDPIScale = -3,
|
||||||
|
GetSourceName = 1,
|
||||||
|
GetTargetName = 2,
|
||||||
|
GetTargetPreferredMode = 3,
|
||||||
|
GetAdapterName = 4,
|
||||||
|
SetTargetPersistence = 5,
|
||||||
|
GetTargetBaseType = 6,
|
||||||
|
GetSupportVirtualResolution = 7,
|
||||||
|
SetSupportVirtualResolution = 8
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possbile types of modes
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayConfigModeInfoType : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid value for mode type
|
||||||
|
/// </summary>
|
||||||
|
Invalid = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Source mode type
|
||||||
|
/// </summary>
|
||||||
|
Source = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target mode type
|
||||||
|
/// </summary>
|
||||||
|
Target = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display image type
|
||||||
|
/// </summary>
|
||||||
|
DesktopImage = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DisplayConfigPathInfoFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Active = 1,
|
||||||
|
SupportVirtualMode = 8
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DisplayConfigPathSourceInfoFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
InUse = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DisplayConfigPathTargetInfoFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
InUse = 1,
|
||||||
|
Forcible = 2,
|
||||||
|
AvailabilityBoot = 3,
|
||||||
|
AvailabilityPath = 4,
|
||||||
|
AvailabilitySystem = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible pixel formats
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553963(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayConfigPixelFormat : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Pixel format is not specified
|
||||||
|
/// </summary>
|
||||||
|
NotSpecified = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates 8 bits per pixel format.
|
||||||
|
/// </summary>
|
||||||
|
PixelFormat8Bpp = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates 16 bits per pixel format.
|
||||||
|
/// </summary>
|
||||||
|
PixelFormat16Bpp = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates 24 bits per pixel format.
|
||||||
|
/// </summary>
|
||||||
|
PixelFormat24Bpp = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates 32 bits per pixel format.
|
||||||
|
/// </summary>
|
||||||
|
PixelFormat32Bpp = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the current display is not an 8, 16, 24, or 32 bits per pixel GDI desktop mode.
|
||||||
|
/// </summary>
|
||||||
|
PixelFormatNonGDI = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Rotation modes
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553970(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayConfigRotation : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Rotation mode is not specified
|
||||||
|
/// </summary>
|
||||||
|
NotSpecified = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that rotation is 0 degrees—landscape mode.
|
||||||
|
/// </summary>
|
||||||
|
Identity = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that rotation is 90 degrees clockwise—portrait mode.
|
||||||
|
/// </summary>
|
||||||
|
Rotate90 = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that rotation is 180 degrees clockwise—inverted landscape mode.
|
||||||
|
/// </summary>
|
||||||
|
Rotate180 = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that rotation is 270 degrees clockwise—inverted portrait mode.
|
||||||
|
/// </summary>
|
||||||
|
Rotate270 = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scaling modes
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553974(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayConfigScaling : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scaling mode is not specified
|
||||||
|
/// </summary>
|
||||||
|
NotSpecified = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the identity transformation; the source content is presented with no change. This transformation is
|
||||||
|
/// available only if the path's source mode has the same spatial resolution as the path's target mode.
|
||||||
|
/// </summary>
|
||||||
|
Identity = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the centering transformation; the source content is presented unscaled, centered with respect to the
|
||||||
|
/// spatial resolution of the target mode.
|
||||||
|
/// </summary>
|
||||||
|
Centered = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the content is scaled to fit the path's target.
|
||||||
|
/// </summary>
|
||||||
|
Stretched = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the aspect-ratio centering transformation.
|
||||||
|
/// </summary>
|
||||||
|
AspectRatioCenteredMax = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the caller requests a custom scaling that the caller cannot describe with any of the other values.
|
||||||
|
/// Only a hardware vendor's value-add application should use this value, because the value-add application might
|
||||||
|
/// require a private interface to the driver. The application can then use this value to indicate additional context
|
||||||
|
/// for the driver for the custom value on the specified path.
|
||||||
|
/// </summary>
|
||||||
|
Custom = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the caller does not have any preference for the scaling.
|
||||||
|
/// </summary>
|
||||||
|
Preferred = 128
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible values for display scan line ordering
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553977(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayConfigScanLineOrdering : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that scan-line ordering of the output is unspecified.
|
||||||
|
/// </summary>
|
||||||
|
NotSpecified = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the output is a progressive image.
|
||||||
|
/// </summary>
|
||||||
|
Progressive = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the output is an interlaced image that is created beginning with the upper field.
|
||||||
|
/// </summary>
|
||||||
|
InterlacedWithUpperFieldFirst = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the output is an interlaced image that is created beginning with the lower field.
|
||||||
|
/// </summary>
|
||||||
|
InterlacedWithLowerFieldFirst = 3
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
public enum DisplayConfigSourceDPIScale : uint
|
||||||
|
{
|
||||||
|
Identity = 100,
|
||||||
|
Scale125Percent = 125,
|
||||||
|
Scale150Percent = 150,
|
||||||
|
Scale175Percent = 175,
|
||||||
|
Scale200Percent = 200,
|
||||||
|
Scale225Percent = 225,
|
||||||
|
Scale250Percent = 250,
|
||||||
|
Scale300Percent = 300,
|
||||||
|
Scale350Percent = 350,
|
||||||
|
Scale400Percent = 400,
|
||||||
|
Scale450Percent = 450,
|
||||||
|
Scale500Percent = 500
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum DisplayConfigTargetDeviceNameFlags : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
FriendlyNameFromEDID = 1,
|
||||||
|
FriendlyNameForced = 2,
|
||||||
|
EDIDIdsValid = 4
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible topology identifications
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff554001(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum DisplayConfigTopologyId : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invalid topology identification
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the display topology is an internal configuration.
|
||||||
|
/// </summary>
|
||||||
|
Internal = 0x00000001,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the display topology is clone-view configuration.
|
||||||
|
/// </summary>
|
||||||
|
Clone = 0x00000002,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the display topology is an extended configuration.
|
||||||
|
/// </summary>
|
||||||
|
Extend = 0x00000004,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the display topology is an external configuration.
|
||||||
|
/// </summary>
|
||||||
|
External = 0x00000008
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible target's connector types
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff554003(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
public enum DisplayConfigVideoOutputTechnology : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a connector that is not one of the types that is indicated by the following enumerators in this
|
||||||
|
/// enumeration.
|
||||||
|
/// </summary>
|
||||||
|
Other = 0xFFFFFFFF,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an HD15 (VGA) connector.
|
||||||
|
/// </summary>
|
||||||
|
HD15 = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an S-video connector.
|
||||||
|
/// </summary>
|
||||||
|
SVideo = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a composite video connector group.
|
||||||
|
/// </summary>
|
||||||
|
CompositeVideo = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a component video connector group.
|
||||||
|
/// </summary>
|
||||||
|
ComponentVideo = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a Digital Video Interface (DVI) connector.
|
||||||
|
/// </summary>
|
||||||
|
DVI = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a High-Definition Multimedia Interface (HDMI) connector.
|
||||||
|
/// </summary>
|
||||||
|
HDMI = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a Low Voltage Differential Swing (LVDS) connector.
|
||||||
|
/// </summary>
|
||||||
|
LVDS = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a Japanese D connector.
|
||||||
|
/// </summary>
|
||||||
|
DJPN = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an SDI connector.
|
||||||
|
/// </summary>
|
||||||
|
SDI = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an external display port, which is a display port that connects externally to a display device.
|
||||||
|
/// </summary>
|
||||||
|
DisplayPortExternal = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an embedded display port that connects internally to a display device.
|
||||||
|
/// </summary>
|
||||||
|
DisplayPortEmbedded = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an external Unified Display Interface (UDI), which is a UDI that connects externally to a display device.
|
||||||
|
/// </summary>
|
||||||
|
UDIExternal = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates an embedded UDI that connects internally to a display device.
|
||||||
|
/// </summary>
|
||||||
|
UDIEmbedded = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a dongle cable that supports standard definition television (SDTV).
|
||||||
|
/// </summary>
|
||||||
|
SDTVDongle = 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the VidPN target is a Miracast wireless display device.
|
||||||
|
/// </summary>
|
||||||
|
Miracast = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the video output device connects internally to a display device (for example, the internal
|
||||||
|
/// connection in a laptop computer).
|
||||||
|
/// </summary>
|
||||||
|
Internal = 0x80000000
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible values for QueryDisplayConfig() flags property
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff569215(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum QueryDeviceConfigFlags : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All the possible path combinations of sources to targets.
|
||||||
|
/// </summary>
|
||||||
|
AllPaths = 0x00000001,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Currently active paths only.
|
||||||
|
/// </summary>
|
||||||
|
OnlyActivePaths = 0x00000002,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Active path as defined in the CCD database for the currently connected displays.
|
||||||
|
/// </summary>
|
||||||
|
DatabaseCurrent = 0x00000004,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Virtual Mode Aware
|
||||||
|
/// </summary>
|
||||||
|
VirtualModeAware = 0x0000010
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum SetDisplayConfigFlags : uint
|
||||||
|
{
|
||||||
|
TopologyInternal = 0x00000001,
|
||||||
|
TopologyClone = 0x00000002,
|
||||||
|
TopologyExtend = 0x00000004,
|
||||||
|
TopologyExternal = 0x00000008,
|
||||||
|
UseDatabaseCurrent = TopologyInternal | TopologyClone | TopologyExtend | TopologyExternal,
|
||||||
|
TopologySupplied = 0x00000010,
|
||||||
|
UseSuppliedDisplayConfig = 0x00000020,
|
||||||
|
Validate = 0x00000040,
|
||||||
|
Apply = 0x00000080,
|
||||||
|
NoOptimization = 0x00000100,
|
||||||
|
SaveToDatabase = 0x00000200,
|
||||||
|
AllowChanges = 0x00000400,
|
||||||
|
PathPersistIfRequired = 0x00000800,
|
||||||
|
ForceModeEnumeration = 0x00001000,
|
||||||
|
AllowPathOrderChanges = 0x00002000,
|
||||||
|
VirtualModeAware = 0x00008000
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553913(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfig2DRegion : IEquatable<DisplayConfig2DRegion>
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Width;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Height;
|
||||||
|
|
||||||
|
public DisplayConfig2DRegion(uint width, uint height)
|
||||||
|
{
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfig2DRegion other)
|
||||||
|
{
|
||||||
|
return Width == other.Width && Height == other.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfig2DRegion region && Equals(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return ((int) Width * 397) ^ (int) Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfig2DRegion left, DisplayConfig2DRegion right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfig2DRegion left, DisplayConfig2DRegion right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/ff553915(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
internal struct DisplayConfigAdapterName
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||||
|
public readonly string AdapterDevicePath;
|
||||||
|
|
||||||
|
public DisplayConfigAdapterName(LUID adapter) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/mt622102(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigDesktopImageInfo : IEquatable<DisplayConfigDesktopImageInfo>
|
||||||
|
{
|
||||||
|
public const ushort InvalidDesktopImageModeIndex = 0xffff;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly PointL PathSourceSize;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly RectangleL DesktopImageRegion;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly RectangleL DesktopImageClip;
|
||||||
|
|
||||||
|
public DisplayConfigDesktopImageInfo(
|
||||||
|
PointL pathSourceSize,
|
||||||
|
RectangleL desktopImageRegion,
|
||||||
|
RectangleL desktopImageClip)
|
||||||
|
{
|
||||||
|
PathSourceSize = pathSourceSize;
|
||||||
|
DesktopImageRegion = desktopImageRegion;
|
||||||
|
DesktopImageClip = desktopImageClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfigDesktopImageInfo other)
|
||||||
|
{
|
||||||
|
return PathSourceSize == other.PathSourceSize &&
|
||||||
|
DesktopImageRegion == other.DesktopImageRegion &&
|
||||||
|
DesktopImageClip == other.DesktopImageClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfigDesktopImageInfo info && Equals(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = PathSourceSize.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ DesktopImageRegion.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ DesktopImageClip.GetHashCode();
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfigDesktopImageInfo left, DisplayConfigDesktopImageInfo right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfigDesktopImageInfo left, DisplayConfigDesktopImageInfo right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553920(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigDeviceInfoHeader
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigDeviceInfoType Type;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Size;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly LUID AdapterId;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Id;
|
||||||
|
|
||||||
|
public DisplayConfigDeviceInfoHeader(LUID adapterId, Type requestType) : this()
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
Size = (uint) Marshal.SizeOf(requestType);
|
||||||
|
|
||||||
|
if (requestType == typeof(DisplayConfigSourceDeviceName))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.GetSourceName;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigTargetDeviceName))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.GetTargetName;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigTargetPreferredMode))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.GetTargetPreferredMode;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigAdapterName))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.GetAdapterName;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigSetTargetPersistence))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.SetTargetPersistence;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigTargetBaseType))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.GetTargetBaseType;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigGetSourceDPIScale))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.GetSourceDPIScale;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigSetSourceDPIScale))
|
||||||
|
{
|
||||||
|
Type = DisplayConfigDeviceInfoType.SetSourceDPIScale;
|
||||||
|
}
|
||||||
|
else if (requestType == typeof(DisplayConfigSupportVirtualResolution))
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw exception?
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigDeviceInfoHeader(LUID adapterId, uint id, Type requestType) : this(adapterId, requestType)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigDeviceInfoHeader(
|
||||||
|
LUID adapterId,
|
||||||
|
uint id,
|
||||||
|
Type requestType,
|
||||||
|
DisplayConfigDeviceInfoType request)
|
||||||
|
: this(adapterId, id, requestType)
|
||||||
|
{
|
||||||
|
Type = request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// Internal undocumented structure
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigGetSourceDPIScale
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
|
||||||
|
[field: MarshalAs(UnmanagedType.U4)]
|
||||||
|
public int MinimumScaleSteps { get; }
|
||||||
|
|
||||||
|
[field: MarshalAs(UnmanagedType.U4)]
|
||||||
|
public int CurrentScaleSteps { get; }
|
||||||
|
|
||||||
|
[field: MarshalAs(UnmanagedType.U4)]
|
||||||
|
public int MaximumScaleSteps { get; }
|
||||||
|
|
||||||
|
public DisplayConfigGetSourceDPIScale(LUID adapter, uint sourceId) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, sourceId, GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553933(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Explicit)] // Size = 64
|
||||||
|
internal struct DisplayConfigModeInfo : IEquatable<DisplayConfigModeInfo>
|
||||||
|
{
|
||||||
|
public const uint InvalidModeIndex = 0xffffffff;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(0)]
|
||||||
|
public readonly DisplayConfigModeInfoType InfoType;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.U4)] [FieldOffset(4)]
|
||||||
|
public readonly uint Id;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] [FieldOffset(8)]
|
||||||
|
public readonly LUID AdapterId;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] [FieldOffset(16)]
|
||||||
|
public readonly DisplayConfigTargetMode TargetMode;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] [FieldOffset(16)]
|
||||||
|
public readonly DisplayConfigSourceMode SourceMode;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] [FieldOffset(16)]
|
||||||
|
public readonly DisplayConfigDesktopImageInfo
|
||||||
|
DesktopImageInfo;
|
||||||
|
|
||||||
|
public DisplayConfigModeInfo(LUID adapterId, uint id, DisplayConfigTargetMode targetMode) : this()
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
Id = id;
|
||||||
|
TargetMode = targetMode;
|
||||||
|
InfoType = DisplayConfigModeInfoType.Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigModeInfo(LUID adapterId, uint id, DisplayConfigSourceMode sourceMode) : this()
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
Id = id;
|
||||||
|
SourceMode = sourceMode;
|
||||||
|
InfoType = DisplayConfigModeInfoType.Source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigModeInfo(LUID adapterId, uint id, DisplayConfigDesktopImageInfo desktopImageInfo) : this()
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
Id = id;
|
||||||
|
DesktopImageInfo = desktopImageInfo;
|
||||||
|
InfoType = DisplayConfigModeInfoType.DesktopImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfigModeInfo other)
|
||||||
|
{
|
||||||
|
return InfoType == other.InfoType &&
|
||||||
|
Id == other.Id &&
|
||||||
|
AdapterId == other.AdapterId &&
|
||||||
|
(InfoType == DisplayConfigModeInfoType.Source && SourceMode == other.SourceMode ||
|
||||||
|
InfoType == DisplayConfigModeInfoType.Target && TargetMode == other.TargetMode ||
|
||||||
|
InfoType == DisplayConfigModeInfoType.DesktopImage &&
|
||||||
|
DesktopImageInfo == other.DesktopImageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfigModeInfo info && Equals(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = (int) InfoType;
|
||||||
|
hashCode = (hashCode * 397) ^ (int) Id;
|
||||||
|
hashCode = (hashCode * 397) ^ AdapterId.GetHashCode();
|
||||||
|
|
||||||
|
switch (InfoType)
|
||||||
|
{
|
||||||
|
case DisplayConfigModeInfoType.Source:
|
||||||
|
hashCode = (hashCode * 397) ^ SourceMode.GetHashCode();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DisplayConfigModeInfoType.Target:
|
||||||
|
hashCode = (hashCode * 397) ^ TargetMode.GetHashCode();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case DisplayConfigModeInfoType.DesktopImage:
|
||||||
|
hashCode = (hashCode * 397) ^ DesktopImageInfo.GetHashCode();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfigModeInfo left, DisplayConfigModeInfo right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfigModeInfo left, DisplayConfigModeInfo right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553945(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigPathInfo
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigPathSourceInfo SourceInfo;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigPathTargetInfo TargetInfo;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigPathInfoFlags Flags;
|
||||||
|
|
||||||
|
public DisplayConfigPathInfo(
|
||||||
|
DisplayConfigPathSourceInfo sourceInfo,
|
||||||
|
DisplayConfigPathTargetInfo targetInfo,
|
||||||
|
DisplayConfigPathInfoFlags flags)
|
||||||
|
{
|
||||||
|
SourceInfo = sourceInfo;
|
||||||
|
TargetInfo = targetInfo;
|
||||||
|
Flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigPathInfo(DisplayConfigPathSourceInfo sourceInfo, DisplayConfigPathInfoFlags flags)
|
||||||
|
{
|
||||||
|
SourceInfo = sourceInfo;
|
||||||
|
Flags = flags;
|
||||||
|
TargetInfo = new DisplayConfigPathTargetInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553951(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigPathSourceInfo
|
||||||
|
{
|
||||||
|
public const ushort InvalidCloneGroupId = 0xffff;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly LUID AdapterId;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint SourceId;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint ModeInfoIndex;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigPathSourceInfoFlags StatusFlags;
|
||||||
|
|
||||||
|
public ushort SourceModeInfoIndex
|
||||||
|
{
|
||||||
|
get => (ushort) ((ModeInfoIndex << 16) >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort CloneGroupId
|
||||||
|
{
|
||||||
|
get => (ushort) (ModeInfoIndex >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigPathSourceInfo(LUID adapterId, uint sourceId, uint modeInfoIndex) : this()
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
SourceId = sourceId;
|
||||||
|
ModeInfoIndex = modeInfoIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigPathSourceInfo(
|
||||||
|
LUID adapterId,
|
||||||
|
uint sourceId,
|
||||||
|
ushort sourceModeInfoIndex,
|
||||||
|
ushort cloneGroupId) : this(adapterId, sourceId, 0)
|
||||||
|
{
|
||||||
|
ModeInfoIndex = (uint) (sourceModeInfoIndex + (cloneGroupId << 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553954(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigPathTargetInfo
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly LUID AdapterId;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint TargetId;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint ModeInfoIndex;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigVideoOutputTechnology OutputTechnology;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigRotation Rotation;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigScaling Scaling;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigRational RefreshRate;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigScanLineOrdering ScanLineOrdering;
|
||||||
|
[MarshalAs(UnmanagedType.Bool)] public readonly bool TargetAvailable;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigPathTargetInfoFlags StatusFlags;
|
||||||
|
|
||||||
|
public ushort TargetModeInfoIndex
|
||||||
|
{
|
||||||
|
get => (ushort) ((ModeInfoIndex << 16) >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort DesktopModeInfoIndex
|
||||||
|
{
|
||||||
|
get => (ushort) (ModeInfoIndex >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigPathTargetInfo(
|
||||||
|
LUID adapterId,
|
||||||
|
uint targetId,
|
||||||
|
uint modeInfoIndex,
|
||||||
|
DisplayConfigVideoOutputTechnology outputTechnology,
|
||||||
|
DisplayConfigRotation rotation,
|
||||||
|
DisplayConfigScaling scaling,
|
||||||
|
DisplayConfigRational refreshRate,
|
||||||
|
DisplayConfigScanLineOrdering scanLineOrdering,
|
||||||
|
bool targetAvailable) : this()
|
||||||
|
{
|
||||||
|
AdapterId = adapterId;
|
||||||
|
TargetId = targetId;
|
||||||
|
ModeInfoIndex = modeInfoIndex;
|
||||||
|
OutputTechnology = outputTechnology;
|
||||||
|
Rotation = rotation;
|
||||||
|
Scaling = scaling;
|
||||||
|
RefreshRate = refreshRate;
|
||||||
|
ScanLineOrdering = scanLineOrdering;
|
||||||
|
TargetAvailable = targetAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigPathTargetInfo(
|
||||||
|
LUID adapterId,
|
||||||
|
uint targetId,
|
||||||
|
ushort targetModeInfoIndex,
|
||||||
|
ushort desktopModeInfoIndex,
|
||||||
|
DisplayConfigVideoOutputTechnology outputTechnology,
|
||||||
|
DisplayConfigRotation rotation,
|
||||||
|
DisplayConfigScaling scaling,
|
||||||
|
DisplayConfigRational refreshRate,
|
||||||
|
DisplayConfigScanLineOrdering scanLineOrdering,
|
||||||
|
bool targetAvailable)
|
||||||
|
: this(
|
||||||
|
adapterId, targetId, 0, outputTechnology, rotation, scaling, refreshRate, scanLineOrdering,
|
||||||
|
targetAvailable)
|
||||||
|
{
|
||||||
|
ModeInfoIndex = (uint) (targetModeInfoIndex + (desktopModeInfoIndex << 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553968(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigRational : IEquatable<DisplayConfigRational>
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Numerator;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Denominator;
|
||||||
|
|
||||||
|
public DisplayConfigRational(uint numerator, uint denominator, bool simplify)
|
||||||
|
: this((ulong) numerator, denominator, simplify)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigRational(ulong numerator, ulong denominator, bool simplify)
|
||||||
|
{
|
||||||
|
var gcm = simplify & (numerator != 0) ? Euclidean(numerator, denominator) : 1;
|
||||||
|
Numerator = (uint) (numerator / gcm);
|
||||||
|
Denominator = (uint) (denominator / gcm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ulong Euclidean(ulong a, ulong b)
|
||||||
|
{
|
||||||
|
while (a != 0 && b != 0)
|
||||||
|
{
|
||||||
|
if (a > b)
|
||||||
|
{
|
||||||
|
a %= b;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b %= a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a == 0 ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public ulong ToValue(ulong multiplier = 1)
|
||||||
|
{
|
||||||
|
if (Numerator == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Numerator * multiplier / Denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfigRational other)
|
||||||
|
{
|
||||||
|
if (Numerator == other.Numerator && Denominator == other.Denominator)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var left = Numerator / (double) Denominator;
|
||||||
|
var right = other.Numerator / (double) other.Denominator;
|
||||||
|
|
||||||
|
return Math.Abs(left - right) <= Math.Max(Math.Abs(left), Math.Abs(right)) * 1E-15;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfigRational rational && Equals(rational);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return ((int) Numerator * 397) ^ (int) Denominator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfigRational left, DisplayConfigRational right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfigRational left, DisplayConfigRational right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// Internal undocumented structure
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigSetSourceDPIScale
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
|
||||||
|
[field: MarshalAs(UnmanagedType.U4)]
|
||||||
|
public int ScaleSteps { get; }
|
||||||
|
|
||||||
|
public DisplayConfigSetSourceDPIScale(LUID adapter, uint sourceId, int scaleSteps) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, sourceId, GetType());
|
||||||
|
ScaleSteps = scaleSteps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/ff553981(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigSetTargetPersistence
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] private readonly uint _BootPersistenceOn;
|
||||||
|
|
||||||
|
public bool BootPersistence
|
||||||
|
{
|
||||||
|
get => _BootPersistenceOn > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigSetTargetPersistence(LUID adapter, uint targetId, bool bootPersistence) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, targetId, GetType());
|
||||||
|
_BootPersistenceOn = bootPersistence ? 1u : 0u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/ff553983(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
internal struct DisplayConfigSourceDeviceName
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||||
|
public readonly string DeviceName;
|
||||||
|
|
||||||
|
public DisplayConfigSourceDeviceName(LUID adapter, uint sourceId) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, sourceId, GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553986(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigSourceMode : IEquatable<DisplayConfigSourceMode>
|
||||||
|
{
|
||||||
|
public const ushort InvalidSourceModeIndex = 0xffff;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Width;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Height;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigPixelFormat PixelFormat;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly PointL Position;
|
||||||
|
|
||||||
|
public DisplayConfigSourceMode(uint width, uint height, DisplayConfigPixelFormat pixelFormat, PointL position)
|
||||||
|
{
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
PixelFormat = pixelFormat;
|
||||||
|
Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfigSourceMode other)
|
||||||
|
{
|
||||||
|
return Width == other.Width &&
|
||||||
|
Height == other.Height &&
|
||||||
|
PixelFormat == other.PixelFormat &&
|
||||||
|
Position == other.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfigSourceMode mode && Equals(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = (int) Width;
|
||||||
|
hashCode = (hashCode * 397) ^ (int) Height;
|
||||||
|
hashCode = (hashCode * 397) ^ (int) PixelFormat;
|
||||||
|
hashCode = (hashCode * 397) ^ Position.GetHashCode();
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfigSourceMode left, DisplayConfigSourceMode right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfigSourceMode left, DisplayConfigSourceMode right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/mt622103(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
internal struct DisplayConfigSupportVirtualResolution
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] private readonly int _DisableMonitorVirtualResolution;
|
||||||
|
|
||||||
|
public bool DisableMonitorVirtualResolution
|
||||||
|
{
|
||||||
|
get => _DisableMonitorVirtualResolution > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigSupportVirtualResolution(LUID adapter, uint targetId) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, targetId, GetType(),
|
||||||
|
DisplayConfigDeviceInfoType.GetSupportVirtualResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayConfigSupportVirtualResolution(LUID adapter, uint targetId, bool disableMonitorVirtualResolution)
|
||||||
|
: this()
|
||||||
|
{
|
||||||
|
_DisableMonitorVirtualResolution = disableMonitorVirtualResolution ? 1 : 0;
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, targetId, GetType(),
|
||||||
|
DisplayConfigDeviceInfoType.SetSupportVirtualResolution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/dn362043(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigTargetBaseType
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigVideoOutputTechnology BaseOutputTechnology;
|
||||||
|
|
||||||
|
public DisplayConfigTargetBaseType(LUID adapter, uint targetId) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, targetId, GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/ff553989(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
internal struct DisplayConfigTargetDeviceName
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigTargetDeviceNameFlags Flags;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigVideoOutputTechnology OutputTechnology;
|
||||||
|
[MarshalAs(UnmanagedType.U2)] public readonly ushort EDIDManufactureId;
|
||||||
|
[MarshalAs(UnmanagedType.U2)] public readonly ushort EDIDProductCodeId;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint ConnectorInstance;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
||||||
|
public readonly string MonitorFriendlyDeviceName;
|
||||||
|
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||||
|
public readonly string MonitorDevicePath;
|
||||||
|
|
||||||
|
|
||||||
|
public DisplayConfigTargetDeviceName(LUID adapter, uint targetId) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, targetId, GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff553993(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigTargetMode : IEquatable<DisplayConfigTargetMode>
|
||||||
|
{
|
||||||
|
public const ushort InvalidTargetModeIndex = 0xffff;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigVideoSignalInfo TargetVideoSignalInfo;
|
||||||
|
|
||||||
|
public DisplayConfigTargetMode(DisplayConfigVideoSignalInfo targetVideoSignalInfo)
|
||||||
|
{
|
||||||
|
TargetVideoSignalInfo = targetVideoSignalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfigTargetMode other)
|
||||||
|
{
|
||||||
|
return TargetVideoSignalInfo == other.TargetVideoSignalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfigTargetMode mode && Equals(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return TargetVideoSignalInfo.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfigTargetMode left, DisplayConfigTargetMode right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfigTargetMode left, DisplayConfigTargetMode right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/ff553996(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigTargetPreferredMode
|
||||||
|
{
|
||||||
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] private readonly DisplayConfigDeviceInfoHeader _Header;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Width;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly uint Height;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigTargetMode TargetMode;
|
||||||
|
|
||||||
|
public DisplayConfigTargetPreferredMode(LUID adapter, uint targetId) : this()
|
||||||
|
{
|
||||||
|
_Header = new DisplayConfigDeviceInfoHeader(adapter, targetId, GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff554007(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct DisplayConfigVideoSignalInfo : IEquatable<DisplayConfigVideoSignalInfo>
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.U8)] public readonly ulong PixelRate;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigRational HorizontalSyncFrequency;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfigRational VerticalSyncFrequency;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfig2DRegion ActiveSize;
|
||||||
|
[MarshalAs(UnmanagedType.Struct)] public readonly DisplayConfig2DRegion TotalSize;
|
||||||
|
[MarshalAs(UnmanagedType.U2)] public readonly VideoSignalStandard VideoStandard;
|
||||||
|
[MarshalAs(UnmanagedType.U2)] public readonly ushort VerticalSyncFrequencyDivider;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly DisplayConfigScanLineOrdering ScanLineOrdering;
|
||||||
|
|
||||||
|
public DisplayConfigVideoSignalInfo(
|
||||||
|
ulong pixelRate,
|
||||||
|
DisplayConfigRational horizontalSyncFrequency,
|
||||||
|
DisplayConfigRational verticalSyncFrequency,
|
||||||
|
DisplayConfig2DRegion activeSize,
|
||||||
|
DisplayConfig2DRegion totalSize,
|
||||||
|
VideoSignalStandard videoStandard,
|
||||||
|
ushort verticalSyncFrequencyDivider,
|
||||||
|
DisplayConfigScanLineOrdering scanLineOrdering)
|
||||||
|
{
|
||||||
|
PixelRate = pixelRate;
|
||||||
|
HorizontalSyncFrequency = horizontalSyncFrequency;
|
||||||
|
VerticalSyncFrequency = verticalSyncFrequency;
|
||||||
|
ActiveSize = activeSize;
|
||||||
|
TotalSize = totalSize;
|
||||||
|
VideoStandard = videoStandard;
|
||||||
|
VerticalSyncFrequencyDivider = verticalSyncFrequencyDivider;
|
||||||
|
ScanLineOrdering = scanLineOrdering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DisplayConfigVideoSignalInfo other)
|
||||||
|
{
|
||||||
|
return PixelRate == other.PixelRate &&
|
||||||
|
HorizontalSyncFrequency == other.HorizontalSyncFrequency &&
|
||||||
|
VerticalSyncFrequency == other.VerticalSyncFrequency &&
|
||||||
|
ActiveSize == other.ActiveSize &&
|
||||||
|
TotalSize == other.TotalSize &&
|
||||||
|
VideoStandard == other.VideoStandard &&
|
||||||
|
VerticalSyncFrequencyDivider == other.VerticalSyncFrequencyDivider &&
|
||||||
|
ScanLineOrdering == other.ScanLineOrdering;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is DisplayConfigVideoSignalInfo info && Equals(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = PixelRate.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ HorizontalSyncFrequency.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ VerticalSyncFrequency.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ ActiveSize.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ TotalSize.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ (int) VideoStandard;
|
||||||
|
hashCode = (hashCode * 397) ^ VerticalSyncFrequencyDivider.GetHashCode();
|
||||||
|
hashCode = (hashCode * 397) ^ (int) ScanLineOrdering;
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(DisplayConfigVideoSignalInfo left, DisplayConfigVideoSignalInfo right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(DisplayConfigVideoSignalInfo left, DisplayConfigVideoSignalInfo right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native.DisplayConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible video signal standards
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/hardware/ff546632(v=vs.85).aspx
|
||||||
|
/// </summary>
|
||||||
|
public enum VideoSignalStandard : ushort
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the variable has not yet been assigned a meaningful value.
|
||||||
|
/// </summary>
|
||||||
|
Uninitialized = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Video Electronics Standards Association (VESA) Display Monitor Timing (DMT) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
VESA_DMT = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the VESA Generalized Timing Formula (GTF) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
VESA_GTF = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the VESA Coordinated Video Timing (CVT) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
VESA_CVT = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the IBM standard.
|
||||||
|
/// </summary>
|
||||||
|
IBM = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Apple standard.
|
||||||
|
/// </summary>
|
||||||
|
Apple = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the National Television Standards Committee (NTSC) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
NTSC_M = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the NTSC japanese standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
NTSC_J = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the NTSC standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
NTSC_443 = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Phase Alteration Line (PAL) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_B = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_B1 = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_G = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_H = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_I = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_D = 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_N = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_NC = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Systeme Electronic Pour Couleur Avec Memoire (SECAM) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_B = 17,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_D = 18,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_G = 19,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_H = 20,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_K = 21,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_K1 = 22,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_L = 23,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the SECAM standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
SECAM_L1 = 24,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Electronics Industries Association (EIA) standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
EIA_861 = 25,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the EIA standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
EIA_861A = 26,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the EIA standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
EIA_861B = 27,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_K = 28,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_K1 = 29,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_L = 30,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the PAL standard.
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
PAL_M = 31,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents any video standard other than those represented by the previous constants in this enumeration.
|
||||||
|
/// </summary>
|
||||||
|
Other = 255
|
||||||
|
}
|
||||||
|
}
|
||||||
96
app/WindowsDisplayAPI/Native/DisplayConfigApi.cs
Normal file
96
app/WindowsDisplayAPI/Native/DisplayConfigApi.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig;
|
||||||
|
using WindowsDisplayAPI.Native.DisplayConfig.Structures;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native
|
||||||
|
{
|
||||||
|
internal class DisplayConfigApi
|
||||||
|
{
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigSupportVirtualResolution targetSupportVirtualResolution
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigGetSourceDPIScale targetSupportVirtualResolution
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigTargetDeviceName deviceName
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigAdapterName deviceName
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigSourceDeviceName deviceName
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigTargetPreferredMode targetPreferredMode
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigGetDeviceInfo(
|
||||||
|
ref DisplayConfigTargetBaseType targetBaseType
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigSetDeviceInfo(
|
||||||
|
ref DisplayConfigSetTargetPersistence targetPersistence
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigSetDeviceInfo(
|
||||||
|
ref DisplayConfigSupportVirtualResolution targetSupportVirtualResolution
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status DisplayConfigSetDeviceInfo(
|
||||||
|
ref DisplayConfigSetSourceDPIScale setSourceDpiScale
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status GetDisplayConfigBufferSizes(
|
||||||
|
QueryDeviceConfigFlags flags,
|
||||||
|
out uint pathArrayElements,
|
||||||
|
out uint modeInfoArrayElements
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status QueryDisplayConfig(
|
||||||
|
QueryDeviceConfigFlags flags,
|
||||||
|
ref uint pathArrayElements,
|
||||||
|
[Out] DisplayConfigPathInfo[] pathInfoArray,
|
||||||
|
ref uint modeInfoArrayElements,
|
||||||
|
[Out] DisplayConfigModeInfo[] modeInfoArray,
|
||||||
|
IntPtr currentTopologyId
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status QueryDisplayConfig(
|
||||||
|
QueryDeviceConfigFlags flags,
|
||||||
|
ref uint pathArrayElements,
|
||||||
|
[Out] DisplayConfigPathInfo[] pathInfoArray,
|
||||||
|
ref uint modeInfoArrayElements,
|
||||||
|
[Out] DisplayConfigModeInfo[] modeInfoArray,
|
||||||
|
[Out] out DisplayConfigTopologyId currentTopologyId
|
||||||
|
);
|
||||||
|
|
||||||
|
[DllImport("user32")]
|
||||||
|
public static extern Win32Status SetDisplayConfig(
|
||||||
|
[In] uint pathArrayElements,
|
||||||
|
[In] DisplayConfigPathInfo[] pathInfoArray,
|
||||||
|
[In] uint modeInfoArrayElements,
|
||||||
|
[In] DisplayConfigModeInfo[] modeInfoArray,
|
||||||
|
[In] SetDisplayConfigFlags flags
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
app/WindowsDisplayAPI/Native/Structures/LUID.cs
Normal file
104
app/WindowsDisplayAPI/Native/Structures/LUID.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.Structures
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Locally unique identifier is a 64-bit value guaranteed to be unique only on the system on which it was generated.
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct LUID : IEquatable<LUID>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 32Bit unsigned integer, low
|
||||||
|
/// </summary>
|
||||||
|
public readonly uint LowPart;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 32Bit signed integer, high
|
||||||
|
/// </summary>
|
||||||
|
public readonly int HighPart;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new LUID
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lowPart">32Bit unsigned integer, low</param>
|
||||||
|
/// <param name="highPart">32Bit signed integer, high</param>
|
||||||
|
public LUID(uint lowPart, int highPart)
|
||||||
|
{
|
||||||
|
LowPart = lowPart;
|
||||||
|
HighPart = highPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{{ {LowPart:X} - {HighPart:X} }}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(LUID other)
|
||||||
|
{
|
||||||
|
return LowPart == other.LowPart && HighPart == other.HighPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is LUID luid && Equals(luid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for equality between two objects of same type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first object</param>
|
||||||
|
/// <param name="right">The second object</param>
|
||||||
|
/// <returns>true, if both objects are equal, otherwise false</returns>
|
||||||
|
public static bool operator ==(LUID left, LUID right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for inequality between two objects of same type
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first object</param>
|
||||||
|
/// <param name="right">The second object</param>
|
||||||
|
/// <returns>true, if both objects are not equal, otherwise false</returns>
|
||||||
|
public static bool operator !=(LUID left, LUID right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return ((int) LowPart * 397) ^ HighPart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if this type is empty and holds no real data
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if empty, otherwise false</returns>
|
||||||
|
public bool IsEmpty()
|
||||||
|
{
|
||||||
|
return LowPart == 0 && HighPart == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an empty instance of this type
|
||||||
|
/// </summary>
|
||||||
|
public static LUID Empty
|
||||||
|
{
|
||||||
|
get => default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
app/WindowsDisplayAPI/Native/Structures/PointL.cs
Normal file
74
app/WindowsDisplayAPI/Native/Structures/PointL.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/dd162807(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct PointL : IEquatable<PointL>
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.I4)] public readonly int X;
|
||||||
|
[MarshalAs(UnmanagedType.I4)] public readonly int Y;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public Point ToPoint()
|
||||||
|
{
|
||||||
|
return new Point(X, Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public Size ToSize()
|
||||||
|
{
|
||||||
|
return new Size(X, Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointL(Point point) : this(point.X, point.Y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointL(Size size) : this(size.Width, size.Height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointL(int x, int y)
|
||||||
|
{
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(PointL other)
|
||||||
|
{
|
||||||
|
return X == other.X && Y == other.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is PointL point && Equals(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
return (X * 397) ^ Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(PointL left, PointL right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(PointL left, PointL right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
app/WindowsDisplayAPI/Native/Structures/RectangleL.cs
Normal file
73
app/WindowsDisplayAPI/Native/Structures/RectangleL.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace WindowsDisplayAPI.Native.Structures
|
||||||
|
{
|
||||||
|
// https://msdn.microsoft.com/en-us/library/vs/alm/dd162907(v=vs.85).aspx
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct RectangleL : IEquatable<RectangleL>
|
||||||
|
{
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly int Left;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly int Top;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly int Right;
|
||||||
|
[MarshalAs(UnmanagedType.U4)] public readonly int Bottom;
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public Rectangle ToRectangle()
|
||||||
|
{
|
||||||
|
return new Rectangle(Left, Top, Right - Left, Bottom - Top);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RectangleL(int left, int top, int right, int bottom)
|
||||||
|
{
|
||||||
|
Left = left;
|
||||||
|
Top = top;
|
||||||
|
Right = right;
|
||||||
|
Bottom = bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RectangleL(Rectangle rectangle) : this(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(RectangleL other)
|
||||||
|
{
|
||||||
|
return Left == other.Left && Top == other.Top && Right == other.Right && Bottom == other.Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj is RectangleL rectangle && Equals(rectangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = Left;
|
||||||
|
hashCode = (hashCode * 397) ^ Top;
|
||||||
|
hashCode = (hashCode * 397) ^ Right;
|
||||||
|
hashCode = (hashCode * 397) ^ Bottom;
|
||||||
|
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(RectangleL left, RectangleL right)
|
||||||
|
{
|
||||||
|
return Equals(left, right) || left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(RectangleL left, RectangleL right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
app/WindowsDisplayAPI/Native/Win32Status.cs
Normal file
8
app/WindowsDisplayAPI/Native/Win32Status.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace WindowsDisplayAPI.Native
|
||||||
|
{
|
||||||
|
internal enum Win32Status
|
||||||
|
{
|
||||||
|
Success = 0x0,
|
||||||
|
ErrorInsufficientBuffer = 0x7A
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user