Тема: AHK: Экранная лупа
Перекопав примеры, так и не нашёл код с нормальным указателем пикселя (рамка пикселя который под курсором), поддержкой нескольких мониторов и толковым масштабированием при изменении размера окна лупы.
Наваял код, в нём остались проблемы:
[РЕШЕНО] При зуме равном 1, края экрана "зеркалируются". Возможно в параметре dwRop функции StretchBlt надо скомбинировать флаги (я таковую комбинацию не нашёл), или вообще StretchBlt заменить на другой метод.
[РЕШЕНО] Если поставить на паузу (F12), то при сворачивании \ разворачивании прежняя картинка пропадает, также затирается та часть окна, которую при передвижении окна перенесли за край экрана.
Небольшие мелькания при изменении увеличения или растягивании окна (терпимо).
#NoEnv
#SingleInstance Force
#KeyHistory 0
ListLines Off
SetBatchLines,-1
OnExit, ZoomOnClose
Global oZoom := {}
oZoom.Zoom := 12
oZoom.Mark := "Cross" ; Cross, Square, Grid
WinX := 1559
WinY := 594
WinW := 300
WinH := 360
Gui, Zoom: +AlwaysOnTop +Resize -DPIScale +hwndhGui +LabelZoomOn
Gui, Zoom: Font, s12
Gui, Zoom: Color, ffffff
Gui, Zoom: Add, Slider, vSliderZoom gSliderZoom x8 Range1-50 w176 Center AltSubmit NoTicks, % oZoom.Zoom
Gui, Zoom: Add, Text, vTextZoom Center x+10 yp+3 w36, % oZoom.Zoom
Gui, Zoom: Font
Gui, Zoom: Add, Button, gChangeMark vChangeMark x+10 yp w52, % oZoom.Mark
Gui, Dev: +HWNDhDev -Caption -DPIScale +Parent%hGui%
Gui, Dev: Add, Text, hwndhDevCon
Gui, Dev: Show, NA
Gui, Dev: Color, ffffff
Gui, Zoom: Show, x%WinX% y%WinY% w%WinW% h%WinH%, Magnify
Gui, Zoom: +MinSize
oZoom.hdcSrc := DllCall("GetDC", Ptr, "")
oZoom.hdcDest := DllCall("GetDC", Ptr, hDevCon, Ptr)
DllCall("gdi32.dll\SetStretchBltMode", "Ptr", oZoom.hdcDest, "Int", 4)
oZoom.hGui := hGui
oZoom.hDev := hDev
oZoom.hDevCon := hDevCon
Magnify()
Return
#If !oZoom.Minimize
+Up::MouseMove, 0, -1, 0, R
+Down::MouseMove, 0, 1, 0, R
+Left::MouseMove, -1, 0, 0, R
+Right::MouseMove, 1, 0, 0, R
^Up::
^DoWn::
^WheelUp::
^WheelDown::ChangeZoom(InStr(A_ThisHotKey, "DoWn") ? oZoom.Zoom + 1 : oZoom.Zoom - 1)
F12::Pause
#If
Magnify() {
S_CoordModeMouse := A_CoordModeMouse
CoordMode, Mouse, Screen
MouseGetPos, mX, mY, WinID, CtrlID, 2
CoordMode, Mouse, %S_CoordModeMouse%
If (oZoom.hDev != CtrlID)
{
StretchBlt(oZoom.hdcDest, oZoom.hdcSrc, 0, 0, oZoom.nWidthDest, oZoom.nHeightDest
, mX - oZoom.nXOriginSrcOffset, mY - oZoom.nYOriginSrcOffset, oZoom.nWidthSrc, oZoom.nHeightSrc)
For k, v In oZoom.oMarkers[oZoom.Mark]
StretchBlt(oZoom.hdcDest, oZoom.hdcDest, v.x, v.y, v.w, v.h, v.x, v.y, v.w, v.h, 0x5A0049) ; PATINVERT
}
SetTimer, Magnify, -50
}
SetSize() {
Static Top := 64, Left := 4, Right := 4, Bottom := 4
SetTimer, Magnify, Off
GetClientPos(oZoom.hGui, GuiWidth, GuiHeight)
Width := GuiWidth - Left - Right
Height := GuiHeight - Top - Bottom
Zoom := oZoom.Zoom
conW := Mod(Width, Zoom) ? Width - Mod(Width, Zoom) + Zoom : Width
conW := Mod(conW // Zoom, 2) ? conW : conW + Zoom
conH := Mod(Height, Zoom) ? Height - Mod(Height, Zoom) + Zoom : Height
conH := Mod(conH // Zoom, 2) ? conH : conH + Zoom
conX := ((conW - Width) // 2) * -1
conY := ((conH - Height) // 2) * -1
oZoom.nWidthSrc := conW // Zoom
oZoom.nHeightSrc := conH // Zoom
oZoom.nXOriginSrcOffset := oZoom.nWidthSrc//2
oZoom.nYOriginSrcOffset := oZoom.nHeightSrc//2
oZoom.nWidthDest := conW
oZoom.nHeightDest := conH
oZoom.xCenter := conW / 2 - Zoom / 2
oZoom.yCenter := conH / 2 - Zoom / 2
Zoom := oZoom.Zoom
nWidthDest := oZoom.nWidthDest
nHeightDest := oZoom.nHeightDest
xCenter := oZoom.xCenter, yCenter := oZoom.yCenter
oZoom.oMarkers["Cross"] := [{x:0,y:yCenter - 1,w:nWidthDest,h:1}
, {x:0,y:yCenter + Zoom,w:nWidthDest,h:1}
, {x:xCenter - 1,y:0,w:1,h:nHeightDest}
, {x:xCenter + Zoom,y:0,w:1,h:nHeightDest}]
oZoom.oMarkers["Square"] := [{x:xCenter - 1,y:yCenter,w:Zoom + 2,h:1}
, {x:xCenter - 1,y:yCenter + Zoom + 1,w:Zoom + 2,h:1}
, {x:xCenter - 1,y:yCenter + 1,w:1,h:Zoom}
, {x:xCenter + Zoom,y:yCenter + 1,w:1,h:Zoom}]
oZoom.oMarkers["Grid"] := Zoom = 1 ? oZoom.oMarkers["Square"]
: [{x:xCenter - Zoom,y:yCenter - Zoom,w:Zoom * 3,h:1}
, {x:xCenter - Zoom,y:yCenter,w:Zoom * 3,h:1}
, {x:xCenter - Zoom,y:yCenter + Zoom,w:Zoom * 3,h:1}
, {x:xCenter - Zoom,y:yCenter + Zoom * 2,w:Zoom * 3,h:1}
, {x:xCenter - Zoom,y:yCenter - Zoom,w:1,h:Zoom * 3}
, {x:xCenter,y:yCenter - Zoom,w:1,h:Zoom * 3}
, {x:xCenter + Zoom,y:yCenter - Zoom,w:1,h:Zoom * 3}
, {x:xCenter + Zoom * 2,y:yCenter - Zoom,w:1,h:Zoom * 3}]
WinMove, % "ahk_id" oZoom.hDev, , Left, Top, Width, Height
GuiControl, Dev: -Redraw, % oZoom.hDevCon
WinMove, % "ahk_id" oZoom.hDevCon, , conX, conY, conW, conH
Magnify()
GuiControl, Dev: +Redraw, % oZoom.hDevCon
}
StretchBlt(hdcDest, hdcSrc, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc, dwRop = 0xC000CA) { ; MERGECOPY
DllCall("gdi32.dll\StretchBlt", Ptr, hdcDest
, Int, nXOriginDest
, Int, nYOriginDest
, Int, nWidthDest
, Int, nHeightDest
, Ptr, hdcSrc
, Int, nXOriginSrc
, Int, nYOriginSrc
, Int, nWidthSrc
, Int, nHeightSrc
, UInt, dwRop)
}
ZoomOnSize() {
If A_EventInfo != 1
{
SetTimer, SetSize, -100
oZoom.Minimize := 0
}
Else
oZoom.Minimize := 1
}
SliderZoom() {
GuiControlGet, SliderZoom, Zoom:
ChangeZoom(SliderZoom)
}
ChangeZoom(Val) {
If (Val < 1 || Val > 50)
Return
GuiControl, Zoom: , TextZoom, % oZoom.Zoom := Val
GuiControl, Zoom: , SliderZoom, % oZoom.Zoom
SetTimer, SetSize, -150
}
ChangeMark() {
oZoom.Mark := ["Cross","Square","Grid","None"][{"Cross":2,"Square":3,"Grid":4,"None":1}[oZoom.Mark]]
GuiControl, Zoom: , ChangeMark, % oZoom.Mark
}
ZoomOnClose:
DllCall("gdi32.dll\DeleteDC", "Ptr", oZoom.hdcDest)
DllCall("gdi32.dll\DeleteDC", "Ptr", oZoom.hdcSrc)
ExitApp
GetClientPos(hwnd, ByRef W, ByRef H) {
VarSetCapacity(pwi, 60, 0), NumPut(60, pwi, 0, "UInt")
DllCall("GetWindowInfo", "Ptr", hwnd, "UInt", &pwi)
W := NumGet(pwi, 28, "int") - NumGet(pwi, 20, "int")
H := NumGet(pwi, 32, "int") - NumGet(pwi, 24, "int")
}
Текущая версия здесь.
Win10x64 AhkSpy, Hotkey, ClockGui