Descolada UIA speed issue

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Nixcalo
Posts: 116
Joined: 06 Feb 2018, 04:24

Descolada UIA speed issue

Post by Nixcalo » 13 Dec 2023, 22:41

Hi people!

I have been working with the fantastic UIA libraries by Descolada, but I have an issue. The thing is, it is too slow. I have been trying for hours to use caching but it's not very documented (or I am dumb, as I have been reading all wikis and examples)...

If someone could help me point out what I am doing wrong...

The script basically gets the clipboard, and uses UIA to paste it in certain window elements of the translation application Trados Studio. It pastes the clipboard on one field, then checks a button is on/off, toggles it if necessary and then inserts the clipboard on a different field.

This script takes between 5 and 7 seconds to execute which is too long. The fields are unchangind, so caching should be a good idea here (if I understand correctly what it does)
I changed the script to have it check whether UIA_interface was already in memory, but time savings are not noticeable, perhaps loading UIA:=UI_Interface() is not where the time goes. But I guess it does not hurt.

I tried to use, instead of the relevant lines of the original script, the following lines:
if not UIA {
UIA := UIA_Interface() ; Initialize UIA interface ; Parece más rápido que new UIA_Browser
cacheRequest := UIA.CreateCacheRequest()
cacheRequest.TreeScope := 5 ; Set TreeScope to include the starting element and all descendants as well
cacheRequest.AddProperty("ControlType")
cacheRequest.AddProperty("LocalizedControlType")
cacheRequest.AddProperty("AutomationId")
cacheRequest.AddProperty("Name")
cacheRequest.AddProperty("Value")
cacheRequest.AddPattern("Toggle")
}


without really knowing what they do, but those are the properties and patterns that my script uses so I guess this should be the way to go.
and then
npEl:= UIA.ElementFromHandleBuildCache(WinExist(ahk_exe SDLTradosStudio.exe), cacheRequest)
instead of
npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe))
but this modification does nothing. It does not search any element, does not paste anything. So I don't know what I am doing wrong, to be honest. Documentation and examples do not seem to indicate how to perform searched with FindFirstBy in cached elements. So I have no idea what to do or how to speed up this script.

Any ideas?

Code: Select all

F3:: ; Búsqueda de Concordancia en Trados o, si no está abierto, en Kantan
StartTime:= A_TickCount
ClipBoard:=""
SendInput, {ControlDown}c{ControlUp}
ClipWait, .1
If WinExist("SDL Trados Studio") ; ESTÁ ABIERTA UNA INSTANCIA DE TRADOS ASÍ QUE HACE CONCORDANCE SEARCH EN TRADOS
{
	Winactivate, SDL Trados Studio
	if not UIA
		UIA := UIA_Interface() ; Initialize UIA interface ; Parece más rápido que 	new UIA_Browser
	
	WinWaitActive, ahk_exe SDLTradosStudio.exe
	npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe)) ; Get the element for the Trados window
	npEl.FindFirstBy("AutomationID=[Editor] Edit Area").SetValue(Clipboard) ; Copia el clipboard en Concordance Search
	Sleep, 100
	SendInput, {Enter}
	
	Boton:=npEl.FindFirstBy("ControlType=Button AND Name=Fuzzy Search") ; Busca si el botón Fuzzy Search en Termbase Search está desactivado. Si no, lo activa
	TogglePattern:=Boton.TogglePattern
	If TogglePattern.ToggleState=0 ; El botón está desactivado
		TogglePattern.Toggle() ; Lo activa
	npEl.FindFirstBy("ControlType=Edit AND LocalizedControlType=editar AND Name=").SetValue(Clipboard) ; Copia el clipboard en Termbase Search
	SendInput, {Enter}
	
	Sleep, 500
		Desplazamiento := npEl.FindFirstBy("ControlType=Tree AND AutomationId=_TreeHits") ; La barrita de desplazamiento, el árbol en realidad de Termbase Search
	
	scrollPattern := Desplazamiento.ScrollPattern
	
	Loop, 10
		scrollPattern.Scroll(, UIA.ScrollAmount_LargeIncrement) ; Llevo la barra de desplazamiento 10 páginas hacia abajo
}
EndTime := A_TickCount
ElapsedSeconds := (EndTime - StartTime)/1000.0
Msgbox, the msgbox was on the screen for %ElapsedSeconds% Seconds before you closed it.
Return

Descolada
Posts: 1202
Joined: 23 Dec 2021, 02:30

Re: Descolada UIA speed issue

Post by Descolada » 14 Dec 2023, 06:40

Hello,
I'm fairly sure that caching isn't the answer here. More likely you need to optimize the Find calls, and maybe replace the Scroll part with SetScrollPercent to make only 1 UIA call instead of 10.

Code: Select all

npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe))
This is unrelated to speed, but WinExist expects a string, so it should be WinExist("ahk_exe SDLTradosStudio.exe") instead.

