Monitor Config Class [a122] - Brightness, Contrast, Gamma, DisplayArea, Color Gain & Drive, VCP Query/Setting, Degauss

Share the finished AutoHotkey v2 Scripts and libraries you made here. Please put the current version of AutoHotkey v2 you used in Square Brackets at the start of the topic title.
User avatar
Tigerlily
Posts: 353
Joined: 04 Oct 2018, 22:31

Monitor Config Class [a122] - Brightness, Contrast, Gamma, DisplayArea, Color Gain & Drive, VCP Query/Setting, Degauss

Post by Tigerlily » 28 Jul 2020, 20:15

This class was originally created by jNizM (Original v1 Monitor Class Thread).

I've updated it to be compatible with v2 a111+ and added many more (most) of the Monitor Configuration WinAPIs as methods, as well as some special custom Monitor methods I've been experimenting with :geek: I have tested mainly on a119 though, so there may be other bugs I'm unaware of in previous alpha releases.

This v2 class functions mainly the same as the v1 class by jNizM, but please read the docs before experimenting as I've made some critical changes.

This class can be used very effectively to reduce computer light induced eye strain, I am using it to create a robust screen dimming/monitor control application.

You can also use it to retrieve certain monitor info, although v2 already has some built-in functions that can accomplish getting some of this info via the Monitor functions.
However, I found that the methods in this class were 3-5x faster than the built-in functions. When I tested them against each other in a 1,000,000 iteration loop, I found that most the methods in this class executed in around 1.5 to 2.5 milliseconds, whereas the built-in AHK functions executed in around 5.5 to 6.5 millseconds.

Additionally, v2 still lacks the ability to retrieve monitor handles with built-in functions AFAIK.

UPDATES


Here is the most up-to-date Monitor Class, written in v2 a119 - compatible with v2 a111+:

Code: Select all

; =================================================================================================== ;
; AutoHotkey V2 a122 Wrapper for Monitor Configuration WinAPI Functions
;
; Original Author ....: jNizM
; Released ...........: 2015-05-26
; Modified ...........: 2020-08-17
; Adapted By .........: tigerlily, CloakerSmoker
; Version ............: 2.3.1
; Github .............: https://github.com/tigerlily-dev/Monitor-Configuration-Class
; 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, hWindow := 0){

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

		if (!hMonitor) ;	MONITOR_DEFAULTTONEAREST = 0x00000002
			hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow, "uint", 0x00000002)
		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 := "", 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))
	}	
}




I hope others can find this class as useful as I have!!

Please report back any bugs you may find or any additional features you are interested in having me add to this class.
This is my first time working on a class of this scale, so any tips are much appreciated!

Enjoy. :thumbup:
Last edited by Tigerlily on 18 Aug 2020, 11:37, edited 52 times in total.
-TL

swagfag
Posts: 3972
Joined: 11 Jan 2017, 17:59

Re: Monitor Class [a119] (a111+) - Brightness, Contrast, Gamma

Post by swagfag » 28 Jul 2020, 21:12

the access violation is due to

Code: Select all

	GetMonitorTechnologyType(hMonitor, DisplayTechnologyType := "")
	{
		if (DllCall("dxva2\GetMonitorTechnologyType", "ptr", hMonitor))
			return true
		return false
	}
being called with an incorrect number of parameters
https://docs.microsoft.com/en-us/windows/win32/api/highlevelmonitorconfigurationapi/nf-highlevelmonitorconfigurationapi-getmonitortechnologytype

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

Re: Monitor Class [a119] (a111+) - Brightness, Contrast, Gamma

Post by Tigerlily » 01 Aug 2020, 07:55

Check out the associated MSDN Docs for Monitor Configuration.



[ EXAMPLES & DOCUMENTATION ]

Code: Select all

; All examples assume you have:
; 
;	(1) Included the Monitor Class within your script with or without 
;		using the #Include directive:
;
	#Include "Monitor Class.ahk"
; 
;	(2) created a new class instance already in your script by using:
; 
	mon := Monitor.New() ; Create new class instance

GET___() METHODS:

Code: Select all

; =================================================================================================== ;	
;
; ================= 
; == GET METHODS == 
; ================= 
;
;
; NOTE:
; All Get___() Methods in this class will function identically with the following 
; examples and documentation shown for the GetBrightness() Method (affecting their 
; respective setting; e.g. "Contrast", "Red Gain", etc.), with the exception of the 
; following Methods:
; 

	GetInfo()
	GetGammaRamp()
	GetVCPFeatureAndReply()	
	CapabilitiesRequestAndCapabilitiesReply()	
	GetCapabilitiesStringLength()	
	GetCapabilities()
	GetSupportedColorTemperatures()
	GetColorTemperature()
	GetTechnologyType()


; GetBrightness() Method:
;
	GetBrightness([Display])
;
; Returns a Map object with details about a monitor's Brightness Level:
; the Current Value, as well as the Minumum Value and Maximum Value supported 
; by the monitor. Typically, this is a value range of [0 to 100], with [0]  
; being the lowest value supported and [100] being the highest value supported.	
; 
; [PARAMETERS]
;
;	DISPLAY (Optional, defaults to primary monitor)
;		Type:		 Integer or "String"
;		Description: The number or name of the monitor to query. If omitted,
;						defaults to primary monitor.
;       Example:     Integer: 2 
;                    String : "\\.\DISPLAY2"
;
;
; A visualized structure of the Map object with key-value names:
;
;    -MAP{ key	           -value
;		  -["Minimum"]-MinimumValue   
;		  -["Current"]-CurrentValue  
;		  -["Maximum"]-MaximumValue  
;		  }
;
;	
; Example 1 - Return the Current Value, Minimum Value, and Maximum Value of
;			Brightness supported by the primary monitor:
	
	InfoList := ""
	Brightness := mon.GetBrightness()
	for k, v in Brightness
		InfoList .= k ":`n" v "`n`n"
	
	MsgBox InfoList
;	
; Example 2 - Return and display the Minimum Value of Brightness supported  
;			by monitor #1:

	MsgBox MinBrightnessLevel := mon.GetBrightness(1)["MinimumValue"]
	
; Example 3 - Return and display the Current Value of Brightness of
;			a specific monitor ("\\.\DISPLAY1"):
	
	MsgBox CurrentBrightnessLevel := mon.GetBrightness("\\.\DISPLAY1")["CurrentValue"]
;	
;
;   NOTE:
;   The following Methods will function identically with the above
;   documentation and examples shown for GetBrightness(), with the  
;   exception of instead affecting their respective setting  
;	(e.g. "Contrast", "Red Gain", "DisplayAreaWidth", etc.):
;
	GetContrast()
	GetRedDrive()
	GetGreenDrive()
	GetBlueDrive()
	GetRedGain()
	GetGreenGain()
	GetBlueGain()
	GetDisplayAreaWidth()
	GetDisplayAreaHeight()
	GetDisplayAreaPositionHorizontal()
	GetDisplayAreaPositionVertical()
;
; =================================================================================================== ;
	
	
; =================================================================================================== ;	
;
; GetInfo() Method:
;
	GetInfo()
