WindowList - Viewer and manipulation of window data

Post your working scripts, libraries and tools for AHK v1.1 and older
AHK_user
Posts: 515
Joined: 04 Dec 2015, 14:52
Location: Belgium

WindowList - Viewer and manipulation of window data

15 Sep 2020, 17:05

Here is the code for a viewer for used windows information, with functionalities to several autohotkey commands for windows.

Functionalities:
- Filters with radio buttons only visible windows and windows with titles
- Allows to filter on strings with Edit fields above the list
- Doubleclick on the window info in the list to be able to retrieve the coordinates and exicute several commands regarding that window
- The move button can move the window to the entered coordinates (changing the width and Height currently does not work yet)
- Rightclick the windowlist to show a menu to Activate, Hide, copy the title, get Acc data,...
- Doubleclick on controls to draw a rectangle arround the control
- Transparency of window can be changed with the slider
- Also includes a button to Kill the selected window
WindowList.ahk.png
WindowList.ahk.png (74.62 KiB) Viewed 1557 times

Code: Select all

#NoEnv
SendMode Input
#SingleInstance force
#InstallKeybdHook

SetWorkingDir %A_ScriptDir%
SetTitleMatchMode, 2
SetTitleMatchMode, RegEx
SetBatchLines, -1

global vVisible
vVisible := 1
Gui, Add, Text, ,WinSearch:
Gui, Add, Edit, yp x70 w200 vSearchTerm glVisible
Gui, Add, Checkbox, xp+210 yp+4 vvVisible glVisible checked, Visible
Gui, Add, Checkbox, xp+75 yp vvTitle glVisible checked, Title

Gui, Add, Text, yp x620,ControlSearch:
Gui, Add, Edit, yp x+10 w200 vcSearchTerm glUpdateControlList
Gui, Add, Checkbox, xp+210 yp+4 vvcTextVisible glUpdateControlList checked, Text visible

Gui, Add, ListView, xm r15 w600 vMyWinList gMyWinList section AltSubmit, Title|Process|ID|Style
LV_ModifyCol()
LV_ModifyCol(1, 300)
LV_ModifyCol(3, "Integer")
LV_ModifyCol(4, "SortDesc")

Gui, Add, ListView, x+m r15 w600 vMyControlList gMyControlList AltSubmit, Control|Hwnd|Text|X|Y|With|Height
Gui, Add, Button, gKill xm w50, Kill
Gui, Add, Text,xm, X:
Gui, Add, Edit, vXPos xp+20 w40,
Gui, Add, Text, xp+50 , Y:
Gui, Add, Edit, vYPos xp+20 w40,
Gui, Add, Text, xp+50 , Width:
Gui, Add, Edit, vwWidth xp+40 w40,
Gui, Add, Text, xp+50 , Height:
Gui, Add, Edit, vwHeight xp+40 w40,
Gui, Add, Button, gMove xp+50 w50, Move
Gui, Add, Text,xm, Transparent:
Gui, Add, Slider, xp+60 vvTransparent glTransparent Range0-255 ToolTip, 255
LV_Update()
Gui, Add, StatusBar,
Gui, Show
return

GuiClose:
Gui, Destroy
ExitApp
return

MyWinList:
{
	Gui, ListView, MyWinList
	if (A_GuiEvent = "DoubleClick"){
		ControlGet, Selected, List, Selected, SysListView321,
		Selected := StrSplit(Selected, A_Tab)
		wid := Selected[3]
		WinGetPos, wX, wY,wWidth ,wHeight , ahk_id %wid%
		WinGet, wTransparent, Transparent, ahk_id %wid%
		if(wTransparent=""){
			wTransparent:=255
		}
		DebugWindow(wTransparent "`n")
		GuiControl, Text, XPos , %wX%
		GuiControl, Text, YPos , %wY%
		GuiControl, Text, wWidth , %wWidth%
		GuiControl, Text, wHeight , %wHeight%
		GuiControl, Text, vTransparent , %wTransparent%
		Gosub, lUpdateControlList
	}
	if (A_GuiEvent = "RightClick"){
		Menu, Menu_Win, add
		Menu, Menu_Win, DeleteAll
		ControlGet, Selected, List, Selected, SysListView321,
		Selected := StrSplit(Selected, A_Tab)
		wTitle := Selected[1]
		wProcess := Selected[2]
		wId := Selected[3]
		wStyle := Selected[4]
		BoundGivePar := Func("WinActivate").Bind("ahk_id " wId)
		Menu, Menu_Win, Add, Activate, % BoundGivePar
		
		WinGet, wStyle, Style, ahk_id %wId%
		If (wStyle & 0x10000000){  ; 0x10000000 is WS_VISIBLE
			BoundGivePar := Func("WinHide").Bind("ahk_id " wId)
			Menu, Menu_Win, Add, Visible, % BoundGivePar
			Menu, Menu_Win, Check, Visible,
			BoundGivePar := Func("WinSet").Bind("AlwaysOnTop", "ahk_id " wId)
			Menu, Menu_Win, Add, AlwaysOnTop, % BoundGivePar
			WinGet, ExStyle, ExStyle, ahk_id %wId%
			If (ExStyle & 0x8){
				Menu, Menu_Win, Check, AlwaysOnTop
			}
		}  
		Else{
			BoundGivePar := Func("WinShow").Bind("ahk_id " Selected[3])
			Menu, Menu_Win, Add, Visible, % BoundGivePar
		}
		Menu, Menu_Win, Add,
		BoundGivePar := Func("ClipboardSet").Bind(wTitle)
		Menu, Menu_Win, Add, Copy Title, % BoundGivePar
		Menu, Menu_Win, Icon, Copy Title, C:\Windows\syswow64\SHELL32.dll , 261
		BoundGivePar := Func("ClipboardSet").Bind(wProcess)
		Menu, Menu_Win, Add, Copy Process, % BoundGivePar
		Menu, Menu_Win, Icon, Copy Process, C:\Windows\syswow64\SHELL32.dll , 261
		Menu, Menu_Win, Add
		BoundGivePar := Func("Gui_Acc").Bind(wId)
		Menu, Menu_Win, Add, Get Acc, % BoundGivePar
		Menu, Menu_Win, Show
	}
	return
}

lUpdateControlList:
{
	Gui, Submit, Nohide
	
	WinGet, cList, ControlList, ahk_id %wid%
	Gui, ListView, MyControlList
	LV_Delete()
	loop,{ 
		cSearchTermOld := cSearchTerm
		vcTextVisibleOld := vcTextVisible
		Loop, Parse,  cList, `n, `r
		{
			Control := A_LoopField
			ControlGetText, cText, %Control%, ahk_id %wid%
			ControlGetPos, cX, cY, cW, cH, %Control%, ahk_id %wid%
			Controlget,cHwnd, Hwnd , , %Control%, ahk_id %wid%
			if (vcTextVisible=0 or cText !=""){
				If (InStr(Control " " cText, cSearchTerm) or (cSearchTerm = "")){
					LV_Add("", A_LoopField, cHwnd, cText, cX, cY, cW, cH)
				}
			}
			GuiControlGet, cSearchTerm
			GuiControlGet, vcTextVisible
			if(cSearchTermOld != cSearchTerm or vcTextVisible != vcTextVisibleOld){
				Break
			}
		}
		if(cSearchTermOld = cSearchTerm and vcTextVisible = vcTextVisibleOld){
			Break
		}
	}
	
	LV_ModifyCol()
	Return
}