For the Find calls make sure that your searches aren't traversing too much of the UIA tree. For example I see that your window contains at least one Tree element, which potentially has a lot of elements that you probably don't want to traverse. Try measuring the speed of the UIA calls to see what the cause of the slowdown is.
Also I recommend taking a look at Speed Improvements in the wiki, and the [url=https://www.youtube.com/playlist?list=PLg-VAp_I6_oTfdL9sUqcC7s61jcQW9K38]tutorial series for UIA-v2 might be of help as well.

By the way, I highly recommend switching to AHK v2 and using UIA v2 library instead, which is easier to debug and has more advanced features implemented. There probably wouldn't be much of a speed gain though.

Nixcalo
Posts: 116
Joined: 06 Feb 2018, 04:24

Re: Descolada UIA speed issue

Post by Nixcalo » 14 Dec 2023, 21:33

Hi Descolada, thank you for answering, awesome job there!

I'll cover all relevants points for your answer.
1.- I thought caching might be a good idea because I actually use the script (pressing F3) a LOT. I am a translator, and every time I find a term I don' tknow, I press F3 to check the terminology base in Trados. That's why I thought of caching, because everything in trados stays the same, the windows are the same, their positions are the same, etc.

2.-I have found that was the only way to reach the bottom of the scroll bar. I tried SetScrollPercent but it was MUCH slower... you can test it yourself, while scrollPattern.Scroll(, UIA.ScrollAmount_LargeIncrement) is very fast scrolling down (as pressing Page Down multiple times), scrollPattern.SetScrollPercent(,100) moves more smoothly and, consequently, much more slowly. I found no way to replicate a Control-End hotkey which would move you to the bottommost part of the scroll bar instantly.

3.- About npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe))
Although it seems weird, my version works and yours doesn't (just tested it). While it's true that I have lines such as If WinExist("SDL Trados Studio") that need the quotes, the command npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe)) works perfectly and does the job whereas npEl := UIA.ElementFromHandle(WinExist("ahk_exe SDLTradosStudio.exe")) does nothing. I have no idea why, but that is what happens. You can test it yourself in V1, it's strange but true.

4.- This is my tree, does not seem so large.
image.png
image.png (32.83 KiB) Viewed 409 times
The highlighted "editar" (controlType=50004) is one of two places where I need to insert my text (the other is a bit below the first). I have no idea on how to start from there and traverse less elements. However, I have read the Speed Improvements section in the wiki and it recommends making TreeScope_Children=0x2. Well it does not find the elements so it does nothing, I have had to go back to scope:=0x4

5.- I can't change to V2 because I have a very long script 1000 lines long... Converting it to AHK v2 gives me nightmares so I'll postpone it. I would have to learn V2 as well and I am even not that good with V1!

So... I am a little lost here.

Descolada
Posts: 1202
Joined: 23 Dec 2021, 02:30

Re: Descolada UIA speed issue

Post by Descolada » 16 Dec 2023, 15:10

Nixcalo wrote:
14 Dec 2023, 21:33
1.- I thought caching might be a good idea because I actually use the script (pressing F3) a LOT. I am a translator, and every time I find a term I don' tknow, I press F3 to check the terminology base in Trados. That's why I thought of caching, because everything in trados stays the same, the windows are the same, their positions are the same, etc.
If the elements stay the same then you can use caching in the sense of storing the elements in a static variable until the next call of the function, and then you can reuse the element without finding it all over again. In my first post when I mentioned that caching probably isn't useful I actually meant that using UIA CacheRequest probably isn't useful (since your example included an attempt to use it), but caching elements in AHK most definitely is.

2.-I have found that was the only way to reach the bottom of the scroll bar. I tried SetScrollPercent but it was MUCH slower... you can test it yourself, while scrollPattern.Scroll(, UIA.ScrollAmount_LargeIncrement) is very fast scrolling down (as pressing Page Down multiple times), scrollPattern.SetScrollPercent(,100) moves more smoothly and, consequently, much more slowly. I found no way to replicate a Control-End hotkey which would move you to the bottommost part of the scroll bar instantly.
You could also try getting the last element of the tree and using ScrollIntoView. Something like UIA.TreeWalkerTrue.GetLastChildElement(Desplazamiento).ScrollItemPattern.ScrollIntoView()
3.- About npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe))
Although it seems weird, my version works and yours doesn't (just tested it). While it's true that I have lines such as If WinExist("SDL Trados Studio") that need the quotes, the command npEl := UIA.ElementFromHandle(WinExist(ahk_exe SDLTradosStudio.exe)) works perfectly and does the job whereas npEl := UIA.ElementFromHandle(WinExist("ahk_exe SDLTradosStudio.exe")) does nothing. I have no idea why, but that is what happens. You can test it yourself in V1, it's strange but true.
Although it might work, it is most definitely NOT correct. It works because in AHK v1, inside WinExist ahk_exe SDLTradosStudio.exe gets evaluated as a variable ahk_exe (which is undefined, meaning an empty string) concatenated with SDLTradosStudio.exe which also evaluates to an empty string, so it becomes WinExist("") which gets you the Last Found Window from the previous WinWaitActive call. So the question is that why doesn't WinExist("ahk_exe SDLTradosStudio.exe") return the correct window?
4.- This is my tree, does not seem so large. image.png
The highlighted "editar" (controlType=50004) is one of two places where I need to insert my text (the other is a bit below the first). I have no idea on how to start from there and traverse less elements. However, I have read the Speed Improvements section in the wiki and it recommends making TreeScope_Children=0x2. Well it does not find the elements so it does nothing, I have had to go back to scope:=0x4
Some nodes of the tree are collapsed so I can't tell how large it is. The TreeScope_Children=0x2 suggestion means that instead of searching the whole tree for the target element, write multiple Find calls to get to the target element layer by layer. For example to get the element in your screenshot you could use FindByPath: npEl.FindByPath("5.1.2.1.1.1.1.1.2.1.1.2.1"), which starts from the main window element, gets the fifth child element, then its first child element and so on. If the window layout doesn't change then using a numeric path like so might give speed improvements. UIA-v2 UIAViewer has a way to get this numeric path more easily.
But I still recommend speed-testing the different parts of your code to figure out what exactly is causing the slowdown.

Post Reply

Return to “Ask for Help (v1)”