tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

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

tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by Tigerlily » 19 Aug 2020, 08:27

tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads Working in Low- and No-Light Environments


Download the EXE !


Raw Source Code (GitHub Repo)


Description: A lightweight, portable, multi-monitor compatible screen dimming app that can adjust:
  • RGB gamma output
  • monitor brightness (if supported)
  • monitor contrast (if supported)
  • monitor power state (if supported)
  • system-wide colors
  • dimmer (screen overlay)
  • and more features to be added soon!
I've been wanting to make something like this for a long time ever since I started having to pull all-nighters during University. When you are up really late or having to work in a low- / no-light environment, this screen dimmer is a godsend.

It allows your laptop monitor or external monitors to be dimmed WAY below the default lowest brightness setting that Windows provides natively 8-) this really frustrated me for a while because I just assumed that there was no way to get my screen dimmer. Most of the Windows screen dimming apps out there only put a fullscreen transparent overlay OR let you adjust color temperatures between a certain range.

This screen dimmer does all that and more by allowing you to adjust individual gamma output levels exactly how feels best for your eyes in your current environment. For instance, you can set Blue Gamma Output to 0%, effectively becoming the best "blue light blocker" you can have when working on a computer! Doing this doesn't allow your computer to emit blue light anymore (only green and red output)! You can also of course do this for Red and Green gamma too, if wanted.

I've found that reducing blue gamma almost entirely to 0-20% and green gamma to 20-60% is much less straining on my eyes. A good way to test for your preferences is when you are up really late and tired and your eyes are already shot from all day behind a screen. This magnifies the eye-strain feeling you have, so as you adjust each gamma output it becomes really clear what feels better for your eyes.


Features:

For each monitor individually or simultaneously:
  • Gamma Color Output Adjustment Slider (All / Red / Green / Blue)
  • Brightness Adjustment Slider***
  • Contrast Adjustment Slider***
  • Dimmer Adjustment Slider - transparent black overlay that will likely work regardless of system (has some drawbacks)
  • Power State Controller*** - turn a specific monitor or all monitors truly OFF and ON
  • Background System Color Theming - Choose between 4 additional temporary system-wide color themes that make the font and window background colors more relaxing on the eyes (aimed at really bright white background apps like Excel, Notepad, and even things like dialog/message boxes that are really bright grey)
*** if supported, if your monitor doesn't support it then the slider will be disabled


A couple of gif demos:

Multi-Monitor customization
Image


Background theming for hard-to-look-at White/Grey backgrounds
Image




Please test it out and let me know what you think! (*: report any bugs or desired features that you feel are missing :rainbow:


Code:

Code: Select all

;...............................................................................;
;                                                                               ;
; app ...........: tigerlily's Screen Dimmer		                             ;
; version .......: 0.5.1                                                        ;
;                                                                               ;
;...............................................................................;
;                                                                               ;
; author ........: tigerlily                                                    ;
; language ......: AutoHotkey V2 (alpha 122-f595abc2)                           ;
; github repo ...: https://git.io/tigerlilysScreenDimmer						;
; download EXE ..: https://git.io/JUUAu											;
; forum thread ..: https://bit.ly/tigerlilys-screen-dimmer-AHK-forum			;
; license .......: MIT (https://git.io/tigerlilysScreenDimmerLicense)			;
;                                                                               ;
;...............................................................................;
; [CHANGE LOG], [PENDING] and [REMARKS] @ bottom of script                      ;
;...............................................................................;


;................................................................................
;          ...........................................................          ;
;           A U T O - E X E C U T E   &   I N I T I A L I Z A T I O N           ;
;................................................................................

#SingleInstance
global mon := Monitor.New()


;................................................................................
;                     ..................................                        ;
;                      T R A Y  M E N U   &   I C O N S                         ;
;................................................................................

;	Set Icon ToolTip and App Name
A_IconTip := "tigerlily's Screen Dimmer"

; Create tray menu with only a "Close App" option
,	A_TrayMenu.Delete()
,	A_TrayMenu.Add(A_IconTip, (*) => monitorMenu.Show()) 
,	A_TrayMenu.Add() 
,	A_TrayMenu.Add("Close", (*) => ExitApp()) 

; Allows a single left-click on taskbar icon to open monitor menu
,	OnMessage(0x404, (wParam, lParam, *) => lParam = 0x201 ? monitorMenu.Show() : "") 

; Try to download and set tray/menu icons without keeping images saved locally
try Download("https://i.imgur.com/VoXGvak.png", A_ScriptDir "\tray-icon.png")
try Download("https://i.imgur.com/Ea1kZrE.png", A_ScriptDir "\close-app.png")
try TraySetIcon(A_ScriptDir "\tray-icon.png")
try A_TrayMenu.SetIcon(A_IconTip , A_ScriptDir "\tray-icon.png")
try A_TrayMenu.SetIcon("Close" , A_ScriptDir "\close-app.png")
try (FileExist(A_ScriptDir "\tray-icon.png")) ? FileDelete(A_ScriptDir "\tray-icon.png") : ""
try (FileExist(A_ScriptDir "\close-app.png")) ? FileDelete(A_ScriptDir "\close-app.png") : ""



;................................................................................
;                                    .......                                    ;
;                                     G U I                                     ;
;................................................................................

; Create monitor config menu
	monitorMenu := Gui.New("Resize", A_IconTip)
,   monitorMenu.OnEvent("Close", (monitorMenu) => monitorMenu.Hide())
,   monitorMenu.OnEvent("Size" , (monitorMenu, MinMax, *) => (MinMax = -1 ? monitorMenu.Hide() : ""))
,   monitorMenu.SetFont("c0x7678D0 s9 bold q5")
,   monitorMenu.BackColor := 0x000000,   monitorMenu.MarginX := 20,   monitorMenu.MarginY := 20

; Get all monitor info
,   info := mon.GetInfo()
,   monitorCount := info.Length

;	x, y, width, height associative arrays to hold monitor coords, etc.
,   x := Map(), y := Map(), w := Map(), h := Map()

; Create config tabs
,   monitorMenuTabs := monitorMenu.Add("Tab3", , MonitorTabs(info, monitorCount))

;	Create empty associative arrays to hold each GUI control object for each monitor found
#Warn VarUnset, Off ; Stops useless warnings from being thrown due to dynamic variable/object creation below

;	Note: going to replace the psuedo-arrays with proper Map() objects eventually
for feature in features := ["gammaAll", "gammaRed", "gammaGreen", "gammaBlue", "contrast", "brightness", "dimmer"]
{
 	%feature%				:= Map() ; slider controls
,	%feature%Title			:= Map() ; title text controls
,	%feature%SliderStart	:= Map() ; slider front-end control ("0")
,	%feature%SliderEnd		:= Map() ; slider back-end control ("100")
}
	PowerOn  := Map(), PowerOff := Map()
,	overlay  := Map(), dimmerVisible := Map(), ResetSettings := Map()

;	Detect hidden windows so script can see transparent dimmer overlay GUIs when present
,	DetectHiddenWindows("On")
; iterate [once for each monitor found plus 1] OR [only once for single-monitor setups]
while ((i := A_Index - (monitorCount > 1 ? 1 : 0)) <= monitorCount)
{
	; Use the correct tab for each monitor / all monitor config
    monitorMenuTabs.UseTab(monitorCount = 1 ?info[1]["Name"] : (!i ? "All Monitors" : (info[i]["Primary"] ? info[i]["Name"] " [Primary]" : info[i]["Name"])))

	; Get gamma output for each monitor and set All Monitors Config gamma to 100% initially
    g := (i ? mon.GetGammaRamp(i) : 100) 

    if (i)	; Specific to each monitor (e.g. not ALL monitors)
    {
	;	Get each monitor's x & y coords, width, height
		x[i] := info[i]["Left"], w[i] := (info[i]["Right"] - x[i])
	,	y[i] := info[i]["Top"] , h[i] := (info[i]["Bottom"] - y[i])
	
	;	Create Dimmer (Black Overlay)
	,   overlay[i] := Gui.New("+AlwaysOnTop +Owner +E0x20 +ToolWindow -DPIscale -Caption -SysMenu")	
    ,   overlay[i].BackColor := "0x000000" ; Sets dimmer color as pure black


		;	Determine monitor capabilities for each monitor for gamma, brightness, contrast, power mode
    	;	Get each monitor's gamma output levels	
		try
		{
        	gR := g["Red"], gG := g["Green"], gB := g["Blue"]
			gammaCapability := true
		}
		catch
			gammaCapability := false    
		
		try 
        {
            b  := mon.GetBrightness(i)["Current"]
            brightnessCapability := true
        }    
        catch
            brightnessCapability := false
            
        try 
        {
            c  := mon.GetContrast(i)["Current"]
            contrastCapability := true
        }    
        catch
            contrastCapability := false
            
        try 
        {
            p  := mon.GetPowerMode(i)
            powerCapability := true
        }    
        catch
            powerCapability := false    
            
        if (brightnessCapability && contrastCapability && powerCapability) 
            resetCapability := true
        else
            resetCapability := false 

		
		if (!gammaCapability && !resetCapability)
			resetAbility := "Disabled"
		else
			resetAbility := ""
	}	;	Note: these all need to be recreated with a map for each monitor found

	; Create Monitor Config controls
    gammaAllTitle[i]	:= monitorMenu.Add("Text",	"w200 Section Center", "Gamma (All):`t`t" 100 "%")
,   gammaAll[i]			:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaAll" i, 100)

,   gammaRedTitle[i]	:= monitorMenu.Add("Text",	"w200 xp Center", "Gamma (Red):`t`t" Round(i ? gR : 100) "%")
,   gammaRed[i]			:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaRed" i, (i ? gR : 100))

,   gammaGreenTitle[i]	:= monitorMenu.Add("Text",	  "w200 xp Center", "Gamma (Green):`t" Round(i ? gG : 100) "%")
,   gammaGreen[i]		:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaGreen" i, (i ? gG : 100))

,   gammaBlueTitle[i]	:= monitorMenu.Add("Text",	 "w200 xp Center", "Gamma (Blue):`t`t" Round(i ? gB : 100) "%")
,   gammaBlue[i]		:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 vGammaBlue" i, (i ? gB : 100)) ; add iset

,   brightnessTitle[i]	:= monitorMenu.Add("Text",	  "w200 xs+220 ys Center", "Brightness:`t`t" Round(i ? (IsSet(b) ? b : 0) : 100) "%")
,   brightness[i]		:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 " (i ? (IsSet(b) ? "" : "Disabled") : "") " vBrightnessSlider" i, (i ? (IsSet(b) ? b : 0) : 100))

,   contrastTitle[i]	:= monitorMenu.Add("Text",	  "w200 xp Center", "Contrast:`t`t" Round(i ? (IsSet(c) ? c : 0) : 100) "%")
,   contrast[i]			:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 " (i ? (IsSet(c) ? "" : "Disabled") : "") "  vContrastSlider" i, (i ? (IsSet(c) ? c : 0) : 100))

,   dimmerTitle[i]		:= monitorMenu.Add("Text",	  "w200 xp Center", "Dimmer (Overlay):`t" 0 "%")
,   dimmer[i]			:= monitorMenu.Add("Slider", "xp AltSubmit ToolTip TickInterval10 Page10 Thick30 vDimmerSlider" i, 0)
,	dimmerVisible[i]	:= false

,   PowerOn[i]  := monitorMenu.Add("Radio", "xp Group " (i ? (IsSet(p) ? "" : "Disabled") : "") " vPowerOnRadio"  i, "Turn " ( i ? "[" info[i]["Name"] "]" : "All Monitors" ) " On")
,   PowerOff[i] := monitorMenu.Add("Radio", "xp " 	    (i ? (IsSet(p) ? "" : "Disabled") : "") " vPowerOffRadio" i, "Turn " ( i ? "[" info[i]["Name"] "]" : "All Monitors" ) " Off")

,	ResetSettings[i] := monitorMenu.Add("Checkbox", "xp " (i ? (resetCapability ? "" : "Disabled") : "") " vResetSettings" i, "Reset to Factory Settings")

,   gammaAll[i].OnEvent(  	 "Change", "AdjustGamma")
,   gammaRed[i].OnEvent(  	 "Change", "AdjustGamma")
,   gammaGreen[i].OnEvent(	 "Change", "AdjustGamma")
,   gammaBlue[i].OnEvent( 	 "Change", "AdjustGamma")
,   brightness[i].OnEvent(	 "Change", "AdjustBrightnessOrContrast")
,   contrast[i].OnEvent(  	 "Change", "AdjustBrightnessOrContrast")    
,   dimmer[i].OnEvent(	  	 "Change", "AdjustDimmer")    
,	PowerOn[i].OnEvent(	  	 "Click" , "ChangePowerState")    
,	PowerOff[i].OnEvent(  	 "Click" , "ChangePowerState")    
,	ResetSettings[i].OnEvent("Click" , "ResetSettings")    
}

	; Make additional tabs
	monitorMenuTabs.UseTab("Background Modes")
,	monitorMenu.Add("Text", "w400", 
		"Background Modes:`n`n"
		"Some backgrounds in programs like Excel or Notepad are terribly white and even in the day time can be way too bright. The following Background Modes helps partially solve this issue by changing the background, window, and text colors system-wide.`n`n"
		"(This will reset to default system colors when you close this app)")
,	BackgroundNormalModeRadio	:= monitorMenu.Add("Radio", "Group vNormal", "Normal Mode (default)").OnEvent("Click", "ChangeBackgroundMode") 
,	BackgroundMorningModeRadio	:= monitorMenu.Add("Radio", "vMorning"	   , "Morning Mode"	).OnEvent("Click", "ChangeBackgroundMode")
,	BackgroundDayModeRadio		:= monitorMenu.Add("Radio", "vDay"		   , "Day Mode"		).OnEvent("Click", "ChangeBackgroundMode")
,	BackgroundNightModeRadio	:= monitorMenu.Add("Radio", "vNight"	   , "Night Mode"	).OnEvent("Click", "ChangeBackgroundMode")
,	BackgroundEveningModeRadio	:= monitorMenu.Add("Radio", "vEvening"	   , "Evening Mode"	).OnEvent("Click", "ChangeBackgroundMode")
,	BackgroundMidnightModeRadio	:= monitorMenu.Add("Radio", "vMidnight"	   , "Midnight Mode").OnEvent("Click", "ChangeBackgroundMode")
,	BackgroundTwilightModeRadio	:= monitorMenu.Add("Radio", "vTwilight"	   , "Twilight Mode").OnEvent("Click", "ChangeBackgroundMode")

,	monitorMenuTabs.UseTab("Background Themes")
,	monitorMenu.Add("Text", "w400", 
		"Background Themes:`n`n"
		"This alters your Windows Theme and will not reset when you reboot, log back in, or close this app. A known limitation is that in Excel you cannot see the font or background cell colors (except black && white) since it places your system into High Contrast mode.`n`n"
		"This is the best way to have your entire system color set be ultra dark / low-light. To change it back to your Custom User Theme, go to`n`n"
		"Windows Settings > Personalization > Themes")
,	midnightTheme	:= monitorMenu.Add("Radio", "vMidnightTheme", "Midnight Theme").OnEvent("Click", "ActivateTheme")
,	twilightTheme	:= monitorMenu.Add("Radio", "vTwilightTheme", "Twilight Theme").OnEvent("Click", "ActivateTheme")
,	darkTheme	:= monitorMenu.Add("Radio", "vDarkTheme", "Windows Default (Dark) Theme").OnEvent("Click", "ActivateTheme")
,	lightTheme	:= monitorMenu.Add("Radio", "vLightTheme", "Windows Default (Light) Theme").OnEvent("Click", "ActivateTheme")

,	monitorMenuTabs.UseTab("Advanced Settings")
,	monitorMenu.Add("Text", "w400", "Custom hotkey support coming soon.")

,	monitorMenuTabs.UseTab("App Info / Report Bug")
,	monitorMenu.Add("Link", "w400 Center", 
		"Thanks so much for choosing to use tigerlily's Screen Dimmer!`n`n"
		"I hope you really enjoy this screen dimmer as I believe it is the best one out there. f.lux, iris, and other well known screen dimmers do not give as much control as I would like and sometimes only create a transparent black screen overlay, which is prone to annoyances.`n`n"
		"This screen dimmer allows you to adjust actual gamma color output, making your screen completely stop emitting blue, green, or red light if desired, which is way more beneficial than an arbitrary color temperature or simple screen overlay. `n`n"
		"It also allows you to turn on/off your monitors with a click of a button, which can sometimes help with focusing on a multi-monitor setup.`n`n"
		"This is a work in progress, but will eventually contain customizable hotkeys, custom timers, color temperature settings, and more.`n`n`n"
		"Please report any bugs / feedback / comments at either:`n`n"
		"<a href=`"https://git.io/tigerlilysScreenDimmer`">---> GitHub Repository</a>`n`n" 
		"<a href=`"https://bit.ly/tigerlilys-screen-dimmer-AHK-forum`">---> AutoHotkey Forum Thread</a>`n`n`n"
		"Feel free email me directly about bugs and about any desired features you want me to add at: <a href=`"mailto: [email protected]`">[email protected]</a>")


; Sets "All Monitors" Tab sliders if all monitors have matching current feature setting values
if (monitorCount > 1)
{	; Note: Going to replace dynamic variables with proper Map() objects at some point
	for feature in ["gammaRed", "gammaGreen", "gammaBlue", "contrast", "brightness"]
	{
		while ((i := A_Index) <= monitorCount)
		{
			z := (i < monitorCount ? (i + 1) : 1)
			if (%feature%[i].Value = %feature%[z].Value)
			{
				%feature%LoadAll := true
			}
			else
			{
				%feature%LoadAll := false
				break
			}			
		}

		if (%feature%LoadAll = true)
		{
			%feature%[0].Value := %feature%[1].Value
		,	%feature%Title[0].Value := %feature%Title[1].Value
		}	

		if (feature = "gammaRed"   && %feature%LoadAll = true 
		||  feature = "gammaGreen" && %feature%LoadAll = true 
		||  feature = "gammaBlue"  && %feature%LoadAll = true)
		{
			%feature%AllLoadAll := true
		}	
		else
		{
			%feature%AllLoadAll := false
		}	

	}
	if (gammaRedAllLoadAll = true && gammaGreenAllLoadAll = true && gammaBlueAllLoadAll = true)
	{
		gammaAll[0].Value := gammaRed[1].Value
	,	gammaAllTitle[0].Value := "Gamma (All):`t`t" Round(gammaAll[0].Value) "%"
		Loop(monitorCount)
		{
			gammaAll[A_Index].Value := gammaAll[0].Value 
		,	gammaAllTitle[A_Index].Value := gammaAllTitle[0].Value 
		}	
	}	
}
monitorMenu.Show()



;................................................................................
;								  ...............								;
;								   H O T K E Y S								;
;................................................................................


;   Close app
^Esc::ExitApp()


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



;................................................................................
;                               ...................                             ;
;                                F U N C T I O N S                              ;
;................................................................................


MonitorTabs(info, monitorCount){ ; Creates tabs based on # of monitors found

	; Additional Tabs:
	static adv	    := "Advanced Settings"
	,	   bgThemes := "Background Themes"
	,	   bgModes  := "Background Modes"
	,	   appInfo  := "App Info / Report Bug"

    if (monitorCount = 1)
        return [info[1]["Name"], bgModes, bgThemes, adv, appInfo]
    else
    {    
        monitorTabs := ["All Monitors"]
        while ((i := A_Index) <= monitorCount)
            monitorTabs.Push((info[i]["Primary"] ? info[i]["Name"] " [Primary]" : info[i]["Name"]))
        monitorTabs.Push(bgModes, bgThemes, adv, appInfo)
        return monitorTabs
    }
}

AdjustGamma(slider, *){

    global
	if (gammaCapability)
	{
		name := slider.Name, v := slider.Value, n := Integer(SubStr(name, -1)), _R := "Red", _G := "Green", _B := "Blue"	
		try
		{
			if (n)
			{
				g := mon.GetGammaRamp(n)
				InStr(name, _R) ? ((gR := v), (color := _R), (gG := g[_G]), (gB := g[_B]), mon.SetGammaRamp(gamma%color%[n].Value := gR, gG, gB, n), gamma%color%Title[n].Value := "Gamma (" color "):`t`t" Round(gR) "%")     
			:	InStr(name, _G) ? ((gG := v), (color := _G), (gR := g[_R]), (gB := g[_B]), mon.SetGammaRamp(gR, gamma%color%[n].Value := gG, gB, n), gamma%color%Title[n].Value := "Gamma (" color "):`t" Round(gG) "%")
			:	InStr(name, _B) ? ((gB := v), (color := _B), (gR := g[_R]), (gG := g[_G]), mon.SetGammaRamp(gR, gG, gamma%color%[n].Value := gB, n), gamma%color%Title[n].Value := "Gamma (" color "):`t`t" Round(gB) "%")
			:	(mon.SetGammaRamp(gammaRed[n].Value := v, gammaGreen[n].Value := v, gammaBlue[n].Value := v, n), (gammaAllTitle[n].Value := "Gamma (All):`t`t" Round(v) "%"), (gammaRedTitle[n].Value := "Gamma (Red):`t`t" Round(v) "%"), (gammaGreenTitle[n].Value := "Gamma (Green):`t" Round(v) "%"), (gammaBlueTitle[n].Value := "Gamma (Blue):`t`t" Round(v) "%"))		
			}
			else
			{
				while ((i := A_Index) <= monitorCount)
				{
					g := mon.GetGammaRamp(i)
				,	InStr(name, _R) ? ((gR := v), (color := _R), (gG := g[_G]), (gB := g[_B]), mon.SetGammaRamp(gamma%color%[i].Value := gR, gG, gB, i), gamma%color%Title[0].Value := gamma%color%Title[i].Value := "Gamma (" color "):`t`t" Round(gR) "%")     
				:	InStr(name, _G) ? ((gG := v), (color := _G), (gR := g[_R]), (gB := g[_B]), mon.SetGammaRamp(gR, gamma%color%[i].Value := gG, gB, i), gamma%color%Title[0].Value := gamma%color%Title[i].Value := "Gamma (" color "):`t" Round(gG) "%")
				:	InStr(name, _B) ? ((gB := v), (color := _B), (gR := g[_R]), (gG := g[_G]), mon.SetGammaRamp(gR, gG, gamma%Color%[i].Value := gB, i), gamma%color%Title[0].Value := gamma%color%Title[i].Value := "Gamma (" color "):`t`t" Round(gB) "%")
				:	(mon.SetGammaRamp(gammaAll[0].Value := gammaRed[0].Value := gammaGreen[0].Value := gammaBlue[0].Value := gammaAll[i].Value :=  gammaRed[i].Value := v, gammaGreen[i].Value := v, gammaBlue[i].Value := v, i), (gammaAllTitle[0].Value := gammaAllTitle[i].Value := "Gamma (All):`t`t" Round(v) "%"), (gammaRedTitle[0].Value := gammaRedTitle[i].Value := "Gamma (Red):`t`t" Round(v) "%"), (gammaGreenTitle[0].Value := gammaGreenTitle[i].Value := "Gamma (Green):`t" Round(v) "%"), (gammaBlueTitle[0].Value := gammaBlueTitle[i].Value := "Gamma (Blue):`t`t" Round(v) "%"))   
				}
			}  
		}
	}
}

