Что нового

UIAutomate - автоматизация нестандартных элементов GUI

Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
Обновление до версии 1.2:
- добавлены функции _UIA_CreateLogicalCondition(), _UIA_CreatePropertyCondition(), _UIA_ElementGetFirstLastChild(), _UIA_ElementGetParent(), _UIA_FindAllElementsEx(), _UIA_GetElementFromCondition(), _UIA_WaitElementFromCondition()
 

POMKA

Новичок
Сообщения
5
Репутация
0
Пробую запускать скриптик из Ответ #32
И вот, как самый начинающий, нашел такие фишки: Если Chrome не запущен, то скрипт работает отлично! Если же Chrome уже работает со всякими окошками, то запускаемаое новаое окно или вкладка (по настроению Chrome) уже не отрабатывает опцию --force-renderer-accessibility и скрипт выдает ошибки ожидания :(
Моя задача автоматизировать некоторые действия в интернете, пользователь сидит в инете в Chrome с открытыми несколькими страничками и иногда для некоторых страниц хочет автоматически выполнить некоторые действия (обновить объявления). Получается, что в этом случает автоматизация Chrome невозможна? Или нужно Chrome закрывать и запускать с опцией --force-renderer-accessibility, что совсем не есть гуд :(
Куда копать, посоветуйте новичку?

и сам скрипт из ответа 32
Код:
#include "UIAutomate.au3"
Opt("WinTitleMatchMode", 2)

Run(@ProgramFilesDir & "\Google\Chrome\Application\chrome.exe www.iqoption.ru --force-renderer-accessibility")
$hWnd = WinWait(" - Google Chrome", "", 5)
If Not $hWnd Then Exit

$oParent = _UIA_GetElementFromHandle($hWnd)
$oElement = _UIA_WaitControlTypeElement($oParent, "UIA_ButtonControlTypeId", "Войти", Default, True, 20)
_UIA_ElementDoDefaulAction($oElement)
_UIA_WaitControlTypeElement($oParent, "UIA_TextControlTypeId", "Авторизация")

$aAllElements = _UIA_FindAllElements($oParent)
For $i = 1 To $aAllElements[0]
  If _UIA_ElementGetPropertyValue($aAllElements[$i], "Name") = " Запомнить меня" Then
    ConsoleWrite(_UIA_ElementGetPropertyValue($aAllElements[$i - 2], "Name") & @CRLF)
    ConsoleWrite(_UIA_ElementGetPropertyValue($aAllElements[$i + 2], "Name") & @CRLF)
    ExitLoop
  EndIf
Next
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
POMKA [?]
Куда копать, посоветуйте новичку
Во-первых, что мешает сразу прописать параметр --force-renderer-accessibility в ярлык запуска Chrome?
Во-вторых, если в адресной строке запущенного Chrome ввести chrome://accessibility[enter], то можно перейти на одноимённую страницу, позволяющую управлять режимом доступа (глобально или отдельно по открытым вкладкам).

и сам скрипт из ответа 32
И зачем? :stars:
 

coolpunk

Новичок
Сообщения
7
Репутация
2
[Элементы GUI] Re: UIAutomate - автоматизация нестандартных элементов GUI

Спасибо автору за работу, очень помогли данные функции в моем хобби.
Субъективно сужу только по своей задаче, но с поиском и массивами получилось сложновато.
Гораздо проще, если бы поиск возвращал индекс объекта в массиве. Предусмотреть в параметрах начальный индекс поиска. В общем, как реализован поиск в строках.
Для примера покажу свое дерево, в котором объекты не всегда на своем месте.
Ближайший точный ориентир для нужного объекта - надпись "НАПАСТЬ", который бывает и кнопкой и текстом.
В данном случае мне нужен текст "19" (выделен на скринах). Попробовал новой функцией, не получилось, разбираться не стал, потому что в процессе написания уже не понравилось.

Код:
$aFinds = _UIA_FindElementsInArray($aAllElements, $UIA_NamePropertyId, "НАПАСТЬ")
If IsArray($aFinds) And $aFinds[0] > 0 Then
    ;Local $property = _UIA_CreatePropertyCondition($UIA_ControlTypePropertyId, 0xC364)
    Local $aFindText = _UIA_FindAllElementsEx($aFinds[$aFinds[0]]) ;$property
    If IsArray($aFindText) And $aFindText[0] > 0 Then
        _DebugOut(_UIA_ElementGetPropertyValue($aFindText[1], $UIA_NamePropertyId))
    EndIf
EndIf


Вот так делал раньше, работает.
Код:
For $i = 1 To $aAllElements[0]
	If _UIA_ElementGetPropertyValue($aAllElements[$i], $UIA_NamePropertyId) = "НАПАСТЬ" Then
		For $j = $i+1 To $aAllElements[0]
			If _UIA_ElementGetPropertyValue($aAllElements[$j], $UIA_ControlTypePropertyId) = 0xC364 And _
				_UIA_ElementGetPropertyValue($aAllElements[$j], $UIA_NamePropertyId) <> "НАПАСТЬ" Then
					_DebugOut(_UIA_ElementGetPropertyValue($aAllElements[$j], $UIA_NamePropertyId))
					ExitLoop 2
			EndIf
		Next
	EndIf
Next

В данном случае возврат в поиске только индекса избавил бы нас от лишних циклов и условий, освобождение стека от передачи и возвратов массивов.
 

Вложения

Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
coolpunk
если бы поиск возвращал индекс объекта в массиве
Если вы про функцию _UIA_FindElementsInArray(), то она возвращает самостоятельный массив и была задумана, как "фильтр" по определённому свойству-значению. Если же у вас есть массив, в котором нужно найти определённый элемент, то просто пробегитесь по нему в цикле до нужного совпадения. Это всего 3-4 строчки кода...

coolpunk
Вот так делал раньше, работает.
И чем вас теперь это не устраивает?

В любом случае поиск в UIAutomation работает только для дочерних элементов и потомков. Я имею в виду поиск, когда возвращается массив элементов. В вашем случае, насколько я понял, нужно найти текст, находящийся после кнопки, на этом же уровне вложенности. Вариант может быть следующий:
- найти кнопку "UIA_ButtonControlTypeId" с именем "НАПАСТЬ" при помощи _UIA_GetControlTypeElement()
- в цикле вызывать _UIA_ElementGetPreviousNext(), начиная с этой кнопки, пока не найдёте свой элемент (или пока элементы не закончатся)
 

coolpunk

Новичок
Сообщения
7
Репутация
2
Почти все устраивает, в примере и показал примерно то, что вы пишите. Суть поста была в последней строчке.
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
coolpunk
Суть поста была в последней строчке
Если вы про это
избавил бы нас от лишних циклов и условий
то вместо пользователя это бы делала функция. К тому же элемент с подходящим условием может быть не один и придётся возвращать массив индексов. А это ещё сложнее - перебирать массив для каждого элемента другого массива. Поэтому проще создать цикл под конкретное условие, что, собственно, вы и сделали.

Кстати, при помощи "новых" функций с использованием условий (Condition), можно сразу находить элементы по нескольким условиям без "фильтрации" через _UIA_FindElementsInArray(). Для вашего случая, например, можно выбрать в массив только кнопки и тексты.
 

coolpunk

Новичок
Сообщения
7
Репутация
2
то вместо пользователя это бы делала функция
я вижу другое, в теле функции цикл выполняется и у меня он выполняется второй раз, только для того, чтобы узнать индекс объекта-метки, и третий цикл для поиска нужного объекта.
Вы не до конца поняли меня, не важно сколько найденных результатов, возвращается индекс первого совпадения. Для поиска следующих применяется поиск со следующей позиции. Я привел аналогию с функцией StringInStr(), в моей памяти везде только такой поиск и используется (кроме StringRegExp() с флагом 3).

Для вашего случая, например, можно выбрать в массив только кнопки и тексты
Большого выигрыша я здесь не получу, не вижу упрощенного решения с помощью данных условий.
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
coolpunk
не до конца поняли
Теперь понял. Но для этого нужно делать отдельную функцию, в которой будет куча проверок на корректность переданных параметров, плюс тот же цикл, плюс сам вызов функции. А ваш код, который "так делал раньше", как раз это всё и делает. И если его заменить на два вызова подобной функции, то скорости это точно не прибавит.

не вижу упрощенного решения
Если ваша проблема только в "лишнем" текстовом элементе, то можно попробовать так
Код:
$pCond = _UIA_CreatePropertyCondition("Name", "НАПАСТЬ") ; условие
$aFind = _UIA_FindAllElementsEx($oParent, $pCond) ; поиск по условию
If Not @error Then
  If $aFind[0] = 2 Then ; если найдено два, то берём следующий для второго
    $Name = _UIA_ElementGetPropertyValue(_UIA_ElementGetPreviousNext($aFind[2])[1], "Name")
  Else ; иначе берём следующий через один для первого
    $Name = _UIA_ElementGetPropertyValue(_UIA_ElementGetPreviousNext(_UIA_ElementGetPreviousNext($aFind[1])[1])[1], "Name")
  EndIf
EndIf
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
Обновление до версии 1.3:
- добавлена функция _UIA_ElementFindInArray(), позволяющая находить объект в массиве объектов и возвращающая индекс элемента исходного массива
- функция _UIA_ElementDoDefaulAction() переименована в _UIA_ElementDoDefaultAction()
- добавлена проверка ошибок выполнения методов объекта UIAutomation
- в функцию _UIA_ElementMouseClick() добавлена опция активации элемента перед кликом
- в функцию _UIA_FindElementsInArray() добавлен переключатель: элементами возвращаемого массива могут быть или объекты или индексы элементов исходного массива
 

yuraiva

Новичок
Сообщения
3
Репутация
0
Подскажите пожалуйста ссылочку на скачивание API UIAutomation для Win XP. По ссылке указанной в шапке темы отыскать соответствующий файл не хватило сообразительности. :scratch: Заранее благодарен.
 

alex33

Скриптер
Сообщения
1 455
Репутация
183
yuraiva сказал(а):
Подскажите пожалуйста ссылочку на скачивание API UIAutomation для Win XP. По ссылке указанной в шапке темы отыскать соответствующий файл не хватило сообразительности. :scratch: Заранее благодарен.
Вот ссылка на скачивание: https://www.microsoft.com/en-us/download/confirmation.aspx?id=13821
А вот видео, где я показал как скачивать: http://youtu.be/qQs589U-Cyg
 

uritalex

Новичок
Сообщения
197
Репутация
3
Добрый день! Выражаю глубокую благодарность автору темы за столь полезный инструмент для решения иногда весьма не стандартных задач и запросов. Прошу подсказать: работает ли функция _UIA_GetControlTypeElement в окне IE если оно свернуто? просто составил функцию для поиска всплывающего окна на странице (стандартными средствами по анализу кода страницы не получилось т.к. все данные по которым можно отловить окно присутствуют в коде странице изначально т.е. получается что этот элемент есть всегда даже если он не отображается визуально) :
Код:
.....................
Func Eror ($Eror)
   $oParent = _UIA_GetElementFromHandle($hnd)
   $oElement = _UIA_GetControlTypeElement($oParent, $UIA_TextControlTypeId, $Eror, "Name")
     If IsObj($oElement) Then Return 1
EndFunc
....................

при развернутом окне, не обязательно активном, код работает, но стоит окно свернуть то отлов окна не производится :( выдает это:
Код:
!> _UIA_GetControlTypeElement : элементы указанного типа не найдены
Возможно заставить функцию работать и в свернутом окне?
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
uritalex
в окне IE если оно свернуто
Да, работает. Но родительским элементом в этом случае нужно делать не окно IE, а контрол "Internet Explorer_Server"
Код:
$oParent = _UIA_GetElementFromHandle(ControlGetHandle("[class:IEFrame]", "", "Internet Explorer_Server1"))


для поиска всплывающего окна
даже если он не отображается визуально
Дело в том, что интерфейс UIAutomation работает только с деревом видимых объектов. Скрытые (hidden) объекты найдены не будут.
Например, если в блокноте открыть диалог поиска или замены и свернуть главное окно, то окно диалога вместе со всеми его элементами станут невидимы (скрыты) и UIAutomation дерево этих объектов не построит.
Я не знаю, о каком всплывающем окне говорите вы, но имейте в виду, что при сворачивании IE данное окно тоже может быть скрыто.
 

uritalex

Новичок
Сообщения
197
Репутация
3
Благодарю за пояснения буду пробовать :beer:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 275
Репутация
2 352
Как можно использовать эту штуку для определения имени файла (желательно включая полный путь к нему), над которым находится курсор?
Я имею в виду системный Explorer и рабочий стол.

:scratch:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 275
Репутация
2 352
Сам себе же отвечаю:

Код:
#include 'UIAutomate.au3'

Local $oElement = _UIA_GetElementFromPoint(MouseGetPos(0), MouseGetPos(1))
Local $sVal = _UIA_ElementGetPropertyValue($oElement, 'LegacyIAccessible.Value')

If $sVal = '' Then
	$sVal = _UIA_ElementGetPropertyValue($oElement, 'LegacyIAccessible.Name')
EndIf

MsgBox(0, '', $sVal)
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
CreatoR
определения имени файла (желательно включая полный путь к нему), над которым находится курсор
Пример для проводника
Код:
#include <WinAPI.au3>
#include "UIAutomate.au3"

$UIA_ConsoleWriteError = 0

While Sleep(100)
  ToolTip(GetPath())
WEnd

Func GetPath()
  Local $sPrefix = "Адрес: ", $oParent, $tPoint = _WinAPI_GetMousePos()
  Local $hCtrl = _WinAPI_WindowFromPoint($tPoint)
  If _WinAPI_GetClassName($hCtrl) <> "DirectUIHWND" Then Return ""
  Local $oElement = _UIA_GetElementFromPoint($tPoint.X, $tPoint.Y)
  If _UIA_ElementGetPropertyValue($oElement, "ControlType") = $UIA_ListItemControlTypeId Then
    $sName = _UIA_ElementGetPropertyValue($oElement, "Name")
  Else
    $oParent = _UIA_ElementGetParent($oElement)
    If _UIA_ElementGetPropertyValue($oParent, "ControlType") = $UIA_ListItemControlTypeId Then
      $sName = _UIA_ElementGetPropertyValue($oParent, "Name")
    Else
      Return ""
    EndIf
  EndIf
  $sPath = ControlGetText(_WinAPI_GetAncestor($hCtrl, 2), "", "ToolbarWindow322") ; Win7
;~   $sPath = ControlGetText(_WinAPI_GetAncestor($hCtrl, 2), "", "ToolbarWindow323") ; Win81, Win10
  If StringRight($sPath, 1) <> "\" Then $sPath &= "\"
  Return StringReplace($sPath & $sName, $sPrefix, "")
EndFunc
 
Автор
I

InnI

AutoIT Гуру
Сообщения
4 331
Репутация
1 168
CreatoR
как быть с рабочим столом
Для рабочего стола эта UDF, в общем-то, и не нужна - достаточно GuiListView. Здесь главное как-то различать пользовательский рабочий стол и общий, т.к. в них могут находиться файлы с одинаковыми именами. И на системах х64 нужно запускать из-под х64
Код:
#include <GuiListView.au3>

While Sleep(100)
  ToolTip(GetPath())
WEnd

Func GetPath()
  Local $tPoint = _WinAPI_GetMousePos(), $hLV = _WinAPI_WindowFromPoint($tPoint)
  If  _WinAPI_GetClassName($hLV) <> "SysListView32" _
  And _WinAPI_GetClassName(_WinAPI_GetAncestor($hLV, 2)) <> "Progman" Then Return ""
  Local $aHitTest = _GUICtrlListView_HitTest($hLV)
  If @error Or Not IsArray($aHitTest) Then Return ""
  Local $sName = "\" & _GUICtrlListView_GetItemText($hLV, $aHitTest[0])
  Local $aPaths[] = [@DesktopDir & $sName, @DesktopDir & $sName & ".lnk", _
                     @DesktopCommonDir & $sName, @DesktopCommonDir & $sName & ".lnk"]
  For $i = 0 To UBound($aPaths) - 1
    If FileExists($aPaths[$i]) Then Return $aPaths[$i]
  Next
  Return ""
EndFunc
 
Верх