Invert window color with magnification + UIACCESS

Post your working scripts, libraries and tools for AHK v1.1 and older
malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Invert window color with magnification + UIACCESS

29 Aug 2021, 20:37

For Win8+.
To invert/remove invert - activate window and press f11.

Code: Select all

Gui, +HWNDhGui +AlwaysOnTop
DllCall("GetWindowBand", "ptr", hGui, "uint*", band)
Gui, Destroy
hGui := ""
if (band = 1)
{
   If (A_PtrSize = 8)
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU64_UIA.exe" "%A_ScriptFullPath%"
   Else If A_IsUnicode
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU32_UIA.exe" "%A_ScriptFullPath%"
   Else
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyA32_UIA.exe" "%A_ScriptFullPath%"
}
#SingleInstance Force
#MaxThreadsPerHotkey 2
DetectHiddenWindows, On
SetBatchLines -1
SetWinDelay -1
OnExit, Uninitialize
return

f11::
hTarget := WinExist("A")
if (hTarget = hTargetPrev)
{
   hTargetPrev := ""
   count--
   return
}
count++
hTargetPrev := hTarget
if (hGui = "")
{
   DllCall("LoadLibrary", "str", "magnification.dll")
   DllCall("magnification.dll\MagInitialize")
   Matrix := "-1|0|0|0|0|"
           . "0|-1|0|0|0|"
           . "0|0|-1|0|0|"
           . "0|0|0|1|0|"
           . "1|1|1|0|1"
   VarSetCapacity(MAGCOLOREFFECT, 100, 0)
   Loop, Parse, Matrix, |
      NumPut(A_LoopField, MAGCOLOREFFECT, (A_Index - 1) * 4, "float")
   loop 2
   {
      if (A_Index = 2)
         Gui, %A_Index%: +AlwaysOnTop   ; needed for ZBID_UIACCESS
      Gui, %A_Index%: +HWNDhGui%A_Index% -DPIScale +toolwindow -Caption +E0x02000000 +E0x00080000 +E0x20 ;  WS_EX_COMPOSITED := E0x02000000  WS_EX_LAYERED := E0x00080000  WS_EX_CLICKTHROUGH := E0x20
      hChildMagnifier%A_Index% := DllCall("CreateWindowEx", "uint", 0, "str", "Magnifier", "str", "MagnifierWindow", "uint", WS_CHILD := 0x40000000, "int", 0, "int", 0, "int", 0, "int", 0, "ptr", hGui%A_Index%, "uint", 0, "ptr", DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr" : ""), "ptr", hGui%A_Index%, "int", GWL_HINSTANCE := -6 , "ptr"), "uint", 0, "ptr")
      DllCall("magnification.dll\MagSetColorEffect", "ptr", hChildMagnifier%A_Index%, "ptr", &MAGCOLOREFFECT)
   }
}
Gui, 2: Show, NA   ; needed for removing flickering
hGui := hGui1
hChildMagnifier := hChildMagnifier1
loop
{
   if (count != 1)   ; target window changed
   {
      if (count = 2)
         count--
      WinHide, ahk_id %hGui%
      return
   }
   VarSetCapacity(WINDOWINFO, 60, 0)
   if (DllCall("GetWindowInfo", "ptr", hTarget, "ptr", &WINDOWINFO) = 0) and (A_LastError = 1400)   ; destroyed
   {
      count--
      WinHide, ahk_id %hGui%
      return
   }
   if (NumGet(WINDOWINFO, 36, "uint") & 0x20000000) or !(NumGet(WINDOWINFO, 36, "uint") & 0x10000000)  ; minimized or not visible
   {
      if (wPrev != 0)
      {
         WinHide, ahk_id %hGui%
         wPrev := 0
      }
      sleep 10
      continue
   }
   x := NumGet(WINDOWINFO, 20, "int")
   y := NumGet(WINDOWINFO, 8, "int")
   w := NumGet(WINDOWINFO, 28, "int") - x
   h := NumGet(WINDOWINFO, 32, "int") - y
   if (hGui = hGui1) and ((NumGet(WINDOWINFO, 44, "uint") = 1) or (DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr") = hTarget))   ; activated
   {
      hGui := hGui2
      hChildMagnifier := hChildMagnifier2
      WinMove, ahk_id %hGui%,, x, y, w, h
      WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
      WinShow, ahk_id %hChildMagnifier%
      WinShow, ahk_id %hGui%
      hideGui := hGui1
   }
   else if (hGui = hGui2) and (NumGet(WINDOWINFO, 44, "uint") != 1) and ((hr := DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr")) != hTarget) and hr   ; deactivated
   {
      hGui := hGui1
      hChildMagnifier := hChildMagnifier1
      WinMove, ahk_id %hGui%,, x, y, w, h
      WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
      WinShow, ahk_id %hChildMagnifier%
      DllCall("SetWindowPos", "ptr", hGui, "ptr", hTarget, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
      DllCall("SetWindowPos", "ptr", hTarget, "ptr", 1, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)   ; some windows can not be z-positioned before setting them to bottom
      DllCall("SetWindowPos", "ptr", hTarget, "ptr", hGui, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
      hideGui := hGui2 
   }
   else if (x != xPrev) or (y != yPrev) or (w != wPrev) or (h != hPrev)   ; location changed
   {
      WinMove, ahk_id %hGui%,, x, y, w, h
      WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
      WinShow, ahk_id %hChildMagnifier%
      WinShow, ahk_id %hGui%
   }
   if (A_PtrSize = 8)
   {
      VarSetCapacity(RECT, 16, 0)
      NumPut(x, RECT, 0, "int")
      NumPut(y, RECT, 4, "int")
      NumPut(w, RECT, 8, "int")
      NumPut(h, RECT, 12, "int")
      DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "ptr", &RECT)
   }
   else
      DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "int", x, "int", y, "int", w, "int", h)
   xPrev := x, yPrev := y, wPrev := w, hPrev := h
   if hideGui
   {
      WinHide, ahk_id %hideGui%
      hideGui := ""
   }
}
return

Uninitialize:
if (hGui != "")
   DllCall("magnification.dll\MagUninitialize")
ExitApp
unnamed9710
Posts: 6
Joined: 02 Jun 2023, 08:55

Re: Invert window color with magnification + UIACCESS

23 Aug 2023, 05:02

Thank you for your amazing script. But I have a problem. When I invert a second window, the first window is back to normal. Basically, it can only invert one window
ninjspks
Posts: 8
Joined: 01 Nov 2020, 22:30
Contact:

Re: Invert window color with magnification + UIACCESS

23 Sep 2023, 11:19

unnamed9710 wrote:
23 Aug 2023, 05:02
Thank you for your amazing script. But I have a problem. When I invert a second window, the first window is back to normal. Basically, it can only invert one window
I couldnt manage to decompose the routines into a class, so what i did was manage instances of the script wth a master script as follows :

Code: Select all

#SingleInstance force
global invertedWindows:=[]
, invertedpids:=[]
onexit,closeall
return,

F12::Invert(winExist("a"))

Invert(hWnd) {
	loop
		if invertedWindows[a_index] {
			if(hwnd=invertedWindows[a_index]) {
				invertedWindows.delete(a_index)
				msgbox % a_index " was inverted- restoring"
				PostMessage,0x0111,65307,,,% "ahk_pid " invertedpids[a_index]
				return,
			}
		} else {
			invertedWindows[a_index]:= hWnd
			run,% "C:\Program Files\Autohotkey13602\AutoHotkeyU64.exe c:\Script\AHK\yinvertfunc.ahk " . hWnd,,,pid
			invertedpids[a_index]:= pid
			break,
		}
}

closeall:
for,pid in invertedpids
	PostMessage,0x0111,65307,,,% "ahk_pid " invertedpids[pid]
exitapp,
this calls the inversion script, excuse my naming above c:\Script\AHK\yinvertfunc.ahk or simillar

inversion script:

Code: Select all

if(!A_args[1])
	exitapp,
else,hTarget:= A_args[1]

Gui, +HWNDhGui +AlwaysOnTop
DllCall("GetWindowBand", "ptr", hGui, "uint*", band)
Gui,Destroy
hGui:= ""
if(band = 1) {
	If(A_PtrSize=8)
		RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU64_UIA.exe" "%A_ScriptFullPath%"
	Else,If(A_IsUnicode)
		RunWait,"C:\Program Files\AutoHotkey\AutoHotkeyU32_UIA.exe" "%A_ScriptFullPath%"
	Else,RunWait,"C:\Program Files\AutoHotkey\AutoHotkeyA32_UIA.exe" "%A_ScriptFullPath%"
}
#SingleInstance off
#MaxThreadsPerHotkey 2
DetectHiddenWindows, On
SetBatchLines -1
SetWinDelay -1
OnExit, Uninitialize
if(hTarget=hTargetPrev) {
	hTargetPrev:= "",	count--
	return
} count++
hTargetPrev:= hTarget
if(hGui = "") {
   DllCall("LoadLibrary", "str", "magnification.dll")
   DllCall("magnification.dll\MagInitialize")
   Matrix := "-1|0|0|0|0|"
           . "0|-1|0|0|0|"
           . "0|0|-1|0|0|"
           . "0|0|0|1|0|"
           . "1|1|1|0|1"
   VarSetCapacity(MAGCOLOREFFECT, 100, 0)
   Loop, Parse, Matrix, |
      NumPut(A_LoopField, MAGCOLOREFFECT, (A_Index - 1) * 4, "float")
   loop 2
   {
      if (A_Index = 2)
         Gui, %A_Index%: +AlwaysOnTop   ; needed for ZBID_UIACCESS
      Gui, %A_Index%: +HWNDhGui%A_Index% -DPIScale +toolwindow -Caption +E0x02000000 +E0x00080000 +E0x20 ;  WS_EX_COMPOSITED := E0x02000000  WS_EX_LAYERED := E0x00080000  WS_EX_CLICKTHROUGH := E0x20
      hChildMagnifier%A_Index% := DllCall("CreateWindowEx", "uint", 0, "str", "Magnifier", "str", "MagnifierWindow", "uint", WS_CHILD := 0x40000000, "int", 0, "int", 0, "int", 0, "int", 0, "ptr", hGui%A_Index%, "uint", 0, "ptr", DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr" : ""), "ptr", hGui%A_Index%, "int", GWL_HINSTANCE := -6 , "ptr"), "uint", 0, "ptr")
      DllCall("magnification.dll\MagSetColorEffect", "ptr", hChildMagnifier%A_Index%, "ptr", &MAGCOLOREFFECT)
   }
}
Gui, 2: Show, NA   ; needed for removing flickering
hGui := hGui1
hChildMagnifier := hChildMagnifier1
loop
{
   if (count != 1)   ; target window changed
   {
      if (count = 2)
         count--
      WinHide, ahk_id %hGui%
      return
   }
   VarSetCapacity(WINDOWINFO, 60, 0)
   if (DllCall("GetWindowInfo", "ptr", hTarget, "ptr", &WINDOWINFO) = 0) and (A_LastError = 1400)   ; destroyed
   {
      count--
      WinHide, ahk_id %hGui%
      return
   }
   if (NumGet(WINDOWINFO, 36, "uint") & 0x20000000) or !(NumGet(WINDOWINFO, 36, "uint") & 0x10000000)  ; minimized or not visible
   {
      if (wPrev != 0)
      {
         WinHide, ahk_id %hGui%
         wPrev := 0
      }
      sleep 10
      continue
   }
   x := NumGet(WINDOWINFO, 20, "int")
   y := NumGet(WINDOWINFO, 8, "int")
   w := NumGet(WINDOWINFO, 28, "int") - x
   h := NumGet(WINDOWINFO, 32, "int") - y
   if (hGui = hGui1) and ((NumGet(WINDOWINFO, 44, "uint") = 1) or (DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr") = hTarget))   ; activated
   {
      hGui := hGui2
      hChildMagnifier := hChildMagnifier2
      WinMove, ahk_id %hGui%,, x, y, w, h
      WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
      WinShow, ahk_id %hChildMagnifier%
      WinShow, ahk_id %hGui%
      hideGui := hGui1
   }
   else if (hGui = hGui2) and (NumGet(WINDOWINFO, 44, "uint") != 1) and ((hr := DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr")) != hTarget) and hr   ; deactivated
   {
      hGui := hGui1
      hChildMagnifier := hChildMagnifier1
      WinMove, ahk_id %hGui%,, x, y, w, h
      WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
      WinShow, ahk_id %hChildMagnifier%
      DllCall("SetWindowPos", "ptr", hGui, "ptr", hTarget, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
      DllCall("SetWindowPos", "ptr", hTarget, "ptr", 1, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)   ; some windows can not be z-positioned before setting them to bottom
      DllCall("SetWindowPos", "ptr", hTarget, "ptr", hGui, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
      hideGui := hGui2 
   }
   else if (x != xPrev) or (y != yPrev) or (w != wPrev) or (h != hPrev)   ; location changed
   {
      WinMove, ahk_id %hGui%,, x, y, w, h
      WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
      WinShow, ahk_id %hChildMagnifier%
      WinShow, ahk_id %hGui%
   }
   if (A_PtrSize = 8)
   {
      VarSetCapacity(RECT, 16, 0)
      NumPut(x, RECT, 0, "int")
      NumPut(y, RECT, 4, "int")
      NumPut(w, RECT, 8, "int")
      NumPut(h, RECT, 12, "int")
      DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "ptr", &RECT)
   }
   else
      DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "int", x, "int", y, "int", w, "int", h)
   xPrev := x, yPrev := y, wPrev := w, hPrev := h
   if hideGui
   {
      WinHide, ahk_id %hideGui%
      hideGui := ""
   }
}
return

Uninitialize:
if (hGui != "")
   DllCall("magnification.dll\MagUninitialize")
ExitApp,
now f12 toggles a windows inverted state per window with a process per inversion which are all closed at exit.
unnamed9710
Posts: 6
Joined: 02 Jun 2023, 08:55

Re: Invert window color with magnification + UIACCESS

25 Sep 2023, 11:39

Wow I've been making good use of this. It seems that sometimes when I close a window without reverting back to normal first, the icon remains. Can you please add process name for each icon? And these extra icons doesn't close when I close the manager icon.
fmnijk
Posts: 2
Joined: 19 Oct 2023, 09:40

Re: Invert window color with magnification + UIACCESS

19 Oct 2023, 09:48

May I ask how to have multiple Matrix values option and switch between them via different hotkeys?
I would like to know How to make new Matrix value take effect.

Code: Select all

F12::
^F12::
Mode := A_ThisHotkey = "F12" ? "DarkModeA" : "DarkModeB"
if(Mode = "DarkModeA")
{
    Matrix := "-1|0|0|0|0|"
            . "0|-1|0|0|0|"
            . "0|0|-1|0|0|"
            . "0|0|0|1|0|"
            . "1|1|1|0|1"
}
else
{
    Matrix := "-0.8|0|0|0|0|"
            . "0|-0.8|0|0|0|"
            . "0|0|-0.8|0|0|"
            . "0|0|0|1|0|"
            . "1|1|1|0|1"
}
; How to make new Matrix value take effect?
KnIfER
Posts: 12
Joined: 27 Nov 2023, 06:10

Re: Invert window color with magnification + UIACCESS

14 Mar 2024, 04:02

This is an interesting and tricky script. It is helpful for consistent color .

Some application has no day theme or night theme (for example Aurora.exe) , just imagine a mixture of bright window and dark window, nightmare!

This script makes the color consistent. I updated it to using class and ——

1. Single script for multiple windows.
2. Escape taskbar height.
3. Automatically turn on inverting color according to group! (for example Aurora.exe)

Code: Select all


global Inverters := []
global WINDOWINFO

GroupAdd, auto_invert_gp, ahk_exe Aurora.exe
    
VarSetCapacity(WINDOWINFO, 60, 0)

Gui, +HWNDhGui +AlwaysOnTop
DllCall("GetWindowBand", "ptr", hGui, "uint*", band)
Gui, Destroy
hGui := ""
if (band = 1)
{
   If (A_PtrSize = 8)
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU64_UIA.exe" "%A_ScriptFullPath%"
   Else If A_IsUnicode
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU32_UIA.exe" "%A_ScriptFullPath%"
   Else
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyA32_UIA.exe" "%A_ScriptFullPath%"
}
#SingleInstance Force
#MaxThreadsPerHotkey 2
DetectHiddenWindows, On
SetBatchLines -1
SetWinDelay -1

OnExit, Uninitialize


inGroup(GroupName, WinTitle = "A", WinText = "", ExcludeTitle = "", ExcludeText = "")
{
    WinGet, GroupIDs, List, ahk_group %GroupName%
    WinGet, Window, ID, %WinTitle%, %WinText%, %ExcludeTitle%, %ExcludeText%
    Loop, %GroupIDs%
    {
        if (GroupIDs%A_Index% = Window)
        {
            ;found match
            return Window
        }
    }
    return false
}


class Inverter
{
    hTarget := ""
    hGui := ""
    hGui1 := ""
    hGui2 := ""
    hChildMagnifier := ""
    hChildMagnifier1 := ""
    hChildMagnifier2 := ""
    xPrev := ""
    yPrev := ""
    wPrev := ""
    hPrev := ""
    stopped := 0
    
    __New(hTarget)
    {
        this.hTarget := hTarget
        DllCall("LoadLibrary", "str", "magnification.dll")
        DllCall("magnification.dll\MagInitialize")
        Matrix := "-1|0|0|0|0|"
                . "0|-1|0|0|0|"
                . "0|0|-1|0|0|"
                . "0|0|0|1|0|"
                . "1|1|1|0|1"
        VarSetCapacity(MAGCOLOREFFECT, 100, 0)
        Loop, Parse, Matrix, |
            NumPut(A_LoopField, MAGCOLOREFFECT, (A_Index - 1) * 4, "float")
        loop 2
        {
            gid := hTarget "_" A_Index
            if (A_Index = 2)
                Gui, %gid%: +AlwaysOnTop   ; needed for ZBID_UIACCESS
            Gui, %gid%: +HWNDhGui%A_Index% -DPIScale +toolwindow -Caption +E0x02000000 +E0x00080000 +E0x20 ;  WS_EX_COMPOSITED := E0x02000000  WS_EX_LAYERED := E0x00080000  WS_EX_CLICKTHROUGH := E0x20
            hChildMagnifier%A_Index% := DllCall("CreateWindowEx", "uint", 0, "str", "Magnifier", "str", "MagnifierWindow", "uint", WS_CHILD := 0x40000000, "int", 0, "int", 0, "int", 0, "int", 0, "ptr", hGui%A_Index%, "uint", 0, "ptr", DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr" : ""), "ptr", hGui%A_Index%, "int", GWL_HINSTANCE := -6 , "ptr"), "uint", 0, "ptr")
            DllCall("magnification.dll\MagSetColorEffect", "ptr", hChildMagnifier%A_Index%, "ptr", &MAGCOLOREFFECT)
        }
        gid := hTarget "_" 2
        Gui, %gid%: Show, NA   ; needed for removing flickering
        hGui := hGui1
        hChildMagnifier := hChildMagnifier1
        this.hGui := hGui 
        this.hGui1 := hGui1
        this.hGui2 := hGui2 
        this.hChildMagnifier := hChildMagnifier
        this.hChildMagnifier1 := hChildMagnifier1
        this.hChildMagnifier2 := hChildMagnifier2
        ; xx(this.hGui)
        return this 
    }
    
    stop() {
        if(!this.stopped) {
            this.stopped := 1
            hGui := this.hGui
            WinHide, ahk_id %hGui%
            hGui := this.hGui1
            WinHide, ahk_id %hGui%
            hGui := this.hGui2
            WinHide, ahk_id %hGui%
            
            hChildMagnifier := this.hChildMagnifier
            WinHide, ahk_id %hChildMagnifier%
            hChildMagnifier := this.hChildMagnifier1
            WinHide, ahk_id %hChildMagnifier%
            hChildMagnifier := this.hChildMagnifier2
            WinHide, ahk_id %hChildMagnifier%
        }
    }

    doit()
    {
        hTarget := this.hTarget
        hGui := this.hGui
        hGui1 := this.hGui1
        hGui2 := this.hGui2
        hChildMagnifier := this.hChildMagnifier
        hChildMagnifier1 := this.hChildMagnifier1
        hChildMagnifier2 := this.hChildMagnifier2
        ; VarSetCapacity(WINDOWINFO, 60, 0)
        if (this.stopped or DllCall("GetWindowInfo", "ptr", hTarget, "ptr", &WINDOWINFO) = 0) and (A_LastError = 1400)   
        {
            ; xx("destroyed")
            return
        }
        if (NumGet(WINDOWINFO, 36, "uint") & 0x20000000) or !(NumGet(WINDOWINFO, 36, "uint") & 0x10000000) 
        {
            ; minimized or not visible
            if (this.wPrev != 0)
            {
                WinHide, ahk_id %hGui%
                this.wPrev := 0
            }
            sleep 10
            return 1
        }
        x := NumGet(WINDOWINFO, 20, "int")
        y := NumGet(WINDOWINFO, 8, "int")
        w := NumGet(WINDOWINFO, 28, "int") - x
        h := NumGet(WINDOWINFO, 32, "int") - y
        move := 0
        if (hGui = hGui1) and ((NumGet(WINDOWINFO, 44, "uint") = 1) or (DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr") = hTarget))   
        {
            ; xx("activated")
            hGui := hGui2
            hChildMagnifier := hChildMagnifier2
            move := 1
            hideGui := hGui1
        }
        else if (hGui = hGui2) and (NumGet(WINDOWINFO, 44, "uint") != 1) and ((hr := DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr")) != hTarget) and hr  
        {
            ; deactivated
            hGui := hGui1
            hChildMagnifier := hChildMagnifier1
            WinMove, ahk_id %hGui%,, x, y, w, h
            WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
            WinShow, ahk_id %hChildMagnifier%
            DllCall("SetWindowPos", "ptr", hGui, "ptr", hTarget, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
            DllCall("SetWindowPos", "ptr", hTarget, "ptr", 1, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)   ; some windows can not be z-positioned before setting them to bottom
            DllCall("SetWindowPos", "ptr", hTarget, "ptr", hGui, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
            hideGui := hGui2 
        }
        else if (x != this.xPrev) or (y != this.yPrev) or (w != this.wPrev) or (h != this.hPrev)  
        {
            ; location changed
            move := 1
        }
        if(move) {
            WinGetPos,,,_w_, _h_, ahk_class Shell_TrayWnd
            hs := A_ScreenHeight-_h_
            if(y+h>hs) {
                h := hs-y ; escape taskbar
            }
            WinMove, ahk_id %hGui%,, x, y, w, h
            WinMove, ahk_id %hChildMagnifier%,, 0, 0, w, h
            WinShow, ahk_id %hChildMagnifier%
            WinShow, ahk_id %hGui%
        }
        if (A_PtrSize = 8)
        {
            VarSetCapacity(RECT, 16, 0)
            NumPut(x, RECT, 0, "int")
            NumPut(y, RECT, 4, "int")
            NumPut(w, RECT, 8, "int")
            NumPut(h, RECT, 12, "int")
            DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "ptr", &RECT)
        }
        else
            DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "int", x, "int", y, "int", w, "int", h)
        this.xPrev := x, this.yPrev := y, this.wPrev := w, this.hPrev := h
        this.hChildMagnifier := hChildMagnifier
        this.hGui := hGui
        if hideGui
        {
            WinHide, ahk_id %hideGui%
            hideGui := ""
        }
        return 1
    }
}

; Automatically turn on inversion filter
loop 
{	
	WinGet, _id, ID, A
	if(inGroup("auto_invert_gp")) {
        hTarget := _id
        array := Inverters
        For index, tmp in array {
            if(tmp.hTarget=hTarget) {
                return
            }
        }
        ToggleInversion()
	}
	WinWaitNotActive, ahk_id %_id%
}

ToggleInversion() {
    hTarget := WinExist("A")
	; GroupAdd, invert_gp, ahk_id %hTarget%
    array := Inverters
	For index, tmp in array {
		if(tmp.hTarget=hTarget) {
            tmp.stop()
            array.removeAt(index)
            return
        }
	}
    tmp := new Inverter(hTarget)
    array.push(tmp)
    if(array.Length()==1) {
        loop {
            For index, tmp in array {
                ret := tmp.doit()
                if(!ret) {
                    tmp.stop()
                    array.removeAt(index)
                }
            }
            ; xx(tmp.hTarget " " array.Length() " " hGui)
            if(array.Length()==0)
                break
        }
    }
}

F11::
    ToggleInversion()
return

Uninitialize:
    if (hGui != "")
    DllCall("magnification.dll\MagUninitialize")
ExitApp



the code is dirty about variables and fields. I'm not familiar with python-like scripting. is
this.
necessary?
unnamed9710
Posts: 6
Joined: 02 Jun 2023, 08:55

Re: Invert window color with magnification + UIACCESS

21 Mar 2024, 01:46

@KnIfER
I tried running your code but it doesn't work. Pressing f11 makes that screen flash between dark and light mode infinitely
KnIfER
Posts: 12
Joined: 27 Nov 2023, 06:10

Re: Invert window color with magnification + UIACCESS

21 Mar 2024, 19:40

@unnamed9710 at least it runs, good news..

what's the version of windows? It works will on my computer (win10)

how about the original script?
unnamed9710
Posts: 6
Joined: 02 Jun 2023, 08:55

Re: Invert window color with magnification + UIACCESS

24 Mar 2024, 20:40

@KnIfER
Windows 10 Version 21H2 (Build 19044.3086)
The original script works
charlie89
Posts: 1
Joined: 28 Mar 2024, 15:38
Contact:

Re: Invert window color with magnification + UIACCESS

28 Mar 2024, 16:02

Huge thanks for the script @KnIfER, it saves me from so much eye strain from bright white windows :D

I ported it to AutoHotkey v2, added some default windows programs and completely reworked the automatic activation so it works on multiple windows at the same time.
When you activate it for all windows with ahk_class #32770 then many of the old windows dialogs (like Windows Explorer properties, Run As, ...) can be shown in dark mode, but you need to specifically exclude the Windows Open/Save dialog as those are already in modern windows style.

Code: Select all

#Requires AutoHotkey v2.0

; This script creates a dark mode for specific windows by inverting their colors.
; It uses the Windows Magnifier in the background for the color inverting, but it only inverts just the rectangle in place
; of the specific windows, NOT the whole screen like the Magnifier applicaion does. This is possible through DLL calls.
; Big thanks to the original source at https://www.autohotkey.com/boards/viewtopic.php?p=563023#p563023.

; Requirements:
;   - AutoHotkey needs to be installed in C:\Program Files (or use the workaround from https://www.reddit.com/r/AutoHotkey/comments/16ux144/ui_access_without_reinstalling_in_program_files_v2/).
;   - In the 'Launch Settings' of 'AutoHotkey Dash' you need to enable 'UI Access'.

; Usage:
; Use Win+i to invert a window manually or add it to the auto_invert_gp group to invert it automatically.

#SingleInstance Force
if (!A_IsCompiled && !InStr(A_AhkPath, "_UIA")) {
	Run "*uiAccess " A_ScriptFullPath
	ExitApp
}

SetTitleMatchMode "RegEx"
; Add Programs for automatic dark mode here:
GroupAdd "auto_invert_gp", "ahk_class #32770", , "Find|Öffnen|Speichern unter"  ; Windows Explorer properties window and many others (but not the file open/save dialog that is already dark)
GroupAdd "auto_invert_gp", "ahk_class OperationStatusWindow" ; Windows Explorer dialogs
GroupAdd "auto_invert_gp", "ahk_exe AutoHotkeyUX.exe"
GroupAdd "auto_invert_gp", "ahk_exe hh.exe"		 ; Windows Help
GroupAdd "auto_invert_gp", "ahk_exe mmc.exe"
GroupAdd "auto_invert_gp", "ahk_exe procexp64.exe"  ; Process Explorer
GroupAdd "auto_invert_gp", "ahk_exe regedit.exe"
GroupAdd "auto_invert_gp", "ahk_exe Taskmgr.exe"
GroupAdd "auto_invert_gp", "ahk_exe WinRAR.exe"

; Add Programs where automatic dark mode should never be applied here:
; This is mostly because they have dialogs that match ahk_class #32770 but are already in dark mode
AutoInvIgnProcName:= ["notepad++.exe"]


#MaxThreadsPerHotkey 2
DetectHiddenWindows true
; SetBatchLines -1
SetWinDelay -1
OnExit Uninitialize

global Inverters := []
global WINDOWINFO
global pTarget := 0

inGroup(GroupName, WinTitle := "A", WinText := "", ExcludeTitle := "", ExcludeText := "")
{
	GroupIDs := WinGetList("ahk_group " GroupName)
	Window := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText)
	Loop GroupIDs.Length
	{
		if (GroupIDs[A_Index] = Window)
		{
			;found match
			return Window
		}
	}
	return false
}


class Inverter
{
	hTarget := ""
	hGui := ""
	hGui1 := ""
	hGui2 := ""
	hChildMagnifier := ""
	hChildMagnifier1 := ""
	hChildMagnifier2 := ""
	xPrev := ""
	yPrev := ""
	wPrev := ""
	hPrev := ""
	stopped := 0
	
	__New(hTarget)
	{
		DetectHiddenWindows true
		this.hTarget := hTarget
		DllCall("LoadLibrary", "str", "magnification.dll")
		DllCall("magnification.dll\MagInitialize")
		Matrix := "-1|0|0|0|0|"
				. "0|-1|0|0|0|"
				. "0|0|-1|0|0|"
				. "0|0|0|1|0|"
				. "1|1|1|0|1"
		MAGCOLOREFFECT := Buffer(100, 0)
		Loop Parse Matrix, "|"
			NumPut("Float", A_LoopField, MAGCOLOREFFECT, (A_Index - 1) * 4)
		Loop 2
		{
			gid := hTarget "_" A_Index
			MyGui := Gui(, gid,)
			if (A_Index = 2)
				MyGui.Opt("+AlwaysOnTop")   ; needed for ZBID_UIACCESS
			; +HWNDhGui%A_Index%
			MyGui.Opt("-DPIScale +toolwindow -Caption +E0x02000000 +E0x00080000 +E0x20") ;  WS_EX_COMPOSITED := E0x02000000  WS_EX_LAYERED := E0x00080000  WS_EX_CLICKTHROUGH := E0x20
			MyGui.Show("NA")
			this.hGui%A_Index%:= MyGui.Hwnd
			this.hChildMagnifier%A_Index% := DllCall("CreateWindowEx", "uint", 0, "str", "Magnifier", "str", "MagnifierWindow", "uint", WS_CHILD := 0x40000000, "int", 0, "int", 0, "int", 0, "int", 0, "ptr", this.hGui%A_Index%, "uint", 0, "ptr", DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr" : ""), "ptr", this.hGui%A_Index%, "int", GWL_HINSTANCE := -6 , "ptr"), "uint", 0, "ptr")
			DllCall("magnification.dll\MagSetColorEffect", "ptr", this.hChildMagnifier%A_Index%, "ptr", MAGCOLOREFFECT)
		}
		gid := hTarget "_" 2
		this.hGui := this.hGui1
		this.hChildMagnifier := this.hChildMagnifier1
		return this 
	}
	
	stop() {
		DetectHiddenWindows true
		if(!this.stopped) {
			this.stopped := 1
			hGui := this.hGui
			WinHide "ahk_id " hGui
			hGui := this.hGui1
			WinHide "ahk_id " hGui
			hGui := this.hGui2
			WinHide "ahk_id " hGui
			
			hChildMagnifier := this.hChildMagnifier
			WinHide "ahk_id " hChildMagnifier
			hChildMagnifier := this.hChildMagnifier1
			WinHide "ahk_id " hChildMagnifier
			hChildMagnifier := this.hChildMagnifier2
			WinHide "ahk_id " hChildMagnifier
		}
	}
	
	start() {
		DetectHiddenWindows true
		if(this.stopped) {
			this.stopped := 0
			
			hChildMagnifier := this.hChildMagnifier
			WinShow "ahk_id " hChildMagnifier
			
			hGui := this.hGui
			WinShow "ahk_id " hGui	
		}
	}

	doit()
	{
		DetectHiddenWindows true
		hTarget := this.hTarget
		hGui := this.hGui
		hGui1 := this.hGui1
		hGui2 := this.hGui2
		hChildMagnifier := this.hChildMagnifier
		hChildMagnifier1 := this.hChildMagnifier1
		hChildMagnifier2 := this.hChildMagnifier2
		hideGui := ""
		
		WINDOWINFO := Buffer(60, 0)
		if (this.stopped or DllCall("GetWindowInfo", "ptr", hTarget, "ptr", WINDOWINFO) = 0) and (A_LastError = 1400)   
		{
			; xx("destroyed")
			return
		}
		if (NumGet(WINDOWINFO, 36, "uint") & 0x20000000) or !(NumGet(WINDOWINFO, 36, "uint") & 0x10000000) 
		{
			; minimized or not visible
			if (this.wPrev != 0)
			{
				WinHide "ahk_id " hGui
				this.wPrev := 0
			}
			sleep 10
			return 1
		}
		x := NumGet(WINDOWINFO, 20, "int")
		y := NumGet(WINDOWINFO, 8, "int")
		w := NumGet(WINDOWINFO, 28, "int") - x
		h := NumGet(WINDOWINFO, 32, "int") - y
		move := 0
		if (hGui = hGui1) and ((NumGet(WINDOWINFO, 44, "uint") = 1) or (DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr") = hTarget))   
		{
			; xx("activated")
			hGui := hGui2
			hChildMagnifier := hChildMagnifier2
			move := 1
			hideGui := hGui1
		}
		else if (hGui = hGui2) and (NumGet(WINDOWINFO, 44, "uint") != 1) and ((hr := DllCall("GetAncestor", "ptr", WinExist("A"), "uint", GA_ROOTOWNER := 3, "ptr")) != hTarget) and hr  
		{
			; deactivated
			hGui := hGui1
			hChildMagnifier := hChildMagnifier1
			WinMove x, y, w, h, "ahk_id " hGui
			WinMove 0, 0, w, h, "ahk_id " hChildMagnifier
			WinShow "ahk_id " hChildMagnifier
			DllCall("SetWindowPos", "ptr", hGui, "ptr", hTarget, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
			DllCall("SetWindowPos", "ptr", hTarget, "ptr", 1, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)   ; some windows can not be z-positioned before setting them to bottom
			DllCall("SetWindowPos", "ptr", hTarget, "ptr", hGui, "int", 0, "int", 0, "int", 0, "int", 0, "uint", 0x0040|0x0010|0x001|0x002)
			hideGui := hGui2 
		}
		else if (x != this.xPrev) or (y != this.yPrev) or (w != this.wPrev) or (h != this.hPrev)  
		{
			; location changed
			move := 1
		}
		if(move) {
			WinGetPos ,,&_w_, &_h_, "ahk_class Shell_TrayWnd"
			hs := A_ScreenHeight-_h_
			if(y+h>hs) {
				h := hs-y ; escape taskbar
			}
			WinMove x, y, w, h, "ahk_id " hGui
			WinMove 0, 0, w, h, "ahk_id " hChildMagnifier
			WinShow "ahk_id " hChildMagnifier
			WinShow "ahk_id " hGui
		}
		if (A_PtrSize = 8)
		{
			RECT := Buffer(16, 0)
			NumPut("int", x, RECT, 0)
			NumPut("int", y, RECT, 4)
			NumPut("int", w, RECT, 8)
			NumPut("int", h, RECT, 12)
			DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "ptr", RECT)
		}
		else
			DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "int", x, "int", y, "int", w, "int", h)
		this.xPrev := x, this.yPrev := y, this.wPrev := w, this.hPrev := h
		this.hChildMagnifier := hChildMagnifier
		this.hGui := hGui
		if hideGui
		{
			WinHide "ahk_id " hideGui
			hideGui := ""
		}
		return 1
	}
}

; Automatically turn on inversion filter
loop 
{	
	DetectHiddenWindows false ;would otherwise find many other windows

	aTarget := WinExist("A")
	if (aTarget != pTarget) { ; other window focused, check if it should be automatically inverted
		pTarget:= aTarget
		GroupIDs := WinGetList("ahk_group auto_invert_gp")

		;Concat := ""
		;For Each, Element In GroupIDs {
		;	If (Concat != "") {
		;		Concat .= "`n"
		;	}
		;	Concat .= Element ": " WinGetProcessName(Element) ;WinGetTitle(Element)
		;}
		;MsgBox Concat
	
		Loop GroupIDs.Length
		{
			hTarget := GroupIDs[A_Index]
			if (hTarget = aTarget) { ;currently focused window in auto_invert_gp group
				found:= 0
				For index, tmp in Inverters {
					if(tmp.hTarget = hTarget) {
						found:= 1
						Break
					}
				}
				if (found = 0) {
					;MsgBox "Invert " hTarget " " WinGetProcessName(hTarget)
					hTargetName:= WinGetProcessName(hTarget)
					ignore:= 0
					Loop AutoInvIgnProcName.Length
					{
						if AutoInvIgnProcName[A_Index] = hTargetName {
							ignore:= 1
							Break
						}
					}
					if (ignore = 0) {
						ToggleInversion(hTarget)
					}
				}
				Break
			}
		}
	}
	
	; Refresh all inverted windows
	For index, tmp in Inverters {
		if(!tmp.stopped) {
			ret := tmp.doit()
			if(!ret) {
				tmp.stop()
				Inverters.removeAt(index)
				Break
			}
		}
	}
}

ToggleInversion(hTarget) {
	found:= 0
	For index, tmp in Inverters {
		if(tmp.hTarget=hTarget) {
			found:= 1
			if(tmp.stopped) {
				tmp.start()
			}
			else {
				tmp.stop()
			}
			Break
		}
	}
	if (found = 0) {
		tmp := Inverter(hTarget)
		Inverters.push(tmp)
	}
}


#i:: ;Win+i
{
	ToggleInversion(WinExist("A"))
}

Uninitialize(ExitReason, ExitCode)
{
  DllCall("magnification.dll\MagUninitialize")
  ExitApp
}
(or see the gist at https://gist.github.com/charlie89/5670d46c90abf3351ed012b2afd926ca)

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 172 guests