MyControlList:
{
	Gui, ListView, MyWinList
	ControlGet, wSelected, List, Selected, SysListView321,
	wSelected := StrSplit(wSelected, A_Tab)
	wId := wSelected[3]
	wStyle := wSelected[4]
	Gui, ListView, MyControlList
	if (A_GuiEvent = "DoubleClick"){
		ControlGet, cSelected, List, Selected, SysListView322,
		cSelected := StrSplit(cSelected, A_Tab)
		cControl := cSelected[1]
		cId := cSelected[2]
		cX := cSelected[4]
		cY := cSelected[5]
		cW := cSelected[6]
		cH := cSelected[7]
		
		WinGetPos, wX, wY,,, ahk_id %wId%
		DebugWindow(cControl cX "-" cY "-" cW "-" cH "`n")
		Box_Init(C="FF0000")
		Box_Draw(cX+wX, cY+wY, cW, cH, 2, "in")
	}
	if (A_GuiEvent = "RightClick"){
		Menu, Menu_Contr, add
		Menu, Menu_Contr, DeleteAll
		ControlGet, cSelected, List, Selected, SysListView322,
		cSelected := StrSplit(cSelected, A_Tab)
		cControl := cSelected[1]
		cId := cSelected[2]
		
		BoundGivePar := Func("ControlFocus").Bind(cId)
		Menu, Menu_Contr, Add, Focus, % BoundGivePar
		Menu, Menu_Contr, Add
		BoundGivePar := Func("ClipboardSet").Bind(cControl)
		Menu, Menu_Contr, Add, Copy Control, % BoundGivePar
		Menu, Menu_Contr, Icon, Copy Control, C:\Windows\syswow64\SHELL32.dll , 261
		Menu, Menu_Contr, Add
		BoundGivePar := Func("Gui_Acc").Bind(cId)
		Menu, Menu_Contr, Add, Get Acc, % BoundGivePar
		Menu, Menu_Contr, Show
	}
	return
}

Kill:
ControlGet, Selected, List, Selected, SysListView321,
Selected := StrSplit(Selected, A_Tab)
id := Selected[3]
WinClose, ahk_id %id%
return

lTransparent:
Gui, Submit, Nohide
ControlGet, Selected, List, Selected, SysListView321,
Selected := StrSplit(Selected, A_Tab)
id := Selected[3]
WinSet, Transparent, %vTransparent%, ahk_id %id%
return

Move:
{
	ControlGet, Selected, List, Selected, SysListView321,
	Selected := StrSplit(Selected, A_Tab)
	id := Selected[3]
	WinGetPos, wX, wY, , , ahk_id %id%
	GuiControlGet, xPos
	GuiControlGet, yPos
	GuiControlGet, wWidth
	GuiControlGet, wHeight
	WinActivate, ahk_id %id%
	WinWaitActive, ahk_id %id%
	WinMove, xPos, yPos
	return
}

lVisible:
Gui,Submit, NoHide
GuiControl, -Redraw, LV
LV_Update()
GuiControl, +Redraw, LV
return

LV_Update() {
	Gui, ListView, MyWinList
	
	WinGet,  windowList, List,,, Program Manager
	GuiControlGet, SearchTerm
	GuiControlGet, vTitle
	GuiControlGet, vVisible
	SearchTermOld := SearchTerm
	loop,{ 
		SearchTermOld := SearchTerm
		vTitleOld := vTitle
		vVisibleOld := vVisible
		TotalItems := 0
		LV_Delete()
		Loop %windowList%
		{
			id := windowList%A_Index%
			WinGetTitle wTitle, ahk_id %id%
			WinGet, wProcessName, ProcessName, ahk_id %id%
			DetectHiddenWindows, Off
			WinGetPos, x,,,,ahk_id %id%
			if !x{
				wStyle := "Hidden"
			}
			else{
				wStyle := "Visible"
			}
			DetectHiddenWindows, On
			if (vVisible=0  or wStyle = "Visible"){
				If (InStr(wTitle " " wProcessName, SearchTerm) or (SearchTerm = "")){
					DebugWindow(vTitle "`n")
					if(!vTitle or wTitle !=""){
						LV_Add("", wTitle, wProcessName, id, wStyle)
					}
				}
				TotalItems++
			}
			GuiControlGet, SearchTerm
			GuiControlGet, vTitle
			GuiControlGet, vVisible
			if(SearchTermOld != SearchTerm){
				Break
			}
		}
		GuiControlGet, SearchTerm
		GuiControlGet, vTitle
		GuiControlGet, vVisible
		if(SearchTermOld = SearchTerm and vTitleOld = vTitle and vVisibleOld = vVisible){
			Break
		}
	}
	
	LV_ModifyCol()
	LV_ModifyCol(1, 300)
	LV_ModifyCol(3, "Integer")
	LV_ModifyCol(4, "SortDesc")
	Items := LV_GetCount()
	SB_SetText("   " . Items . " of " . TotalItems . " Items")
	
	return
}

WinActivate(WinTitle:=""){
	WinActivate, %WinTitle%
	return
}

WinHide(WinTitle:=""){
	WinHide, %WinTitle%
	return
}