;
; Returns an array with nested Map object containing info for each monitor found: 
; Handle, Name, Number, X & Y coordinates for total display area and work area. 
; The value of key["Primary"] is true (i.e "1") if it is the Primary monitor
; and is false (i.e. "0") if it is not the primary monitor.
;
; A visualized structure of the Array objeict with key-value names:
;
; -ARRAY[key-value
;		-[1]-MAP{ key		 -value
;				-["Handle"]  -Handle  
;				-["Name"]    -Name  
;				-["Number"]  -Number  
;				-["Left"]    -Left  
;				-["Top"]     -Top  
;				-["Right"]   -Right 
;				-["Bottom"]  -Bottom  
;				-["WALeft"]  -WALeft  
;				-["WATop"]   -WATop  
;				-["WARight"] -WARight 
;				-["WABottom"]-WABottom
;				-["Primary"] -Primary
;				}
;	    -[n]-MAP{ key		 -value
;				-["Handle"]  -Handle  
;				-["Name"]    -Name  
;				-["Number"]  -Number  
;				-["Left"]    -Left  
;				-["Top"]     -Top  
;				-["Right"]   -Right 
;				-["Bottom"]  -Bottom  
;				-["WALeft"]  -WALeft  
;				-["WATop"]   -WATop  
;				-["WARight"] -WARight 
;				-["WABottom"]-WABottom
;				-["Primary"] -Primary
;				}
;		]		
;
;	
; Example 1 - Return all info found for all monitors found:	
		
	AllInfo := ""
	MonitorInfo := mon.GetInfo()
	for MonitorNumber, InfoMap in MonitorInfo
		for InfoName, InfoValue in InfoMap
			AllInfo .= InfoName ":`t`t" InfoValue "`n"
	
	MsgBox AllInfo
	
; Example 2 - Identify which monitor # is the Primary monitor
	
	for Info in mon.GetInfo()
		if Info["Primary"]
			MsgBox "Your system's Primary Monitor is Monitor #" A_Index "."
	
; Example 3 - Retreive handle to specified monitor # (Monitor #1 in this example)
	
	MsgBox mon.GetInfo()[1]["Handle"]
;
; =================================================================================================== ;


; =================================================================================================== ;
; GetGammaRamp() Method:
;
	GetGammaRamp([Display])
;
; Returns a Map object with details about a monitor's current Gamma Color   
; Output Levels:
; Red gamma, Green gamma, and Blue Gamma. These are within a value range 
; of [0 to 100], with [0] being the lowest value supported and [100] 
; being the highest value supported.	
; 
; [PARAMETERS]
;
;	DISPLAY (Optional, defaults to primary monitor)
;		Type:		 Integer or "String"
;		Description: The number or name of the monitor to query. If omitted,
;						defaults to primary monitor.
;       Example:     Integer: 2 
;                    String : "\\.\DISPLAY2"
;
;
; A visualized structure of the Map object with key-value names:
;
;     -MAP{ key	    -value
;		  -["Red"]  -RedGamma   
;		  -["Green"]-GreenGamma 
;		  -["Blue"] -BlueGamma
;		  }
;
;	
; Example 1 - Return the Current Red, Green, and Blue gamma color output 
;			levels of the primary monitor:
	
	InfoList := ""
	Gamma := mon.GetGammaRamp()
	for k, v in Gamma
		InfoList .= k ":`n" v "`n`n"
	
	MsgBox InfoList
;	
; Example 2 - Return and display the Minimum Value of Brightness supported  
;			by monitor #1:

	MsgBox RedGammaLevel := mon.GetGammaRamp(1)["Red"]
	
; Example 3 - Return and display the Current Value of Green gamma color 
;			output for a specific monitor ("\\.\DISPLAY1"):
	
	MsgBox GreenGammaLevel := mon.GetGammaRamp("\\.\DISPLAY1")["Green"]
;	
; =================================================================================================== ;


; =================================================================================================== ;	
;
; GetVCPFeatureAndReply() Method:
;
	GetVCPFeatureAndReply(VCPCode[, Display])
