Skip to content

Instantly share code, notes, and snippets.

@w-e-w
Created June 3, 2023 13:54
Show Gist options
  • Save w-e-w/a7b16879754badc96044d819d9a01adb to your computer and use it in GitHub Desktop.
Save w-e-w/a7b16879754badc96044d819d9a01adb to your computer and use it in GitHub Desktop.
AutoHotkey V2 WindowSpy.ahk mod
; modify version of https://github.com/AutoHotkey/AutoHotkeyUX/blob/988fc7e6f84635dc0eb8ebee679d6766f4e25e65/WindowSpy.ahk
; ahk_exe as Regex escape full path
; id of Control Under Mouse
;
; Window Spy for AHKv2
;
#Requires AutoHotkey v2.0
#NoTrayIcon
#SingleInstance Ignore
SetWorkingDir A_ScriptDir
CoordMode "Pixel", "Screen"
Global oGui
WinSpyGui()
WinSpyGui() {
Global oGui
try TraySetIcon "inc\spy.ico"
DllCall("shell32\SetCurrentProcessExplicitAppUserModelID", "wstr", "AutoHotkey.WindowSpy")
oGui := Gui("AlwaysOnTop Resize MinSize +DPIScale","Window Spy for AHKv2")
oGui.OnEvent("Close",WinSpyClose)
oGui.OnEvent("Size",WinSpySize)
oGui.Add("Text",,"Window Title, Class and Process:")
oGui.Add("Checkbox","yp xp+175 w54 Right vCtrl_DetectHiddenWindows","Hidden").Value := 1
oGui.Add("Checkbox","yp xp+53 w92 Right vCtrl_FollowMouse","Follow Mouse").Value := 1
oGui.Add("Edit","xm w320 r6 ReadOnly -Wrap vCtrl_Title")
oGui.Add("Text",,"Mouse Position")
oGui.Add("Edit","w320 r4 ReadOnly vCtrl_MousePos")
oGui.Add("Text","w320 vCtrl_CtrlLabel",(txtFocusCtrl := "Focused Control") ":")
oGui.Add("Edit","w320 r5 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 r5 ReadOnly vCtrl_VisText")
oGui.Add("Text",,"All Text:")
oGui.Add("Edit","w320 r5 ReadOnly vCtrl_AllText")
oGui.Add("Text","w320 r1 vCtrl_Freeze",(txtNotFrozen := "(Hold Ctrl or Shift to suspend updates)"))
oGui.Show("NoActivate")
WinGetClientPos(&x_temp, &y_temp2,,,"ahk_id " oGui.hwnd)
; oGui.horzMargin := x_temp*96//A_ScreenDPI - 320 ; now using oGui.MarginX
oGui.txtNotFrozen := txtNotFrozen ; create properties for futur use
oGui.txtFrozen := "(Updates suspended)"
oGui.txtMouseCtrl := "Control Under Mouse Position"
oGui.txtFocusCtrl := txtFocusCtrl
SetTimer Update, 250
}
WinSpySize(GuiObj, MinMax, Width, Height) {
Global oGui
If !oGui.HasProp("txtNotFrozen") ; WinSpyGui() not done yet, return until it is
return
SetTimer Update, (MinMax=0)?250:0 ; suspend updates on minimize
ctrlW := Width - (oGui.MarginX * 2) ; ctrlW := Width - horzMargin
list := "Title,MousePos,Ctrl,Pos,SBText,VisText,AllText,Freeze"
Loop Parse list, ","
oGui["Ctrl_" A_LoopField].Move(,,ctrlW)
}
WinSpyClose(GuiObj) {
ExitApp
}
Update() { ; timer, no params
Try TryUpdate() ; Try
}
TryUpdate() {
Global oGui
If !oGui.HasProp("txtNotFrozen") ; WinSpyGui() not done yet, return until it is
return
Ctrl_DetectHiddenWindows := oGui["Ctrl_DetectHiddenWindows"].Value
If(Ctrl_DetectHiddenWindows)
DetectHiddenWindows True
Else
DetectHiddenWindows False
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 = oGui.hwnd || t2 = "MultitaskingViewFrame") { ; Our Gui || Alt-tab
UpdateText("Ctrl_Freeze", oGui.txtFrozen)
return
}
UpdateText("Ctrl_Freeze", oGui.txtNotFrozen)
t3 := WinGetProcessName(), t4 := WinGetPID(), t3_1 := WinGetProcessPath()
t3_2 := RegExReplace(t3_1, "([\^$.+()[\]{}\\])", "\$1")
WinDataText := t1 "`n" ; ZZZ
. "ahk_class " t2 "`n"
. "ahk_exe " t3 "`n"
. "ahk_exe " t3_2 "`n"
. "ahk_pid " t4 "`n"
. "ahk_id " curWin
UpdateText("Ctrl_Title", WinDataText)
CoordMode "Mouse", "Window"
MouseGetPos &mrX, &mrY
CoordMode "Mouse", "Client"
MouseGetPos &mcX, &mcY
mClr := PixelGetColor(msX,msY,"RGB")
mpText := "Screen:`t" msX ", " msY "`n"
. "Window:`t" mrX ", " mrY "`n"
. "Client:`t" mcX ", " mcY "`t(default)`n"
. "Color:`t" Format("0x{:x}", mClr) "`t(r:" SubStr(mClr, 3, 2) " g:" SubStr(mClr, 5, 2) " b:" SubStr(mClr, 7) ")"
UpdateText("Ctrl_MousePos", mpText)
UpdateText("Ctrl_CtrlLabel", (Ctrl_FollowMouse ? oGui.txtMouseCtrl : oGui.txtFocusCtrl) ":")
if (curCtrl) {
ctrlTxt := ControlGetText(curCtrl)
WinGetClientPos(&sX, &sY, &sW, &sH, curCtrl)
ControlGetPos &cX, &cY, &cW, &cH, curCtrl
cText := "ClassNN:`t" curCtrlClassNN "`n"
. "Text:`t" textMangle(ctrlTxt) "`n"
. "Screen:`tx: " sX "`ty: " sY "`tw: " sW "`th: " sH "`n"
. "Client`tx: " cX "`ty: " cY "`tw: " cW "`th: " cH "`n"
. "id:`t" curCtrl
} else
cText := ""
UpdateText("Ctrl_Ctrl", cText)
wX := "", wY := "", wW := "", wH := ""
WinGetPos &wX, &wY, &wW, &wH, "ahk_id " curWin
WinGetClientPos(&wcX, &wcY, &wcW, &wcH, "ahk_id " curWin)
wText := "Screen:`tx: " wX "`ty: " wY "`tw: " wW "`th: " wH "`n"
. "Client:`tx: " wcX "`ty: " wcY "`tw: " wcW "`th: " wcH
UpdateText("Ctrl_Pos", wText)
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 "slow" mode - TitleMatchMode only affects
; WinText/ExcludeText parameters. In "fast" mode, GetWindowText() is used
; to retrieve the text of each control.
; ===========================================================================================
WinGetTextFast(detect_hidden) {
controls := WinGetControlsHwnd()
static WINDOW_TEXT_SIZE := 32767 ; Defined in AutoHotkey source.
buf := Buffer(WINDOW_TEXT_SIZE * 2,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 .= StrGet(buf) "`r`n" ; text .= buf "`r`n"
}
return text
}
; ===========================================================================================
; 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) {
Global oGui
static OldText := {}
ctl := oGui[vCtl], hCtl := Integer(ctl.hwnd)
if (!oldText.HasProp(hCtl) Or OldText.%hCtl% != NewText) {
ctl.Value := NewText
OldText.%hCtl% := NewText
}
}
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
}
suspend_timer() {
Global oGui
SetTimer Update, 0
UpdateText("Ctrl_Freeze", oGui.txtFrozen)
}
~*Shift::
~*Ctrl::suspend_timer()
~*Ctrl up::
~*Shift up::SetTimer Update, 250
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment