Window Spy for AHKv2 - 2020/09/10 - a122

Share the finished AutoHotkey v2 Scripts and libraries you made here. Please put the current version of AutoHotkey v2 you used in Square Brackets at the start of the topic title.
User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Window Spy for AHKv2 - 2020/09/10 - a122

Post by TheArkive » 07 Feb 2020, 11:13

Haven't seen this posted anywhere yet, or anything like it. Hope this helps someone.

Of course I didn't write this, I just updated it.

User @Steely Wing also has a version of Window Spy for AHK v2 recently updated.

==================================================
Updates
==================================================

Code: Select all

; 
; Window Spy for AHKv2
;

#NoTrayIcon
#SingleInstance Ignore
SetWorkingDir A_ScriptDir
CoordMode "Pixel", "Screen"

Global oGui

WinSpyGui()

WinSpyGui() {
	txtNotFrozen := "(Hold Ctrl or Shift to suspend updates)"
	txtFrozen := "(Updates suspended)"
	txtMouseCtrl := "Control Under Mouse Position"
	txtFocusCtrl := "Focused Control"
	
	oGui := Gui.New("AlwaysOnTop Resize MinSize +DPIScale","Window Spy for AHKv2"), hGui := oGui.hwnd
	oGui.OnEvent("Close","WinSpyClose")
	oGui.OnEvent("Size","WinSpySize")
	
	oGui.Add("Text",,"Window Title, Class and Process:")
	oGui.Add("Checkbox","yp xp+200 w120 Right vCtrl_FollowMouse","Follow Mouse").Value := 1
	oGui.Add("Edit","xm w320 r5 ReadOnly -Wrap vCtrl_Title")
	oGui.Add("Text",,"Mouse Position")
	oGui.Add("Edit","w320 r4 ReadOnly vCtrl_MousePos")
	oGui.Add("Text","w320 vCtrl_CtrlLabel",txtFocusCtrl ":")
	oGui.Add("Edit","w320 r4 ReadOnly vCtrl_Ctrl")
	oGui.Add("Text",,"Active Window Postition:")
	oGui.Add("Edit","w320 r2 ReadOnly vCtrl_Pos")
	oGui.Add("Text",,"Status Bar Text:")
	oGui.Add("Edit","w320 r2 ReadOnly vCtrl_SBText")
	oGui.Add("Checkbox","vCtrl_IsSlow","Slow TitleMatchMode")
	oGui.Add("Text",,"Visible Text:")
	oGui.Add("Edit","w320 r2 ReadOnly vCtrl_VisText")
	oGui.Add("Text",,"All Text:")
	oGui.Add("Edit","w320 r2 ReadOnly vCtrl_AllText")
	oGui.Add("Text","w320 r1 vCtrl_Freeze",txtNotFrozen)
	
	oGui.Show("NoActivate")
	GetClientSize(hGui, temp)
	
	horzMargin := temp*96//A_ScreenDPI - 320
	oGui.horzMargin := horzMargin
	
	oGui.txtNotFrozen := txtNotFrozen, oGui.txtFrozen := txtFrozen
	oGui.txtMouseCtrl := txtMouseCtrl, oGui.txtFocusCtrl := txtFocusCtrl
	
	SetTimer "Update", 250
}

WinSpySize(GuiObj, MinMax, Width, Height) {
	horzMargin := oGui.horzMargin
	if !horzMargin
		return
	
	SetTimer "Update", (MinMax=0)?250:0 ; suspend updates on minimize
	
	ctrlW := Width - horzMargin
	list := "Title,MousePos,Ctrl,Pos,SBText,VisText,AllText,Freeze"
	Loop Parse list, ","
		ctl := oGui["Ctrl_" A_LoopField], ctl.Move(,,ctrlW)
}

WinSpyClose(GuiObj) {
	ExitApp
}