WinShow(WinTitle:=""){
	WinShow, %WinTitle%
	return
}
WinSet(SubCommand, Wintitle){
	WinSet, %SubCommand%, , %WinTitle%
	return ErrorLevel
}
ControlFocus(Control){
	ControlFocus, %Control%
	return
}

ClipboardSet(strClipboard){
	Clipboard := strClipboard
	return
}

DebugWindow(Text,Clear:=0,LineBreak:=0,Sleep:=0,AutoHide:=0,MsgBox:=0){
	if WinExist("AHK Studio"){
		x:=ComObjActive("{DBD5A90A-A85C-11E4-B0C7-43449580656B}"),x.DebugWindow(Text,Clear,LineBreak,Sleep,AutoHide,MsgBox)
	}
}

/*
	Box_Init - Creates the necessary GUIs.
	Author: berban and Wicked
	https://autohotkey.com/board/topic/54443-box-ie-draw-simple-gui-based-boxes-on-screen/
	C - The color of the box.
*/

Box_Init(C="FF0000") {
	Gui, 96: +ToolWindow -Caption +AlwaysOnTop +LastFound
	Gui, 96: Color, % C
	Gui, 97: +ToolWindow -Caption +AlwaysOnTop +LastFound
	Gui, 97: Color, % C
	Gui, 98: +ToolWindow -Caption +AlwaysOnTop +LastFound
	Gui, 98: Color, % C
	Gui, 99: +ToolWindow -Caption +AlwaysOnTop +LastFound
	Gui, 99: Color, % C
}

/*
	Box_Draw - Draws a box on the screen using 4 GUIs.
	
	X - The X coord.
	
	Y - The Y coord.
	
	W - The width of the box.
	
	H - The height of the box.
	
	T - The thickness of the borders.
	
	O - The offset. O - Outside. C - Centered. I - Inside.
*/

Box_Draw(X, Y, W, H, T="1", O="I") {
	If(W < 0)
		X += W, W *= -1
	If(H < 0)
		Y += H, H *= -1
	If(T >= 2)
	{
		If(O == "O")
			X -= T, Y -= T, W += T, H += T
		If(O == "C")
			X -= T / 2, Y -= T / 2
		If(O == "I")
			W -= T, H -= T
	}
	Gui, 96: Show, % "x" X " y" Y " w" W " h" T " NA", Horizontal 1
	Gui, 98: Show, % "x" X " y" Y + H " w" W " h" T " NA", Horizontal 2
	Gui, 97: Show, % "x" X " y" Y " w" T " h" H " NA", Vertical 1
	Gui, 99: Show, % "x" X + W " y" Y " w" T " h" H " NA", Vertical 2
}

/*
	Box_Destroy - Destoyes the 4 GUIs.
*/

Box_Destroy() {
	Loop, 4
		Gui, % A_Index + 95 ":  Destroy"
}

/*
	Box_Hide - Hides the 4 GUIs.
*/

Box_Hide() {
	Loop, 4
		Gui, % A_Index + 95 ":  Hide"
}

