-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from tombayley/feature/ddc
Feature/ddc
- Loading branch information
Showing
35 changed files
with
1,388 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
namespace NightGlow.MonitorConfig; | ||
|
||
public class Monitors | ||
{ | ||
|
||
public List<VirtualMonitor> VirtualMonitors = new List<VirtualMonitor>(); | ||
|
||
public bool Scan() | ||
{ | ||
VirtualMonitors.Clear(); | ||
bool success = WinApi.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumCallback, IntPtr.Zero); | ||
return success; | ||
} | ||
|
||
private bool MonitorEnumCallback(IntPtr hMonitor, IntPtr hdcMonitor, ref WinApi.RECT lprcMonitor, IntPtr dwData) | ||
{ | ||
VirtualMonitors.Add(new VirtualMonitor(hMonitor, VirtualMonitors.Count)); | ||
return true; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using System.Diagnostics; | ||
using static NightGlow.MonitorConfig.WinApi; | ||
|
||
namespace NightGlow.MonitorConfig; | ||
|
||
public class PhysicalMonitor | ||
{ | ||
|
||
// Sometimes setting/getting monitor settings can fail. Retry this many times before assuming failure. | ||
private const int DDC_ATTEMPTS = 3; | ||
|
||
PHYSICAL_MONITOR Monitor; | ||
|
||
public string Description; | ||
|
||
private readonly Setting Brightness = new(); | ||
private readonly Setting Contrast = new(); | ||
|
||
public PhysicalMonitor(PHYSICAL_MONITOR monitor) | ||
{ | ||
Monitor = monitor; | ||
Description = new string(Monitor.szPhysicalMonitorDescription); | ||
} | ||
|
||
public Setting GetBrightness() | ||
{ | ||
bool success = RetryGet((monitor) => GetMonitorBrightness( | ||
monitor, out Brightness.Min, out Brightness.Current, out Brightness.Max), Monitor.hPhysicalMonitor | ||
); | ||
return Brightness; | ||
} | ||
|
||
public void SetBrightness(uint value) | ||
{ | ||
bool success = RetrySet(SetMonitorBrightness, Monitor.hPhysicalMonitor, value); | ||
if (success) | ||
Brightness.Current = value; | ||
} | ||
|
||
public Setting GetContrast() | ||
{ | ||
bool success = RetryGet((monitor) => GetMonitorContrast( | ||
monitor, out Contrast.Min, out Contrast.Current, out Contrast.Max), Monitor.hPhysicalMonitor | ||
); | ||
return Contrast; | ||
} | ||
|
||
public void SetContrast(uint value) | ||
{ | ||
bool success = RetrySet(SetMonitorContrast, Monitor.hPhysicalMonitor, value); | ||
if (success) | ||
Contrast.Current = value; | ||
} | ||
|
||
private bool RetrySet(Func<nint, uint, bool> function, nint monitor, uint value) | ||
{ | ||
int attempt = 1; | ||
while (attempt <= DDC_ATTEMPTS) | ||
{ | ||
if (function(monitor, value)) return true; | ||
attempt++; | ||
} | ||
return false; | ||
} | ||
|
||
private bool RetryGet(Func<nint, bool> function, nint monitor) | ||
{ | ||
int attempt = 1; | ||
while (attempt <= DDC_ATTEMPTS) | ||
{ | ||
if (function(monitor)) return true; | ||
attempt++; | ||
} | ||
return false; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
namespace NightGlow.MonitorConfig; | ||
|
||
public class Setting | ||
{ | ||
|
||
public uint Min; | ||
public uint Max; | ||
public uint Current; | ||
|
||
public Setting() | ||
{ | ||
Min = 0; | ||
Max = 0; | ||
Current = 0; | ||
} | ||
|
||
public Setting(uint min, uint max, uint current) | ||
{ | ||
Min = min; | ||
Max = max; | ||
Current = current; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using static NightGlow.MonitorConfig.WinApi; | ||
|
||
namespace NightGlow.MonitorConfig; | ||
|
||
public class VirtualMonitor | ||
{ | ||
|
||
public string DeviceName = ""; | ||
public string FriendlyName = ""; | ||
|
||
public List<PhysicalMonitor> PhysicalMonitors = new(); | ||
|
||
private MONITORINFOEX MonitorInfo; | ||
|
||
public VirtualMonitor(IntPtr hMonitor, int index) | ||
{ | ||
MonitorInfo = new MONITORINFOEX { cbSize = (uint)Marshal.SizeOf<MONITORINFOEX>() }; | ||
|
||
if (!GetMonitorInfo(hMonitor, ref MonitorInfo)) | ||
{ | ||
// TODO throw error or log | ||
Debug.WriteLine("Error: GetMonitorInfo"); | ||
} | ||
|
||
DeviceName = MonitorInfo.szDevice; | ||
|
||
LoadFriendlyName(index); | ||
|
||
GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, out uint physicalMonitorCount); | ||
if (physicalMonitorCount == 0) | ||
return; | ||
|
||
PHYSICAL_MONITOR[] physicalMonitorArray = new PHYSICAL_MONITOR[physicalMonitorCount]; | ||
GetPhysicalMonitorsFromHMONITOR(hMonitor, physicalMonitorCount, physicalMonitorArray); | ||
|
||
for (int i = 0; i < physicalMonitorCount; i++) | ||
{ | ||
PhysicalMonitors.Add(new PhysicalMonitor(physicalMonitorArray[i])); | ||
} | ||
} | ||
|
||
public bool IsPrimary() | ||
{ | ||
return (MonitorInfo.dwFlags & MONITORINFOF.MONITORINFOF_PRIMARY) == MONITORINFOF.MONITORINFOF_PRIMARY; | ||
} | ||
|
||
private void LoadFriendlyName(int index) | ||
{ | ||
FriendlyName = ""; | ||
|
||
uint pathCount = 0, modeCount = 0; | ||
|
||
long error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, | ||
ref pathCount, ref modeCount); | ||
if (error != ERROR_SUCCESS) | ||
{ | ||
// TODO throw error or log | ||
Debug.WriteLine("Error: GetDisplayConfigBufferSizes"); | ||
return; | ||
} | ||
|
||
DISPLAYCONFIG_PATH_INFO[] displayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount]; | ||
DISPLAYCONFIG_MODE_INFO[] displayModes = new DISPLAYCONFIG_MODE_INFO[modeCount]; | ||
|
||
error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, | ||
ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero); | ||
if (error != ERROR_SUCCESS) | ||
{ | ||
// TODO throw error or log | ||
Debug.WriteLine("Error: QueryDisplayConfig"); | ||
return; | ||
} | ||
|
||
int modeTargetCount = 0; | ||
for (int i = 0; i < modeCount; i++) | ||
{ | ||
if (displayModes[i].infoType != DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET) | ||
continue; | ||
|
||
if (modeTargetCount != index) | ||
{ | ||
modeTargetCount++; | ||
continue; | ||
} | ||
|
||
DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME(); | ||
deviceName.header.size = (uint)Marshal.SizeOf(typeof(DISPLAYCONFIG_TARGET_DEVICE_NAME)); | ||
deviceName.header.adapterId = displayModes[i].adapterId; | ||
deviceName.header.id = displayModes[i].id; | ||
deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; | ||
|
||
error = DisplayConfigGetDeviceInfo(ref deviceName); | ||
if (error != ERROR_SUCCESS) | ||
{ | ||
// TODO throw error or log | ||
Debug.WriteLine("Error: DisplayConfigGetDeviceInfo"); | ||
return; | ||
} | ||
FriendlyName = deviceName.monitorFriendlyDeviceName; | ||
return; | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.