Update() { ; timer, no params
	hGui := oGui.hwnd
	txtNotFrozen := oGui.txtNotFrozen, txtFrozen := oGui.txtFrozen
	txtMouseCtrl := oGui.txtMouseCtrl, txtFocusCtrl := oGui.txtFocusCtrl
	
	Ctrl_FollowMouse := oGui["Ctrl_FollowMouse"].Value
	CoordMode "Mouse", "Screen"
	MouseGetPos msX, msY, msWin, msCtrl, 2 ; get ClassNN and hWindow
	actWin := WinExist("A")
	
	if (Ctrl_FollowMouse) {
		curWin := msWin, curCtrl := msCtrl
		WinExist("ahk_id " curWin) ; updating LastWindowFound?
	} else {
		curWin := actWin
		curCtrl := ControlGetFocus() ; get focused control hwnd from active win
	}
	curCtrlClassNN := ""
	Try curCtrlClassNN := ControlGetClassNN(curCtrl)
	
	t1 := WinGetTitle(), t2 := WinGetClass()
	if (curWin = hGui || t2 = "MultitaskingViewFrame") { ; Our Gui || Alt-tab
		UpdateText("Ctrl_Freeze", txtFrozen)
		return
	}
	
	UpdateText("Ctrl_Freeze", txtNotFrozen)
	t3 := WinGetProcessName(), t4 := WinGetPID()
	
	UpdateText("Ctrl_Title", t1 "`nahk_class " t2 "`nahk_exe " t3 "`nahk_pid " t4 "`nahk_id " curWin)
	CoordMode "Mouse", "Window"
	MouseGetPos mrX, mrY
	CoordMode "Mouse", "Client"
	MouseGetPos mcX, mcY
	mClr := PixelGetColor(msX,msY,"RGB")
	mClr := SubStr(mClr, 3)
	
	UpdateText("Ctrl_MousePos", "Screen:`t" msX ", " msY " (less often used)`nWindow:`t" mrX ", " mrY " (default)`nClient:`t" mcX ", " mcY " (recommended)"
		. "`nColor:`t" mClr " (Red=" SubStr(mClr, 1, 2) " Green=" SubStr(mClr, 3, 2) " Blue=" SubStr(mClr, 5) ")")
	
	UpdateText("Ctrl_CtrlLabel", (Ctrl_FollowMouse ? txtMouseCtrl : txtFocusCtrl) ":")
	
	if (curCtrl) {
		ctrlTxt := ControlGetText(curCtrl)
		cText := "ClassNN:`t" curCtrlClassNN "`nText:`t" textMangle(ctrlTxt)
		ControlGetPos cX, cY, cW, cH, curCtrl
		cText .= "`n`tx: " cX "`ty: " cY "`tw: " cW "`th: " cH
		WinToClient(curWin, cX, cY)
		GetClientSize(curCtrl, cW, cH)
		cText .= "`nClient:`tx: " cX "`ty: " cY "`tw: " cW "`th: " cH
	} else
		cText := ""
	
	UpdateText("Ctrl_Ctrl", cText)
	wX := "", wY := "", wW := "", wH := ""
	Try WinGetPos wX, wY, wW, wH
	GetClientSize(curWin, wcW, wcH)
	
	UpdateText("Ctrl_Pos", "`tx: " wX "`ty: " wY "`tw: " wW "`th: " wH "`nClient:`tx: 0`ty: 0`tw: " wcW "`th: " wcH)
	sbTxt := ""
	
	Loop {
		ovi := ""
		Try ovi := StatusBarGetText(A_Index)
		if (ovi = "")
			break
		sbTxt .= "(" A_Index "):`t" textMangle(ovi) "`n"
	}
	
	sbTxt := SubStr(sbTxt,1,-1) ; StringTrimRight, sbTxt, sbTxt, 1
	UpdateText("Ctrl_SBText", sbTxt)
	bSlow := oGui["Ctrl_IsSlow"].Value ; GuiControlGet, bSlow,, Ctrl_IsSlow
	
	if (bSlow) {
		DetectHiddenText False
		ovVisText := WinGetText() ; WinGetText, ovVisText
		DetectHiddenText True
		ovAllText := WinGetText() ; WinGetText, ovAllText
	} else {
		ovVisText := WinGetTextFast(false)
		ovAllText := WinGetTextFast(true)
	}
	
	UpdateText("Ctrl_VisText", ovVisText)
	UpdateText("Ctrl_AllText", ovAllText)
}