;
; Returns a Map object with details about a monitor's VCP Code (if supported):
; the VCP Code queried, VCP Code Type, Current Value and Maximum Value.	
; 
; [PARAMETERS]
;
;	VCPCODE
;		Type:		 "String"
;		Description: A specific VCP code to query, which can be found at 
;						https://milek7.pl/ddcbacklight/mccs.pdf.
;       Example:    Integer (decimal)    : 2
;                   Integer (hexidecimal): 0xD6
;
;	DISPLAY (Optional, defaults to primary monitor)
;		Type:		 Integer or "String"
;		Description: The number or name of the monitor to query. If omitted,
;						defaults to primary monitor.
;       Example:     Integer: 2 
;                    String : "\\.\DISPLAY2"
;
;
; A visualized structure of the Map object with key-value names:
;
;     -MAP{ key	           -value
;		  -["VCPCode"]	   -VCPCode  
;		  -["VCPCodeType"] -VCPCodeType  
;		  -["CurrentValue"]-CurrentValue  
;		  -["MaximumValue"]-MaximumValue  
;		  }
;
;	
; Example 1 - Return and display the details about the Power Mode of a specific
;			monitor ("\\.\DISPLAY1") and it's associated VCP Code:
;	
	InfoList := ""
	VCPInfo := mon.GetVCPFeatureAndReply(0xD6, "\\.\DISPLAY1")
	for k, v in VCPInfo
		InfoList .= k ":`n" v "`n`n"
	
	MsgBox InfoList

;	A Current Value of 1   = ON
;	A Current Value of 2-4 = STANDBY / SUSPENDED / OFF
;	A Current Value of 5   = POWER OFF
;	
; Example 2 - Return and display the Minimum Value of Luminance (Brightness) 
;			supported by the primary monitor:

	MsgBox MaxBrightnessLevel := mon.GetVCPFeatureAndReply(0x10)["MaximumValue"]
	
; Example 3 - Return and display the Current Value of the Contrast of
;			monitor #2:
	
	MsgBox CurrentContrastLevel := mon.GetVCPFeatureAndReply(0x12, 2)["CurrentValue"]
;	
; =================================================================================================== ;


SET___() METHODS:

Code: Select all

; =================================================================================================== ;	
;
; ================= 
; == SET METHODS == 
; ================= 
;
;
; All Set___() Methods in this class will function identically with the following 
; examples and documentation shown for the SetBrightness() Method (affecting their 
; respective setting; e.g. "Contrast", "Red Gain", etc.), with the exception of the 
; following Methods:

	SetVCPFeature()	
	SetColorTemperature()


; SetBrightness() Method:
;
	SetBrightness(Brightness[, Display])
;
; Sets a monitor's Brightness level, then returns the monitor's updated
; Brightness Level.
;
; [PARAMETERS]
;
;	BRIGHTNESS
;		Type:		 Integer
;		Description: The new Brightness Level to set the monitor to.
;       Example:     Integer: 50 
;
;	DISPLAY (Optional, defaults to primary monitor)
;		Type:		 Integer or "String"
;		Description: The number or name of the monitor to query. If omitted,
;						defaults to primary monitor.
;       Example:     Integer: 2 
;                    String : "\\.\DISPLAY2"
;
;	
; Example 1 - Set, return, and display new brightness level (50) of primary 
;           monitor:
;				
	MsgBox mon.SetBrightness(50)
;	
; Example 2 - Set, return, and display new brightness level (100) of  
;           monitor #1:

	MsgBox mon.SetBrightness(100, 1)
	
; Example 3 - Set, return, and display new brightness level (0) of  
;			a specific monitor ("\\.\DISPLAY1"):
	
	MsgBox mon.SetBrightness(0, "\\.\DISPLAY1")
;	
;
;   NOTE:
;   The following Methods will function identically with the above
;   documentation and examples shown for GetBrightness(), with the  
;   exception of instead affecting their respective setting  
;	(e.g. "Contrast", "Red Gain", "DisplayAreaWidth", etc.):
;
	SetContrast()
	SetRedDrive()
	SetGreenDrive()
	SetBlueDrive()
	SetRedGain()
	SetGreenGain()
	SetBlueGain()
	SetDisplayAreaWidth()
	SetDisplayAreaHeight()
	SetDisplayAreaPositionHorizontal()
	SetDisplayAreaPositionVertical()
;
; =================================================================================================== ;
	
	
; =================================================================================================== ;
; SetGammaRamp() Method:
;
	SetGammaRamp([Red, Green, Blue, Display])
