[Func] AccMatchTextAll - Easily search for Acc info

Post your working scripts, libraries and tools for AHK v1.1 and older
evilmanimani
Posts: 29
Joined: 24 Jun 2020, 16:42

[Func] AccMatchTextAll - Easily search for Acc info

Post by evilmanimani » 12 Sep 2021, 18:23

Acc.ahk has been very useful to me in automating tasks, however it's always been a pain when having to manually look up paths which would often break if the application was updated. This function I've put together has made the process much easier for me, once you've found one or two of the values for the controls you're looking for with AccViewer.ahk or even by modifying the example, you can then retrieve info for specific controls. This relies on a simple modification to jeeswg's JEE_AccGetTextAll which is in the second code block, it now has the option to return an object containing all Acc data, which is then parsed by the function. This object is cached and is looked up when doing subsequent queries, which is significantly faster than running AccGetTextAll every time, however the reload option can be set to refresh that. Let me know if anyone has any suggestions or feedback, cheers.

Get AccV2.ahk from here viewtopic.php?t=40532

Code: Select all

#Include AccV2.ahk

; Example
q::
hwnd := "ahk_exe chrome.exe"
menuPath := AccMatchTextAll(hwnd,{name:"Chrome",roletext:"menu button"})
backPath := AccMatchTextAll(hwnd,{name:"Back",role:43})
addressPath := AccMatchTextAll(hwnd,{name:"address and search"})
addressRole := AccMatchTextAll(hwnd,{path:addressPath},"roletext")
addressValue := Acc_Get("Value",addressPath,,hwnd) ; Get the current value rather than the cached value
Msgbox, % Format("Menu path: {}`r`nBack button path: {}`r`nAddress bar path: {}`r`nAddress bar role: {}`r`nURL: {}",menuPath,backPath,addressPath,addressRole,addressValue)
Return

; Acceptable values for matchlist & get:
; name,value,role,roletext,state
; matchlist is formatted as an array, i.e. AccMatchTextAll("Google Chrome",{name:"Chrome",roletext:"menu button"})
AccMatchTextAll(hwnd, matchList, get := "path", regex := 0, reload := 0) {
    static
    if !IsObject(foundPaths)
        foundPaths := Object()
    nWindow := WinExist(hwnd)
    , matchStr := ""
    , idx := 0
    if (!IsObject(%nWindow%) || reload = 1)
        %nWindow% := JEE_AccGetTextAll(nWindow, , ,"o")
    for k, v in matchList {
        idx++
        matchStr .= k . ":" . StrReplace(v,A_Space) . (idx<matchList.Count()?",":"")
    }
    if !IsObject(foundPaths[nWindow] || reload = 1)
        foundPaths[nWindow] := Object()
    else if foundPaths[nWindow].HasKey(matchStr)
        return foundPaths[nWindow,matchStr,get]
    for i, e in %nWindow% {
        found := 0
        for k, v in e {
            if (v <> "" && matchList.HasKey(k))
                if (regex = 0 && InStr(v,matchlist[k])
                || (regex = 1 && RegExMatch(v, matchList[k])))
                    found++
        }
        if (found = matchList.Count()) {
            foundPaths[nWindow,matchStr] := e
            return e[get]
        }
    }
    return 0
}

Code: Select all

JEE_AccGetTextAll(hWnd:=0, vSep:="`n", vIndent:="`t", vOpt:="")
{
	vLimN := 20, vLimV := 20, retObj := 0, oOutput := []
	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)
		else if (SubStr(vTemp, 1, 1) = "o")
            retObj := 1, vLimN := vLimV := 255
	}

	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)
		{
            vRole := oKey.accRole(0)
			vRoleText := Acc_GetRoleText(vRole)
            vState := Acc_State(oKey)
			try vName := oKey.accName(0)
			try vValue := oKey.accValue(0)
		}
		else
		{
			oParent := oMem[vLevel-1,oPos[vLevel-1]]
			vChildId := IsObject(oKey) ? 0 : oPos[vLevel]
            vRole := oParent.accRole(vChildID)
			vRoleText := Acc_GetRoleText(vRole)
            vState := Acc_State(oParent)
			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()]
		}
		vOutput .= vAccPath "`t" JEE_StrRept(vIndent, vLevel-1) vRoleText " [" vName "][" vValue "]" vSep
        oOutput.Push({path:vAccPath,name:vName,value:vValue,roletext:vRoleText,role:vRole,state:vState})

		oChildren := Acc_Children(oKey)
		if !oChildren.Length()
			oPos[vLevel]++
		else
		{
			vLevelLast := vLevel, vLevel += 1
			oMem[vLevel] := oChildren
			oPos[vLevel] := 1
		}
	}

	return retObj = 1 ? oOutput : SubStr(vOutput, 1, -StrLen(vSep))
}

JEE_StrRept(vText, vNum)
{
	if (vNum <= 0)
		return
	return StrReplace(Format("{:" vNum "}", ""), " ", vText)
	;return StrReplace(Format("{:0" vNum "}", 0), 0, vText)
}

Return to “Scripts and Functions (v1)”