; ===========================================================================================
; WinGetText ALWAYS uses the "fast" mode - TitleMatchMode only affects to retrieve the text
; of each control. WinText/ExcludeText parameters.  In Slow mode, GetWindowText() is used.
; ===========================================================================================
WinGetTextFast(detect_hidden) {	
	controls := WinGetControlsHwnd() ; "ahk_id " curWin
	
	If (Type(controls) = "Array") {
		static WINDOW_TEXT_SIZE := 32767 ; Defined in AutoHotkey source.
		
		buf := BufferAlloc(WINDOW_TEXT_SIZE * 1,0) ; BufferAlloc(WINDOW_TEXT_SIZE * (A_IsUnicode ? 2 : 1),0)
		
		text := ""
		
		Loop controls.Length {
			hCtl := controls[A_Index]
			if !detect_hidden && !DllCall("IsWindowVisible", "ptr", hCtl)
				continue
			if !DllCall("GetWindowText", "ptr", hCtl, "Ptr", buf.ptr, "int", WINDOW_TEXT_SIZE)
				continue
			; text .= buf "`r`n"
			text .= StrGet(buf)
		}
		return text
	} Else
		return ""
}

; ===========================================================================================
; Unlike using a pure GuiControl, this function causes the text of the
; controls to be updated only when the text has changed, preventing periodic
; flickering (especially on older systems).
; ===========================================================================================
UpdateText(vCtl, NewText) {
	static OldText := {}
	ctl := oGui[vCtl], hCtl := Integer(ctl.hwnd)
    ; msgbox hCtl
	
	if (!oldText.HasProp(hCtl) Or OldText.%hCtl% != NewText) {
		ctl.Value := NewText
		OldText.%hCtl% := NewText
	}
}

GetClientSize(hWnd, ByRef w := "", ByRef h := "") {
	rect := BufferAlloc(16,0)
	; VarSetCapacity(rect, 16)
	DllCall("GetClientRect", "ptr", hWnd, "ptr", rect.ptr)
	w := NumGet(rect, 8, "int"), h := NumGet(rect, 12, "int")
}

WinToClient(hWnd, ByRef x, ByRef y) {
    WinGetPos wX, wY,,, "ahk_id " hWnd
	If (wX != "" And wY != "") {
		x += wX, y += wY
		pt := BufferAlloc(8,0)
		; VarSetCapacity(pt, 8)
		
		NumPut "Int", x, pt
		NumPut "Int", y, pt, 4
		
		; NumPut(y, NumPut(x, pt, "int"), "int")
		
		if !DllCall("ScreenToClient", "ptr", hWnd, "ptr", pt.ptr)
			return false
		x := NumGet(pt, 0, "int"), y := NumGet(pt, 4, "int")
		return true
	} Else
		return false
    
}

textMangle(x) {
	elli := false
	if (pos := InStr(x, "`n"))
		x := SubStr(x, 1, pos-1), elli := true
	else if (StrLen(x) > 40)
		x := SubStr(x,1,40), elli := true
	if elli
		x .= " (...)"
	return x
}

~*Ctrl::
~*Shift::
{
	txtFrozen := oGui.txtFrozen
	SetTimer "Update", 0
	UpdateText("Ctrl_Freeze", txtFrozen)
}

~*Ctrl up::
~*Shift up::SetTimer "Update", 250
Last edited by TheArkive on 10 Sep 2020, 13:33, edited 24 times in total.

burque505
Posts: 1354
Joined: 22 Jan 2017, 19:37

Re: Window Spy for AHKv2

Post by burque505 » 24 Feb 2020, 14:40

@TheArkive, thanks a lot, working great on Win7 Pro 64-bit, SP1, AHK2 v2.0-a107, at 125% scaling.
Nice!
Regards,
burque505

User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Window Spy for AHKv2

Post by TheArkive » 26 Feb 2020, 10:32

@burque505 glad to know it's helping someone :-) ... I've been wanting to mess around with AHKv2 for a while, but only a few months ago did I have time to really dig in to the installation, syntax, and everything else. I found this tool to be vital for me to find window information to figure out how to compose certain scripts.

User avatar
vvhitevvizard
Posts: 405
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: Window Spy for AHKv2

Post by vvhitevvizard » 30 Apr 2020, 20:45

@TheArkive Thank u for preserving all the original calculations and stuff. This code, when compared to the original v1 code side by side, can be a good example for ones struggling to convert v1 GUI code for v2-108!

User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Window Spy for AHKv2

Post by TheArkive » 01 May 2020, 00:56

@vvhitevvizard
That was part of the idea for sure, and it makes life easier when really digging in to AHK v2 and setting up your system to really start AHK v2 coding.

User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Window Spy for AHKv2 - 2020/06/11

Post by TheArkive » 11 Jun 2020, 12:28

Update 2020/06/11 - works with AHK v2 a110
  • a few stability fixes when quickly moving the mouse over several windows
  • converted VarSetCapacity() to BufferAlloc()
  • Added Try to a few lines to bypass errors

User avatar
Tigerlily
Posts: 353
Joined: 04 Oct 2018, 22:31

Re: Window Spy for AHKv2 - 2020/06/18

Post by Tigerlily » 19 Jun 2020, 19:50

Looks nearly identical, not sure if this because of DPI scaling but with Win 10 at 125% DPI I get the text boxes pushed too far to the left. Here is a comparison of me running a AHK .exe file of Window Spy for v1 next to your v2 version.

Image

Nice work! I was just actually about to make this myself the other day but got distracted and did something else :p
-TL

User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Window Spy for AHKv2 - 2020/07/01 - a113

Post by TheArkive » 01 Jul 2020, 07:21

@Tigerlily
Sorry for the late reply, the misalignment with scaling should now be fixed.

Steely Wing
Posts: 9
Joined: 12 Dec 2019, 06:26

Re: Window Spy for AHKv2 - 2020/07/31 - a121

Post by Steely Wing » 07 Sep 2020, 02:04

I have rewrite part of the script, is should more easy to read, and update for AHK version a122, please have a check if you interest.

https://github.com/steelywing/AutoHotkey-Release/blob/master/installer/source/WindowSpy.v2.ahk

And I want to change some function, may be update a few days later.

User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Window Spy for AHKv2 - 2020/07/31 - a122

Post by TheArkive » 07 Sep 2020, 08:06

Thanks @Steely Wing, I updated the OP and included your link.

My rewrite is currently working in a122 so I'm not updating mine yet. I'll take a closer look at yours at some point too.

I haven't bothered to do a true "rewrite" yet... I was just wanted to maintain a functional version for AHK v2 alpha, and I wanted to make minimal changes to preserve the original code (as mush as possible) for people looking for some potential examples of AHK v1 / v2 equivalent code.

Steely Wing
Posts: 9
Joined: 12 Dec 2019, 06:26

Re: Window Spy for AHKv2 - 2020/07/31 - a122

Post by Steely Wing » 09 Sep 2020, 09:39

Just because I have some time these days :P I added some option, it would be useful.

User avatar
Tigerlily
Posts: 353
Joined: 04 Oct 2018, 22:31

Re: Window Spy for AHKv2 - 2020/07/31 - a122

Post by Tigerlily » 09 Sep 2020, 14:36

@TheArkive

Just tried this out again and still getting some odd control sizing again. Seems like nothing works as good as a compiled v1 version XD.

Also, you need to take out the #INCLUDE TheArkive_Debug.ahk from the top of the script since I don't think you intended to leave that in there :D

On a side note, the #SingleInstance, Ignore is annoying lol but I understand that's probably leftovers from original author.


Example:
Image

I also tried
@Steely Wing's version which appeared to work a little better visually, however I did get a string warnings and errors when trying to take this screenshot using ShareX:

Image

Errors:
Image
-TL

Steely Wing
Posts: 9
Joined: 12 Dec 2019, 06:26

Re: Window Spy for AHKv2 - 2020/07/31 - a122

Post by Steely Wing » 10 Sep 2020, 05:59

@Tigerlily, I add a error handler, please try the updated version.

User avatar
Tigerlily
Posts: 353
Joined: 04 Oct 2018, 22:31

Re: Window Spy for AHKv2 - 2020/07/31 - a122

Post by Tigerlily » 10 Sep 2020, 11:29

@Steely Wing

Works like a charm - thank you!
-TL

User avatar
TheArkive
Posts: 330
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

Re: Window Spy for AHKv2 - 2020/09/10 - a122

Post by TheArkive » 10 Sep 2020, 13:35

@Tigerlily, thanks for the heads up. Somehow i got my wires crossed and the posted script was out of sync with what i actually have.

Also, changed -DPIScale to +DPIScale, that seems to have fixed it on my end. Let me know if not.

@Steely Wing thanks for the updates :) ... let me know if your link ever changes so i can update the OP.

Post Reply

Return to “AutoHotkey v2 Scripts and Functions”