Auto screenshot by detecting screen changes

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Jento
Posts: 6
Joined: 13 Oct 2021, 12:38

Auto screenshot by detecting screen changes

Post by Jento » 18 Oct 2021, 09:52

Hi, i made an automatic screenshot script:
1. Fist you click Win+LMB(and hold lmb) and mark the area you want to be watched for changes and to be screenshoted
2. Then script detects pixel changes in that area and if any occur it screenshot previously selected window and save it to a folder
3. Folder is automatically created with the subfolder named after today's date
4. Every screenshot is counted and named afterwards

Stop script by pressing Ctrl+y
End script by clicking ESC
The script need gdip library to work

Script is REALLY sensitive, i've tried to crack the ScrCmp() to set % of pixel changed to return 'true' but im not that proficient in ahk.

So if anyone could help with that and point it to me or rewrite that part of the script? Or just have any idea how to do that?

Code: Select all

#NoEnv
#SingleInstance, Force
#Include Gdip.ahk
SetBatchLines, -1
CoordMode, Mouse, Screen

#LButton::
InputRect(vX1, vY1, vX2, vY2)

StopLoop := False
vW := vX2-vX1, vH := vY2-vY1
if (vInputRectState = -1)
	return

Loop {
sleep, 200
ScrCmp(vX1, vY1, vW, vH)

FormatTime, dt_string,, yyyyMMdd
datei = C:\Users\%A_UserName%\Desktop\Screeny\%dt_string%
  ifNotExist, %datei%
    FileCreateDir, %datei%
    
; Read last filename.png - this will be the last one apha-numerically
MaxNum := "000"
Loop, %datei%\*.*
{ if(A_LoopFileName ~= "^SC") 
   && (substr(A_LoopFileName,3,(A_LoopFileName ~= "\d+")) > MaxNum)
   MaxNum := MaxNum := substr(A_LoopFileName,3,(A_LoopFileName ~= "\d+"))
}
MaxNum := printf("%03d",MaxNum + 1)
FileNam := "SC" . MaxNum . ".PNG"  ; create new filename
datei .= "\" 
datei .= FileNam

pToken := Gdip_Startup()
snap := Gdip_BitmapFromScreen(vX1 "|" vY1 "|" vW "|" vH)
Gdip_SaveBitmapToFile(snap, datei)
Gdip_DisposeImage(snap)
Gdip_Shutdown(pToken)

sleep, 200

if StopLoop
	break
}
return

^y:: 
  StopLoop := True 
return

Esc:: ExitApp
;==================================================
;thx jeeswg
;https://www.autohotkey.com/boards/viewtopic.php?t=42810

;based on LetUserSelectRect by Lexikos:
;LetUserSelectRect - select a portion of the screen - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/45921-letuserselectrect-select-a-portion-of-the-screen/

;note: 'CoordMode, Mouse, Screen' must be used in the auto-execute section

;e.g.
;InputRect(vWinX, vWinY, vWinR, vWinB)
;vWinW := vWinR-vWinX, vWinH := vWinB-vWinY
;if (vInputRectState = -1)
;	return

InputRect(ByRef vX1, ByRef vY1, ByRef vX2, ByRef vY2)
{
	global vInputRectState := 0
	DetectHiddenWindows, On
	Gui, 1: -Caption +ToolWindow +AlwaysOnTop +hWndhGuiSel
	Gui, 1: Color, Red
	WinSet, Transparent, 128, % "ahk_id " hGuiSel
	Hotkey, *LButton, InputRect_Return, On
	Hotkey, *RButton, InputRect_End, On
	Hotkey, Esc, InputRect_End, On
	KeyWait, LButton, D
	MouseGetPos, vX0, vY0
	SetTimer, InputRect_Update, 10
	KeyWait, LButton
	Hotkey, *LButton, Off
	Hotkey, Esc, InputRect_End, Off
	SetTimer, InputRect_Update, Off
	Gui, 1: Destroy
	return

	InputRect_Update:
	if !vInputRectState
	{
		MouseGetPos, vX, vY
		(vX < vX0) ? (vX1 := vX, vX2 := vX0) : (vX1 := vX0, vX2 := vX)
		(vY < vY0) ? (vY1 := vY, vY2 := vY0) : (vY1 := vY0, vY2 := vY)
		Gui, 1:Show, % "NA x" vX1 " y" vY1 " w" (vX2-vX1) " h" (vY2-vY1)
		return
	}
	vInputRectState := 1

	InputRect_End:
	if !vInputRectState
		vInputRectState := -1
	Hotkey, *LButton, Off
	Hotkey, *RButton, Off
	Hotkey, Esc, Off
	SetTimer, InputRect_Update, Off
	Gui, 1: Destroy

	InputRect_Return:
	return
}

;==================================================

ScrCmp( X, Y, W, H, Hwnd:=0x0, Sleep* )  {                                        ; v0.66 By SKAN on D3B3/D3B6 @ tiny.cc/scrcmp
Local
Global A_Args
  Sleep[1] := Sleep[1]="" ? 100 : Format("{:d}", Sleep[1])
  Sleep[2] := Sleep[2]="" ? 100 : Format("{:d}", Sleep[2])

  VarSetCapacity(BITMAPINFO, 40, 0)
  NumPut(32, NumPut(1, NumPut(0-H*2, NumPut(W, NumPut(40,BITMAPINFO,"Int"),"Int"),"Int"),"Short"),"Short")

  hBM := DllCall("Gdi32.dll\CreateDIBSection", "Ptr",0, "Ptr",&BITMAPINFO, "Int",0, "PtrP",pBits := 0, "Ptr",0, "Int",0, "Ptr")
  sDC := DllCall("User32.dll\GetDC", "Ptr",(Hwnd := WinExist("ahk_id" . Hwnd)), "Ptr")
  mDC := DllCall("Gdi32.dll\CreateCompatibleDC", "Ptr",sDC, "Ptr")
  DllCall("Gdi32.dll\SaveDC", "Ptr",mDC)
  DllCall("Gdi32.dll\SelectObject", "Ptr",mDC, "Ptr",hBM)
  DllCall("Gdi32.dll\BitBlt", "Ptr",mDC, "Int",0, "Int",H, "Int",W, "Int",H, "Ptr",sDC, "Int",X, "Int",Y, "Int",0x40CC0020)

  A_Args.ScrCmp := {"Wait": 1},   Bytes := W*H*4,  Count := 0
  hMod := DllCall("Kernel32.dll\LoadLibrary", "Str","ntdll.dll", "Ptr")
  While ( A_Args.ScrCmp.Wait && (Count<2) )
  {
      DllCall("Gdi32.dll\BitBlt", "Ptr",mDC, "Int",0, "Int",0, "Int",W, "Int",H, "Ptr",sDC, "Int",X, "Int",Y, "Int",0x40CC0020)
      Count := ( (Byte := DllCall("ntdll.dll\RtlCompareMemory", "Ptr",pBits, "Ptr",pBits+Bytes, "Ptr",Bytes) ) != Bytes )
               ? (Count + 1) : 0
      Sleep % (Count ? Sleep[2] : Sleep[1])
  }   Byte +=1
  DllCall("Kernel32.dll\FreeLibrary", "Ptr",hMod)

  SX := (CX := Mod((Byte-1)//4, W) + X),    SY := (CY := (Byte-1) // (W*4)   + Y)
  If (Hwnd)
    VarsetCapacity(POINT,8,0), NumPut(CX,POINT,"Int"), NumPut(CY,POINT,"Int")
  , DllCall("User32.dll\ClientToScreen", "Ptr",Hwnd, "Ptr",&POINT)
  , SX := NumGet(POINT,0,"Int"),  SY := NumGet(POINT,4,"Int")

  If (Wait := A_Args.ScrCmp.Wait)
      A_Args.ScrCmp := { "Wait":0, "CX":CX, "CY":CY, "SX":SX, "SY":SY }
  DllCall("Gdi32.dll\RestoreDC", "Ptr",mDC, "Int",-1)
  DllCall("Gdi32.dll\DeleteDC", "Ptr",mDC)
  DllCall("User32.dll\ReleaseDC", "Ptr",Hwnd, "Ptr",sDC)
  DllCall("Gdi32.dll\DeleteObject", "Ptr",hBM)
Return ( !!Wait )
}


printf(string, prms*)    ; uses variadics to handle variable number of inputs
{ listlines, off
  padchar := " "
  
  for each, prm in prms
  { RegExMatch(string,"`%(.*?)([s|f|d])",m) ; regular expression search
    format := m1
	stringleft, Pad, format, 1
	if(Pad = "0")
	  padchar := "0"
    type := m2
    if (type = "f")  ; format float using setformat command
    { originalformat := A_FormatFloat
      SetFormat, Float, %format%
      prm += 0.0
      SetFormat, Float, %originalformat%
    } 
    else if (type = "s")    ; format string (pad string if necessary, negative number indicates right justify)
    { if (format < 0)
        loop % -format-StrLen(prm)
          prm := padchar prm
      else
        loop % format-StrLen(prm)
          prm := prm padchar
    } 
    else if(type = "d")
    { originalformat := A_FormatInteger
      SetFormat, Integer, %format%
      Str =
      loop % abs(format)-StrLen(prm) ; %
        str .= padchar
      if(format < 0)
        prm .= str
      else
        prm := str prm
      SetFormat, Integer, %originalformat%
    } 
    else 
      msgbox, unknown type = %type% specified in call to printf
    StringReplace, string, string, % "`" m, % prm     ; "%" symbol must be escaped with backtick
  }
  listlines, on
  return string
}

Return to “Ask for Help (v1)”