1 (изменено: Malcev, 2021-08-31 16:00:23)

Тема: AHK: Инвертирование цвета окна с magnification + UIACCESS

Для Win 8+.
Инвертировать/снять инвертирование - активировать окно и нажать f11.

If !RegExMatch(DllCall("GetCommandLine", "Str"), " /restart(?!\S)")
{
   If (A_PtrSize = 8)
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU64_UIA.exe" /restart "%A_ScriptFullPath%"
   Else If A_IsUnicode
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU32_UIA.exe" /restart "%A_ScriptFullPath%"
   Else
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyA32_UIA.exe" /restart "%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

2

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Этот код у меня вызывает перманентное мелькание, если активное окно изначально развёрнуто в полный экран. Вместо цикла я бы использовал хук, будет быстрее реагировать на изменение размеров окна, и меньше грузить процессор (сейчас на 10-15%).
И вместо CreateWindowInBand не проще сделать целевое окно окном-владельцем?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

3

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Этот код у меня вызывает перманентное мелькание, если активное окно изначально развёрнуто в полный экран.

Я такого не обнаружил, но пока тестировал получил мелькание при перезапуске скрипта.
Вроде поправил.

teadrinker пишет:

Вместо цикла я бы использовал хук, будет быстрее реагировать на изменение размеров окна, и меньше грузить процессор (сейчас на 10-15%).

Можно и хук использовать, только процессор это не разгрузит, а запарок будет больше, так как надо отслеживать не только изменения, но и z-order, чтобы менять гуи.
Так-как первый гуи (ZBID_DESKTOP) создается для случаев, когда целевое окно перекрывается другими окнами, второй же создается для случаев когда целевое окно активно и в нем могут создаваться дополнительные дочерние окна, дабы избежать мельканий создаем гуи с ZBID_UIACCESS.
Вот загрузка процессора без отслеживания измененя размеров:

if !RegExMatch(DllCall("GetCommandLine", "str"), " /restart(?!\S)")
{
   if A_Is64bitOS
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU64_UIA.exe" /restart "%A_ScriptFullPath%"
   else
      RunWait "C:\Program Files\AutoHotkey\AutoHotkeyU32_UIA.exe" /restart "%A_ScriptFullPath%"
}
Global hPic
#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
   {
      Gui, %A_Index%: +HWNDhGui%A_Index% -DPIScale +toolwindow -Caption +E0x02000000 +E0x00080000 +E0x20 ;  WS_EX_COMPOSITED := E0x02000000  WS_EX_LAYERED := E0x00080000
      Gui, %A_Index%: Margin, 0,0
      Gui, %A_Index%: Add, text, w1 h1 0xE hwndhPic   ; SS_BITMAP
      if (A_Index  = 2)
      {
         Gui, %A_Index%: +AlwaysOnTop
         Gui, %A_Index%: Show, NA
      }
      hChildMagnifier%A_Index% := DllCall("CreateWindowInBand", "uint", 0, "str", "Magnifier", "str", "MagnifierWindow", "uint", WS_CHILD := 0x40000000, "int", 0, "int", 0, "int", 1, "int", 1, "ptr", hGui%A_Index%, "uint", 0, "ptr", DllCall("GetWindowLong" (A_PtrSize=8 ? "Ptr" : ""), "ptr", hGui%A_Index%, "int", GWL_HINSTANCE := -6 , "ptr"), "uint", 0, "uint", A_Index, "ptr")   ; ZBID_DESKTOP ZBID_UIACCESS
      DllCall("magnification.dll\MagSetColorEffect", "ptr", hChildMagnifier%A_Index%, "ptr", &MAGCOLOREFFECT)
      DllCall("magnification.dll\MagSetImageScalingCallback", "ptr", hChildMagnifier%A_Index%, "ptr", RegisterCallback("MagImageScalingCallback"))
   }
}
hGui := hGui2
hChildMagnifier := hChildMagnifier2
WinMove, ahk_id %hGui%,, 0, 0, A_ScreenWidth, A_ScreenHeight
WinMove, ahk_id %hChildMagnifier%,, 0, 0, A_ScreenWidth, A_ScreenHeight
WinShow ahk_id %hGui%
WinShow, ahk_id %hChildMagnifier%
loop
{
   if (A_PtrSize = 8)
   {
      VarSetCapacity(RECT, 16, 0)
      NumPut(0, RECT, 0, "int")
      NumPut(0, RECT, 4, "int")
      NumPut(A_ScreenWidth, RECT, 8, "int")
      NumPut(A_ScreenHeight, RECT, 12, "int")
      DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "ptr", &RECT)
   }
}
return

MagImageScalingCallback(hwnd, srcdata, srcheader, destdata, destheader, unclipped, clipped, dirty)
{
   Static CBM_INIT := 6, DIB_RGB_COLORS := 0, STM_SETIMAGE := 0x172, IMAGE_BITMAP := 0x0, _ := VarSetCapacity(BITMAPV5HEADER, 124, 0), __ := VarSetCapacity(BITMAPINFO, 44, 0)
   if (A_PtrSize = 8)
   {
      bV5Width := NumGet(srcheader + 0, 0, "uint")
      bV5Height := NumGet(srcheader + 0, 4, "uint") 
   }
   else
   {
      bV5Width := srcheader
      bV5Height := destdata
   }
   NumPut(124, BITMAPV5HEADER, 0, "uint")		;	DWORD		bV5Size;
   NumPut(bV5Width, BITMAPV5HEADER, 4, "uint")		;	LONG		bV5Width;
   NumPut(bV5Height, BITMAPV5HEADER, 8, "uint")		;	LONG		bV5Height;
   NumPut(1, BITMAPV5HEADER, 12, "short")		;	WORD		bV5Planes;
   NumPut(32, BITMAPV5HEADER, 14, "short")		;	WORD		bV5BitCount;

   NumPut(44, BITMAPINFO, 0, "uint")			;	DWORD		biSize;
   NumPut(bV5Width, BITMAPINFO, 4, "uint")  		;	LONG		biWidth;
   NumPut(-bV5Height, BITMAPINFO, 8, "uint")  		;	LONG		biHeight;
   NumPut(1, BITMAPINFO, 12, "short")  			;	WORD		biPlanes;
   NumPut(32, BITMAPINFO, 14, "short") 			;	WORD		biBitCount;
   hDC := DllCall("GetDC", "ptr", hwnd, "ptr")
   hBMP := DllCall("CreateDIBitmap", "ptr", hDC, "ptr", &BITMAPV5HEADER, "uint", CBM_INIT, "ptr",  srcdata, "ptr", &BITMAPINFO, "uint", DIB_RGB_COLORS, "ptr") 
   SendMessage, STM_SETIMAGE, IMAGE_BITMAP, hBMP,, ahk_id %hPic% 
   DllCall("DeleteObject", "ptr", ErrorLevel)
   DllCall("DeleteDC", "ptr", hDC)
   DllCall("DeleteObject", "ptr", hBMP)
   return
}

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

И вместо CreateWindowInBand не проще сделать целевое окно окном-владельцем?

Пример можешь привести?

4

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Так у меня на весь экран получается, и не выключается по F11, и загрузка ещё больше почему-то.

Malcev пишет:

Пример можешь привести?

С окном из кода не пробовал, но в принципе так:

Gui, New, +hwndhGui
Gui, Show, w300 h300
Run notepad,,, PID
WinWait, ahk_pid %PID%
DllCall("SetWindowLong" . (A_PtrSize = 4 ? "" : "Ptr"), "Ptr", hGui, "Int", GWLP_HWNDPARENT := -8, "Ptr", WinExist())
WinActivate, ahk_id %hGui%
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Он и не должен выключаться.
Это просто пример загрузки процессора при инвертировании экрана целиком.

teadrinker пишет:

С окном из кода не пробовал, но в принципе так:

Так не подходит, так-как не перекрываются созданные дочерние окна.

6

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Как я понимаю, загрузка из-за этого цикла:

loop
{
   if (A_PtrSize = 8)
   {
      VarSetCapacity(RECT, 16, 0)
      NumPut(0, RECT, 0, "int")
      NumPut(0, RECT, 4, "int")
      NumPut(A_ScreenWidth, RECT, 8, "int")
      NumPut(A_ScreenHeight, RECT, 12, "int")
      DllCall("magnification.dll\MagSetWindowSource", "ptr", hChildMagnifier, "ptr", &RECT)
   }
}

А без него никак?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Не, без него никак, но зато можно обойтись без callback.
Поправил первый пост.

8

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Почему? По идее MagSetWindowSource должна вызываться, только когда область нужно менять.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Ну а как узнать, что нужно менять область?
Без колбека вообще процессор не подгружает.
Я чувствовал, что какой-то затык в коде.

10

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Malcev пишет:

Ну а как узнать, что нужно менять область?

Когда целевое окно меняет расположение.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

11

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

Так оно может и не менять расположения.
Например при проигрывании видео в плеере.

12

Re: AHK: Инвертирование цвета окна с magnification + UIACCESS

А, теперь понял. Ну сейчас действительно уже не грузит.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder