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

Post your working scripts, libraries and tools.
User avatar
Tigerlily
Posts: 377
Joined: 04 Oct 2018, 22:31

Monitor Config Class [V2 b12] - 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 beta 12 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:

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 beta 12:

Code: Select all

; =================================================================================================== ;
; AutoHotkey V2.0-beta.12 Wrapper for Monitor Configuration WinAPI Functions
;
; Original Author ....: jNizM
; Released ...........: 2015-05-26
; Modified ...........: 2022-10-19
; Improved By ........: tigerlily, CloakerSmoker
; Version ............: 2.4.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)
;
;
; =================================================================================================== ;


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)["Current"]

	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 Error(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 Error(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)["Current"]]
	}
	

	; ===== 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 Error("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 := Buffer(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 Error("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)
			hMonitor := DllCall("user32\MonitorFromWindow", "ptr", hWindow, "uint", 0x00000002) ; MONITOR_DEFAULTTONEAREST = 0x00000002
		return hMonitor
	}
	
	GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, NumberOfPhysicalMonitors := 0){

		if (DllCall("dxva2\GetNumberOfPhysicalMonitorsFromHMONITOR", "ptr", hMonitor, "uint*", &NumberOfPhysicalMonitors))
			return NumberOfPhysicalMonitors
		return false
	}
	
	GetPhysicalMonitorsFromHMONITOR(hMonitor, PhysicalMonitorArraySize, &PHYSICAL_MONITOR){
        
		PHYSICAL_MONITOR := Buffer((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 Error("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 Error("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 Error("Unable to get handle to monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GammaSetting(GammaMethodName, Red := "", Green := "", Blue := "", Display := ""){
    
        MonitorInfo := this.EnumDisplayMonitors() ; might be able to find a better way to write this if-else code section below

        if (!Display){                      ; if no display # is passed, default to primary
            for Info in MonitorInfo {                                               
                if (Info["Primary"]){                                  
                    Display := A_Index                                 
                    break                                              
                }                                                                                 
            }          
        }
        else if (!IsNumber(Display)){       ; if a display name is passed, determine which display # belongs to it
            for Info in MonitorInfo {                                   
                if (MonitorInfo[A_Index]["Name"] = Display){           
                    Display := A_Index                                 
                    break                                              
                }       
            }
        }

        if (Display > MonitorInfo.Length){  ; if an invalid monitor # is passed, default to primary monitor #             
            for Info in MonitorInfo {                                               
                if (Info["Primary"]){                                  
                    Display := A_Index                                 
                    break                                              
                }                                                                                 
            }          
        }                    

        if (hDC := this.CreateDC(MonitorInfo[Display]["Name"])){	
            if (GammaMethodName = "SetDeviceGammaRamp"){
                for Color in ["Red", "Green", "Blue"]{
                    %Color% := (%Color% <    0)	?    0  ; ensure values passed are within the valid ranges
                            :  (%Color% >  100) ?  100
                            :  (%Color%)	
                    %Color% := Round((2.56 * %Color%) - 128, 1) ; convert RGB values to decimal	(function-compatible)
                }			
                this.SetDeviceGammaRamp(hDC, Red, Green, Blue)
                this.DeleteDC(hDC)
                
                for Color in ["Red", "Green", "Blue"]
                    %Color% := Round((%Color% + 128) / 2.56, 1) ; convert RBG values back to percentage	(human-readable)

                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 RGB values to percentage (human-readable)
                this.DeleteDC(hDC)
                return GammaRamp
            }			

        }
        this.DeleteDC(hDC)
        throw Error("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 Error("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 Error("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	GetDeviceGammaRamp(hMonitor){
					
		if (DllCall("gdi32\GetDeviceGammaRamp", "ptr", hMonitor, "ptr", GAMMA_RAMP := Buffer(1536)))
			return Map(
			"Red"  , NumGet(GAMMA_RAMP.Ptr,        2, "ushort") - 128,
			"Green", NumGet(GAMMA_RAMP.Ptr,  512 + 2, "ushort") - 128,
			"Blue" , NumGet(GAMMA_RAMP.Ptr, 1024 + 2, "ushort") - 128)
		throw Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("Unable to retreive values.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	MonitorCapabilitiesRequestAndCapabilitiesReply(hMonitor, ASCIICapabilitiesString := "", CapabilitiesStrLen := 0){

        if (CapabilitiesStrLen := this.GetMonitorCapabilitiesStringLength(hMonitor)){
            ASCIICapabilitiesString := Buffer(CapabilitiesStrLen)
            if (DllCall("dxva2\GetCapabilitiesStringLength", "ptr", hMonitor, "ptr", ASCIICapabilitiesString.Ptr, "uint", CapabilitiesStrLen))
                return ASCIICapabilitiesString			
        }
        throw Error("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 Error("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 Error("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 Error("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 Error("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 Error("Unable to set value.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	SetDeviceGammaRamp(hMonitor, red, green, blue){

        GAMMA_RAMP := Buffer(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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("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 Error("Unable to degauss monitor.`n`nError code: " Format("0x{:X}", A_LastError))
	}
	
	RestoreMonitorFactoryDefaults(hMonitor){

		if (DllCall("dxva2\RestoreMonitorFactoryDefaults", "ptr", hMonitor))
			return true
		throw Error("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 Error("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 Error("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 19 Oct 2022, 10:15, edited 56 times in total.
-TL

swagfag
Posts: 6222
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: 377
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() ; 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)["Minimum"]
	
; Example 3 - Return and display the Current Value of Brightness of
;			a specific monitor ("\\.\DISPLAY1"):
	
	MsgBox CurrentBrightnessLevel := mon.GetBrightness("\\.\DISPLAY1")["Current"]
;	
;
;   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  
;		  -["Current"]     -CurrentValue  
;		  -["Maximum"]     -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 Maximum Value of Luminance (Brightness) 
;			supported by the primary monitor:

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


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"]
;	
;
; =================================================================================================== ;


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


MORE EXAMPLES / DOCS ON THEIR WAY


===================================
Last edited by Tigerlily on 19 Oct 2022, 10:53, edited 15 times in total.
-TL

User avatar
Tigerlily
Posts: 377
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: 377
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

Greast
Posts: 71
Joined: 24 Oct 2020, 19:01

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

Post by Greast » 01 Nov 2020, 19:46

There is an error...
image.png
image.png (6.3 KiB) Viewed 6748 times
“You see things; you say, 'Why?' But I dream things that never were; and I say 'Why not?”
― George Bernard Shaw

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

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

Post by Tigerlily » 16 Nov 2020, 16:07

Greast wrote:
01 Nov 2020, 19:46
There is an error...
@Greast,

Can you please be more specific? What is the code you are trying to use? Are you running the latest version of AHK v2?

Happy to assist you in making the code work for you, I believe you are not using the script correctly.

Cheers,
tigerlily
-TL

User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

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

Post by TheArkive » 19 Nov 2020, 19:06

This is a very nice looking library. I am particularly interested how you are able to modify system colors for a darker theme without any special patching!

This is on my to-do list :)

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

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

Post by Tigerlily » 20 Nov 2020, 02:55

@TheArkive,

Thank you ^^; It was adapted from the great work of jNizM. You have an impressive list of v2 libs on the forums - I really appreciate all your contributions!

Those images showing modified system colors are actually from a early beta version of a screen dimmer app I'm developing, and actually this Monitor lib is not the mechanic behind changing the system colors. Rather, I was trying to make a screen dimming app that went a little further than just dimming the screen and adjusting color output, but also that would reskin particularly bright and annoying colors to more soothing-to-the-eye alternatives.

The most up-to-date source code is here, with updated features : (AHK Thread) and here (GitHub Repo). Please test it out and see if it is of any value to you! You can look at the source code and see how the app uses it. I'm still adding many more features to it, as time permits.

Partial reskinning can be done via the SetSysColors WinAPI, while more thorough reskinning can be acheived using custom High-Contrast themes.

If you look at the ahk forum source code lines 467-842, you can see how I achieved this. I must add that this is somewhat experimental, findings from many hours of trial and error (there is suprisingly not much clear info on doing this successfully out on the net). Using SetSysColors is temporary (typically resets to normal when you log out/shut down/reboot, while using the High-Contrast Themes stays static between log outs/shut downs/reboots and is my preferred method since it is more thorough and less temporary.

If you have any more questions about it, feel free to ask about it in the related forum thread!

Cheers,
tigerlily
-TL

sniemetz
Posts: 9
Joined: 17 Mar 2021, 16:53

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

Post by sniemetz » 03 Apr 2021, 14:59

Tigerlily wrote:
16 Nov 2020, 16:07
Greast wrote:
01 Nov 2020, 19:46
There is an error...
@Greast,

Can you please be more specific? What is the code you are trying to use? Are you running the latest version of AHK v2?

Happy to assist you in making the code work for you, I believe you are not using the script correctly.

Cheers,
tigerlily

Hey TL -
found my way to your Monitor Class (awesome work btw).

I get the same error Greasy T mentioned - all I did was save the class in the Lib dir, and add it at bottom of my script #Include <MonitorClass>. THis keeps my script from loading, ofc.
4-3-2021 12-58-45 PM.jpg
4-3-2021 12-58-45 PM.jpg (14.33 KiB) Viewed 5810 times

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

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

Post by Tigerlily » 09 Apr 2021, 02:01

HI @sniemetz!

Thank you (:

#1: This script is currently incompatible with the latest alpha build - I need to update it from a122 compatibility to a130, but don't have enough time to atm. So first make sure you are running v2 a122.

#2: Provide a absolute/relative filepath, see if that fixes things for you (may just be a file location mishap).

Cheers.
-TL

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

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

Post by Tigerlily » 09 Apr 2021, 02:10

A Sad Update. :( :( :shock: :? :x :cry:

The latest Windows 10 Update (Version 10.0.19042 Build 19042) does not allow any RGB Gamma values under ~50% to have effect on the monitor, at least on my laptop monitor and external monitors that I've tested this lib out to write the current code.

Oddly, the Windows Error returned is 0x0 Success when a value between 0-49.79 is passed to the SetGammaRamp method. Attempting to ignore this error that is raised, still no effect on monitor as before this windows update. :problem:

I'm in the process of examining the update to the related DLL file to see if maybe I can bypass this annoying update, but since this is a first for me I know it will probably take awhile to figure this out.

I haven't tested out reverting my Windows build to the previous build, but I imagine this may help temporarily fix this issue.

If anyone knows what to do here, please let me know ^^;

Thank you. Love and Cheers :rainbow:
-TL

hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

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

Post by hasantr » 16 Jul 2021, 02:48

Thank you Tigerlily for this beautiful library. I've been following your work for a long time. Because of astigmat, the screen can tire me out too much. I've done a little work with AHK before with the jnzim class. I will do a new study in more detail with V2. But you're talking about problems with the latest W10 update. Should I cancel my work? I don't quite understand the problem. Also, are there problems with the W11?
Thanks for everything.

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

Re: Monitor Config Class [V2 b12] - Brightness, Contrast, Gamma, DisplayArea, Color Gain & Drive, VCP Query/Setting, Deg

Post by Tigerlily » 19 Oct 2022, 10:20

@hasantr
sorry for the late reply, I haven't been active on here in a while. Happy to hear that you've been following my work, I hope you find some use out of me fiddling around with code :lol: I have a lot of fun messing around anyways.

I still haven't found a solution, or if there even is a solution, to the problem you are referencing. The only issue is that RGB Gamma values used to be able to be adjusted below 50%, but now I am unable to dim them to below 50% nowadays. I'm not sure if this is due to a Win10 update or an update to the actual WinAPI function itself, either way it sucks. I used to be able to 100% remove blue light being emitted from my screen, but not so much now. Still is very effective and dims my screen enough to where I still use this class in a screen dimming app that I use every day.

I haven't tested this out on Win11 yet, and I don't really plan on switching to Win11 whatsoever for the time being.
-TL

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

Re: Monitor Config Class [V2 b12] - Brightness, Contrast, Gamma, DisplayArea, Color Gain & Drive, VCP Query/Setting, Deg

Post by Tigerlily » 19 Oct 2022, 10:22

Hey everyone, I just updated this class to be compatible with the latest version of AHK V2 (beta 12). Hope you enjoy. :angel:
-TL

Post Reply

Return to “Scripts and Functions (v2)”