Gui_Acc(hWnd){
	global
	TrayTip, Acc, Get objects %hWnd%
	Menu, Tray, Tip, Loading data...
	
	AccData := JEE_AccGetTextAll2(hWnd, "`r`n")
	Menu, Tray, Tip, %A_ScriptName%
	Gui, 2:default
	Gui, Add, Text, ,Search:
	Gui, Add, Edit, x+10 w400 vvSearchAcc glSearchAcc
	
	; Create the ListView with two columns, Name and Size:
	Gui, Add, ListView, xm r20 w700 vMyAccList glMyAccList AltSubmit, Path|ChildId|Name|Value|Role
	TotalItems :=0
	loop,{ 
		vSearchAccOld := vSearchAcc
		; Gather a list of file names from a folder and put them into the ListView:
		Loop, Parse, AccData, `n
		{
			Line := StrSplit(A_LoopField, "|`t")
			LV_Add("", Line*)
			TotalItems ++
			GuiControlGet, vSearchAcc
			if(vSearchAcc!=vSearchAccOld){
				break
			}
		}  
		if(vSearchAcc=vSearchAccOld){
			break
		}
	}
	
	Gui, Add, StatusBar, , % "   " . TotalItems . " of " . TotalItems . " Items"
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,50)
	
	; Display the window and return. The script will be notified whenever the user double clicks a row.
	Gui, Show, , Acc Data - %hWnd%
	return
	
	2GuiClose:  ; Indicate that the script should exit automatically when the window is closed.
	Gui, Destroy
	return
	
	lSearchAcc:
	Gui, 2:default
	Gui, Submit, NoHide
	;~ GuiControlGet, vSearchAcc
	GuiControl, -Redraw, MyAccList
	LV_Delete()
	
	Loop, Parse, AccData, `n
	{
		If (InStr(A_LoopField, vSearchAcc) or (vSearchAcc = "")){
			
			Line := StrSplit(A_LoopField, "|`t")
			LV_Add("", Line*)
		}
	}  
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,50)
	Items := LV_GetCount()
	SB_SetText("   " . Items . " of " . TotalItems . " Items")
	GuiControl, +Redraw, MyAccList
	Return
	
	lMyAccList:
	ControlGet, accSelected, List, Selected, SysListView321,
	accSelected := StrSplit(accSelected, A_Tab)
	accPath := accSelected[1]
	accChildId := accSelected[2]
	accValue := accSelected[3]
	accRole := accSelected[4]
	
	if (A_GuiEvent = "DoubleClick"){
		oAcc := Acc_Get("Object", accPath, accChildId, "Ahk_id " hWnd)
		GetAccLocation(oAcc, accChildId, accX, accY, accW, accH)
		WinGetPos, wX, wY,,, ahk_id %wId%
		DebugWindow(cControl accX "-" accY "-" accW "-" accH "`n")
		Box_Init(C="FF0000")
		Box_Draw(accX+wX, accY+wY, accW, accH, 2, "in")
	}
	if (A_GuiEvent = "RightClick"){
		try Menu, Menu_Acc, DeleteAll
		ControlGet, accSelected, List, Selected, SysListView321,
		accSelected := StrSplit(accSelected, A_Tab)
		accControl := accSelected[1]
		
		BoundGivePar := Func("AccDefaultAction").Bind(accPath, accChildId, "ahk_id " hWnd)
		Menu, Menu_Acc, Add, AccDefaultAction, % BoundGivePar
		Menu, Menu_Acc, Add
		BoundGivePar := Func("ClipboardSet").Bind(accPath "." accChildId)
		Menu, Menu_Acc, Add, Copy Path, % BoundGivePar
		Menu, Menu_Acc, Icon, Copy Path, C:\Windows\syswow64\SHELL32.dll , 261
		Menu, Menu_Acc, Show
	}
	return
	
}

AccDefaultAction(ChildPath="", ChildID=0, WinTitle=""){
	oAcc := Acc_Get("Object", ChildPath, ChildID, WinTitle)
	oAcc.accDoDefaultAction(ChildID)
}

; Borrowed From ACC Viewer
GetAccLocation(AccObj, Child=0, byref x="", byref y="", byref w="", byref h="") {
	AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), Child)
	return	"x" (x:=NumGet(x,0,"int")) "  "
	.	"y" (y:=NumGet(y,0,"int")) "  "
	.	"w" (w:=NumGet(w,0,"int")) "  "
	.	"h" (h:=NumGet(h,0,"int"))
}

;==================================================
; Borrowed jeeswg from https://www.autohotkey.com/boards/viewtopic.php?f=6&t=40615
JEE_StrRept(vText, vNum)
{
	if (vNum <= 0)
		return
	return StrReplace(Format("{:" vNum "}", ""), " ", vText)
	;return StrReplace(Format("{:0" vNum "}", 0), 0, vText)
}

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

;vOpt: space-separated list
;vOpt: n#: e.g. n20 ;limit retrieve name to first 20 characters
;vOpt: v#: e.g. v20 ;limit retrieve value to first 20 characters

JEE_AccGetTextAll2(hWnd:=0, vSep:="`n", vIndent:="`t", vOpt:="")
{
	vLimN := 20, vLimV := 20
	Loop, Parse, vOpt, % " "
	{
		vTemp := A_LoopField
		if (SubStr(vTemp, 1, 1) = "n")
			vLimN := SubStr(vTemp, 2)
		else if (SubStr(vTemp, 1, 1) = "v")
			vLimV := SubStr(vTemp, 2)
	}
	
	oMem := {}, oPos := {}
	;OBJID_WINDOW := 0x0
	oMem[1, 1] := Acc_ObjectFromWindow(hWnd, 0x0)
	oPos[1] := 1, vLevel := 1
	VarSetCapacity(vOutput, 1000000*2)
	
	Loop
	{
		if !vLevel
			break
		if !oMem[vLevel].HasKey(oPos[vLevel])
		{
			oMem.Delete(vLevel)
			oPos.Delete(vLevel)
			vLevelLast := vLevel, vLevel -= 1
			oPos[vLevel]++
			continue
		}
		oKey := oMem[vLevel, oPos[vLevel]]
		
		vName := "", vValue := ""
		if IsObject(oKey)
		{
			vRoleText := Acc_GetRoleText(oKey.accRole(0))
			try vName := oKey.accName(0)
			try vValue := oKey.accValue(0)
		}
		else
		{
			oParent := oMem[vLevel-1,oPos[vLevel-1]]
			vChildId := IsObject(oKey) ? 0 : oPos[vLevel]
			vRoleText := Acc_GetRoleText(oParent.accRole(vChildID))
			try vName := oParent.accName(vChildID)
			try vValue := oParent.accValue(vChildID)
		}
		if (StrLen(vName) > vLimN)
			vName := SubStr(vName, 1, vLimN) "..."
		if (StrLen(vValue) > vLimV)
			vValue := SubStr(vValue, 1, vLimV) "..."
		vName := RegExReplace(vName, "[`r`n]", " ")
		vValue := RegExReplace(vValue, "[`r`n]", " ")
		
		vAccPath := ""
		if IsObject(oKey)
		{
			Loop, % oPos.Length() - 1
				vAccPath .= (A_Index=1?"":".") oPos[A_Index+1]
		}
		else
		{
			Loop, % oPos.Length() - 2
				vAccPath .= (A_Index=1?"":".") oPos[A_Index+1]
			vAccPath .= " c" oPos[oPos.Length()]
		}
		; Quick Modify by AHK_User
		vChildCount := Acc_Get("ChildCount", vAccPath, 0, "ahk_id " hWnd)
		if (vChildCount=""){
			vParent_Path := RegExReplace(vAccPath, "(.*)\.(\d*)", "$1")
			vChild_Id := RegExReplace(vAccPath, "(.*)\.(\d*)", "$2")
			vName := Acc_Get("Name", vParent_Path, vChild_Id, "ahk_id " hWnd)
			vRoleText := Acc_Get("Role", vParent_Path, vChild_Id, "ahk_id " hWnd)
			vOutput .= vParent_Path "|`t" vChild_Id "|`t"  vName "|`t" vValue "|`t" vRoleText vSep
		}
		else{
			vOutput .= vAccPath "|`t0|`t"  vName "|`t" vValue "|`t" vRoleText  vSep
		}
		;~ vOutput .= vAccPath "`t" JEE_StrRept(vIndent, vLevel-1) vRoleText " [" vName "][" vValue "]" vSep
		
		oChildren := Acc_Children(oKey)
		if !oChildren.Length()
			oPos[vLevel]++
		else
		{
			vLevelLast := vLevel, vLevel += 1
			oMem[vLevel] := oChildren
			oPos[vLevel] := 1
		}
	}
	return SubStr(vOutput, 1, -StrLen(vSep))
}
Here is ACC.ahk

Code: Select all

; http://www.autohotkey.com/board/topic/77303-acc-library-ahk-l-updated-09272012/
; https://dl.dropbox.com/u/47573473/Web%20Server/AHK_L/Acc.ahk
;------------------------------------------------------------------------------
; Acc.ahk Standard Library
; by Sean
; Updated by jethrow:
; 	Modified ComObjEnwrap params from (9,pacc) --> (9,pacc,1)
; 	Changed ComObjUnwrap to ComObjValue in order to avoid AddRef (thanks fincs)
; 	Added Acc_GetRoleText & Acc_GetStateText
; 	Added additional functions - commented below
; 	Removed original Acc_Children function
; last updated 2/25/2010
;------------------------------------------------------------------------------