; 
; Sets the Red, Blue, and Green Gamma Color Output Levels for a monitor,
; within a range of [0 to 100], then returns a Map object with the 
; updated Gamma Color Output Levels.
;
;	PRO TIP: Increasing / decreasing all Gamma Color Output Levels by the  
;	same amount will mimic the native backlight brightness found on laptops
;	by reducing / increasing screen brightness via RGB light output. 
;	NOTE: this is DIFFERENT than the brightness level adjusted by the 
;	SetBrightness() Method, which may not be supported on laptops.
;
;	Example: 
	SetGammaRamp() ; sets primary monitor to full gamma color output (100%) for all colors
    SetGammaRamp(70, 70, 70) ; minus 30 for all colors mimics native backlight brightness reduction
    SetGammaRamp(50, 50, 50) ; minus 20 for all colors mimics native backlight brightness reduction
    SetGammaRamp(90, 90, 90) ; plus  40 for all colors mimics native backlight brightness increase
;
;   ***WARNING*** USE WITH CAUTION
;   Exercise extreme caution with this Method when setting ALL GammaRamp 
;   values to 0, as this will cause complete screen blackout. Without 
;   measures in place to increase the GammaRamp values after setting them 
;   to 0, your monitor will be stuck blacked out.. worst case scenario 
;   would be doing this to all monitors on your computer and even if you 
;   restart ;your computer, it may boot with 0% color output AKA complete 
;   blackout. SEE EXAMPLE 4 BELOW AND SERIOUSLY CONSIDER PUTTING A CUSTOM 
;   SAFETY MEASURE IN PLACE!!
;
;   Additionally, setting GammaRamp values outside of the [0 to 100] range 
;   (not recommended) may cause some extreme colors on your monitor where 
;   you are unable to see anything well enough to get your monitor back to 
;   normal.
;
;   For added safety, there is a safety check which doesn't allow the user
;   to set Gamma color output values outside of the [0 to 100] range.
;   This can only be altered by removing / altering the ternary operator 
;   check found in the GammaSetting() Method.
;
; [PARAMETERS]
;
;	RED (Optional, defaults to 100)
;		Type:		 Integer
;		Description: The new value of Red Gamma Color Output Level to set 
;						a monitor to. If omitted, defaults to a value of   
;                       100 (typically the default value for monitors).
;       Example:     Integer: 90 
;
;	GREEN (Optional, defaults to 100)
;		Type:		 Integer
;		Description: The new value of Green Gamma Color Output Level to set 
;						a monitor to. If omitted, defaults to a value of   
;                       100 (typically the default value for monitors).
;       Example:     Integer: 0 
;
;	GREEN (Optional, defaults to 100)
;		Type:		 Integer
;		Description: The new value of Blue Gamma Color Output Level to set 
;						a monitor to. If omitted, defaults to a value of   
;                       100 (typically the default value for monitors).
;       Example:     Integer: 50 
;
;	DISPLAY (Optional, defaults to primary monitor
;		Type:		 Integer or "String"
;		Description: The number or name of the monitor to query. If omitted,
;						defaults to primary monitor.
;       Example:     Integer: 2 
;                    String : "\\.\DISPLAY2"
;
;
; A visualized structure of the Map object with key-value names:
;
;     -MAP{ key	    -value
;		  -["Red"]  -RedGamma   
;		  -["Green"]-GreenGamma 
;		  -["Blue"] -BlueGamma
;		  }
;
;	
; Example 1 - Set, return, and display the new Red, Green, and Blue gamma
;           color output levels of the primary monitor all to 100%:
	
	InfoList := ""
	Gamma := mon.SetGammaRamp()
	for k, v in Gamma
		InfoList .= k ":`n" v "`n`n"
	
	MsgBox InfoList
;	
; Example 2 - Set and return the new Red, Green, and Blue gamma color
;           output levels for monitor #1 to 50%, 20%, 0%, respectively.
;           Then, display the updated Blue gamma color output level:

	MsgBox BlueGammaLevel := mon.SetGammaRamp(50, 20, 0, 1)["Blue"]
	
;   NOTE:
;   Setting a Gamma color output value to 0% effectively stops your 
;   monitor from emitting that color. In this example, all Blue light
;   is "blocked", creating a Blue Light Blocker for your computer,
;   which has been known to help developers like us with eye strain.
;
;
; Example 3 - Set and return the new Red, Green, and Blue gamma color
;           output levels for a specific monitor ("\\.\DISPLAY1") to 
;           50%, 0%, 0%, respectively. Then, display the updated 
;           Green gamma color output level:
	
	MsgBox GreenGammaLevel := mon.SetGammaRamp(50, 0, 0, "\\.\DISPLAY1")["Green"]
;	
; Example 4 - In case you set your monitor to a point where it is unusable,
;             it is wise to have a couple backup measures in place:
;
;   Consider having an emergency hotkey
    !x::
    {        
        monitorCount := mon.GetInfo().Length ; Retreive total monitor count
        Loop( monitorCount )
            mon.SetGammaRamp( , , , A_Index)
    }

;   ...or an OnExit() function
    OnExit("ResetGammaOutput")
    ResetGammaOutput(*){

        monitorCount := mon.GetInfo().Length
        Loop( monitorCount ) 
            mon.SetGammaRamp( , , , A_Index)
            
    }
;
; =================================================================================================== ;


===================================


MORE EXAMPLES / DOCS ON THEIR WAY


===================================
Last edited by Tigerlily on 11 Aug 2020, 01:28, edited 11 times in total.
-TL

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

Re: Monitor Class [a119] (a111+) - Brightness, Contrast, Gamma, DisplayArea, Color Gain & Drive, VCP Query/Setting, Dega

Post by Tigerlily » 04 Aug 2020, 06:31

Here is a working example of using the Set/GetGammaRamp to adjust individual gamma levels using a v2 GUI.
It only adjusts the primary monitor (#1 if you are on a single-monitor setup like a laptop).

You can't actually see the adjustment in the gif below because the recording doesn't pick up the different colors.
This is really nice if you need to take snapshots with dimmed brightness because you don't get that awful black overlay on top of your img/gif/vid when snapshotting/recording.

Gif of GUI:
Image


Working Code (requires the Monitor class to be included ofc):

Code: Select all

#SingleInstance
#Include "Monitor Class.ahk"
OnExit("ResetGammaOutput")
global mon := Monitor.New()

monitorMenu := Gui.New( "+MaximizeBox", "tigerlily's Screen Dimmer" )
monitorMenu.OnEvent("Close", "Destroy")
monitorMenu.SetFont("cFFFFFF s8 bold")
monitorMenu.BackColor := 000000
monitorMenu.MarginX := 30
monitorMenu.MarginY := 30

gammaAllTitle := monitorMenu.Add("Text", "w200 Center", "Gamma (All):")
gammaAllSliderStart := monitorMenu.Add("Text", "Section", "0")
gammaAllSlider := monitorMenu.Add("Slider", "ys AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaSlider ", 100)
gammaAllSliderEnd := monitorMenu.Add("Text", "ys", "100")
gammaAllSlider.OnEvent("Change", "gammaAllSlider_Change")
gammaAllSlider_Change(gammaAllSlider, info){

    global
    g := gammaAllSlider.Value
    mon.SetGammaRamp(gammaRedSlider.Value := g, gammaGreenSlider.Value := g, gammaBlueSlider.Value := g)
}

gammaRedTitle := monitorMenu.Add("Text", "w200 xm Center", "Gamma (Red):")
gammaRedSliderStart := monitorMenu.Add("Text", "xm Section", "0")
gammaRedSlider := monitorMenu.Add("Slider", "ys AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaRedSlider", 100)
gammaRedSliderEnd := monitorMenu.Add("Text", "ys", "100")
gammaRedSlider.OnEvent("Change", "gammaRedSlider_Change")
gammaRedSlider_Change(gammaRedSlider, info){

    g := mon.GetGammaRamp()
    gR := gammaRedSlider.Value, gG := g["Green"], gB := g["Blue"]
    mon.SetGammaRamp(gR, gG, gB)
}

gammaGreenTitle := monitorMenu.Add("Text", "w200 xm Center", "Gamma (Green):")
gammaGreenSliderStart := monitorMenu.Add("Text", "xm Section", "0")
gammaGreenSlider := monitorMenu.Add("Slider", "ys AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaGreenSlider", 100)
gammaGreenSliderEnd := monitorMenu.Add("Text", "ys", "100")
gammaGreenSlider.OnEvent("Change", "gammaGreenSlider_Change")
gammaGreenSlider_Change(gammaGreenSlider, info){

    g := mon.GetGammaRamp()
    gR := g["Red"], gG := gammaGreenSlider.Value, gB := g["Blue"]
    mon.SetGammaRamp(gR, gG, gB)
}

gammaBlueTitle := monitorMenu.Add("Text", "w200 xm Center", "Gamma (Blue):")
gammaBlueSliderStart := monitorMenu.Add("Text", "xm Section", "0")
gammaBlueSlider := monitorMenu.Add("Slider", "ys AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaBlueSlider", 100)
gammaBlueSliderEnd := monitorMenu.Add("Text", "ys", "100")
gammaBlueSlider.OnEvent("Change", "gammaBlueSlider_Change")
gammaBlueSlider_Change(gammaBlueSlider, info){

    g := mon.GetGammaRamp()
    gR := g["Red"], gG := g["Green"], gB := gammaBlueSlider.Value
    mon.SetGammaRamp(gR, gG, gB)
}
monitorMenu.Show()

Destroy(monitorMenu){

    monitorMenu.Destroy()
}

;   Emergency reset hotkey
!x::
{        
    global
    mon.SetGammaRamp()
}

;   Reset gamma on exit
ResetGammaOutput(*){

    global
    mon.SetGammaRamp()        
}
-TL

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

Re: Monitor Class [a121] (a111+) - Brightness, Contrast, Gamma, DisplayArea, Color Gain & Drive, VCP Query/Setting, Dega

Post by Tigerlily » 13 Aug 2020, 19:12

A more robust version of the previous post allowing precise control of each monitor's gamma, brightness, contrast, and power state. This screen dimmer does what any other screen dimmer out there does (f.lux, redshift, etc., except gives you more precise control over each monitor's features. It supports single- and multi-monitor setups, and is much cleaner than most other screen dimmers I've tried using out there.

Some system's may not support any of the above mentioned common monitor features, so an alternative Dimmer (Overlay) option was added for added flexibility. This script may not work properly on some systems that don't support gamma, brightness, contrast, etc., but works fine on my single monitor laptop and multi-monitor desktop setups. I will later add some system capabilities checks to circumvent this issue in the future.

Note:
This app has a built-in safety feature to protect against total screen blackout, so will reset all gamma output levels to 100% when the app closes. It will also restore all Window Display Elements to their default colors if Background Modes are used. To disable these features, comment out line 537.

HOTKEYS:

Code: Select all

;   Close app
^Esc::ExitApp()

;   Open config
!t::
{
    global
    monitorMenu.Show()
}

;   Emergency gamma reset hotkey
!x::
{        
    global
    Loop( monitorCount )
        mon.SetGammaRamp( , , , A_Index)
}
Please test and lmk if this is useful for you (*:

A simple demo:
Image




Adjust backgrounds of things that are too bright!
Image.


I've decided to make this app/script it's own thread entirely: find updated code here (AHK Thread) and here (GitHub Repo).
-TL

Post Reply

Return to “AutoHotkey v2 Scripts and Functions”