AdjustBrightnessOrContrast(slider, *){

    global       
	try
	{	
		v := slider.Value, name := slider.Name
		if (n := Integer(SubStr(name, -1)))
			InStr(name, "Brightness") ? (mon.SetBrightness(v, n), (brightnessTitle[n].Value := "Brightness:`t`t" Round(v) "%")) 
									  : (mon.SetContrast(v, n), (contrastTitle[n].Value := "Contrast:`t`t" Round(v) "%"))
		else
			while ((i := A_Index) <= monitorCount)
				InStr(name, "Brightness") ? (mon.SetBrightness(brightness[i].Value := v, i), (brightnessTitle[0].Value := brightnessTitle[i].Value := "Brightness:`t`t" Round(v) "%"))  
										  : (mon.SetContrast(contrast[i].Value := v, i), (contrastTitle[0].Value := contrastTitle[i].Value := "Contrast:`t`t" Round(v) "%"))
		Sleep(100) ; Calling these methods below too fast can throw errors, so give 100 ms break
	}
}

AdjustDimmer(slider, *){

    global   
    v := slider.Value, dim := v * 2.55
	try 
	{
		if (n := Integer(SubStr(slider.Name, -1)))  
		{   
			if (dim)
			{
				WinSetTransparent(dim, "ahk_id " overlay[n].hWnd)
				if (dimmerVisible[n] = false)
				{
					overlay[n].Show("x" x[n] " y" y[n] " w" w[n] " h" h[n])
					dimmerVisible[n] := true
				}
				dimmerTitle[n].Value := "Dimmer (Overlay):`t" Round(v) "%"
			}
			else
			{
				overlay[n].Hide(), dimmerVisible[n] := false, dimmerTitle[n].Value := "Dimmer (Overlay):`t" Round(v) "%"
			}
		}
		else
		{
			while ((i := A_Index) <= monitorCount)
			{
				if (dim)
				{
					WinSetTransparent(dim, "ahk_id " overlay[i].hWnd)
					if (dimmerVisible[i] = false)
					{
						overlay[i].Show("x" x[i] " y" y[i] " w" w[i] " h" h[i])
						dimmerVisible[i] := true
					}
					dimmerTitle[0].Value := dimmerTitle[i].Value := "Dimmer (Overlay):`t" Round(dimmer[i].Value := v) "%"
				}
				else
				{
					overlay[i].Hide(), dimmerVisible[i] := false, dimmerTitle[0].Value := dimmerTitle[i].Value := "Dimmer (Overlay):`t" Round(v) "%"
				}  
			}      
		}        
	}
}

ChangePowerState(radio, *){

    global   
	name := radio.Name
	try  
	{     
		if (powerCapability) 
		{
			if (InStr(name, "On"))
			{
				if (n := Integer(SubStr(name, -1)))
					mon.SetPowerMode("On", n), PowerOn[n].Value := 0
				else
				{
					PowerOn[0].Value := 0 
					Loop(monitorCount)
						mon.SetPowerMode("On", A_Index)    
				}		
			}        
			else
			{
				if (n := Integer(SubStr(name, -1)))
					mon.SetPowerMode("PowerOff", n), PowerOff[n].Value := 0
				else
				{
					PowerOff[0].Value := 0       
					Loop(monitorCount)
						mon.SetPowerMode("PowerOff", A_Index)
				}
			}
		}        
	}
}

ChangeBackgroundMode(radio, *){

	static userBg := DllCall("user32\GetSysColor", "int", 1) ; Desktop background color
	static backgroundModes := Map(
		"Normal"  , Map(0x000000, 0xC8C8C8, 1,   userBg, 2, 0xD1B499, 3, 0xDBCDBF, 4, 0xF0F0F0, 5, 0xFFFFFF, 6, 0x646464, 7, 0x000000, 8, 0x000000, 9, 0x000000, 10, 0xB4B4B4, 11, 0xFCF7F4, 12, 0xABABAB, 13, 0xD77800, 14, 0xFFFFFF, 15, 0xF0F0F0, 16, 0xA0A0A0, 17, 0x6D6D6D, 18, 0x000000, 19, 0x000000, 20, 0xFFFFFF, 21, 0x696969, 22, 0xE3E3E3, 23, 0x000000, 24, 0xE1FFFF, 26, 0xCC6600, 27, 0xEAD1B9, 28, 0xF2E4D7, 29, 0xD77800, 30, 0xF0F0F0),
		"Morning" , Map(0x000000, 0xC7EDCC, 1,   userBg, 2, 0xD1B499, 3, 0xC7EDCC, 4, 0xC7EDCC, 5, 0xC7EDCC, 6, 0x646464, 7, 0x000000, 8, 0x000000, 9, 0x000000, 10, 0xB4B4B4, 11, 0xFCF7F4, 12, 0xC7EDCC, 13, 0xD77800, 14, 0xFFFFFF, 15, 0xC7EDCC, 16, 0xA0A0A0, 17, 0x6D6D6D, 18, 0x000000, 19, 0x000000, 20, 0xFFFFFF, 21, 0x696969, 22, 0xE3E3E3, 23, 0x000000, 24, 0xE1FFFF, 26, 0xCC6600, 27, 0xEAD1B9, 28, 0xF2E4D7, 29, 0xD77800, 30, 0xF0F0F0),
		"Day"	  , Map(0x000000, 0xABABAB, 1,   userBg, 2, 0xD1B499, 3, 0xABABAB, 4, 0xABABAB, 5, 0xABABAB, 6, 0x646464, 7, 0x000000, 8, 0x000000, 9, 0x000000, 10, 0xB4B4B4, 11, 0xFCF7F4, 12, 0xABABAB, 13, 0xD77800, 14, 0xFFFFFF, 15, 0xABABAB, 16, 0xA0A0A0, 17, 0x6D6D6D, 18, 0x000000, 19, 0x000000, 20, 0xFFFFFF, 21, 0x696969, 22, 0xE3E3E3, 23, 0x000000, 24, 0xE1FFFF, 26, 0xCC6600, 27, 0xEAD1B9, 28, 0xF2E4D7, 29, 0xD77800, 30, 0xF0F0F0),
		"Night"	  , Map(0x000000, 0x000000, 1, 0x000000, 2, 0x595757, 3, 0x595757, 4, 0x595757, 5, 0x595757, 6, 0x000000, 7, 0x000000, 8, 0xC6C8C5, 9, 0xC6C8C5, 10, 0x000000, 11, 0x000000, 12, 0x595757, 13, 0x5A5A57, 14, 0xC6C8C5, 15, 0x595757, 16, 0x000000, 17, 0x808080, 18, 0xC6C8C5, 19, 0xC6C8C5, 20, 0x5A5A57, 21, 0x000000, 22, 0x5A5A57, 23, 0xC6C8C5, 24, 0x000000, 26, 0xF0B000, 27, 0x000000, 28, 0x000000, 29, 0x5A5A57, 30, 0x000000),
		"Evening" , Map(0x000000, 0x000000, 1, 0x000000, 2, 0x222223, 3, 0x222223, 4, 0x222223, 5, 0x222223, 6, 0x000000, 7, 0x000000, 8, 0xC6C8C5, 9, 0xC6C8C5, 10, 0x000000, 11, 0x000000, 12, 0x222223, 13, 0x5A5A57, 14, 0xC6C8C5, 15, 0x222223, 16, 0x000000, 17, 0x808080, 18, 0xC6C8C5, 19, 0xC6C8C5, 20, 0x5A5A57, 21, 0x000000, 22, 0x5A5A57, 23, 0xC6C8C5, 24, 0x000000, 26, 0xF0B000, 27, 0x000000, 28, 0x000000, 29, 0x5A5A57, 30, 0x000000),
		"Midnight", Map(0x000000, 0x000000, 1, 0x000000, 2, 0xC6C8C5, 3, 0x000000, 4, 0x000000, 5, 0x000000, 6, 0x000000, 7, 0x000000, 8, 0xC6C8C5, 9, 0xC6C8C5, 10, 0x000000, 11, 0x000000, 12, 0x000000, 13, 0x5A5A57, 14, 0xC6C8C5, 15, 0x000000, 16, 0x000000, 17, 0x808080, 18, 0xC6C8C5, 19, 0xC6C8C5, 20, 0x000000, 21, 0x000000, 22, 0x000000, 23, 0xC6C8C5, 24, 0x000000, 26, 0xF0B000, 27, 0x000000, 28, 0x000000, 29, 0x5A5A57, 30, 0x000000),
		"Twilight", Map(0x000000, 0x000000, 1, 0x000000, 2, 0x8C3230, 3, 0x000000, 4, 0x000000, 5, 0x000000, 6, 0x000000, 7, 0x000000, 8, 0x8C3230, 9, 0xC6C8C5, 10, 0x000000, 11, 0x000000, 12, 0x000000, 13, 0x080816, 14, 0xC04B48, 15, 0x000000, 16, 0x000000, 17, 0x808080, 18, 0x8C3230, 19, 0x8C3230, 20, 0x000000, 21, 0x000000, 22, 0x000000, 23, 0x8C3230, 24, 0x000000, 26, 0xC04B48, 27, 0x000000, 28, 0x000000, 29, 0x5A5A57, 30, 0x000000))
	try 
		for displayElement, color in backgroundModes[radio.Name]
			DllCall("user32\SetSysColors", "Int", 1, "IntP", displayElement, "UIntP", color)
}

ActivateTheme(radio, *){

global

lightThemeFile := "
(
[Theme]
; Windows - IDS_THEME_DISPLAYNAME_AERO_LIGHT
DisplayName=Windows Default (Light)
SetLogonBackground=0

; Computer - SHIDI_SERVER
[CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-109

; UsersFiles - SHIDI_USERFILES
[CLSID\{59031A47-3F72-44A7-89C5-5595FE6B30EE}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-123

; Network - SHIDI_MYNETWORK
[CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-25

; Recycle Bin - SHIDI_RECYCLERFULL SHIDI_RECYCLER
[CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\DefaultIcon]
Full=%SystemRoot%\System32\imageres.dll,-54
Empty=%SystemRoot%\System32\imageres.dll,-55

[Control Panel\Cursors]
AppStarting=%SystemRoot%\cursors\aero_working.ani
Arrow=%SystemRoot%\cursors\aero_arrow.cur
Crosshair=
Hand=%SystemRoot%\cursors\aero_link.cur
Help=%SystemRoot%\cursors\aero_helpsel.cur
IBeam=
No=%SystemRoot%\cursors\aero_unavail.cur
NWPen=%SystemRoot%\cursors\aero_pen.cur
SizeAll=%SystemRoot%\cursors\aero_move.cur
SizeNESW=%SystemRoot%\cursors\aero_nesw.cur
SizeNS=%SystemRoot%\cursors\aero_ns.cur
SizeNWSE=%SystemRoot%\cursors\aero_nwse.cur
SizeWE=%SystemRoot%\cursors\aero_ew.cur
UpArrow=%SystemRoot%\cursors\aero_up.cur
Wait=%SystemRoot%\cursors\aero_busy.ani
DefaultValue=Windows Default
[email protected],-1020

[Control Panel\Desktop]
Wallpaper=%SystemRoot%\web\wallpaper\Windows\img0.jpg
TileWallpaper=0
WallpaperStyle=10
Pattern=

[VisualStyles]
Path=%ResourceDir%\Themes\Aero\Aero.msstyles
ColorStyle=NormalColor
Size=NormalSize
AutoColorization=0
ColorizationColor=0XC40078D7
SystemMode=Light
AppMode=Light

[boot]
SCRNSAVE.EXE=

[MasterThemeSelector]
MTSM=RJSPBS

[Sounds]
; IDS_SCHEME_DEFAULT
SchemeName=@%SystemRoot%\System32\mmres.dll,-800
)"

darkThemeFile := "
(
[Theme]
DisplayName=Windows Default (Dark)
SetLogonBackground=0

; Computer - SHIDI_SERVER
[CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-109

; UsersFiles - SHIDI_USERFILES
[CLSID\{59031A47-3F72-44A7-89C5-5595FE6B30EE}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-123

; Network - SHIDI_MYNETWORK
[CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-25

; Recycle Bin - SHIDI_RECYCLERFULL SHIDI_RECYCLER
[CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\DefaultIcon]
Full=%SystemRoot%\System32\imageres.dll,-54
Empty=%SystemRoot%\System32\imageres.dll,-55

[Control Panel\Cursors]
AppStarting=%SystemRoot%\cursors\aero_working.ani
Arrow=%SystemRoot%\cursors\aero_arrow.cur
Crosshair=
Hand=%SystemRoot%\cursors\aero_link.cur
Help=%SystemRoot%\cursors\aero_helpsel.cur
IBeam=
No=%SystemRoot%\cursors\aero_unavail.cur
NWPen=%SystemRoot%\cursors\aero_pen.cur
SizeAll=%SystemRoot%\cursors\aero_move.cur
SizeNESW=%SystemRoot%\cursors\aero_nesw.cur
SizeNS=%SystemRoot%\cursors\aero_ns.cur
SizeNWSE=%SystemRoot%\cursors\aero_nwse.cur
SizeWE=%SystemRoot%\cursors\aero_ew.cur
UpArrow=%SystemRoot%\cursors\aero_up.cur
Wait=%SystemRoot%\cursors\aero_busy.ani
DefaultValue=Windows Default
[email protected],-1020

[Control Panel\Desktop]
Wallpaper=%SystemRoot%\web\wallpaper\Windows\img0.jpg
TileWallpaper=0
WallpaperStyle=10
Pattern=

[VisualStyles]
Path=%ResourceDir%\Themes\Aero\Aero.msstyles
ColorStyle=NormalColor
Size=NormalSize
AutoColorization=0
ColorizationColor=0XC40078D7
SystemMode=Dark
AppMode=Dark

[boot]
SCRNSAVE.EXE=

[MasterThemeSelector]
MTSM=RJSPBS

[Sounds]
; IDS_SCHEME_DEFAULT
SchemeName=@%SystemRoot%\System32\mmres.dll,-800
)"

midnightThemeFile := "
(
[Theme]
; Windows - IDS_THEME_DISPLAYNAME_AERO
DisplayName=tigerlily's Midnight Theme
ThemeId={09FBF740-B58E-4297-AFDE-F7F599CAB875}

; Computer - SHIDI_SERVER
[CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-109

; UsersFiles - SHIDI_USERFILES
[CLSID\{59031A47-3F72-44A7-89C5-5595FE6B30EE}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-123

; Network - SHIDI_MYNETWORK
[CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-25

; Recycle Bin - SHIDI_RECYCLERFULL SHIDI_RECYCLER
[CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\DefaultIcon]
Full=%SystemRoot%\System32\imageres.dll,-54
Empty=%SystemRoot%\System32\imageres.dll,-55

[Control Panel\Cursors]
AppStarting=%SystemRoot%\cursors\aero_working.ani
Arrow=%SystemRoot%\cursors\aero_arrow.cur
Crosshair=
Hand=%SystemRoot%\cursors\aero_link.cur
Help=%SystemRoot%\cursors\aero_helpsel.cur
IBeam=
No=%SystemRoot%\cursors\aero_unavail.cur
NWPen=%SystemRoot%\cursors\aero_pen.cur
SizeAll=%SystemRoot%\cursors\aero_move.cur
SizeNESW=%SystemRoot%\cursors\aero_nesw.cur
SizeNS=%SystemRoot%\cursors\aero_ns.cur
SizeNWSE=%SystemRoot%\cursors\aero_nwse.cur
SizeWE=%SystemRoot%\cursors\aero_ew.cur
UpArrow=%SystemRoot%\cursors\aero_up.cur
Wait=%SystemRoot%\cursors\aero_busy.ani
DefaultValue=Windows Default

[Control Panel\Desktop]
Wallpaper=
Pattern=
MultimonBackgrounds=0
PicturePosition=4

[VisualStyles]
Path=%SystemRoot%\resources\themes\Aero\AeroLite.msstyles
ColorStyle=NormalColor
Size=NormalSize
AutoColorization=0
ColorizationColor=0XC4000000
SystemMode=Dark
AppMode=Dark
VisualStyleVersion=10
HighContrast=3

[boot]
SCRNSAVE.EXE=

[MasterThemeSelector]
MTSM=RJSPBS

[Sounds]
; IDS_SCHEME_DEFAULT
[email protected],-800

[Control Panel\Colors]
ActiveBorder=0
ActiveTitle=0
AppWorkspace=0
Background=0
ButtonAlternateFace=0
ButtonDkShadow=0
ButtonFace=0
ButtonHilight=0
ButtonLight=0
ButtonShadow=0
ButtonText=197 200 198
GradientActiveTitle=0
GradientlnactiveTitle=0
GrayText=105 101 101
Hilight=64 61 61
HilightText=227 229 228
HotTrackingColor=240 176 0
InactiveBorder=0
InactiveTitle=0
InactiveTitleText=197 200 198
InfoText=197 200 198
InfoWindow=0
Menu=0
MenuBar=0
MenuHilight=35 34 34
MenuText=197 200 198
Scrollbar=0
TitleText=197 200 198
Window=0
WindowFrame=0
WindowText=197 200 198
)"

twilightThemeFile := "
(
[Theme]
; Windows - IDS_THEME_DISPLAYNAME_AERO
DisplayName=tigerlily's Midnight Theme
ThemeId={09FBF740-B58E-4297-AFDE-F7F599CAB875}

; Computer - SHIDI_SERVER
[CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-109

; UsersFiles - SHIDI_USERFILES
[CLSID\{59031A47-3F72-44A7-89C5-5595FE6B30EE}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-123

; Network - SHIDI_MYNETWORK
[CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\DefaultIcon]
DefaultValue=%SystemRoot%\System32\imageres.dll,-25

; Recycle Bin - SHIDI_RECYCLERFULL SHIDI_RECYCLER
[CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\DefaultIcon]
Full=%SystemRoot%\System32\imageres.dll,-54
Empty=%SystemRoot%\System32\imageres.dll,-55

[Control Panel\Cursors]
AppStarting=%SystemRoot%\cursors\aero_working.ani
Arrow=%SystemRoot%\cursors\aero_arrow.cur
Crosshair=
Hand=%SystemRoot%\cursors\aero_link.cur
Help=%SystemRoot%\cursors\aero_helpsel.cur
IBeam=
No=%SystemRoot%\cursors\aero_unavail.cur
NWPen=%SystemRoot%\cursors\aero_pen.cur
SizeAll=%SystemRoot%\cursors\aero_move.cur
SizeNESW=%SystemRoot%\cursors\aero_nesw.cur
SizeNS=%SystemRoot%\cursors\aero_ns.cur
SizeNWSE=%SystemRoot%\cursors\aero_nwse.cur
SizeWE=%SystemRoot%\cursors\aero_ew.cur
UpArrow=%SystemRoot%\cursors\aero_up.cur
Wait=%SystemRoot%\cursors\aero_busy.ani
DefaultValue=Windows Default

[Control Panel\Desktop]
Wallpaper=
Pattern=
MultimonBackgrounds=0
PicturePosition=4

[VisualStyles]
Path=%SystemRoot%\resources\themes\Aero\AeroLite.msstyles
ColorStyle=NormalColor
Size=NormalSize
AutoColorization=0
ColorizationColor=0XC4000000
SystemMode=Dark
AppMode=Dark
VisualStyleVersion=10
HighContrast=3

[boot]
SCRNSAVE.EXE=

[MasterThemeSelector]
MTSM=RJSPBS

[Sounds]
; IDS_SCHEME_DEFAULT
[email protected],-800

[Control Panel\Colors]
ActiveBorder=0
ActiveTitle=0
AppWorkspace=0
Background=0
ButtonAlternateFace=0
ButtonDkShadow=0
ButtonFace=0
ButtonHilight=0
ButtonLight=0
ButtonShadow=0
ButtonText=48 50 140
GradientActiveTitle=0
GradientlnactiveTitle=0
GrayText=105 101 101
Hilight=8 8 22
HilightText=72 75 192
HotTrackingColor=72 75 192
InactiveBorder=0
InactiveTitle=0
InactiveTitleText=48 50 140
InfoText=48 50 140
InfoWindow=0
Menu=0
MenuBar=0
MenuHilight=35 34 34
MenuText=48 50 140
Scrollbar=0
TitleText=48 50 140
Window=0
WindowFrame=0
WindowText=48 50 140
)"

	name := StrReplace(radio.Name, "Theme")

	themeFileName := "tigerlily's " name " Theme.theme"		
	themeFilePath := A_ScriptDir "\" themeFileName	

	; 
	FileExist(themeFilePath) ?  Run(themeFilePath) 
							 : (FileAppend(%name%ThemeFile, themeFilePath), Run(themeFilePath))

	if (WinWaitActive("Settings ahk_class ApplicationFrameWindow"))
		WinClose()

}

ResetSettings(chkbx, *){

    global  

	SetTimer("PleaseWaitNotification", 50)

	; Reset Dimmers
	if (n := Integer(SubStr(chkbx.Name, -1)))
	{
		overlay[n].Hide() 
	,	dimmerTitle[n].Value := "Dimmer (Overlay):`t" (dimmer[n].Value := 0) "%"
	}
	else
	{
		dimmer[0].Value := 0, dimmerTitle[0].Value := "Dimmer (Overlay):`t" 0 "%"
		while ((i := A_Index) <= monitorCount)
		{
			overlay[i].Hide(), dimmerTitle[i].Value := "Dimmer (Overlay):`t" (dimmer[i].Value := 0) "%"
		}
	}

	; Reset Gamma
	try
	{
		if (n := Integer(SubStr(chkbx.Name, -1)))
		{
			mon.SetGammaRamp(gammaAll[n].Value := gammaRed[n].Value := 100, gammaGreen[n].Value := 100, gammaBlue[n].Value := 100, n)
		,	ResetSettings[n].Value := 0
			for color in ["All", "Red", "Green", "Blue"]
				gamma%color%Title[0].Value := gamma%color%Title[n].Value := "Gamma (" color "):" (color = "Green" ? "`t" : "`t`t") " 100%"
		}
		else
		{
			ResetSettings[0].Value := 0  
			gammaAll[0].Value := gammaRed[0].Value := gammaGreen[0].Value := gammaBlue[0].Value := 100 
			while ((i := A_Index) <= monitorCount)
			{
				mon.SetGammaRamp(gammaAll[i].Value := gammaRed[i].Value := 100, gammaGreen[i].Value := 100, gammaBlue[i].Value := 100, i)  
				for color in ["All", "Red", "Green", "Blue"]
					gamma%color%Title[0].Value := gamma%color%Title[i].Value := "Gamma (" color "):" (color = "Green" ? "`t" : "`t`t") " 100%"
			}
		}
	}

	; Reset Brightness and Contrast
	try       
	{
		if (mon.RestoreFactoryDefaults(i)) 
		{
			if (n := Integer(SubStr(chkbx.Name, -1)))
			{
				mon.RestoreFactoryDefaults(n)
			,	ResetSettings[n].Value := 0 
			,	Sleep(1000)
			,	brightnessTitle[n].Value := "Brightness:`t`t" mon.GetBrightness(n)["Current"] "%"
			,	Sleep(1000)
			,	contrastTitle[n].Value   := "Contrast:`t`t" mon.GetContrast(n)["Current"] "%"
			,	Sleep(1000)
			}	
			else
			{
				ResetSettings[0].Value := 0 
				while ((i := A_Index) <= monitorCount)
				{
					mon.RestoreFactoryDefaults(i)  
				,	Sleep(1000)		
				,	brightnessTitle[0].Value := brightnessTitle[i].Value := "Brightness:`t`t" (brightness[0].Value := brightness[i].Value := mon.GetBrightness(i)["Current"]) "%"
				,	Sleep(1000)
				,	contrastTitle[0].Value := contrastTitle[i].Value := "Contrast:`t`t" (contrast[0].Value := contrast[i].Value := mon.GetContrast(i)["Current"]) "%"
				,	Sleep(1000)
				}
			}			       
		}        
	}	

	n ?	(SetTimer("PleaseWaitNotification", 0), ToolTip(), MsgBox("Monitor " n " restored to factory settings!", A_IconTip, "T6"))	
	  : (SetTimer("PleaseWaitNotification", 0), ToolTip(), MsgBox("All monitors restored to factory settings!" , A_IconTip, "T6"))
			
	PleaseWaitNotification(){
		
			ToolTip("Please Wait....")		
	}	
}


;................................................................................
;								 ...............								;
;								  C L A S S E S									;
;................................................................................

;   Monitor Configuration Class
;   https://git.io/MonitorConfigurationClass

;   This is a stripped down version, including only what's needed for app
;	full version for v2 can be found above

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)
	
	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)

	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 ===== ;
	
	RestoreFactoryDefaults(Display := "") => this.VoidSetting("RestoreMonitorFactoryDefaults", 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){

        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 := 0, "uint", 0x00000002)
		return hMonitor
	}
	
	GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor){

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

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

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

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

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

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

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

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

	GammaSetting(GammaMethodName, Red := "", Green := "", Blue := "", Display := "", DisplayName := ""){

		MonitorInfo := this.EnumDisplayMonitors()
		if (Display = ""){
			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))
		}	
	
	}
	
	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))
	}


	; ===== 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))
	}

	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))
	}
	

	; ===== 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))
	}		
	
	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))
	}		


	; ===== VOID METHODS ===== ;
	
	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))
	}
}
	

/* 
;................................................................................
;                             .....................                             ;
;                              C H A N G E   L O G                              ;
;................................................................................


	
	2020-08-25: Changed tray/taskbar icon to a gold color
	2020-08-25: Changed app font color to aqua purple color to be easier on eyes
	2020-08-25: Made Theme popup menu close more reliably when switching themes
	2020-08-25: Fixed bug of dimmer values not updating for individual monitors when
					using "All Monitors" slider
	

	2020-08-24: Re-wrote control positioning code to always display in alignment in Config GUI
	2020-08-24: Added "Reset to Factory Settings" feature for all/specific monitors
	2020-08-24: Added "gamma" and "reset to default" capability checks for each monitor
	2020-08-24: Added "[Primary]" to monitor tab in multi-monitor setup to denote primary monitor
	2020-08-24: Changed Monitor Tab Names to show the monitor's actual Name (e.g. "\\.\DISPLAY2")
	2020-08-24: Removed Gamma Reset hotkey
	2020-08-24: Removed Ends of Slider Controls and added a visual current % level for each slider
	2020-08-24: Re-wrote all Control change functions to be more optimized with less code
	2020-08-24: Removed "safety" OnExit() function - all features can be reset by a reboot/login
					with the exception of Background Themes
	2020-08-24: Added Evening Mode (formerly Night Mode), an in-between background color between
					the new Night Mode and Midnight Modes
	2020-08-24: Changed Night Mode to be lighter background
	2020-08-24: Added Twilight Mode to compliment newly added Twilight Theme
	2020-08-24: Added "Background Themes" tab and feature for ultra-dark system-wide color theming
					with Windows Default Light and Dark Themes, Midnight Theme and Twilight Theme
	
	
	2020-08-20: Changed default GUI font color to a less-bright off white color easier on eyes (0xC6C8C5) 
	2020-08-20: Updated formatting, particularly section headers 


	2020-08-18: Reduced code size by creating maps dynamically instead of hard-coded
	2020-08-18: Updated "App Info / Report Bug" tab to include GitHub repo and AHK Forum thread
	2020-08-18: Removed debug value check MsgBox popup when changing monitor state to Power Off 


	2020-08-16: Added checks to make "All Monitors" tab auto-set to current system values
					if the feature for all monitors are equal
	2020-08-16: Made color shading for white-screened apps like Excel, Notepad, Paint etc.
					more robust (affects more elements than before: 5 vs. 29) 


	2020-08-15: Added "App Info / Report Bug" tab, and moved controls to that tab instead of 
					in "Advanced Settings"
	2020-08-15: Created "Background Modes" in advanced settings to adjust system-wide color 
					settings 
	2020-08-15: Made Power State controls respond quicker and de-selects radio button


	2020-08-14: Reduced codesize by removing unused methods in Monitor Class
	2020-08-14: Added tray and menu icons
	2020-08-14: Added "Advanced Settings" Tab to include contact/bug reporting info and 
					app info
	2020-08-14: Reduced codesize by changing OnEvent functions to fat arrow one-liners
    2020-08-14: Added a way to close down the app in tray menu
    2020-08-14: Made "Minimize" and "Close" buttons in GUI now both hide GUI 
    2020-08-14: Fixed a bug of all non-primary monitor gamma values setting to 
					primary gamma values


    2020-08-13: Fixed a few minor bugs affecting settings adjustment response time
    2020-08-13: Version 0.1.0 published




;................................................................................
;                                ...............                                ;
;                                 P E N D I N G                                 ;
;................................................................................
 


    - Customizable Hotkeys based on which monitor cursor is located in
    - Custom daily/hourly/per-minute timer/auto-adjuster 
	- Adjustable screen focuser for reading, etc (blacks out desired portion of screen)
	- User Profiles to save/load personalized user settings on app start / while app is running
	- Color Temperature adjustments (may not add this)
    - Color Gain / Drive for added color adjustment (may not add this)




;................................................................................
;                                ...............                                ;
;                                 R E M A R K S                                 ;
;................................................................................


	- Background themes and modes are somewhat experimental and can sometimes be known  
		to cause minor coloring issues. Just log back in or reboot if any unusual color
		persists, then the unusual coloring will be reset.



*/
Last edited by Tigerlily on 25 Aug 2020, 19:49, edited 11 times in total.
-TL

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 19 Aug 2020, 08:31

