[Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post your working scripts, libraries and tools for AHK v1.1 and older
Rafaews
Posts: 25
Joined: 16 Mar 2018, 21:19

Re: Class Monitor (Brightness, Contrast, Gamma Ramp)

Post by Rafaews » 22 Jul 2020, 16:06

@jNizM

It's not working on my notebook's native display... But it is working on an Acer external VGA monitor though.

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: Class Monitor (Brightness, Contrast, Gamma Ramp)

Post by jNizM » 23 Jul 2020, 00:53

The high level monitor configuration (brightness, contrast) must be supported by your monitor (DDC/CI).
GammaRamp should be working. To make GammaRamp look like Brightness, you have to go down with all 3 colors simultaneously. (e.g. 80/80/80)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

Rafaews
Posts: 25
Joined: 16 Mar 2018, 21:19

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by Rafaews » 23 Jul 2020, 07:50

@jNizM

Unfortunately GammaRamp isn't also..

This loop:

Code: Select all

for k, v in this.EnumDisplayMonitors()
returns nothing for %v% when I'm not using the external monitor.

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by jNizM » 23 Jul 2020, 08:23

Does this function gives you a valid handle?

Code: Select all

MsgBox % MonitorFromWindow()

MonitorFromWindow(hWindow := 0)
{
	static MONITOR_DEFAULTTOPRIMARY := 0x00000001

	if (hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow, "uint", MONITOR_DEFAULTTOPRIMARY))
		return hMonitor
	return false
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

Rafaews
Posts: 25
Joined: 16 Mar 2018, 21:19

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by Rafaews » 23 Jul 2020, 08:37

@jNizM

Yes! "695995487"

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by jNizM » 23 Jul 2020, 08:53

Could you test this

Code: Select all

Monitor.SetLaptopGammaRamp(80, 80, 80)


class Monitor
{
	static Author  := "jNizM"
	static Version := "1.0"
	static Licence := "MIT"


	; ===== PUBLIC METHODS ======================================================================================================

	GetInfo()
	{
		return this.EnumDisplayMonitors()
	}

	GetBrightness(Display)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v.handle)
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v.handle, PhysicalMonitors, PHYSICAL_MONITOR)
				GetBrightness := this.GetMonitorBrightness(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return GetBrightness
			}
		}
	}

	GetContrast(Display)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v.handle)
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v.handle, PhysicalMonitors, PHYSICAL_MONITOR)
				GetContrast := this.GetMonitorContrast(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return GetContrast
			}
		}
	}

	GetGammaRamp(Display)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				hDC := this.CreateDC(v.Name)
				GetGammaRamp := this.GetDeviceGammaRamp(hDC)
				this.DeleteDC(hDC)
				return GetGammaRamp
			}
		}
	}

	SetGammaRamp(Display, Red, Green, Blue)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				hDC := this.CreateDC(v.Name)
				this.SetDeviceGammaRamp(hDC, Red, Green, Blue)
				this.DeleteDC(hDC)
			}
		}
	}

	SetLaptopGammaRamp(Red, Green, Blue)
	{
		if (hMonitor := this.MonitorFromWindow())
		{
			if (Displayname := this.GetMonitorInfo(hMonitor).Name)
			{
				if (hDC := this.CreateDC(Displayname))
				{
					if (this.SetDeviceGammaRamp(hDC, Red, Green, Blue))
					{
						this.DeleteDC(hDC)
						return true
					}
					this.DeleteDC(hDC)
				}
			}
		}
		return false
	}

	RestoreFactoryDefaults(Display)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v.handle)
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v.handle, PhysicalMonitors, PHYSICAL_MONITOR)
				this.RestoreMonitorFactoryDefaults(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			}
		}
	}

	SetBrightness(Display, Brightness)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v.handle)
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v.handle, PhysicalMonitors, PHYSICAL_MONITOR)
				GetBrightness := this.GetMonitorBrightness(hPhysicalMonitor)
				Brightness := (Brightness < GetBrightness.Minimum) ? GetBrightness.Minimum
							: (Brightness > GetBrightness.Maximum) ? GetBrightness.Maximum
							: (Brightness)
				this.SetMonitorBrightness(hPhysicalMonitor, Brightness)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Brightness
			}
		}
	}

	SetContrast(Display, Contrast)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v.Name, Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v.handle)
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v.handle, PhysicalMonitors, PHYSICAL_MONITOR)
				GetContrast := this.GetMonitorContrast(hPhysicalMonitor)
				Contrast := (Contrast < GetContrast.Minimum) ? GetContrast.Minimum
						: (Contrast > GetContrast.Maximum) ? GetContrast.Maximum
						: (Contrast)
				this.SetMonitorContrast(hPhysicalMonitor, Contrast)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Contrast
			}
		}
	}



	; ===== PRIVATE METHODS =====================================================================================================

	CreateDC(DisplayName)
	{
		if (hDC := DllCall("gdi32\CreateDC", "str", DisplayName, "ptr", 0, "ptr", 0, "ptr", 0, "ptr"))
			return hDC
		return false
	}

	DeleteDC(hDC)
	{
		if (DllCall("gdi32\DeleteDC", "ptr", hDC))
			return true
		return false
	}

	DestroyPhysicalMonitors(PhysicalMonitorArraySize, PHYSICAL_MONITOR)
	{
		if (DllCall("dxva2\DestroyPhysicalMonitors", "uint", PhysicalMonitorArraySize, "ptr", &PHYSICAL_MONITOR))
			return true
		return false
	}

	EnumDisplayMonitors(hMonitor := "")
	{
		static EnumProc := RegisterCallback(Monitor.EnumProc)
		static DisplayMonitors := {}

		if (MonitorNumber = "")
			DisplayMonitors := {}

		if (DisplayMonitors.MaxIndex() = "")
			if (DllCall("user32\EnumDisplayMonitors", "ptr", 0, "ptr", 0, "ptr", EnumProc, "ptr", &DisplayMonitors, "uint"))
				return (MonitorNumber = "") ? DisplayMonitors : DisplayMonitors.HasKey(MonitorNumber) ? DisplayMonitors[MonitorNumber] : False
		return false
	}

	EnumProc(hDC, pRECT, ObjectAddr)
	{
		DisplayMonitors := Object(ObjectAddr)
		MonitorInfo := Monitor.GetMonitorInfo(this)
		DisplayMonitors.Push(MonitorInfo)
		return true
	}

	GetDeviceGammaRamp(hMonitor)
	{
		VarSetCapacity(GAMMA_RAMP, 1536, 0)
		if (DllCall("gdi32\GetDeviceGammaRamp", "ptr", hMonitor, "ptr", &GAMMA_RAMP))
		{
			GammaRamp := {}
			GammaRamp["Red"]   := NumGet(GAMMA_RAMP,        2, "ushort") - 128
			GammaRamp["Green"] := NumGet(GAMMA_RAMP,  512 + 2, "ushort") - 128
			GammaRamp["Blue"]  := NumGet(GAMMA_RAMP, 1024 + 2, "ushort") - 128
			return GammaRamp
		}
		return false
	}

	GetMonitorBrightness(hMonitor)
	{
		if (DllCall("dxva2\GetMonitorBrightness", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return	{ "Minimum": Minimum, "Current": Current, "Maximum": Maximum }
		return false
	}

	GetMonitorContrast(hMonitor)
	{
		if (DllCall("dxva2\GetMonitorContrast", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return	{ "Minimum": Minimum, "Current": Current, "Maximum": Maximum }
		return false
	}

	GetMonitorInfo(hMonitor)
	{
		static MONITORINFOF_PRIMARY := 0x00000001

		NumPut(VarSetCapacity(MONITORINFOEX, 40 + (32 << !!A_IsUnicode)), MONITORINFOEX, 0, "uint")
		if (DllCall("user32\GetMonitorInfo", "ptr", hMonitor, "ptr", &MONITORINFOEX))
		{
			MONITORINFO := {}
			MONITORINFO["Handle"]   := hMonitor
			MONITORINFO["Name"]     := Name := StrGet(&MONITORINFOEX + 40, 32)
			MONITORINFO["Number"]   := RegExReplace(Name, ".*(\d+)$", "$1")
			MONITORINFO["Left"]     := NumGet(MONITORINFOEX,  4, "int")
			MONITORINFO["Top"]      := NumGet(MONITORINFOEX,  8, "int")
			MONITORINFO["Right"]    := NumGet(MONITORINFOEX, 12, "int")
			MONITORINFO["Bottom"]   := NumGet(MONITORINFOEX, 16, "int")
			MONITORINFO["WALeft"]   := NumGet(MONITORINFOEX, 20, "int")
			MONITORINFO["WATop"]    := NumGet(MONITORINFOEX, 24, "int")
			MONITORINFO["WARight"]  := NumGet(MONITORINFOEX, 28, "int")
			MONITORINFO["WABottom"] := NumGet(MONITORINFOEX, 32, "int")
			MONITORINFO["Primary"]  := NumGet(MONITORINFOEX, 36, "uint")
			return MONITORINFO
		}
		return false
	}

	GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
	{
		if (DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint*", NumberOfPhysicalMonitors))
			return NumberOfPhysicalMonitors
		return false
	}

	GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitorArraySize, ByRef PHYSICAL_MONITOR)
	{
		VarSetCapacity(PHYSICAL_MONITOR, (A_PtrSize + 256) * PhysicalMonitorArraySize, 0)
		if (DllCall("dxva2\GetPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint", PhysicalMonitorArraySize, "ptr", &PHYSICAL_MONITOR))
			return NumGet(PHYSICAL_MONITOR, 0, "ptr")
		return false
	}

	MonitorFromWindow(hWindow := 0)
	{
		static MONITOR_DEFAULTTONEAREST := 0x00000002

		if (hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow, "uint", MONITOR_DEFAULTTONEAREST))
			return hMonitor
		return false
	}

	RestoreMonitorFactoryDefaults(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		return false
	}

	SetDeviceGammaRamp(hMonitor, Red, Green, Blue)
	{
		loop % VarSetCapacity(GAMMA_RAMP, 1536, 0) / 6
		{
			NumPut((r := (red   + 128) * (A_Index - 1)) > 65535 ? 65535 : r, GAMMA_RAMP,        2 * (A_Index - 1), "ushort")
			NumPut((g := (green + 128) * (A_Index - 1)) > 65535 ? 65535 : g, GAMMA_RAMP,  512 + 2 * (A_Index - 1), "ushort")
			NumPut((b := (blue  + 128) * (A_Index - 1)) > 65535 ? 65535 : b, GAMMA_RAMP, 1024 + 2 * (A_Index - 1), "ushort")
		}
		if (DllCall("gdi32\SetDeviceGammaRamp", "ptr", hMonitor, "ptr", &GAMMA_RAMP))
			return true
		return false
	}

	SetMonitorBrightness(hMonitor, Brightness)
	{
		if (DllCall("dxva2\SetMonitorBrightness", "ptr", hMonitor, "uint", Brightness))
			return true
		return false
	}

	SetMonitorContrast(hMonitor, Contrast)
	{
		if (DllCall("dxva2\SetMonitorContrast", "ptr", hMonitor, "uint", Contrast))
			return true
		return false
	}
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

Rafaews
Posts: 25
Joined: 16 Mar 2018, 21:19

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by Rafaews » 23 Jul 2020, 09:20

@jNizM

Working!

And now I can set the blue to -128 (threshold) increase red and mimic Windows10's native Night Mode ♥

I wonder if that was possible already with your old class.. set up a negative value.

User avatar
Tigerlily
Posts: 377
Joined: 04 Oct 2018, 22:31

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by Tigerlily » 28 Jul 2020, 19:32

@jNizM

I've successfully ported your class over to the latest version of v2 (a119)!!

I made some minor changes to reduce the overall code size of some methods, however i do believe there is an opportunity to further reduce the code size of most of the public methods since they all have that for-loop-if-return pattern. I tried to figure out how to do this but was unable to make it work.. perhaps someone more skilled like yourself could figure out how to do this.

There appeared to be some redundant constants in the class that I removed, perhaps you were planning to implement at a later date?

I plan to expand on this class to include the majority of the rest of the Monitor Configuration Functions found here. I added a few more methods from that resource (shown in change log below). I received an application Error code 0xc0000005 (Access Violation Error) when trying to call the GetTechnologyType() method and didn't have time to debug any further, maybe you will have a different outcome. I also was unable to figure out how to read the bitwise OR of capabilities flags returned by the GetCapabilities() method, but will continue to try to figure out that puzzle.

@jNizM, I would highly recommend updating your github and your OP with your latest code.

Here is the updated Monitor Class, compatible with v2 a111+:

Code: Select all

class Monitor 
{
	static Author     := "jNizM"
	static Version    := "1.1"
	static Licence    := "MIT"	
	static PortedBy   := "tigerlily (with help from CloakerSmoker)"
	static ChangeLog  := Map(
	"2020-07-28", "Ported to AHK v2.0 alpha 119, compatible with v2 a111+",
	"2020-07-28", "Reduced code size for some methods",
	"2020-07-28", "Removed redundant code",
	"2020-07-28", "Reordered methods to be more visually intuitive (e.i. GetFunc(), then SetFunc() )",
	"2020-07-28", "Added RestoreFactoryColorDefaults() Method",
	"2020-07-28", "Added SaveCurrentSettings() Method",
	"2020-07-28", "Added GetTechnologyType() Method",
	"2020-07-28", "Added GetCapabilities() Method")
	
	
	; ===== PUBLIC METHODS ============================================================================== ;

	GetInfo()
	{
		return this.EnumDisplayMonitors()
	}

	GetBrightness(Display, PHYSICAL_MONITOR := "")
	{
		for v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				GetBrightness := this.GetMonitorBrightness(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return GetBrightness
			}
		}
	}
	
	SetBrightness(Display, Brightness, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				GetBrightness := this.GetMonitorBrightness(hPhysicalMonitor)
				Brightness := (Brightness < GetBrightness["Minimum"]) ? GetBrightness["Minimum"]
							: (Brightness > GetBrightness["Maximum"]) ? GetBrightness["Maximum"]
							: (Brightness)
				this.SetMonitorBrightness(hPhysicalMonitor, Brightness)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Brightness
			}
		}
	}

	GetContrast(Display, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				GetContrast := this.GetMonitorContrast(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return GetContrast
			}
		}
	}

	SetContrast(Display, Contrast, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				GetContrast := this.GetMonitorContrast(hPhysicalMonitor)
				Contrast := (Contrast < GetContrast["Minimum"]) ? GetContrast["Minimum"]
						: (Contrast > GetContrast["Maximum"]) ? GetContrast["Maximum"]
						: (Contrast)
				this.SetMonitorContrast(hPhysicalMonitor, Contrast)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Contrast
			}
		}
	}
	
	GetGammaRamp(Display)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				hDC := this.CreateDC(v["Name"])
				GetGammaRamp := this.GetDeviceGammaRamp(hDC)
				this.DeleteDC(hDC)
				return GetGammaRamp
			}
		}
	}

	SetGammaRamp(Display, Red, Green, Blue)
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				hDC := this.CreateDC(v["Name"])
				this.SetDeviceGammaRamp(hDC, Red, Green, Blue)
				this.DeleteDC(hDC)
			}
		}
	}

	SetLaptopGammaRamp(Red, Green, Blue)
	{
		if (hMonitor := this.MonitorFromWindow())
		{
			if (Displayname := this.GetMonitorInfo(hMonitor)["Name"])
			{
				if (hDC := this.CreateDC(Displayname))
				{
					if (this.SetDeviceGammaRamp(hDC, Red, Green, Blue))
					{
						this.DeleteDC(hDC)
						return true
					}
					this.DeleteDC(hDC)
				}
			}
		}
		return false
	}

	RestoreFactoryDefaults(Display, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				this.RestoreMonitorFactoryDefaults(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			}
		}
	}

	RestoreFactoryColorDefaults(Display, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				this.RestoreMonitorFactoryColorDefaults(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			}
		}
	}

	SaveCurrentSettings(Display, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				this.SaveCurrentMonitorSettings(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			}
		}
	}
	
	GetTechnologyType(Display, PHYSICAL_MONITOR := "")
	{
		for k, v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				this.GetMonitorTechnologyType(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			}
		}
	}
	
	GetCapabilities(Display, PHYSICAL_MONITOR := "")
	{
		for v in this.EnumDisplayMonitors()
		{
			if (InStr(v["Name"], Display))
			{
				PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(v["Handle"])
				hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(v["Handle"], PhysicalMonitors, PHYSICAL_MONITOR)
				GetCapabilities := this.GetMonitorCapabilities(hPhysicalMonitor)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return GetCapabilities
			}
		}
	}
	
	; ===== PRIVATE METHODS ============================================================================= ;
	
	EnumDisplayMonitors(hMonitor := "")
	{
	    
	    static EnumProc := CallbackCreate(Monitor.GetMethod("MonitorEnumProc").Bind(Monitor),, 4)
	    static DisplayMonitors := []

	    if (!DisplayMonitors.Length)
		   if !(DllCall("user32\EnumDisplayMonitors", "ptr", 0, "ptr", 0, "ptr", EnumProc, "ptr", ObjPtrAddRef(DisplayMonitors), "uint"))
			  return false
	    return DisplayMonitors    
	}

	static MonitorEnumProc(hMonitor, hDC, pRECT, ObjectAddr)
	{	
		DisplayMonitors := ObjFromPtrAddRef(ObjectAddr)
		MonitorData := Monitor.GetMonitorInfo(hMonitor)
		DisplayMonitors.Push(MonitorData)
		return true
	}

	static GetMonitorInfo(hMonitor)
	{	; MONITORINFO is a 40 byte struct, but MONITORINFOEX adds 64 bytes to the length
		num := 40 + 64 	
		NumPut("uint", num, MONITORINFOEX := BufferAlloc(num))
		if (DllCall("user32\GetMonitorInfo", "ptr", hMonitor, "ptr", MONITORINFOEX))
		{
			MONITORINFO := Map()
			MONITORINFO["Handle"]   := hMonitor
			MONITORINFO["Name"]     := Name := StrGet(MONITORINFOEX.Ptr + 40, 32)
			MONITORINFO["Number"]   := RegExReplace(Name, ".*(\d+)$", "$1")
			MONITORINFO["Left"]     := NumGet(MONITORINFOEX,  4, "int")
			MONITORINFO["Top"]      := NumGet(MONITORINFOEX,  8, "int")
			MONITORINFO["Right"]    := NumGet(MONITORINFOEX, 12, "int")
			MONITORINFO["Bottom"]   := NumGet(MONITORINFOEX, 16, "int")
			MONITORINFO["WALeft"]   := NumGet(MONITORINFOEX, 20, "int")
			MONITORINFO["WATop"]    := NumGet(MONITORINFOEX, 24, "int")
			MONITORINFO["WARight"]  := NumGet(MONITORINFOEX, 28, "int")
			MONITORINFO["WABottom"] := NumGet(MONITORINFOEX, 32, "int")
			MONITORINFO["Primary"]  := NumGet(MONITORINFOEX, 36, "uint")
			return MONITORINFO
		}
		throw Exception("GetMonitorInfo: " A_LastError, -1)
	}
	
	GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, NumberOfPhysicalMonitors := 0)
	{
		if (DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint*", NumberOfPhysicalMonitors))
			return NumberOfPhysicalMonitors
		return false
	}

	GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitorArraySize, ByRef PHYSICAL_MONITOR)
	{
		PHYSICAL_MONITOR := BufferAlloc((A_PtrSize + 256) * PhysicalMonitorArraySize)
		if (DllCall("dxva2\GetPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint", PhysicalMonitorArraySize, "ptr", PHYSICAL_MONITOR))
			return NumGet(PHYSICAL_MONITOR, 0, "ptr")
		return false
	}
	
	CreateDC(DisplayName)
	{
		if (hDC := DllCall("gdi32\CreateDC", "str", DisplayName, "ptr", 0, "ptr", 0, "ptr", 0, "ptr"))
			return hDC
		return false
	}

	DeleteDC(hDC)
	{
		if (DllCall("gdi32\DeleteDC", "ptr", hDC))
			return true
		return false
	}

	DestroyPhysicalMonitors(PhysicalMonitorArraySize, PHYSICAL_MONITOR)
	{
		if (DllCall("dxva2\DestroyPhysicalMonitors", "uint", PhysicalMonitorArraySize, "ptr", PHYSICAL_MONITOR))
			return true
		return false
	}
	
	GetMonitorBrightness(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{
		if (DllCall("dxva2\GetMonitorBrightness", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		return false
	}

	SetMonitorBrightness(hMonitor, Brightness)
	{
		if (DllCall("dxva2\SetMonitorBrightness", "ptr", hMonitor, "uint", Brightness))
			return true
		return false
	}
	
	GetMonitorContrast(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{				
		if (DllCall("dxva2\GetMonitorContrast", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		return false
	}
	
	SetMonitorContrast(hMonitor, Contrast)
	{
		if (DllCall("dxva2\SetMonitorContrast", "ptr", hMonitor, "uint", Contrast))
			return true
		return false
	}
	
	GetDeviceGammaRamp(hMonitor)
	{		
		GAMMA_RAMP := BufferAlloc(1536)
		if (DllCall("gdi32\GetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP))
		{
			GammaRamp := Map()
			GammaRamp["Red"]   := NumGet(GAMMA_RAMP,        2, "ushort") - 128
			GammaRamp["Green"] := NumGet(GAMMA_RAMP,  512 + 2, "ushort") - 128
			GammaRamp["Blue"]  := NumGet(GAMMA_RAMP, 1024 + 2, "ushort") - 128
			return GammaRamp
		}
		return false
	}

	SetDeviceGammaRamp(hMonitor, Red, Green, Blue)
	{
		GAMMA_RAMP := BufferAlloc(1536)	
		while ((i := A_Index - 1) < 256 )
		{	
			NumPut("ushort", (r := (red   + 128) * i) > 65535 ? 65535 : r, GAMMA_RAMP,        2 * i)
			NumPut("ushort", (g := (green + 128) * i) > 65535 ? 65535 : g, GAMMA_RAMP,  512 + 2 * i)
			NumPut("ushort", (b := (blue  + 128) * i) > 65535 ? 65535 : b, GAMMA_RAMP, 1024 + 2 * i)
		}
		if (DllCall("gdi32\SetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP))
			return true
		return false
	}

	RestoreMonitorFactoryDefaults(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		return false
	}

	RestoreMonitorFactoryColorDefaults(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryColorDefaults", "ptr", hMonitor))
			return true
		return false
	}
	
	MonitorFromWindow(hWindow := 0)
	{
		static MONITOR_DEFAULTTONEAREST := 0x00000002

		if (hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow, "uint", MONITOR_DEFAULTTONEAREST))
			return hMonitor
		return false
	}
	
	SaveCurrentMonitorSettings(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		return false
	}

	GetMonitorTechnologyType(hMonitor, DisplayTechnologyType := "")
	{
		if (DllCall("dxva2\GetMonitorTechnologyType", "ptr", hMonitor))
			return true
		return false
	}

	GetMonitorCapabilities(hMonitor, MonitorCapabilities := 0, SupportedColorTemperatures := 0)
	{
		if (DllCall("dxva2\GetMonitorCapabilities", "ptr", hMonitor, "uint*", MonitorCapabilities, "uint*", SupportedColorTemperatures))
			return Map("MonitorCapabilities", MonitorCapabilities, 
					 "SupportedColorTemperatures", SupportedColorTemperatures)
	}
}
Here is a working demo script that shows various usages of this class:

Code: Select all

#Include "Class_Monitor.ahk"

mon := Monitor.New() ; Construct new class instance

monitorInfo  := mon.GetInfo() 	  	 ; Retreive monitor info
monitorCount := mon.GetInfo().Length ; Retreive total monitor count

; Identify, store and display which monitor is the primary monitor #
while ((i := A_Index) <= monitorCount ) ; Iterate once for each monitor found	
	if monitorInfo[i]["Primary"]		; until the primary monitor is found
		MsgBox "Your Primary Monitor is #" (monitorPrimary := i) "."

; Create and display a list of monitor information found for monitor #1
infoList := ""
for infoName, infoValue in monitorInfo[1]
	infoList .= infoName ":`t`t" infoValue "`n"

MsgBox infoList

; Set some arbitrary values between 0 and 100 to experiment with brightness and contrast levels 
monitorBrightness := 50
monitorContrast := 40 

; Set some arbitrary values for each gamma color between -128 and 128 to experiment with gamma output levels
R := 0
G := 0
B := 0

; ***WARNING*** 
; Setting all gamma values to -128 will cause a total screen blackout
; if you have no way of resetting the gamma values then your monitor(s) will be stuck that way
; be careful

; A gamma value of  128 is considered 100% color output
; A gamma value of    0 is considered 50% color output
; A gamma value of -128 is considered 0% color output

while ((i := A_Index) <= monitorCount ) ; Iterate once for each monitor found	
{
	mon.SetBrightness(i, monitorBrightness) ; Set brightness to previously declared value of 50
	mon.SetContrast(i, monitorContrast)		; Set contrast to previously declared value of 40
	
	brightness := mon.GetBrightness(i)	; Get monitor brightness Map object
	contrast := mon.GetContrast(i)		; Get monitor contrast Map object
	gamma := mon.GetGammaRamp(i)		; Get monitor gamma Map object
	
	Sleep(10) ; allow brightness and contrast methods to finish, calling in succession too quickly throws errors
	
	MsgBox( ; vvv Display monitor brightness, contrast, and gamma levels vvv
	"Monitor Info:`n`n"
	
	"Monitor Number:`t" i					 "`n`n"
	
	"Current Brightness:`t`t" brightness["Current"] "`n"
	"Minimum Brightness:`t" brightness["Minimum"] "`n"
	"Maximum Brightness:`t" brightness["Maximum"] "`n`n"
	
	"Current Contrast:`t" contrast["Current"]	 "`n"
	"Minimum Contrast:`t" contrast["Minimum"]	 "`n"
	"Maximum Contrast:`t" contrast["Maximum"]	 "`n`n"
	"Current Gamma Levels:`n`n"	
	
	; Save current gamma values to reset to later
	"Red:`t"	 (gR := gamma["Red"])	"`n" 
	"Green:`t" (gG := gamma["Green"])	"`n"
	"Blue:`t"	 (gB := gamma["Blue"]) 	"`n"			  )		
	
	Sleep(10) ; allow brightness and contrast methods to finish, calling in succession too quickly throws errors
	
	mon.SetGammaRamp(i, R, G, B)  ; Set all gamma color output values to previously declared values of 0
	mon.RestoreFactoryDefaults(i) ; Restore monitors to factory setting defaults (doesn't affect gamma)	
		
	MsgBox( ; vvv Display monitor brightness, contrast, and gamma levels vvv
	"Updated Monitor Info:`n`n"
	
	"Monitor Number:`t" i					 "`n`n"
	
	"Current Brightness:`t" brightness["Current"] "`n"	
	"Current Contrast:`t" contrast["Current"]	 "`n"
	"Current Gamma Levels:`n`n"	
	
	"Red:`t"	 (gamma["Red"])	"`n" 
	"Green:`t" (gamma["Green"])	"`n"
	"Blue:`t"	 (gamma["Blue"]) 	"`n"				  )	
	
	mon.SetGammaRamp(i, gR, gG, gB) ; Restore all gamma color output values to original values
	
	Sleep(10) ; allow brightness and contrast methods to finish, calling in succession too quickly throws errors	
}
I hope others can find this class as useful as I have!! Thanks for all your hard work @jNizM!!
-TL

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by jNizM » 29 Jul 2020, 00:47

For GetMonitorTechnologyType its something like this:

Code: Select all

GetMonitorTechnologyType(hMonitor)
{
	static DISPLAY_TECHNOLOGY_TYPE := { 0: "Shadow-mask cathode ray tube (CRT)"
									  , 1: "Aperture-grill CRT"
									  , 2: "Thin-film transistor (TFT) display"
									  , 3: "Liquid crystal on silicon (LCOS) display"
									  , 4: "Plasma display"
									  , 5: "Organic light emitting diode (LED) display"
									  , 6: "Electroluminescent display"
									  , 7: "Microelectromechanical display"
									  , 8: "Field emission device (FED) display" }

	if (DllCall("dxva2\GetMonitorTechnologyType", "ptr", hMonitor, "int*", MC_DISPLAY_TECHNOLOGY_TYPE))
		return DISPLAY_TECHNOLOGY_TYPE[MC_DISPLAY_TECHNOLOGY_TYPE]
	return false
}
For the rest I will update soon.


Examples page is up:
https://www.autohotkey.com/boards/viewtopic.php?p=46461#p46461
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by jNizM » 30 Jul 2020, 02:43

The complete sourcecode is rewritten and updated.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

User avatar
Tigerlily
Posts: 377
Joined: 04 Oct 2018, 22:31

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by Tigerlily » 01 Aug 2020, 07:33

@jNizM, thanks for the pointer on that WinAPI.

It appears you have incorrectly put Class FTP in your OP, probably should change that back :D

I went ahead and improved upon my code from my last post using some of your recent updates. I added almost all the rest of the Monitor Configuration WinAPIs to the class (ported to v2 a119 of course).

I was also able to drastically reduce code size using fat arrow definitions and a few helper methods, take a look! Code below:

Code: Select all

; =================================================================================================== ;


; =================================================================================================== ;
; AutoHotkey V2 a119 wrapper for Monitor Configuration API Functions (a111+ compatible)
;
; Original Author ....: jNizM
; Released ...........: 2015-05-26
; Modified ...........: 2020-08-01
; Adapted By .........: tigerlily, CloakerSmoker
; Version ............: 2.1.1
; Forum ..............: https://www.autohotkey.com/boards/viewtopic.php?f=83&t=79220
; License/Copyright ..: The Unlicense (https://unlicense.org)
;
; [Change Log], [Pending], and [Remarks] sections can be found @ bottom of script
;
; =================================================================================================== ;


class Monitor 
{
; ===== PUBLIC METHODS ============================================================================== ;


	; ===== GET METHODS ===== ;
	
	GetInfo() => this.EnumDisplayMonitors()

	GetBrightness(Display := "") => this.GetSetting("GetMonitorBrightness", Display)
	
	GetContrast(Display := "") => this.GetSetting("GetMonitorContrast", Display)
	
	GetGammaRamp(Display := "") => this.GammaSetting("GetDeviceGammaRamp", , , , Display)
	
	GetRedDrive(Display := "") => this.GetSetting("GetMonitorRedDrive", Display)
	
	GetGreenDrive(Display := "") => this.GetSetting("GetMonitorGreenDrive", Display)
	
	GetBlueDrive(Display := "") => this.GetSetting("GetMonitorBlueDrive", Display)
	
	GetRedGain(Display := "") => this.GetSetting("GetMonitorRedGain", Display)
	
	GetGreenGain(Display := "") => this.GetSetting("GetMonitorGreenGain", Display)
	
	GetBlueGain(Display := "") => this.GetSetting("GetMonitorBlueGain", Display)
		
	GetDisplayAreaWidth(Display := "") => this.GetSetting("GetMonitorDisplayAreaWidth", Display)
	
	GetDisplayAreaHeight(Display := "") => this.GetSetting("GetMonitorDisplayAreaHeight", Display)
	
	GetDisplayAreaPositionHorizontal(Display := "") => this.GetSetting("GetMonitorDisplayAreaPositionHorizontal", Display)
		
	GetDisplayAreaPositionVertical(Display := "") => this.GetSetting("GetMonitorDisplayAreaPositionVertical", Display)
		
	GetVCPFeatureAndVCPFeatureReply(VCPCode, Display := "") => this.GetSetting("GetMonitorVCPFeatureAndVCPFeatureReply", Display, , , VCPCode)	
	
	CapabilitiesRequestAndCapabilitiesReply(Display := "") => this.GetSetting("MonitorCapabilitiesRequestAndCapabilitiesReply", Display)
	
	GetCapabilitiesStringLength(Display := "") => this.GetSetting("GetMonitorCapabilitiesStringLength", Display)
	
	GetCapabilities(Display := ""){
		
		static MC_CAPS := Map(
		0x00000000, "MC_CAPS_NONE:`nThe monitor does not support any monitor settings.",
		0x00000001, "MC_CAPS_MONITOR_TECHNOLOGY_TYPE:`nThe monitor supports the GetMonitorTechnologyType function.",
		0x00000002, "MC_CAPS_BRIGHTNESS:`nThe monitor supports the GetMonitorBrightness and SetMonitorBrightness functions.",
		0x00000004, "MC_CAPS_CONTRAST:`nThe monitor supports the GetMonitorContrast and SetMonitorContrast functions.",
		0x00000008, "MC_CAPS_COLOR_TEMPERATURE:`nThe monitor supports the GetMonitorColorTemperature and SetMonitorColorTemperature functions.",
		0x00000010, "MC_CAPS_RED_GREEN_BLUE_GAIN:`nThe monitor supports the GetMonitorRedGreenOrBlueGain and SetMonitorRedGreenOrBlueGain functions.",
		0x00000020, "MC_CAPS_RED_GREEN_BLUE_DRIVE:`nThe monitor supports the GetMonitorRedGreenOrBlueDrive and SetMonitorRedGreenOrBlueDrive functions.",
		0x00000040, "MC_CAPS_DEGAUSS:`nThe monitor supports the DegaussMonitor function.",
		0x00000080, "MC_CAPS_DISPLAY_AREA_POSITION:`nThe monitor supports the GetMonitorDisplayAreaPosition and SetMonitorDisplayAreaPosition functions.",
		0x00000100, "MC_CAPS_DISPLAY_AREA_SIZE:`nThe monitor supports the GetMonitorDisplayAreaSize and SetMonitorDisplayAreaSize functions.",
		0x00000200, "MC_CAPS_RESTORE_FACTORY_DEFAULTS:`nThe monitor supports the RestoreMonitorFactoryDefaults function.",
		0x00000400, "MC_CAPS_RESTORE_FACTORY_COLOR_DEFAULTS:`nThe monitor supports the RestoreMonitorFactoryColorDefaults function.",
		0x00001000, "MC_RESTORE_FACTORY_DEFAULTS_ENABLES_MONITOR_SETTINGS:`nIf this flag is present, calling the RestoreMonitorFactoryDefaults function enables all of the monitor settings used by the high-level monitor configuration functions. For more information, see the Remarks section in RestoreMonitorFactoryDefaults. (https://docs.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-restoremonitorfactorydefaults)")
		
		if (CapabilitiesFlags := this.GetSetting("GetMonitorCapabilities", Display)["MonitorCapabilities"])
		{	
			SupportedCapabilities := []
			for FlagValue, FlagDescription in MC_CAPS
				if (CapabilitiesFlags & FlagValue)
					SupportedCapabilities.Push(FlagDescription)
			return SupportedCapabilities
		}	
		throw MC_CAPS[CapabilitiesFlags]
	}	
	
	GetSupportedColorTemperatures(Display := ""){
		
		static MC_SUPPORTED_COLOR_TEMPERATURE := Map(
		0x00000000, "No color temperatures are supported.",
		0x00000001, "The monitor supports 4,000 kelvins (K) color temperature.",
		0x00000002, "The monitor supports 5,000 K color temperature.",
		0x00000004, "The monitor supports 6,500 K color temperature.",
		0x00000008, "The monitor supports 7,500 K color temperature.",
		0x00000010, "The monitor supports 8,200 K color temperature.",
		0x00000020, "The monitor supports 9,300 K color temperature.",
		0x00000040, "The monitor supports 10,000 K color temperature.",
		0x00000080, "The monitor supports 11,500 K color temperature.")
		
		if (ColorTemperatureFlags := this.GetSetting("GetMonitorCapabilities", Display)["SupportedColorTemperatures"])
		{
			SupportedColorTemperatures := []
			for FlagValue, FlagDescription in MC_SUPPORTED_COLOR_TEMPERATURE
				if (ColorTemperatureFlags & FlagValue)
					SupportedColorTemperatures.Push(FlagDescription)
			return SupportedColorTemperatures
		}
		throw MC_SUPPORTED_COLOR_TEMPERATURE[ColorTemperatureFlags]
	}	
	
	GetColorTemperature(Display := ""){
		
		static MC_COLOR_TEMPERATURE := Map(
		0x00000000,  "Unknown temperature.",
		0x00000001,  "4,000 kelvins (K).",
		0x00000002,  "5,000 kelvins (K).",
		0x00000004,  "6,500 kelvins (K).",
		0x00000008,  "7,500 kelvins (K).",
		0x00000010,  "8,200 kelvins (K).",
		0x00000020,  "9,300 kelvins (K).",
		0x00000040, "10,000 kelvins (K).",
		0x00000080, "11,500 kelvins (K).")
		
		return MC_COLOR_TEMPERATURE[this.GetSetting("GetMonitorColorTemperature", Display)]
	}

	GetTechnologyType(Display := ""){
		
		static DISPLAY_TECHNOLOGY_TYPE := Map(
		0x00000000, "Shadow-mask cathode ray tube (CRT)",
		0x00000001, "Aperture-grill CRT",
		0x00000002, "Thin-film transistor (TFT) display",
		0x00000004, "Liquid crystal on silicon (LCOS) display",
		0x00000008, "Plasma display",
		0x00000010, "Organic light emitting diode (LED) display",
		0x00000020, "Electroluminescent display",
		0x00000040, "Microelectromechanical display",
		0x00000080, "Field emission device (FED) display")
		
		return DISPLAY_TECHNOLOGY_TYPE[this.GetSetting("GetMonitorTechnologyType", Display)]	
	}		
	
	
	; ===== SET METHODS ===== ;
	
	SetBrightness(Brightness, Display := "") => this.SetSetting("SetMonitorBrightness", Brightness, Display)
	
	SetContrast(Contrast, Display := "") => this.SetSetting("SetMonitorContrast", Contrast, Display)
	
	SetGammaRamp(Red := 128, Green := 128, Blue := 128, Display := "") => this.GammaSetting("SetGammaDeviceRamp", Red, Green, Blue, Display)
	
	SetRedDrive(RedDrive, Display := "") => this.SetSetting("SetMonitorRedDrive", RedDrive, Display)
	
	SetGreenDrive(GreenDrive, Display := "") => this.SetSetting("SetMonitorGreenDrive", GreenDrive, Display)
	
	SetBlueDrive(BlueDrive, Display := "") => this.SetSetting("SetMonitorBlueDrive", BlueDrive, Display)
	
	SetRedGain(RedGain, Display := "") => this.SetSetting("SetMonitorRedGain", RedGain, Display)
	
	SetGreenGain(GreenGain, Display := "") => this.SetSetting("SetMonitorGreenGain", GreenGain, Display)
	
	SetBlueGain(BlueGain, Display := "") => this.SetSetting("SetMonitorBlueGain", BlueGain, Display)
	
	SetDisplayAreaWidth(DisplayAreaWidth, Display := "") => this.SetSetting("SetMonitorDisplayAreaWidth", DisplayAreaWidth, Display)
	
	SetDisplayAreaHeight(DisplayAreaHeight, Display := "") => this.SetSetting("SetMonitorDisplayAreaHeight", DisplayAreaHeight, Display)
	
	SetDisplayAreaPositionHorizontal(DisplayAreaPositionHorizontal, Display := "") => this.SetSetting("SetMonitorDisplayAreaPositionHorizontal", DisplayAreaPositionHorizontal, Display)
	
	SetDisplayAreaPositionVertical(DisplayAreaPositionVertical, Display := "") => this.SetSetting("SetMonitorDisplayAreaPositionVertical", DisplayAreaPositionVertical, Display)	
	
	SetVCPFeature(VCPCode, NewValue, Display := "") => this.SetSetting("SetMonitorVCPFeature", VCPCode, Display, , NewValue)	
	
	SetColorTemperature(ColorTemperature, Display := ""){		
		
		static MC_COLOR_TEMPERATURE := Map(
		0x00000000,  "Unknown temperature.",
		0x00000001,  "4,000 kelvins (K).",
		0x00000002,  "5,000 kelvins (K).",
		0x00000004,  "6,500 kelvins (K).",
		0x00000008,  "7,500 kelvins (K).",
		0x00000010,  "8,200 kelvins (K).",
		0x00000020,  "9,300 kelvins (K).",
		0x00000040, "10,000 kelvins (K).",
		0x00000080, "11,500 kelvins (K).")		
		
		return MC_COLOR_TEMPERATURE[this.SetSetting("SetMonitorColorTemperature", ColorTemperature, Display)]
	}	
	
	
	; ===== VOID METHODS ===== ;
	
	Degauss(Display := "") => this.VoidSetting("DegaussMonitor", Display)
	
	RestoreFactoryDefaults(Display := "") => this.VoidSetting("RestoreMonitorFactoryDefaults", Display)
	
	RestoreFactoryColorDefaults(Display := "") => this.VoidSetting("RestoreMonitorFactoryColorDefaults", Display)
	
	SaveCurrentSettings(Display := "") => this.VoidSetting("SaveCurrentMonitorSettings", Display)
	
	
	
; ===== PRIVATE METHODS ============================================================================= ;
	
	
	; ===== CORE MONITOR METHODS ===== ;
	
	EnumDisplayMonitors(hMonitor := "")
	{	    
		static EnumProc := CallbackCreate(Monitor.GetMethod("MonitorEnumProc").Bind(Monitor),, 4)
		static DisplayMonitors := []
		
		if (!DisplayMonitors.Length)
			if !(DllCall("user32\EnumDisplayMonitors", "ptr", 0, "ptr", 0, "ptr", EnumProc, "ptr", ObjPtrAddRef(DisplayMonitors), "uint"))
				return false
		return DisplayMonitors    
	}
	
	static MonitorEnumProc(hMonitor, hDC, pRECT, ObjectAddr)
	{	
		DisplayMonitors := ObjFromPtrAddRef(ObjectAddr)
		MonitorData := Monitor.GetMonitorInfo(hMonitor)
		DisplayMonitors.Push(MonitorData)
		return true
	}
	
	static GetMonitorInfo(hMonitor)	
	{	
		num := 40 + 64 ; (MONITORINFO = 40 byte struct) + (MONITORINFOEX = 64 bytes)
		NumPut("uint", num, MONITORINFOEX := BufferAlloc(num))
		if (DllCall("user32\GetMonitorInfo", "ptr", hMonitor, "ptr", MONITORINFOEX))
		{
			MONITORINFO := Map()
			MONITORINFO["Handle"]   := hMonitor
			MONITORINFO["Name"]     := Name := StrGet(MONITORINFOEX.Ptr + 40, 32)
			MONITORINFO["Number"]   := RegExReplace(Name, ".*(\d+)$", "$1")
			MONITORINFO["Left"]     := NumGet(MONITORINFOEX,  4, "int")
			MONITORINFO["Top"]      := NumGet(MONITORINFOEX,  8, "int")
			MONITORINFO["Right"]    := NumGet(MONITORINFOEX, 12, "int")
			MONITORINFO["Bottom"]   := NumGet(MONITORINFOEX, 16, "int")
			MONITORINFO["WALeft"]   := NumGet(MONITORINFOEX, 20, "int")
			MONITORINFO["WATop"]    := NumGet(MONITORINFOEX, 24, "int")
			MONITORINFO["WARight"]  := NumGet(MONITORINFOEX, 28, "int")
			MONITORINFO["WABottom"] := NumGet(MONITORINFOEX, 32, "int")
			MONITORINFO["Primary"]  := NumGet(MONITORINFOEX, 36, "uint")
			return MONITORINFO
		}
		throw Exception("GetMonitorInfo: " A_LastError, -1)
	}
	
	MonitorFromWindow(hWindow := 0)
	{
		static MONITOR_DEFAULTTONEAREST := 0x00000002
		if (hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow, "uint", MONITOR_DEFAULTTONEAREST))
			return hMonitor
		return false
	}
	
	GetMonitorHandle(Display := "", hMonitor := 0)
	{	
		if ((Display != "") && MonitorInfo := this.EnumDisplayMonitors())
			for Info in MonitorInfo
				if (InStr(Info["Name"], Display))
					hMonitor := Info["Handle"]
				
		(!hMonitor) ? hMonitor := this.MonitorFromWindow() : ""
		return hMonitor
	}
	
	GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, NumberOfPhysicalMonitors := 0)
	{
		if (DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint*", NumberOfPhysicalMonitors))
			return NumberOfPhysicalMonitors
		return false
	}
	
	GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitorArraySize, ByRef PHYSICAL_MONITOR)
	{
		PHYSICAL_MONITOR := BufferAlloc((A_PtrSize + 256) * PhysicalMonitorArraySize)
		if (DllCall("dxva2\GetPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint", PhysicalMonitorArraySize, "ptr", PHYSICAL_MONITOR))
			return NumGet(PHYSICAL_MONITOR, 0, "ptr")
		return false
	}
	
	DestroyPhysicalMonitors(PhysicalMonitorArraySize, PHYSICAL_MONITOR)
	{
		if (DllCall("dxva2\DestroyPhysicalMonitors", "uint", PhysicalMonitorArraySize, "ptr", PHYSICAL_MONITOR))
			return true
		return false
	}
	
	CreateDC(DisplayName)
	{
		if (hDC := DllCall("gdi32\CreateDC", "str", DisplayName, "ptr", 0, "ptr", 0, "ptr", 0, "ptr"))
			return hDC
		return false
	}
	
	DeleteDC(hDC)
	{
		if (DllCall("gdi32\DeleteDC", "ptr", hDC))
			return true
		return false
	}
	
	
	; ===== HELPER METHODS ===== ;
	
	GetSetting(GetMethodName, Display := "", Setting := "", PHYSICAL_MONITOR := "", params*)
	{
		if (hMonitor := this.GetMonitorHandle(Display))
		{
			PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
			hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitors, PHYSICAL_MONITOR)
			Setting := this.%GetMethodName%(hPhysicalMonitor, params*)
			this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			return Setting
		}
		throw Exception("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetSetting(SetMethodName, Setting, Display := "", PHYSICAL_MONITOR := "", params*)
	{
		if (hMonitor := this.GetMonitorHandle(Display))
		{			
			PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
			hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitors, PHYSICAL_MONITOR)
			if (!params && SetMethodName != "SetMonitorColorTemperature")
			{	
				GetMethodName := RegExReplace(SetMethodName, "S(.*)", "G$1")
				GetSetting := this.%GetMethodName%(hPhysicalMonitor)
				Setting := (Setting < GetSetting["Minimum"]) ? GetSetting["Minimum"]
					    :  (Setting > GetSetting["Maximum"]) ? GetSetting["Maximum"]
					    :  (Setting)
				this.%SetMethodName%(hPhysicalMonitor, Setting)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Setting["Current"]
			}
			else
			{
				SetSetting := this.%SetMethodName%(hPhysicalMonitor, Setting, params*)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return SetSetting				
			}
		} 
		throw Exception("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	VoidSetting(VoidMethodName, Display := "", PHYSICAL_MONITOR := "")
	{
		if (hMonitor := this.GetMonitorHandle(Display))
		{
			PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
			hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitors, PHYSICAL_MONITOR)
			this.%VoidMethodName%(hPhysicalMonitor)
			this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			return
		}
		throw Exception("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GammaSetting(GammaMethodName, Red := "", Green := "", Blue := "", Display := "", DisplayName := "")
	{
		MonitorInfo := this.EnumDisplayMonitors()
		if (Display = "") 
			for Info in MonitorInfo
				if (Info["Primary"])
					PrimaryMonitor := A_Index
		
		if (DisplayName := MonitorInfo[Display ? Display : PrimaryMonitor]["Name"]) 
		{
			if (hDC := this.CreateDC(DisplayName))
			{	
				if (GammaMethodName = "SetDeviceGammaRamp")
				{
					Gamma := ["Red", "Green", "Blue"]
					for Color in Gamma
						%Color% := (%Color% < -128) ? -128
						 	    :  (%Color% >  128) ?  128
							    :  (%Color%)				
					this.SetDeviceGammaRamp(hDC, Red, Green, Blue)
					this.DeleteDC(hDC)
					return Map("Red", Red, "Green", Green, "Blue", Blue)
				}
				else
				{
					GammaRamp := this.GetDeviceGammaRamp(hDC)
					this.DeleteDC(hDC)
					return GammaRamp
				}
			}
			this.DeleteDC(hDC)
			throw Exception("Unable to get handle to Device Context.`n`nError code: " Format("0x{:X}", A_LastError))
		}
	}
	
	; ===== GET METHODS ===== ;
	
	GetMonitorBrightness(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{
		if (DllCall("dxva2\GetMonitorBrightness", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorContrast(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{				
		if (DllCall("dxva2\GetMonitorContrast", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetDeviceGammaRamp(hMonitor)
	{			
		if (DllCall("gdi32\GetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP := BufferAlloc(1536)))
		{
			GammaRamp := Map()
			GammaRamp["Red"]   := NumGet(GAMMA_RAMP,        2, "ushort") - 128
			GammaRamp["Green"] := NumGet(GAMMA_RAMP,  512 + 2, "ushort") - 128
			GammaRamp["Blue"]  := NumGet(GAMMA_RAMP, 1024 + 2, "ushort") - 128
			return GammaRamp
		}
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorRedDrive(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_RED_DRIVE := 0x00000000
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", MC_RED_DRIVE, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorGreenDrive(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_GREEN_DRIVE := 0x00000001
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", MC_GREEN_DRIVE, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorBlueDrive(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_BLUE_DRIVE := 0x00000002
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", MC_BLUE_DRIVE, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		MsgBox "Failed"
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorRedGain(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_RED_GAIN := 0x00000000
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", MC_RED_GAIN, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorGreenGain(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_GREEN_GAIN := 0x00000001
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", MC_GREEN_GAIN, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorBlueGain(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_BLUE_GAIN := 0x00000002
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", MC_BLUE_GAIN, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	GetMonitorDisplayAreaWidth(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_WIDTH := 0x00000000
		if (DllCall("dxva2\GetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", MC_WIDTH, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorDisplayAreaHeight(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_HEIGHT := 0x00000001
		if (DllCall("dxva2\GetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", MC_HEIGHT, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorDisplayAreaPositionHorizontal(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_HORIZONTAL_POSITION := 0x00000000
		if (DllCall("dxva2\GetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", MC_HORIZONTAL_POSITION, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorDisplayAreaPositionVertical(hMonitor, Minimum := 0, Current := 0, Maximum := 0)
	{	
		static MC_VERTICAL_POSITION   := 0x00000001
		if (DllCall("dxva2\GetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", MC_VERTICAL_POSITION, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	GetMonitorVCPFeatureAndVCPFeatureReply(hMonitor, VCPCode, vct := 0, CurrentValue := 0, MaximumValue := 0)
	{
		VCP_CODE_TYPE := Map(
		0x00000000, "MC_MOMENTARY — Momentary VCP code. Sending a command of this type causes the monitor to initiate a self-timed operation and then revert to its original state. Examples include display tests and degaussing.",
		0x00000001, "MC_SET_PARAMETER — Set Parameter VCP code. Sending a command of this type changes some aspect of the monitor's operation.")
		
		if (DllCall("dxva2\GetVCPFeatureAndVCPFeatureReply", "ptr", hMonitor, "ptr", VCPCode, "uint*", vct, "uint*", CurrentValue, "uint*", MaximumValue))
			return Map("VCPCode"      ,  Format("0x{:X}", VCPCode),
					   "VCP_CODE_TYPE",  VCP_CODE_TYPE[vct], 
					   "CurrentValue" ,  CurrentValue, 
					   "MaximumValue" , (MaximumValue ? MaximumValue : "Undefined due to non-continuous (NC) VCP Code."))
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorCapabilitiesStringLength(hMonitor, CapabilitiesStrLen := 0)
	{
		if (DllCall("dxva2\GetCapabilitiesStringLength", "ptr", hMonitor, "uint*", CapabilitiesStrLen))
			return CapabilitiesStrLen
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	MonitorCapabilitiesRequestAndCapabilitiesReply(hMonitor, ASCIICapabilitiesString := "", CapabilitiesStrLen := 0)
	{
		CapabilitiesStrLen := this.GetMonitorCapabilitiesStringLength(hMonitor)
		ASCIICapabilitiesString := BufferAlloc(CapabilitiesStrLen)
		if (DllCall("dxva2\GetCapabilitiesStringLength", "ptr", hMonitor, "ptr", ASCIICapabilitiesString.Ptr, "uint", CapabilitiesStrLen))
		{	
			CapabililitiesString := ASCIICapabilitiesString
			return CapabililitiesString
		}	
		throw Exception("Unable to retreive value.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	GetMonitorCapabilities(hMonitor, MonitorCapabilities := 0, SupportedColorTemperatures := 0)
	{
		if (DllCall("dxva2\GetMonitorCapabilities", "ptr", hMonitor, "uint*", MonitorCapabilities, "uint*", SupportedColorTemperatures))
			return Map("MonitorCapabilities"	    , MonitorCapabilities, 
				  	   "SupportedColorTemperatures", SupportedColorTemperatures)		
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorColorTemperature(hMonitor, CurrentColorTemperature := 0)
	{
		if (DllCall("dxva2\GetMonitorColorTemperature", "ptr", hMonitor, "uint*", CurrentColorTemperature))
			return CurrentColorTemperature
		throw Exception("Unable to retreive value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorTechnologyType(hMonitor, DisplayTechnologyType := 0)
	{
		if (DllCall("dxva2\GetMonitorTechnologyType", "ptr", hMonitor, "uint*", DisplayTechnologyType))
			return DisplayTechnologyType
		throw Exception("Unable to retreive value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	
	; ===== SET METHODS ===== ;
	
	SetMonitorBrightness(hMonitor, Brightness)
	{
		if (DllCall("dxva2\SetMonitorBrightness", "ptr", hMonitor, "uint", Brightness))
			return Brightness
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorContrast(hMonitor, Contrast)
	{
		if (DllCall("dxva2\SetMonitorContrast", "ptr", hMonitor, "uint", Contrast))
			return Contrast
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetDeviceGammaRamp(hMonitor, Red, Green, Blue)
	{
		GAMMA_RAMP := BufferAlloc(1536)	
		while ((i := A_Index - 1) < 256 )
		{	
			NumPut("ushort", (r := (red   + 128) * i) > 65535 ? 65535 : r, GAMMA_RAMP,        2 * i)
			NumPut("ushort", (g := (green + 128) * i) > 65535 ? 65535 : g, GAMMA_RAMP,  512 + 2 * i)
			NumPut("ushort", (b := (blue  + 128) * i) > 65535 ? 65535 : b, GAMMA_RAMP, 1024 + 2 * i)
		}
		if (DllCall("gdi32\SetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP))
			return true
		throw Exception("Unable to set values.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	SetMonitorRedDrive(hMonitor, RedDrive)
	{	
		static MC_RED_DRIVE := 0x00000000
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", MC_RED_DRIVE, "uint", RedDrive))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorGreenDrive(hMonitor, GreenDrive)
	{	
		static MC_GREEN_DRIVE := 0x00000001
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", MC_GREEN_DRIVE, "uint", GreenDrive))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorBlueDrive(hMonitor, BlueDrive)
	{	
		static MC_BLUE_DRIVE := 0x00000002
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", MC_BLUE_DRIVE, "uint", BlueDrive))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorRedGain(hMonitor, RedGain)
	{	
		static MC_RED_GAIN := 0x00000000
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", MC_RED_GAIN, "uint", RedGain))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorGreenGain(hMonitor, GreenGain)
	{	
		static MC_GREEN_GAIN := 0x00000001
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", MC_GREEN_GAIN, "uint", GreenGain))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorBlueGain(hMonitor, BlueGain)
	{	
		static MC_BLUE_GAIN := 0x00000002
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", MC_BLUE_GAIN, "uint", BlueGain))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}		
	
	SetMonitorDisplayAreaWidth(hMonitor, DisplayAreaWidth)
	{	
		static MC_WIDTH := 0x00000000
		if (DllCall("dxva2\SetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", MC_WIDTH, "uint", DisplayAreaWidth))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorDisplayAreaHeight(hMonitor, DisplayAreaHeight)
	{	
		static MC_HEIGHT := 0x00000001
		if (DllCall("dxva2\SetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", MC_HEIGHT, "uint", DisplayAreaHeight))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorDisplayAreaPositionHorizontal(hMonitor, NewHorizontalPosition)
	{	
		static MC_HORIZONTAL_POSITION := 0x00000000
		if (DllCall("dxva2\SetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", MC_HORIZONTAL_POSITION, "uint", NewHorizontalPosition))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	SetMonitorDisplayAreaPositionVertical(hMonitor, NewVerticalPosition)
	{	
		static MC_VERTICAL_POSITION := 0x00000001
		if (DllCall("dxva2\SetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", MC_VERTICAL_POSITION, "uint", NewVerticalPosition))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	SetMonitorVCPFeature(hMonitor, VCPCode, NewValue)
	{	
		if (DllCall("dxva2\SetVCPFeature", "ptr", hMonitor, "ptr", VCPCode, "uint", NewValue))
			return Map("VCPCode", Format("0x{:X}", VCPCode), "NewValue", NewValue)
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}		
	
	SetMonitorColorTemperature(hMonitor, CurrentColorTemperature)
	{
		if (DllCall("dxva2\SetMonitorColorTemperature", "ptr", hMonitor, "uint", CurrentColorTemperature))
			return CurrentColorTemperature
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	
	; ===== VOID METHODS ===== ;
	
	DegaussMonitor(hMonitor)
	{
		if (DllCall("dxva2\DegaussMonitor", "ptr", hMonitor))
			return true
		throw Exception("Unable to degauss monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	RestoreMonitorFactoryDefaults(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		throw Exception("Unable to restore monitor to factory defaults.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	RestoreMonitorFactoryColorDefaults(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryColorDefaults", "ptr", hMonitor))
			return true
		throw Exception("Unable to restore monitor to factory color defaults.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SaveCurrentMonitorSettings(hMonitor)
	{
		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		throw Exception("Unable to save current monitor settings to non-volatile storage.`n`nError code: " Format("0x{:X}", A_LastError))
	}

}

; ================= ;
; == Change Log  == ;
; ================= ;
;
; 2020-08-01:	- Changed all SetXXX() Methods, to now return updated values, except for 
;						the SetVCPFeature() Method, which now returns a Map object with
;						"VCPCode" and "NewValue")
; 2020-08-01:	- Changed SetGammaRamp() to return a Map object with all updated gamma color output values
; 2020-08-01:	- GetSupportedColorTemperatures() & GetCapabilities() Methods now throw an error	
;						when no settings are supported showing that instead of an arbritary index error
; 2020-08-01:	- Fixed minor bugs in SetSetting() & VoidSetting() methods throwing errors
;
; 2020-07-31:	- Added support for nearly every WinAPI found here: 
; 						https://docs.microsoft.com/en-us/windows/win32/api/_monitor/
; 2020-07-31:	- Drastically reduced code size with Helper Methods: GetSetting(), SetSetting(), 
; 						VoidSetting(), GammaSetting()
; 2020-07-31:	- Added jNizM's GetMonitorHandle() Method to further reduce code size
; 2020-07-31:	- Removed need to specify monitor # for all methods, now defaults to primary monitor #
; 2020-07-31:	- Changed method params to mirror jNizM's v1 class, making "Display" the final param
; 2020-07-31:	- Set default values for SetGammaRamp() Method to 128 for all Gamma Colors
; 2020-07-31:	- Added safety checks to ensure settlng Gamma Color Values stays within [-128,128] range
; 2020-07-31:	- Added return values for all SetXXX() Methods to optionally show updated values
; 2020-07-31:	- Added Throw-Exception messages for all private methods upon failure 
; 2020-07-31:	- Reordered all methods into "GET, SET, VOID, and CORE MONITOR" Methods for better 
; 						visual organization
; 
; 2020-07-28:	- Ported to AHK v2.0 alpha 119, compatible with v2 a111+
; 2020-07-28:	- Reduced code size for some methods
; 2020-07-28:	- Removed redundant code
; 2020-07-28:	- Reordered methods to be more visually intuitive (e.i. GetXXX(), then SetXXX() )
; 
; 
; ================= ;
; ==   Pending   == ;
; ================= ;
; 
; 	- Add GetTimingReport WinAPI
; 	- Create Exception Handler
; 	- Extra support for querying & setting useful VCP Codes
;	- Create supporting docs and examples
;
; ================= ;
; ==   Remarks   == ;
; ================= ;
; 
; 	- I don't beleive I'm executing the CapabilitiesRequestAndCapabilitiesReply() Method 
;				correctly, needs work
;
;
; =================================================================================================== ;
-TL

User avatar
Tigerlily
Posts: 377
Joined: 04 Oct 2018, 22:31

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by Tigerlily » 08 Aug 2020, 19:47

@jNizM

Added some custom Methods using Get/SetVCP Methods to get/set monitor Power Modes and adjust screen sharpness, changed Get/SetGammaRamp Methods to accept/return values in the [0 to 100] range instead of the [-128 to 128] range - this way it more closely aligns with the rest of the Monitor Config methods. Examples can be found at the forum link found @ the top of code below. Change log is also @ bottom of script:

Code: Select all

; =================================================================================================== ;
; AutoHotkey V2 a119 wrapper for Monitor Configuration API Functions (a111+ compatible)
;
; Original Author ....: jNizM
; Released ...........: 2015-05-26
; Modified ...........: 2020-08-09
; Adapted By .........: tigerlily, CloakerSmoker
; Version ............: 2.3.1
; Forum ..............: https://www.autohotkey.com/boards/viewtopic.php?f=83&t=79220
; License/Copyright ..: The Unlicense (https://unlicense.org)
;
; [Change Log], [Pending], and [Remarks] sections can be found @ bottom of script
;
; =================================================================================================== ;


class Monitor {

; ===== PUBLIC METHODS ============================================================================== ;
	
	
	; ===== GET METHODS ===== ;
	
	GetInfo() => this.EnumDisplayMonitors()
	
	GetBrightness(Display := "") => this.GetSetting("GetMonitorBrightness", Display)
	
	GetContrast(Display := "") => this.GetSetting("GetMonitorContrast", Display)
	
	GetGammaRamp(Display := "") => this.GammaSetting("GetDeviceGammaRamp", , , , Display)
	
	GetRedDrive(Display := "") => this.GetSetting("GetMonitorRedDrive", Display)
	
	GetGreenDrive(Display := "") => this.GetSetting("GetMonitorGreenDrive", Display)
	
	GetBlueDrive(Display := "") => this.GetSetting("GetMonitorBlueDrive", Display)
	
	GetRedGain(Display := "") => this.GetSetting("GetMonitorRedGain", Display)
	
	GetGreenGain(Display := "") => this.GetSetting("GetMonitorGreenGain", Display)
	
	GetBlueGain(Display := "") => this.GetSetting("GetMonitorBlueGain", Display)
	
	GetDisplayAreaWidth(Display := "") => this.GetSetting("GetMonitorDisplayAreaWidth", Display)
	
	GetDisplayAreaHeight(Display := "") => this.GetSetting("GetMonitorDisplayAreaHeight", Display)
	
	GetDisplayAreaPositionHorizontal(Display := "") => this.GetSetting("GetMonitorDisplayAreaPositionHorizontal", Display)
	
	GetDisplayAreaPositionVertical(Display := "") => this.GetSetting("GetMonitorDisplayAreaPositionVertical", Display)
	
	GetVCPFeatureAndReply(VCPCode, Display := "") => this.GetSetting("GetVCPFeatureAndVCPFeatureReply", Display, VCPCode)	
	
    GetSharpness(Display := "") => this.GetSetting("GetVCPFeatureAndVCPFeatureReply", Display, 0x87)["CurrentValue"]

	CapabilitiesRequestAndCapabilitiesReply(Display := "") => this.GetSetting("MonitorCapabilitiesRequestAndCapabilitiesReply", Display)
	
	GetCapabilitiesStringLength(Display := "") => this.GetSetting("GetMonitorCapabilitiesStringLength", Display)
	
	GetCapabilities(Display := ""){
		
		static MC_CAPS := Map(
		0x00000000, "MC_CAPS_NONE:`nThe monitor does not support any monitor settings.",
		0x00000001, "MC_CAPS_MONITOR_TECHNOLOGY_TYPE:`nThe monitor supports the GetMonitorTechnologyType function.",
		0x00000002, "MC_CAPS_BRIGHTNESS:`nThe monitor supports the GetMonitorBrightness and SetMonitorBrightness functions.",
		0x00000004, "MC_CAPS_CONTRAST:`nThe monitor supports the GetMonitorContrast and SetMonitorContrast functions.",
		0x00000008, "MC_CAPS_COLOR_TEMPERATURE:`nThe monitor supports the GetMonitorColorTemperature and SetMonitorColorTemperature functions.",
		0x00000010, "MC_CAPS_RED_GREEN_BLUE_GAIN:`nThe monitor supports the GetMonitorRedGreenOrBlueGain and SetMonitorRedGreenOrBlueGain functions.",
		0x00000020, "MC_CAPS_RED_GREEN_BLUE_DRIVE:`nThe monitor supports the GetMonitorRedGreenOrBlueDrive and SetMonitorRedGreenOrBlueDrive functions.",
		0x00000040, "MC_CAPS_DEGAUSS:`nThe monitor supports the DegaussMonitor function.",
		0x00000080, "MC_CAPS_DISPLAY_AREA_POSITION:`nThe monitor supports the GetMonitorDisplayAreaPosition and SetMonitorDisplayAreaPosition functions.",
		0x00000100, "MC_CAPS_DISPLAY_AREA_SIZE:`nThe monitor supports the GetMonitorDisplayAreaSize and SetMonitorDisplayAreaSize functions.",
		0x00000200, "MC_CAPS_RESTORE_FACTORY_DEFAULTS:`nThe monitor supports the RestoreMonitorFactoryDefaults function.",
		0x00000400, "MC_CAPS_RESTORE_FACTORY_COLOR_DEFAULTS:`nThe monitor supports the RestoreMonitorFactoryColorDefaults function.",
		0x00001000, "MC_RESTORE_FACTORY_DEFAULTS_ENABLES_MONITOR_SETTINGS:`nIf this flag is present, calling the RestoreMonitorFactoryDefaults function enables all of the monitor settings used by the high-level monitor configuration functions. For more information, see the Remarks section in RestoreMonitorFactoryDefaults. (https://docs.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-restoremonitorfactorydefaults)")
		
		if (CapabilitiesFlags := this.GetSetting("GetMonitorCapabilities", Display)["MonitorCapabilities"]){	
			SupportedCapabilities := []
			for FlagValue, FlagDescription in MC_CAPS
				if (CapabilitiesFlags & FlagValue)
					SupportedCapabilities.Push(FlagDescription)
			return SupportedCapabilities
		}	
		throw MC_CAPS[CapabilitiesFlags]
	}	
	
	GetSupportedColorTemperatures(Display := ""){
		
		static MC_SUPPORTED_COLOR_TEMPERATURE := Map(
		0x00000000, "No color temperatures are supported.",
		0x00000001, "The monitor supports 4,000 kelvins (K) color temperature.",
		0x00000002, "The monitor supports 5,000 K color temperature.",
		0x00000004, "The monitor supports 6,500 K color temperature.",
		0x00000008, "The monitor supports 7,500 K color temperature.",
		0x00000010, "The monitor supports 8,200 K color temperature.",
		0x00000020, "The monitor supports 9,300 K color temperature.",
		0x00000040, "The monitor supports 10,000 K color temperature.",
		0x00000080, "The monitor supports 11,500 K color temperature.")
		
		if (ColorTemperatureFlags := this.GetSetting("GetMonitorCapabilities", Display)["SupportedColorTemperatures"]){		
			SupportedColorTemperatures := []
			for FlagValue, FlagDescription in MC_SUPPORTED_COLOR_TEMPERATURE
				if (ColorTemperatureFlags & FlagValue)
					SupportedColorTemperatures.Push(FlagDescription)
			return SupportedColorTemperatures
		}
		throw MC_SUPPORTED_COLOR_TEMPERATURE[ColorTemperatureFlags]
	}	
	
	GetColorTemperature(Display := ""){
		
		static MC_COLOR_TEMPERATURE := Map(
		0x00000000,  "Unknown temperature.",
		0x00000001,  "4,000 kelvins (K).",
		0x00000002,  "5,000 kelvins (K).",
		0x00000004,  "6,500 kelvins (K).",
		0x00000008,  "7,500 kelvins (K).",
		0x00000010,  "8,200 kelvins (K).",
		0x00000020,  "9,300 kelvins (K).",
		0x00000040, "10,000 kelvins (K).",
		0x00000080, "11,500 kelvins (K).")
		
		return MC_COLOR_TEMPERATURE[this.GetSetting("GetMonitorColorTemperature", Display)]
	}
	
	GetTechnologyType(Display := ""){
		
		static DISPLAY_TECHNOLOGY_TYPE := Map(
		0x00000000, "Shadow-mask cathode ray tube (CRT)",
		0x00000001, "Aperture-grill CRT",
		0x00000002, "Thin-film transistor (TFT) display",
		0x00000004, "Liquid crystal on silicon (LCOS) display",
		0x00000008, "Plasma display",
		0x00000010, "Organic light emitting diode (LED) display",
		0x00000020, "Electroluminescent display",
		0x00000040, "Microelectromechanical display",
		0x00000080, "Field emission device (FED) display")
		
		return DISPLAY_TECHNOLOGY_TYPE[this.GetSetting("GetMonitorTechnologyType", Display)]	
	}	

		GetPowerMode(Display := ""){
		
		static PowerModes := Map(
		0x01, "On"      , 
		0x02, "Standby" , 
		0x03, "Suspend" , 
		0x04, "Off"     ,
		0x05, "PowerOff")
		
		return PowerModes[this.GetSetting("GetVCPFeatureAndVCPFeatureReply", Display, 0xD6)["CurrentValue"]]
	}
	

	; ===== SET METHODS ===== ;
	
	SetBrightness(Brightness, Display := "") => this.SetSetting("SetMonitorBrightness", Brightness, Display)
	
	SetContrast(Contrast, Display := "") => this.SetSetting("SetMonitorContrast", Contrast, Display)
	
	SetGammaRamp(Red := 100, Green := 100, Blue := 100, Display := "") => this.GammaSetting("SetDeviceGammaRamp", Red, Green, Blue, Display)
	
	SetRedDrive(RedDrive, Display := "") => this.SetSetting("SetMonitorRedDrive", RedDrive, Display)
	
	SetGreenDrive(GreenDrive, Display := "") => this.SetSetting("SetMonitorGreenDrive", GreenDrive, Display)
	
	SetBlueDrive(BlueDrive, Display := "") => this.SetSetting("SetMonitorBlueDrive", BlueDrive, Display)
	
	SetRedGain(RedGain, Display := "") => this.SetSetting("SetMonitorRedGain", RedGain, Display)
	
	SetGreenGain(GreenGain, Display := "") => this.SetSetting("SetMonitorGreenGain", GreenGain, Display)
	
	SetBlueGain(BlueGain, Display := "") => this.SetSetting("SetMonitorBlueGain", BlueGain, Display)
	
	SetDisplayAreaWidth(DisplayAreaWidth, Display := "") => this.SetSetting("SetMonitorDisplayAreaWidth", DisplayAreaWidth, Display)
	
	SetDisplayAreaHeight(DisplayAreaHeight, Display := "") => this.SetSetting("SetMonitorDisplayAreaHeight", DisplayAreaHeight, Display)
	
	SetDisplayAreaPositionHorizontal(DisplayAreaPositionHorizontal, Display := "") => this.SetSetting("SetMonitorDisplayAreaPositionHorizontal", DisplayAreaPositionHorizontal, Display)
	
	SetDisplayAreaPositionVertical(DisplayAreaPositionVertical, Display := "") => this.SetSetting("SetMonitorDisplayAreaPositionVertical", DisplayAreaPositionVertical, Display)	
	
	SetVCPFeature(VCPCode, NewValue, Display := "") => this.SetSetting("SetMonitorVCPFeature", VCPCode, Display, NewValue)	
	
    SetSharpness(Sharpness, Display := "") => this.SetSetting("SetMonitorVCPFeature", 0x87, Display, Sharpness)

	SetColorTemperature(ColorTemperature, Display := ""){		
		
		static MC_COLOR_TEMPERATURE := Map(
		0x00000000,  "Unknown temperature.",
		0x00000001,  "4,000 kelvins (K).",
		0x00000002,  "5,000 kelvins (K).",
		0x00000004,  "6,500 kelvins (K).",
		0x00000008,  "7,500 kelvins (K).",
		0x00000010,  "8,200 kelvins (K).",
		0x00000020,  "9,300 kelvins (K).",
		0x00000040, "10,000 kelvins (K).",
		0x00000080, "11,500 kelvins (K).")		
		
		return MC_COLOR_TEMPERATURE[this.SetSetting("SetMonitorColorTemperature", ColorTemperature, Display)]
	}	
	
	SetPowerMode(PowerMode, Display := ""){
	
		static PowerModes := Map(
		"On"   	  , 0x01, 
		"Standby" , 0x02,
		"Suspend" , 0x03, 
		"Off"	  , 0x04, 
		"PowerOff", 0x05)
		
		if (PowerModes.Has(PowerMode))
			if (this.SetSetting("SetMonitorVCPFeature", 0xD6, Display, PowerModes[PowerMode]))
				return PowerMode
		throw Exception("An invalid [PowerMode] parameter was passed to the SetPowerMode() Method.")
	}		

	; ===== VOID METHODS ===== ;
	
	Degauss(Display := "") => this.VoidSetting("DegaussMonitor", Display)
	
	RestoreFactoryDefaults(Display := "") => this.VoidSetting("RestoreMonitorFactoryDefaults", Display)
	
	RestoreFactoryColorDefaults(Display := "") => this.VoidSetting("RestoreMonitorFactoryColorDefaults", Display)
	
	SaveCurrentSettings(Display := "") => this.VoidSetting("SaveCurrentMonitorSettings", Display)
	
	
; ===== PRIVATE METHODS ============================================================================= ;
	
	
	; ===== CORE MONITOR METHODS ===== ;
	
	EnumDisplayMonitors(hMonitor := ""){
			    
		static EnumProc := CallbackCreate(Monitor.GetMethod("MonitorEnumProc").Bind(Monitor),, 4)
		static DisplayMonitors := []
		
		if (!DisplayMonitors.Length)
			if !(DllCall("user32\EnumDisplayMonitors", "ptr", 0, "ptr", 0, "ptr", EnumProc, "ptr", ObjPtrAddRef(DisplayMonitors), "uint"))
				return false
		return DisplayMonitors    
	}
	
	static MonitorEnumProc(hMonitor, hDC, pRECT, ObjectAddr){

		DisplayMonitors := ObjFromPtrAddRef(ObjectAddr)
		MonitorData := Monitor.GetMonitorInfo(hMonitor)
		DisplayMonitors.Push(MonitorData)
		return true
	}
	
	static GetMonitorInfo(hMonitor){ ; (MONITORINFO = 40 byte struct) + (MONITORINFOEX = 64 bytes)
	
		NumPut("uint", 104, MONITORINFOEX := BufferAlloc(104))
		if (DllCall("user32\GetMonitorInfo", "ptr", hMonitor, "ptr", MONITORINFOEX)){
			MONITORINFO := Map()
			MONITORINFO["Handle"]   := hMonitor
			MONITORINFO["Name"]     := Name := StrGet(MONITORINFOEX.Ptr + 40, 32)
			MONITORINFO["Number"]   := RegExReplace(Name, ".*(\d+)$", "$1")
			MONITORINFO["Left"]     := NumGet(MONITORINFOEX,  4, "int")
			MONITORINFO["Top"]      := NumGet(MONITORINFOEX,  8, "int")
			MONITORINFO["Right"]    := NumGet(MONITORINFOEX, 12, "int")
			MONITORINFO["Bottom"]   := NumGet(MONITORINFOEX, 16, "int")
			MONITORINFO["WALeft"]   := NumGet(MONITORINFOEX, 20, "int")
			MONITORINFO["WATop"]    := NumGet(MONITORINFOEX, 24, "int")
			MONITORINFO["WARight"]  := NumGet(MONITORINFOEX, 28, "int")
			MONITORINFO["WABottom"] := NumGet(MONITORINFOEX, 32, "int")
			MONITORINFO["Primary"]  := NumGet(MONITORINFOEX, 36, "uint")
			return MONITORINFO
		}
		throw Exception("GetMonitorInfo: " A_LastError, -1)
	}
		
	GetMonitorHandle(Display := "", hMonitor := 0){

		if ((Display != "") && MonitorInfo := this.EnumDisplayMonitors()){
			for Info in MonitorInfo {
				if (InStr(Info["Name"], Display)){
					hMonitor := Info["Handle"]
					break
				}
			}
		}

		if (!hMonitor) ;	MONITOR_DEFAULTTONEAREST = 0x00000002
			hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow := 0, "uint", 0x00000002)
		return hMonitor
	}
	
	GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor){

		if (DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint*", NumberOfPhysicalMonitors := 0))
			return NumberOfPhysicalMonitors
		return false
	}
	
	GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitorArraySize, ByRef PHYSICAL_MONITOR){

		PHYSICAL_MONITOR := BufferAlloc((A_PtrSize + 256) * PhysicalMonitorArraySize)
		if (DllCall("dxva2\GetPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint", PhysicalMonitorArraySize, "ptr", PHYSICAL_MONITOR))
			return NumGet(PHYSICAL_MONITOR, 0, "ptr")
		return false
	}
	
	DestroyPhysicalMonitors(PhysicalMonitorArraySize, PHYSICAL_MONITOR){

		if (DllCall("dxva2\DestroyPhysicalMonitors", "uint", PhysicalMonitorArraySize, "ptr", PHYSICAL_MONITOR))
			return true
		return false
	}
	
	CreateDC(DisplayName){

		if (hDC := DllCall("gdi32\CreateDC", "str", DisplayName, "ptr", 0, "ptr", 0, "ptr", 0, "ptr"))
			return hDC
		return false
	}
	
	DeleteDC(hDC){

		if (DllCall("gdi32\DeleteDC", "ptr", hDC))
			return true
		return false
	}
	
	
	; ===== HELPER METHODS ===== ;
	
	GetSetting(GetMethodName, Display := "", params*){

		if (hMonitor := this.GetMonitorHandle(Display)){
			PHYSICAL_MONITOR := ""
			PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
			hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitors, PHYSICAL_MONITOR)
			Setting := this.%GetMethodName%(hPhysicalMonitor, params*)
			this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			return Setting
		}
		throw Exception("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetSetting(SetMethodName, Setting, Display := "", params*){

		if (hMonitor := this.GetMonitorHandle(Display)){	
			PHYSICAL_MONITOR := ""		
			PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
			hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitors, PHYSICAL_MONITOR)

			if (SetMethodName = "SetMonitorVCPFeature" || SetMethodName = "SetMonitorColorTemperature"){				
				Setting := this.%SetMethodName%(hPhysicalMonitor, Setting, params*)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Setting				
			}
			else {	
				GetMethodName := RegExReplace(SetMethodName, "S(.*)", "G$1")
				GetSetting := this.%GetMethodName%(hPhysicalMonitor)
				Setting := (Setting < GetSetting["Minimum"]) ? GetSetting["Minimum"]
					    :  (Setting > GetSetting["Maximum"]) ? GetSetting["Maximum"]
					    :  (Setting)
				this.%SetMethodName%(hPhysicalMonitor, Setting)
				this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
				return Setting
			}
		
		} 
		throw Exception("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	VoidSetting(VoidMethodName, Display := ""){

		if (hMonitor := this.GetMonitorHandle(Display)){
			PHYSICAL_MONITOR := ""
			PhysicalMonitors := this.GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor)
			hPhysicalMonitor := this.GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitors, PHYSICAL_MONITOR)
			bool := this.%VoidMethodName%(hPhysicalMonitor)
			this.DestroyPhysicalMonitors(PhysicalMonitors, PHYSICAL_MONITOR)
			return bool
		}
		throw Exception("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GammaSetting(GammaMethodName, Red := "", Green := "", Blue := "", Display := "", DisplayName := ""){

		if (Display = "" && MonitorInfo := this.EnumDisplayMonitors()){
			for Info in MonitorInfo {
				if (Info["Primary"]){
					PrimaryMonitor := A_Index
					break
				}
			}
		}

		if (DisplayName := MonitorInfo[Display ? Display : PrimaryMonitor]["Name"]){
			if (hDC := this.CreateDC(DisplayName)){	
				if (GammaMethodName = "SetDeviceGammaRamp"){
					for Color in ["Red", "Green", "Blue"]{
						%Color% := (%Color% <    0)	?    0 
						 	    :  (%Color% >  100) ?  100
							    :  (%Color%)	
						%Color% := Round((2.56 * %Color%) - 128, 1) ; convert to decimal	
					}			
					this.SetDeviceGammaRamp(hDC, Red, Green, Blue)
					this.DeleteDC(hDC)
					
					for Color in ["Red", "Green", "Blue"]
						%Color% := Round((%Color% + 128) / 2.56, 1) ; convert back to percentage	

					return Map("Red", Red, "Green", Green, "Blue", Blue)
				}
				else { ; if (GammaMethodName = "GetDeviceGammaRamp")
					GammaRamp := this.GetDeviceGammaRamp(hDC)	
					for Color, GammaLevel in GammaRamp		
						GammaRamp[Color] := Round((GammaLevel + 128) / 2.56, 1) ; convert to percentage		
					this.DeleteDC(hDC)
					return GammaRamp
				}
			
			
			}
			this.DeleteDC(hDC)
			throw Exception("Unable to get handle to Device Context.`n`nError code: " Format("0x{:X}", A_LastError))
		}	
	
	}
	
	; ===== GET METHODS ===== ;
	
	GetMonitorBrightness(hMonitor, Minimum := 0, Current := 0, Maximum := 0){

		if (DllCall("dxva2\GetMonitorBrightness", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorContrast(hMonitor, Minimum := 0, Current := 0, Maximum := 0){

		if (DllCall("dxva2\GetMonitorContrast", "ptr", hMonitor, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetDeviceGammaRamp(hMonitor){
					
		if (DllCall("gdi32\GetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP := BufferAlloc(1536)))
			return Map(
			"Red"  , NumGet(GAMMA_RAMP,        2, "ushort") - 128,
			"Green", NumGet(GAMMA_RAMP,  512 + 2, "ushort") - 128,
			"Blue" , NumGet(GAMMA_RAMP, 1024 + 2, "ushort") - 128)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorRedDrive(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_RED_DRIVE = 0x00000000
		
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", 0x00000000, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorGreenDrive(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_GREEN_DRIVE = 0x00000001
		
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", 0x00000001, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorBlueDrive(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_BLUE_DRIVE = 0x00000002
		
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", 0x00000002, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		MsgBox "Failed"
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorRedGain(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_RED_GAIN = 0x00000000
		
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", 0x00000000, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorGreenGain(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_GREEN_GAIN = 0x00000001
		
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", 0x00000001, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorBlueGain(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_BLUE_GAIN = 0x00000002
		
		if (DllCall("dxva2\GetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", 0x00000002, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	GetMonitorDisplayAreaWidth(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_WIDTH = 0x00000000
		
		if (DllCall("dxva2\GetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", 0x00000000, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorDisplayAreaHeight(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_HEIGHT = 0x00000001
		
		if (DllCall("dxva2\GetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", 0x00000001, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorDisplayAreaPositionHorizontal(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_HORIZONTAL_POSITION = 0x00000000
		
		if (DllCall("dxva2\GetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", 0x00000000, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorDisplayAreaPositionVertical(hMonitor, Minimum := 0, Current := 0, Maximum := 0){ ;	MC_VERTICAL_POSITION = 0x00000001
		
		if (DllCall("dxva2\GetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", 0x00000001, "uint*", Minimum, "uint*", Current, "uint*", Maximum))
			return Map("Minimum", Minimum, "Current", Current, "Maximum", Maximum)
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	GetVCPFeatureAndVCPFeatureReply(hMonitor, VCPCode, vct := 0, CurrentValue := 0, MaximumValue := 0){

		static VCP_CODE_TYPE := Map(
					0x00000000, "MC_MOMENTARY — Momentary VCP code. Sending a command of this type causes the monitor to initiate a self-timed operation and then revert to its original state. Examples include display tests and degaussing.",
					0x00000001, "MC_SET_PARAMETER — Set Parameter VCP code. Sending a command of this type changes some aspect of the monitor's operation.")
		
		if (DllCall("dxva2\GetVCPFeatureAndVCPFeatureReply", "ptr", hMonitor, "ptr", VCPCode, "uint*", vct, "uint*", CurrentValue, "uint*", MaximumValue))
			return Map("VCPCode"    ,  Format("0x{:X}", VCPCode),
					   "VCPCodeType",  VCP_CODE_TYPE[vct], 
					   "Current"	,  CurrentValue, 
					   "Maximum"	, (MaximumValue ? MaximumValue : "Undefined due to non-continuous (NC) VCP Code."))
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorCapabilitiesStringLength(hMonitor, CapabilitiesStrLen := 0){

		if (DllCall("dxva2\GetCapabilitiesStringLength", "ptr", hMonitor, "uint*", CapabilitiesStrLen))
			return CapabilitiesStrLen
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	MonitorCapabilitiesRequestAndCapabilitiesReply(hMonitor, ASCIICapabilitiesString := "", CapabilitiesStrLen := 0){

		CapabilitiesStrLen := this.GetMonitorCapabilitiesStringLength(hMonitor)
		ASCIICapabilitiesString := BufferAlloc(CapabilitiesStrLen)
		if (DllCall("dxva2\GetCapabilitiesStringLength", "ptr", hMonitor, "ptr", ASCIICapabilitiesString.Ptr, "uint", CapabilitiesStrLen))
			return ASCIICapabilitiesString
		throw Exception("Unable to retreive value.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	GetMonitorCapabilities(hMonitor, MonitorCapabilities := 0, SupportedColorTemperatures := 0){

		if (DllCall("dxva2\GetMonitorCapabilities", "ptr", hMonitor, "uint*", MonitorCapabilities, "uint*", SupportedColorTemperatures))
			return Map("MonitorCapabilities"	   , MonitorCapabilities, 
				  	   "SupportedColorTemperatures", SupportedColorTemperatures)		
		throw Exception("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorColorTemperature(hMonitor, CurrentColorTemperature := 0){

		if (DllCall("dxva2\GetMonitorColorTemperature", "ptr", hMonitor, "uint*", CurrentColorTemperature))
			return CurrentColorTemperature
		throw Exception("Unable to retreive value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetMonitorTechnologyType(hMonitor, DisplayTechnologyType := 0){

		if (DllCall("dxva2\GetMonitorTechnologyType", "ptr", hMonitor, "uint*", DisplayTechnologyType))
			return DisplayTechnologyType
		throw Exception("Unable to retreive value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	
	; ===== SET METHODS ===== ;
	
	SetMonitorBrightness(hMonitor, Brightness){

		if (DllCall("dxva2\SetMonitorBrightness", "ptr", hMonitor, "uint", Brightness))
			return Brightness
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorContrast(hMonitor, Contrast){

		if (DllCall("dxva2\SetMonitorContrast", "ptr", hMonitor, "uint", Contrast))
			return Contrast
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetDeviceGammaRamp(hMonitor, red, green, blue){

		GAMMA_RAMP := BufferAlloc(1536)	
		while ((i := A_Index - 1) < 256 ){	
			NumPut("ushort", (r := (red   + 128) * i) > 65535 ? 65535 : r, GAMMA_RAMP,        2 * i)
			NumPut("ushort", (g := (green + 128) * i) > 65535 ? 65535 : g, GAMMA_RAMP,  512 + 2 * i)
			NumPut("ushort", (b := (blue  + 128) * i) > 65535 ? 65535 : b, GAMMA_RAMP, 1024 + 2 * i)
		}
		if (DllCall("gdi32\SetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP))
			return true
		throw Exception("Unable to set values.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	SetMonitorRedDrive(hMonitor, RedDrive){ ;	MC_RED_DRIVE = 0x00000000
		
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", 0x00000000, "uint", RedDrive))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorGreenDrive(hMonitor, GreenDrive){ ;	MC_GREEN_DRIVE = 0x00000001
		
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", 0x00000001, "uint", GreenDrive))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorBlueDrive(hMonitor, BlueDrive){ ;	MC_BLUE_DRIVE = 0x00000002
		
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueDrive", "ptr", hMonitor, "ptr", 0x00000002, "uint", BlueDrive))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorRedGain(hMonitor, RedGain){ ;	MC_RED_GAIN = 0x00000000
		
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", 0x00000000, "uint", RedGain))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorGreenGain(hMonitor, GreenGain){ ;	MC_GREEN_GAIN = 0x00000001
		
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", 0x00000001, "uint", GreenGain))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorBlueGain(hMonitor, BlueGain){ ;	MC_BLUE_GAIN = 0x00000002
		
		if (DllCall("dxva2\SetMonitorRedGreenOrBlueGain", "ptr", hMonitor, "ptr", 0x00000002, "uint", BlueGain))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}		
	
	SetMonitorDisplayAreaWidth(hMonitor, DisplayAreaWidth){ ;	MC_WIDTH = 0x00000000
		 
		if (DllCall("dxva2\SetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", 0x00000000, "uint", DisplayAreaWidth))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorDisplayAreaHeight(hMonitor, DisplayAreaHeight){ ;	MC_HEIGHT = 0x00000001
		
		if (DllCall("dxva2\SetMonitorDisplayAreaSize", "ptr", hMonitor, "ptr", 0x00000001, "uint", DisplayAreaHeight))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetMonitorDisplayAreaPositionHorizontal(hMonitor, NewHorizontalPosition){ ;	MC_HORIZONTAL_POSITION = 0x00000000
		 
		if (DllCall("dxva2\SetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", 0x00000000, "uint", NewHorizontalPosition))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	SetMonitorDisplayAreaPositionVertical(hMonitor, NewVerticalPosition){ ;	MC_VERTICAL_POSITION = 0x00000001
		
		if (DllCall("dxva2\SetMonitorDisplayAreaPosition", "ptr", hMonitor, "ptr", 0x00000001, "uint", NewVerticalPosition))
			return true
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
	
	SetMonitorVCPFeature(hMonitor, VCPCode, NewValue){

		if (DllCall("dxva2\SetVCPFeature", "ptr", hMonitor, "ptr", VCPCode, "uint", NewValue))
			return Map("VCPCode", Format("0x{:X}", VCPCode), "NewValue", NewValue)
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}		
	
	SetMonitorColorTemperature(hMonitor, CurrentColorTemperature){

		if (DllCall("dxva2\SetMonitorColorTemperature", "ptr", hMonitor, "uint", CurrentColorTemperature))
			return CurrentColorTemperature
		throw Exception("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	
	; ===== VOID METHODS ===== ;
	
	DegaussMonitor(hMonitor){

		if (DllCall("dxva2\DegaussMonitor", "ptr", hMonitor))
			return true
		throw Exception("Unable to degauss monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	RestoreMonitorFactoryDefaults(hMonitor){

		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		throw Exception("Unable to restore monitor to factory defaults.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	RestoreMonitorFactoryColorDefaults(hMonitor){

		if (DllCall("dxva2\RestoreMonitorFactoryColorDefaults", "ptr", hMonitor))
			return true
		throw Exception("Unable to restore monitor to factory color defaults.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SaveCurrentMonitorSettings(hMonitor){

		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		throw Exception("Unable to save current monitor settings to non-volatile storage.`n`nError code: " Format("0x{:X}", A_LastError))
	}	
}

; ================= ;
; == Change Log  == ;
; ================= ;
;
; 2020-08-09:	- Reduced code size: made minor changes, removed unnessary static variables and added 
;						comments instead, removed redundant code, made indentation style consistent 
;						throughout (Stroustrup-style, variant without space after Method parenthesis) 
;
; 2020-08-07:	- Converted GetGammaRamp and SetGammaRamp() Methods to work off a [0 - 100] percentage 
;						scale to function like the rest of the Monitor Configuration API functions 
;				- Fixed Set___() Methods from not initiating setting boundary safety check
;				- Renamed GetVCPFeatureAndFeatureReply() to GetVCPFeatureAndReply()
;				- Changed GetVCPFeatureAndReply() to return ["Current"] and ["Maximum"]
;						as map keys instead (formerly ["CurrentValue"] and "MaximumValue")
;						to match naming convention with all other Get___() Methods
; 2020-08-04:	- Added some special monitor functions based on VCP Code getting/setting:
;						GetPowerMode(), SetPowerMode(), GetSharpness(), SetSharpness()
; 				- Removed the MonitorFromWindow() Method and put similar code inside of the
;						GetMonitorHandle() Method to reduce code size and make it more robust
; 				- Made some minor improvements to code overall.

; 2020-08-01:	- Changed all SetXXX() Methods, to now return updated values, except for 
;						the SetVCPFeature() Method, which now returns a Map object with
;						"VCPCode" and "NewValue")
; 				- Changed SetGammaRamp() to return a Map object with all updated gamma color output values
; 				- GetSupportedColorTemperatures() & GetCapabilities() Methods now throw an error	
;						when no settings are supported showing that instead of an arbritary index error
; 				- Fixed minor bugs in SetSetting() & VoidSetting() methods throwing errors
;
; 2020-07-31:	- Added support for nearly every WinAPI found here: 
; 						https://docs.microsoft.com/en-us/windows/win32/api/_monitor/
; 				- Drastically reduced code size with Helper Methods: GetSetting(), SetSetting(), 
; 						VoidSetting(), GammaSetting()
; 				- Added jNizM's GetMonitorHandle() Method to further reduce code size
; 				- Removed need to specify monitor # for all methods, now defaults to primary monitor #
; 				- Changed method params to mirror jNizM's v1 class, making "Display" the final param
; 				- Set default values for SetGammaRamp() Method to 128 for all Gamma Colors
; 				- Added safety checks to ensure settlng Gamma Color Values stays within [-128,128] range
; 				- Added return values for all SetXXX() Methods to optionally show updated values
; 				- Added Throw-Exception messages for all private methods upon failure 
; 				- Reordered all methods into "GET, SET, VOID, and CORE MONITOR" Methods for better 
; 						visual organization
; 
; 2020-07-28:	- Ported to AHK v2.0 alpha 119, compatible with v2 a111+
; 				- Reduced code size for some methods
; 				- Removed redundant code
; 				- Reordered methods to be more visually intuitive (e.i. GetXXX(), then SetXXX() )
; 
; 
; ================= ;
; ==   Pending   == ;
; ================= ;
; 
; 	- Add GetTimingReport WinAPI
; 	- Create Exception Handler
; 	- Extra support for querying & setting useful VCP Codes
;	- Create supporting docs and examples
;
; ================= ;
; ==   Remarks   == ;
; ================= ;
; 
; 	- I don't beleive I'm executing the CapabilitiesRequestAndCapabilitiesReply() Method 
;				correctly, needs work
;
;
; =================================================================================================== ;
-TL

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by robodesign » 13 Apr 2022, 04:53

Hello!

I have been struggling to get this working and I am failing.

I use MonitorFromWindow(), return value is 65537, but both GetMonitorBrightness and GetMonitorContrast fail, return nothing. I tried GetDeviceGammaRamp as well . It does not work.

Any idea why?

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

deama
Posts: 11
Joined: 05 Jan 2017, 17:08

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by deama » 26 Mar 2023, 11:58

robodesign wrote:
13 Apr 2022, 04:53
Hello!

I have been struggling to get this working and I am failing.

I use MonitorFromWindow(), return value is 65537, but both GetMonitorBrightness and GetMonitorContrast fail, return nothing. I tried GetDeviceGammaRamp as well . It does not work.

Any idea why?

Best regards, Marius.
Hello,

For future reference, there could be 2 reasons why this is not working.

1. it's locked in your nvidia control panel.
Got to the nvidia control panel > display > adjust Desktop colour settings
untick the "Override to reference mode"
That should allow you to make adjustments now on that panel, this is needed I believe for the script to work.

2. The gamma is locked to be only within 100.
Unlock it by going to the following registry place:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ICM
And a new DWORD key called "GdiIcmGammaRange" with a hexidecimal value of "100" (decimal value of 256).
This will unlock it and allow you to blackout the entire screen!

User avatar
PipeDreams
Posts: 165
Joined: 19 Dec 2015, 00:20

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by PipeDreams » 10 Jul 2023, 05:33

@jNizM
This script is so useful; I love it! Thank you. Here are some basic controls for anyone too lazy to set them up. I just wanted to throw my 2 cents in.

Code: Select all

#SingleInstance Force
OnExit, ExitSub
GoSub, SetUp
; ===== Controls ============================================================================================================
~!WheelUp::		;<<< Alt+MouseWheelUp
{	If (Red <= 190) OR (Brightness <= 190) OR (Contrast <= 190)
	{	Red+=10, Green+=10, Blue+=10, Brightness+=10, Contrast+=10
	} GoSub, SetMonitor
} Return
~!WheelDown::	;<<< Alt+MouseWheelDown
{	If (Red >= 10) OR (Brightness >= 10) OR (Contrast >= 10)
	{	Red-=10, Green-=10, Blue-=10, Brightness-=10, Contrast-=10
	} GoSub, SetMonitor
} Return
~!MButton::		;<<< Alt+MouseWheelClick
SetUp:
{	Night:=50	;<<< Set To Desired Value For The Night.
	Day:=70		;<<< Set To Desired Value For The Day.
	Formattime, Time, , HH:mm	;<<< Load Different Settings Depending On The Time Of Day.
	If (Time <= "08:00") OR (Time >= "20:00")	;Before 8AM OR After 8PM
	{	Red:=Night, Green:=Night, Blue:=Night, Brightness:=Night, Contrast:=Night
	} Else, If (Time >= "08:00") OR (Time <= "20:00")	;After 8AM OR Before 8PM
	{	Red:=Day, Green:=Day, Blue:=Day, Brightness:=Day, Contrast:=Day
	} GoSub, SetMonitor
} Return
*~Esc::			;<<< Kill The Script, Press & Hold.
Suspend, Permit
{	KeyWait, Esc, T0.7
	If (ErrorLevel)
	{	SoundBeep, 777, 50
		ExitApp
	} KeyWait,% SubStr(A_ThisHotkey,2)
} Return
SetMonitor:
{	Monitor.SetGammaRamp(Display, Red, Green, Blue), Monitor.SetBrightness(Display, Brightness), Monitor.SetContrast(Display, Contrast)
	ToolTip, Gamma = %Red% `nBrightness = %Brightness% `nContrast = %Contrast%
	SetTimer, RemoveToolTip, -1000		;<<< Tooltip Time-out.
} Return
RemoveToolTip:
{	ToolTip
} Return
ExitSub:
{	GoSub, SetUp
} ExitApp
; ===== Class Monitor =======================================================================================================

ftlsxp
Posts: 13
Joined: 02 Jan 2022, 23:31

Re: [Class] Monitor (Brightness, Contrast, Gamma Ramp)

Post by ftlsxp » 27 Mar 2024, 16:06

@jNizM

First of all, thank you for this. It helps a lot.

I have a silly question but i'm no t being able to find the answer anywhere. Is it possible to apply a different gamma ramp to a specific region of my monitor? For example: half my monitor is set to Monitor.SetGammaRamp(128, 128, 128) and the other half to Monitor.SetGammaRamp(108, 48, 48).

English is not my native language so I'm sorry if i'm no t being able to explain myself clearly.

Thanks in advance.

Post Reply

Return to “Scripts and Functions (v1)”