Acc_Init()
{
	Static	h
	If Not	h
		h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "")
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Acc_ObjectFromWindow(hWnd, idObject = -4)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
	Return	ComObjEnwrap(9,pacc,1)
}

Acc_WindowFromObject(pacc)
{
	If	DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc)?ComObjValue(pacc):pacc, "Ptr*", hWnd)=0
	Return	hWnd
}

Acc_GetRoleText(nRole)
{
	nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
	Return	sRole
}

Acc_GetStateText(nState)
{
	nSize := DllCall("oleacc\GetStateText", "Uint", nState, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetStateText", "Uint", nState, "str", sState, "Uint", nSize+1)
	Return	sState
}

Acc_SetWinEventHook(eventMin, eventMax, pCallback)
{
	Return	DllCall("SetWinEventHook", "Uint", eventMin, "Uint", eventMax, "Uint", 0, "Ptr", pCallback, "Uint", 0, "Uint", 0, "Uint", 0)
}

Acc_UnhookWinEvent(hHook)
{
	Return	DllCall("UnhookWinEvent", "Ptr", hHook)
}
/*	Win Events:
	pCallback := RegisterCallback("WinEventProc")
	WinEventProc(hHook, event, hWnd, idObject, idChild, eventThread, eventTime)
	{
		Critical
		Acc := Acc_ObjectFromEvent(_idChild_, hWnd, idObject, idChild)
		; Code Here:
	}
*/

; Written by jethrow
Acc_Role(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_State(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetStateText(Acc.accState(ChildId)):"invalid object"
}
Acc_Location(Acc, ChildId=0, byref Position="") { ; adapted from Sean's code
	try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
	catch
		return
	Position := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
	return	{x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")}
}
Acc_Parent(Acc) { 
	try parent:=Acc.accParent
	return parent?Acc_Query(parent):
}
Acc_Child(Acc, ChildId=0) {
	try child:=Acc.accChild(ChildId)
	return child?Acc_Query(child):
}
Acc_Query(Acc) { ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
	try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
	static setting:=0
	return p=""?setting:setting:=p
}
Acc_Children(Acc) {
	if ComObjType(Acc,"Name") != "IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren%
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
			return Children.MaxIndex()?Children:
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_ChildrenByRole(Acc, Role) {
	if ComObjType(Acc,"Name")!="IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren% {
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
				if NumGet(varChildren,i-8)=9
					AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild):
				else
					Acc_Role(Acc, child)=Role?Children.Insert(child):
			}
			return Children.MaxIndex()?Children:, ErrorLevel:=0
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {
	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		StringReplace, ChildPath, ChildPath, _, %A_Space%, All
		AccError:=Acc_Error(), Acc_Error(true)
		Loop Parse, ChildPath, ., %A_Space%
			try {
				if A_LoopField is digit
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return
			}
		Acc_Error(AccError)
		StringReplace, Cmd, Cmd, %A_Space%, , All
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
			  , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if Cmd in Role,State
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if Cmd in ChildCount,Selection,Focus
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := """" Cmd """ Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		return ret_val, ErrorLevel:=0
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Last edited by AHK_user on 06 May 2021, 05:31, edited 1 time in total.
gregster
Posts: 9087
Joined: 30 Sep 2013, 06:48

Re: WindowList - Viewer and manipulation of window data

16 Sep 2020, 03:22

Interesting. Thank you :thumbup:
neogna2
Posts: 598
Joined: 15 Sep 2016, 15:44

Re: WindowList - Viewer and manipulation of window data

16 Sep 2020, 17:09

Kind of like Window Spy but for keyboard use - I like it!

Got this error
Error: Call to nonexistent function.
Specifically: Acc_Get
Solved by including Acc

Code: Select all

#Include Acc.ahk
The menu action "Get Acc" can takes a little while for the Acc data listview to show up. Maybe add a visual cue that the command is processing?
User avatar
SirSocks
Posts: 360
Joined: 26 Oct 2018, 08:14

Re: WindowList - Viewer and manipulation of window data

17 Sep 2020, 07:24

This is very handy! Thank you!
Maybe you could provide the #Include acc.ahk within another code block. This way people don't have to go searching for it.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: Bing [Bot] and 53 guests