AHK 任意游戏窗口放大镜:通过屏幕放大镜的原理,普通枪变狙击枪

166 阅读4分钟

普通枪变狙击枪,用的是屏幕放大镜的原理,类似用大屏幕打游戏,有时不用开镜,胜似开镜。

这个代码原本是给任意窗体开启反色滤镜,逛autohotkey论坛找到的。

我把它封装class,发现原理是放大镜api。全屏游戏也能放大。f11切换反色。原本只是给一个窗口开启反色。封装后,支持多窗口、支持开放大镜。

目前测试了就一个游戏,使命召唤 iw4x 联机版,全屏、无边框都能用。按小键盘数字7 1.5x 倍镜, 数字8 2x 倍镜, 数字9 4x 倍镜。 八倍镜就变成像素了,没意义。

切出来会卡一下,切走好像有bug,需要多试几次。运行流畅,实际效用未知,因为 iw4x 服务器太少,都是半血服,子弹碰一下就挂,不如盲射乱射。。

image.png

image.png


代码:

#SingleInstance Force
; #SingleInstance Ignore
#MaxThreadsPerHotkey 2
DetectHiddenWindows, On
; SetBatchLines -1
; SetWinDelay -1
OnExit, Uninitialize
; SendLevel, 1

global Inverters := []
global WINDOWINFO
    
CloseWindow(hwnd) {
	WinHide, ahk_id %hwnd%
	WinClose, ahk_id %hwnd%
}


CloseGui(gui) {
	Gui %gui%:Destroy
}

inGroup(GroupName)
{
   	IfWinActive, ahk_group %GroupName%
    	return true
}


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%"
}

mLockStr := "SideLoadin"
hMutex := DllCall("CreateMutex", "UInt", 0, "Int", 1, "Str", mLockStr)

class Inverter
{
    hTarget := ""
    hGui := ""
    hGui1 := ""
    hGui2 := ""
    hChildMagnifier := ""
    hChildMagnifier1 := ""
    hChildMagnifier2 := ""
    xPrev := ""
    yPrev := ""
    wPrev := ""
    hPrev := ""
    stopped := 0
    zoom := 1
    invert := 1
    
    __New(hTarget, invert, zoom)
    {
        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")
            if(invert)
                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)
        this.zoom :=  zoom
        this.invert :=  invert
        return this 
    }
    
    stop() {
        if(!this.stopped) {
			CloseWindow(this.hGui1)
			CloseWindow(this.hGui2)
			CloseGui(this.hTarget "_1")
			CloseGui(this.hTarget "_2")
            this.stopped := 1
        }
    }

    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
            }
            return 2
        }
        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) {
			if(h<A_ScreenHeight-10) {
				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%
        }
        capture := 1
        if(hTarget != WinExist("A")) {
    	    WinGet, MinMax, MinMax
            if (MinMax == 1) ; The window is maximized
            {
                capture := 0
            }
        }
        if(capture) {
            zoom := this.zoom
            if(zoom != 1) {
                SetMagnificationFactor(hChildMagnifier, zoom)
            }
            if (A_PtrSize = 8)
            {
                VarSetCapacity(RECT, 16, 0)
                zoom := 1-1/zoom
                NumPut(x+zoom*w/2, RECT, 0, "int")
                NumPut(y+zoom*h/2, 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
    }
}

SetMagnificationFactor(hMagnifier, magFactor) {
    ; VarSetCapacity(matrix, 24, 0)

    ; return DllCall("magnification.dll\MagSetWindowTransform", "ptr", hwndMag, "ptr", &matrix)

    VarSetCapacity(MAGTRANSFORM, 36, 0)
    for k, v in [magFactor, magFactor, 1]
        NumPut(v, MAGTRANSFORM, (A_Index - 1) * 16, "Float")
    NumPut(magFactor, matrix, 16, "Float") ; 0 0
    NumPut(magFactor, matrix, 32, "Float") ; 1 1
    NumPut(1.0, matrix, 48, "Float") ; 2 2
    DllCall("magnification\MagSetWindowTransform", "Ptr", hMagnifier, "Ptr", &MAGTRANSFORM)
}

~^!+F12::
    if(inGroup("auto_invert_gp")) {
        hTarget := WinExist("A")
        array := Inverters
        For index, tmp in array {
            if(tmp.hTarget=hTarget) {
                return
            }
        }
        if(inGroup("auto_inverted_gp")) 
            return
	    GroupAdd, auto_inverted_gp, ahk_id %hTarget%
        if(inGroup("auto_invert_gp1")) {
        }
        ToggleInversion()
        sleep, 250
    }
return
F11::
	ToggleInversion()
return


ToggleInversion(invert := true, zoom := 1) {
    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)
            if(zoom = tmp.zoom) {
                return
            }
        }
	}
    tmp := new Inverter(hTarget, invert, zoom)
    array.push(tmp)
    if(array.Length()==1) {
		SetBatchLines -1
		SetWinDelay -1
        loop {
            rev := 0
            For index, tmp in array {
                ret := tmp.doit()
                if(!ret) {
                    tmp.stop()
                    array.removeAt(index)
                }
                else 
                    rev+=ret
            }
            if(rev==array.Length()*2) 
                sleep 150
            ; xx(tmp.hTarget " " array.Length() " " hGui)
            if(array.Length()==0)
                break
        }
		SetBatchLines, 10ms
		SetWinDelay 100
    }
}


Uninitialize:
    if (hGui != "")
    DllCall("magnification.dll\MagUninitialize")
    DllCall("ReleaseMutex", "Ptr", hMutex)
    DllCall("CloseHandle", "Ptr", hMutex)
ExitApp





#IfWinActive ahk_exe iw4x.exe
^w::
NumPad7::
NumPadHome::
	; xx(1)
    ToggleInversion(false, 1.5)
return
NumPad8::
NumPadDiv::
	; xx(1)
    ToggleInversion(false, 2)
return
NumPad9::
NumPadPgup::
	; xx(1)
    ToggleInversion(false, 3)
return