[ F E E D B A C K / I S S U E S / P E N D I N G]

I received some really great anonymous feedback via email and wanted to share the issues reported and my answers to them. Perhaps you may have similar issues that I'm already in the process of remedying, so check this out - it's a good resource to see what features I'm planning to implement. Also, if you are interested, check out the PENDING section at the bottom of the script found above.

This was my email back:

Hi there (*:

Thank you so much for your feedback, it is mighty helpful. Haha - feel free to contact me anytime!! It is highly encouraged. Please note that this app is still in the rapid development phase (currently version 0.4.0), it's bug reports like these that really help me tackle issues like you are experiencing.

Okay some questions for you based on your feedback. Thanks so much for the ordered lists!!

Which version of the app are you running and what are you system specs (specifically: windows version and build)?

Which AHK version are you running?



Hi tigerlily, as you asked for it, I gladly tell you what I don't like so
far. :)

1. downloading icons from imgur, not a good idea from my point of
view - if the site is hacked (unlikely), then your app will show nude pics
- better use icons from windows, they are free and local - or incorporate
icons in the main script (but this will bloat your script)

I thought about this, over the last year I have experimented with imgur hosting my icons/images from a ShareX upload and have had no problems, but good point. I will check out some local icons to see if perhaps there is a "safer" alternative. I was trying to go for portability, so aside from the compiled version which already contains the major tray icon, I don't want any icons as of yet.

UPDATE: After experimenting with local icons found in .dll files, I've decided it's much more reliable across major OS's to retrieve the icons from a reliable page on the net. I will likely find a better host than imgur, but at the moment it's really not an issue to me.

2. in case you
want to stay with imgur add "try" when deleting the pics - i manually
downloaded the pics and set them read-only, the script will fail -
something similar could happen with security software blocking the deletion

I will make this change. I highly doubt someone will manually download the pics and set them to read-only, and if they want to do that to test my app then that is probably their problem lol! The security software is a valid case though.

UPDATE: Fixed.

3. the UI is ugly (sorry) black & white with too much contrast, no fun to
look at

Hehe. In the last release I have made the white less intense so a easier on the eyes off-white now. Not sure if you are running the latest release, but I'd be curious if you are or not. I am not quite sure how I plan to change this for a better UX yet. I like having a pure black background for the GUI since this app is aimed at those working in low- / no-light conditions, although the off-white before the latest release was too intense for my eyes too. Can you give me some ideas based on what you would prefer as the app GUI theming? Because of your feedback, I believe eventually I will implement 5+ built in themes for the GUI, sort of like the Normal, Morning, Day, Night, Midnight modes for Background Modes. What sort of color scheme (background and text colors) would you prefer?


4. I get an error when setting a slider "too" fast

Code: Select all

Error: Unable to
set values. Error code: 0x0 Line# 830: { 831: NumPut("ushort", (r := (red +
128) * i) > 65535 ? 65535 : r, GAMMA_RAMP, 2 * i) 832: NumPut("ushort", (g
:= (green + 128) * i) > 65535 ? 65535 : g, GAMMA_RAMP, 512 + 2 * i) 833:
NumPut("ushort", (b := (blue + 128) * i) > 65535 ? 65535 : b, GAMMA_RAMP,
1024 + 2 * i) 834: } 835: if (DllCall("gdi32\SetDeviceGammaRamp", "ptr",
hMonitor, "ptr", GAMMA_RAMP)) 836: Return 1 ---> 837: Throw
Exception("Unable to set values. Error code: " Format("0x{:X}",
A_LastError)) 838: } 840: { 842: if (DllCall("dxva2\SetVCPFeature", "ptr",
hMonitor, "ptr", VCPCode, "uint", NewValue)) 843: Return Map("VCPCode",
Format("0x{:X}", VCPCode), "NewValue", NewValue) 844: Throw
Exception("Unable to set value. Error code: " Format("0x{:X}",
A_LastError)) 845: } 847: Exit The current thread will exit.


Very interesting, perhaps I need to add a try statement here too. I've found through testing that some of the Monitor Configuration WinAPIs need an unspecified amount of time to return and will cause errors when being called in succession too quickly. Unfortunately, there is nothing in the official documentation that states the time, so its a guessing game based on use-case scenario and user system. I cannot reproduce this error on my system no matter how fast I change the gamma. The issue here partly lies in the way that AHK submits the slider value change, my only options were to (1) spam the commands quickly using AltSubmit Option, or (2) only allow user to see changes once they release their cursor press on a slider. I went with the latter because its much nicer to see the change as you slide around imo. A minor trade off. I will definitely fix this issue you are experiencing. Did you get an error for any other slider, or just Gamma adjustment? Also, when you say too fast, what do you mean exactly? I'm assuming you mean using the mouse cursor to change the slider and moving from one end to the other really fast.

UPDATE: Fixed.

5. enhancement
request: add a reset button for each tab, to reset to default values

I've thought about this, and based on your request I will add it. The alternative for now though is to simply click once at Gamma (All) Slider at 100% and Click on Normal mode (default) in the Advanced Settings tab. The default brightness and contrast levels for each monitor may be different for every monitor, so I would have to build in a ResetToFactoryDefaults checkbox, which I was already considering and should be easy to implement. I will add this feature you request.

UPDATE: Added.

6.
Advanced Settings/ Background Modes, do not work with - Win 10 Device Manager Window - Notepad3

Can you send me a snapshot of the background mode not working? The Background Modes are somewhat experimental, and have a few drawbacks that I'm currently trying to debug. Windows does not allow certain display elements to be changed while in it's Normal theme mode (aka not High Contrast, but what people normally are using on their system by default). The workaround for this is to set your theme in High Contrast Mode: Black. I have created my own custom High Contrast Black theme to use Background Modes, and this nearly solves my issue with the display elements not properly setting. This may be good enough for you. I am unsatisfied currently, and planning to build in a custom High Contrast feature OR find another way to make this happen. I will need some more time to debug this before implementing anything, however the High Contrast workaround is good enough for me in the meantime. The best way to switch between your Saved User Custom Settings is by running the theme files found in

C:\Users\user\AppData\Local\Microsoft\Windows\Themes

or the System-provided Ease-of-Access Themes in

C:\Windows\Resources\Ease of Access Themes

I will likely incorporate running theme files from these directories in some way if there is no other cleaner alternative.


UPDATE: Couldn't find a cleaner way to fix this without using Windows High Contrast Themes, added two default Windows themes (Light & Dark), Midnight Theme, and Twilight Theme. Added a few more Background Modes as well. If anyone else happens to know how I can set ALL system colors without switching to High Contrast themes, please let me know!

7. When using cursor Left/Right the slider value
is not shown

I've thought about this, its just a minor drawback of the AHK GUI. I've been considering adding a Text Control next to the slider that updates to show the current value. I will likely implement this, however it's not a priority for me over some of the other issues you've addressed.

UPDATE: Added a % level indicator right next to each slider.

8. resetting the values when exiting seems not to work. I
dunno where the settings are saved I have monitored the registry
RegSetValue, it's not there. So I'll be careful. I hope you appreciate my
feed-back, please enhance the script, it might be useful, once the bugs are
ironed out...

I have accidentally posted some versions of this script in the past with the "Reset values when exiting" feature was commented out. Search the script to see if the OnExit function is commented out or not. If so, uncomment this line. If not, please let me know as I'd be curious to know why your system is not recieving the commands from my app to reset these things. This feature was mainly to stop people from setting their gamma levels to 0 and being unable to get back to see their screen. I may remove it entirely, and have an advanced setting that allows the user to bring the gamma values below 10%, otherwise cap it at 10%. As I mentioned before, you can reset the gamma in one click and reset the background modes in one click before you exit the program. Also, please note that the only way to truly exit this app is by right clicking the tray icon and clicking close. Closing the app config GUI with the X (close) button minimizes the app to the tray icon - this was done purposefully. Please confirm that you are indeed exiting the app in this way.

Additionally, the reg values may change somewhere, however upon a logout/login, these settings reset, so not sure how this affects registry. I have a suspicion that my Background Modes only affect a temporary setting that is reset upon each login/boot, since i have found a Colors reg folder under HKEY_CURRENT_USER and HKEY_USERS. I'm guessing the values in HKEY_USERS override the HKEY_CURRENT_USER values when you login/boot, however I don't have much experience with registry and havent had the time to look further into this yet.


UPDATE: Removed this entirely. User can reset each or all monitor to factory/default settings with a click on the corresponding tab. If user wants to reset background mode, either reboot/logout and back in or click "Normal Mode" in the Background Modes tab. To restore custom theme, you must do it manually in
Settings > Personalization > Themes

9. The sliders do not show the actual value, only after moving

Refer to answer of Issue #7

UPDATE: Fixed.

10. show monitor Name to make it Mord obvious which monitor is which

I considered doing this before. It would not be difficult to implement this. Additionally, I plan to make it easier for user to identify their Primary monitor. Something I had in mind is like the Identify Monitors feature in the Display Settings which shows a big # on each screen while the user holds down a button. I will likely implement this in the future, but for now it is low priority.

UPDATE: Added. The monitor name is now located on the corresponding tab, as well as within the tab window (bottom-right side).

11. Option to save slider settings to file and Option to read those settings (Reason: the reset when closing the script does not work for me)

This is definitely in the works. Wanted to push out a script for people to test/debug/experiment/enjoy before implementing this. I wanted to avoid having any externally dependent files, but I may have to temporarily defer this until I figure out a good solution.

UPDATE: In the works.



Please check and see if the OnExit function was commented out and report back when you are able! Or perhaps you weren't exiting the app like you had thought (I doubt this since you sound pretty tech savvy, but worth asking just in case)

Thanks again so much for your feedback. I will definitely implement fixes for many of your reported issues. I will update you when I have released a version that has ironed out most or all of these issues.

-tigerlily


Thanks for your feedback whoever you are! (*: And of course, to everyone else: please submit more feedback so I can make this app really cool for you! Even if you are experiencing the same issues mentioned above, please report anyways.
Last edited by Tigerlily on 24 Aug 2020, 20:41, edited 14 times in total.
-TL

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 19 Aug 2020, 08:32

[ R E S E R V E D ]
-TL

User avatar
boiler
Posts: 16774
Joined: 21 Dec 2014, 02:44

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by boiler » 19 Aug 2020, 13:04

Looks well done. I’m interested in the system-wide colors part of it because I use a dark mode for everything but that doesn’t affect the main field in Excel and other apps, as you noted. Are the changes made by your tool permanent other than revising them back again via your tool? (i.e., are any registry changes or anything like that performed?) I would prefer everything to return to “normal” either when I exit your tool or when I reboot my machine.

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 19 Aug 2020, 15:52

Hi @boiler! Happy to see your interest in my app!

The system-wide color scheme is changed using the GetSysColor and SetSysColors WinAPIs (MSDN Docs: SysGetColor, SetSysColors). Unfortunately, it doesn't not appear that changing color of all the display Elements (e.g. Inactive Window Caption, etc.) works on my system. I read a handful of other developers upset at this, but of course MS doesn't seem to have fixed this yet.

Nonetheless, when you use this feature it will be applied on top of whatever theme you are already using on your system. Have no fear, this will not affect your system colors permanently (AKA no way to go back). There are 3 simple ways to revert back:
(1) Everytime you close this app, this OnExit() Function is triggered and sets your background colors back to how they were before you changed them in the app, and also resets Gamma values to 100% (this is not imperative, just a simple safety check). You can comment these lines out if you dislike this feature:

Code: Select all

OnExit("ResetGammaAndBackgroundMode")
ResetGammaAndBackgroundMode(*){

    global
    Loop( monitorCount ) 
        mon.SetGammaRamp( , , , A_Index) 

	resetBackgroundMode := {}
	resetBackgroundMode.Name := "Normal"
	BackgroundMode_Change(resetBackgroundMode)       
}
Comment out lines 505-515 (line numbers are subject to changing in future releases). I'm planning on eventually making this a setting the user is able to check on or off and stays that way for them.

(2) There is a "Normal mode (default)" which restores your system colors back to the default classic theme. Not sure how this will affect everyone who uses it yet, however I am running Win 10, Build 18363, with native dark theme and it works great IMO when reverting back this way.

(3) All else fails, you can simply log out and back in and Windows will reset this for you (say you accidentally restart or log out before closing the app down and you commented out the lines in Option #1, still not to worry).

You know, I haven't had the time to check whether this affects the registry, but I don't think it does based on how everything resets with a logout/login.

The only thing that I believe could be affected (only if you took off the safety checks mentioned in Option #1), is your
desktop background color. My app looks at what the user already has set as the Desktop Background Color and uses that dynamically as the user's "Normal Mode (default)", so if you removed the safety check mentioned in Option #1, you could set your desktop Background color to 0x000000 (pure black) and it would stay that way until you manually switched it back. Now you could set it to 0x000000 in the app, then close it down, restart your computer and I believe you desktop background color will still be black (however, I haven't actually tested this in particular because it didn't seem like a huge deal).

This feature is somewhat experimental and unfortunately it appears like I'm going to have to use something like GetSysColorBrush and related WinAPIs to programmatically change the rest of the display elements that are returning true as if the System Colors are set, but for some reason not actually updating to the chosen colors. Apparently, this may work better on Win 7 and Win 8, but of course issues with Win 10. For me, as of current, this feature is not thorough enough for me to give it a golden stamp of approval, so I look forward to solving the rest of the coloring issues in the near future. It may be as simple as Windows will not accept certain color values for certain display elements, I just haven't tried every option yet to test that out.

Feel free to ask any other questions, and lmk what you think when you test out the app! All comments, critiques, and feedback welcome!! :rainbow: :cookie: :cookie:
-TL

User avatar
boiler
Posts: 16774
Joined: 21 Dec 2014, 02:44

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by boiler » 19 Aug 2020, 21:31

Thanks for the info. That helps a lot. I tried it out, and while I would prefer the main dark color provided by night mode, it creates an issue where there are some pieces of text that are still dark which are now on a dark background, making them difficult to see (such as blue links, lettering on tabs). But day mode seems to be a nice compromise where those dark letters are still visible but the bright white backgrounds are now a bit darker. So I believe I'll be using it as my standard. Thanks for sharing!

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 19 Aug 2020, 22:11

boiler wrote:
19 Aug 2020, 21:31
Thanks for the info. That helps a lot. I tried it out, and while I would prefer the main dark color provided by night mode, it creates an issue where there are some pieces of text that are still dark which are now on a dark background, making them difficult to see (such as blue links, lettering on tabs). But day mode seems to be a nice compromise where those dark letters are still visible but the bright white backgrounds are now a bit darker. So I believe I'll be using it as my standard. Thanks for sharing!
Thanks so much for the feedback! I'm glad you have found some value in this script (*:

Yeah it's almost impossible to create a universal color setting with the current limitations I'm struggling with that works perfect in all scenarios. I usually run with Midnight Mode on, but every once in awhile will need to switch to Day Mode to read some things.

Was there anything that stuck out to you particularly that you think could use a different color? I know the hyperlinks color can be changed, and it sounds like Night Mode makes certain hyperlinks unreadable without highlighting them. Which "tabs" did you find that were showing up like that? A pic would be super helpful to me in fixing that issue.

I'm going to do some testing this week to see if perhaps some colors Windows will not accept, as I noticed (if you look at the paint example in the background mode gif) some backgrounds will not take when commanded to, all the different background colors before Midnight mode will not alter the background in Paint, however 0x000000 is acceptable.. which i found odd since the rest of the colors weren't as extreme (black/white).
-TL

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 20 Aug 2020, 04:02

Hi @boiler,

I wanted to update you. I did some testing and kept running into the same problem. After doing some really hard digging I stumbled upon this post talking about SetThemeAppProperties and DwmSetWindowAttribute and for whatever reason there is an issue on the standard color theming that doesn't allow SetSysColors set certain display elements properly or at all.

Apparently, if you switch to Windows High Contrast mode, this odd issue is resolved. After setting my system to High Contrast mode: Black, it appears to work as intended. This is still not ideal for me, so I'm going to look into how to override this issue taking place when not in High Contrast mode.

Nonetheless, this will allow you to use Night or Midnight Mode and it will affect all elements (like that text you couldn't see, etc. The main drawback is that High Contrast Black mode makes some programs look funny/undesirable colors and there are white borders everywhere in my taskbar and in certain windows, other than that, if you are working in Excel, this should help resolve your issue. You can always switch out of High contrast mode if it's an issue.

Here is a gif showing the successful color theming on High Contrast Black mode:

Image

Hope this helps!
-TL

User avatar
boiler
Posts: 16774
Joined: 21 Dec 2014, 02:44

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by boiler » 20 Aug 2020, 11:26

Tigerlily wrote:
19 Aug 2020, 22:11
Was there anything that stuck out to you particularly that you think could use a different color? I know the hyperlinks color can be changed, and it sounds like Night Mode makes certain hyperlinks unreadable without highlighting them. Which "tabs" did you find that were showing up like that? A pic would be super helpful to me in fixing that issue.
I only noticed a few things so far, although I haven't spent a lot of time with it yet. Yes, the dark blue hyperlink color is one of those things. Even just a bit lighter blue would look fine. The tabs example is from Notepad++. The picture below shows Notepad++ with Night Mode. The inactive tabs are fine, but you can't read the active tab name very easily. It looks fine with Day Mode, by the way, which I am using instead. I would prefer Night Mode if were it not for some issues like this.

notepad++ night mode tabs.png
notepad++ night mode tabs.png (6.83 KiB) Viewed 9224 times

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 20 Aug 2020, 14:20

boiler wrote:
20 Aug 2020, 11:26
Yes, the dark blue hyperlink color is one of those things. Even just a bit lighter blue would look fine. The tabs example is from Notepad++. The inactive tabs are fine, but you can't read the active tab name very easily.
Thanks so much for sending a snapshot! I see what you are talking about here regarding the tabs and experience the same on my system. Changing to High Contrast Mode: Black fixes this issue for me. I'm wondering if I need to do a WM_SYSCOLORCHANGE WinAPI command to make my Background Modes change as intended.. it tells all top-level windows to paint it's internal controls as specified, I'm hoping that is it.. still tracking a solution for this issue, but appears I am getting closer to a resolve.

Regarding the hyperlink issue, where are you coming across this issue? When I set to Midnight or Night mode, it does update the hyperlink color to a brighter blue that's easier to see. perhaps its just not bright enough on your system. Without High Contrast mode enabled, I noticed that if you set Windows Accent Color too close to the color of your Dark/Light Windows theme, it makes some native windows hyperlinks unreadable, but I doubt this is what you are experiencing.
-TL

User avatar
boiler
Posts: 16774
Joined: 21 Dec 2014, 02:44

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by boiler » 20 Aug 2020, 14:44

The hyperlink issue I noticed was in Excel when in Night Mode. I have a spreadsheet I refer to a lot which has email addresses in it, and Excel turns them into hyperlinks, and they’re pretty hard to see in Night Mode but fine in Day Mode.

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 21 Aug 2020, 02:20

boiler wrote:
20 Aug 2020, 14:44
The hyperlink issue I noticed was in Excel when in Night Mode. I have a spreadsheet I refer to a lot which has email addresses in it, and Excel turns them into hyperlinks, and they’re pretty hard to see in Night Mode but fine in Day Mode.
Okay so I did a little more testing and found that my screen dimmer app's window's hyperlinks DO change, however I am not seeing this change take place in other application windows such as Excel or Task Manager. Putting my system in High Contrast mode: Black partially helped with this, however you must set the color manually in the High Contrast settings menu. This is not ideal because no font or background color can be seen besides black and white, but may be fine is some cases.

Much to my dismay, although more display elements are "alterable" in high contrast modes, things like hyperlink color still appear to not be overridden as intended using my current approach. I'm looking into creating and changing .theme files programmatically to see if this may be a viable solution. Thanks for the feedback!

Perhaps I can make a mode between day and night mode that is more suitable for you?
-TL

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers

Post by Tigerlily » 24 Aug 2020, 20:45

@boiler

I've released an updated version that is better overall. I added a couple more Background Modes for more customization, as well as two theme modes that switch the rest of the system colors to darker, which fixes that tab text/background color issue you were experiencing. After doing a lot of digging and testing, I've decided to go with the High Contrast Theme approach due to it's convenience of filetype, compatibility, etc. Will be interesting to see how well the themes work across OS versions and different Win 10 systems (which it was mainly written for).

Unfortunately, for Excel users this may be annoying since you cannot see any cell text/background colors other than the system colors set by the High Contrast theme. In many cases this is not important (speaking from experience), but in other cases it is detrimental, in which case a Default Windows Dark Theme mixed with another Background Mode will be the best alternative.

See demo of updated GUI in OP.
-TL

User avatar
boiler
Posts: 16774
Joined: 21 Dec 2014, 02:44

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by boiler » 25 Aug 2020, 14:51

Thanks for the updates. For me, I'm just looking at the Background Modes without changing any of the themes. I like the darker grey background that Night Mode provides, but the difference in contrast between it and the white text is low enough that I'd rather go with the lighter grey and black text of Day Mode since it's easier to read. I like the white text on the even darker grey (almost black) of Evening Mode, but it still has the problem with the blue hyperlinks and active tab text in Notepad++. I'm not expecting you to change anything...just giving you that feedback. What you have is already a nice improvement, and I thank you for sharing it. :thumbup:

Lisa19
Posts: 48
Joined: 07 Apr 2019, 22:25

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by Lisa19 » 31 Aug 2020, 12:21

It's embarrassing: windows blocked the .exe, so I checked it, and windows found a trojan:
Image

User avatar
boiler
Posts: 16774
Joined: 21 Dec 2014, 02:44

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by boiler » 31 Aug 2020, 13:23

@Lisa19 - That’s very likely a false positive and not embarrassing at all to the author. Anti-virus software often flags software simply because they don’t recognize it, not because it actually found anything in it to be malicious. And if you don’t trust it, download the source instead of the .exe file.

Lisa19
Posts: 48
Joined: 07 Apr 2019, 22:25

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by Lisa19 » 31 Aug 2020, 13:28

boiler wrote:
31 Aug 2020, 13:23
@Lisa19 - That’s not embarrassing at all to the author.
sorry, it wasn't clear: I'm the one who feels embarrassed (because of the result of windows contradict the kindness of the author, and it let me confused).

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by Tigerlily » 01 Sep 2020, 01:02

Hi @Lisa19,

Happy to see your interest in my app! As long as you downloaded the .exe file from my GitHub repository, it is virus-free. The source code can easily be extracted from the .exe file and examined yourself if curious! The source code can also be found in the same repository:

tigerlily's Screen Dimmer GitHub Repository

Please let me know if you are still unable to get it working on your system, I'd be happy to help you get it setup. I would love to hear about your experience using it, let me know if there is anything you would like me to add/improve upon.

Cheers!
-TL

partof
Posts: 110
Joined: 16 Jan 2016, 08:38

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by partof » 02 Sep 2020, 11:12

@Lisa19 Did you installed it?

I have the Same problem than you, the .exe has been flagged by virustotal (which belong to google) https://www.virustotal.com/gui/file/4d3698e964f514db5ec214a065441080aad85240414352309e2419f846e4332c/relations . It says the app contact 10+ domains, 7contacted URL, 6contacted pins, and found a malware, why a simple dimmer would do that?

Beware Lisa: Open source is full of virus (I suffered the consequence 2 times).

tigerlily you know that your code is just to complicate for most users, there is no way to check it.

I

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

Re: tigerlily's Screen Dimmer [a122] - Multi-Monitor Screen Dimmer for Developers, Students, Gamers & Digital Nomads

Post by Tigerlily » 02 Sep 2020, 16:41

@partof

Just because VirusTotal belongs to Google does not mean that it is accurate, believe it or not Google makes a lot of mistakes (my profession is a Google Search Engine Optimizer for websites).

The way VirusTotal works is it sends the file/URL to several other AV companies who perform their own unique virus scan, so if you think about it Google is just aggregating info from multiple sources like it does in a search engine result page. If Google served you up 100 website URLs from a search query, would you assume they are all safe to go to? The fact is that Google will even flag pages that it returns in it's own search engine result page and warn users not to go to it (even when they've already safely visited the site multiple times). Unfortunately, compiled AutoHotkey apps are often falsely flagged as malware when there is nothing malicious about them. This is due to ineffective AntiVirus algorithms that don't actually check what the compiled app is truly doing, it just see's all AHK apps as sketchy if they do a certain criteria of things (e.g. download an image from the internet).


The only Http Requests explicitly coded from this app are

https://i.imgur.com/VoXGvak.png and
https://i.imgur.com/Ea1kZrE.png

which are obviously non-malicious .png image files. In the source code it says in comments right above the following 10 lines: Try to download and set tray/menu icons without keeping images saved locally

I plan on hosting these two image files from my own site soon to make them appear more secure.

The other ones in your link appear to be something Windows OS related that I have no control over. I did not explicitly code anything in there that would do that.

I have removed the file deletion commands in an upcoming release to seem "less sketchy" to false-positive anti-virus scans like the one you shared.


Before you start asking why a simple screen dimmer would show malware, please read this forum post:

Report False-Positives To Anti-Virus Companies

Anti-Virus software falsely flagging compiled AHK .exe's is a well-known issue within this community that we are actively trying to prevent from happening. I can assure you that my .exe file found on the GitHub Repository is malware-free. If you are still skeptical, open the .exe file with notepad or other text editor and you can examine the source code easily by scrolling to the bottom of the document.

For your reference, I uploaded an AHK .exe with only one line of code and here was the result from Virus Total: https://www.virustotal.com/gui/file/35abb8bff8fccb3f87c2384e54ce2e63143e57911df4b236fbe2b48015fc16f6/relations

Here is the code compiled by V2 Ahk2Exe before it was sent to VirusTotal:

Code: Select all

Download("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", A_ScriptDir "\google-logo.png")
Please test this for yourself by compiling a script using the above code, then submitting it to VirusTotal. If you only know how to compile V1 AHK scripts, the equivalent V1 code would be:

Code: Select all

URLDownloadToFile, % "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", % A_ScriptDir "\google-logo.png"
Notice that if you compare this .EXE scan with the one your provided, it still contacts those same exact 10+ domains (except imgur.com since it is not in the code)

Image

Image


Regarding your comment that "I know that my code is too complicated for most users to check":

1. This is AHK V2 code, which arguably is not much different than AHK V1 except it has all commands rewritten as functions. This is overall easier to read.
2. My code doesn't have anything exceptionally fancy in it, so please point out to me what is so difficult for you to understand as I'd be happy to walk you through the code line-by-line so it makes sense for you and you feel comfortable using this app.
3. My code has comments all throughout which explain what each code snippet below or next to it does. Please point to a part of the code in the source that suggests malicious activity and I will notate it further or even rewrite it if you have a valid concern.
4. There are some complex ternary operators with nested functions which I would consider the most difficult code in the app to read, but if you just go line-by-line / function-by-function it is not too difficult to read. There is no purposefully complex code in there to make it difficult to read.

Also, please don't tell others to beware of downloading and using my app before you have effectively vetted the app already yourself.

P.S. if someone could test this on their system to show that there is in fact no virus in my app and post back here I would really appreciate it! (*:
-TL

Post Reply

Return to “Scripts and Functions (v2)”