Что нового

[Элементы GUI] Как управлять списком IAccessible: Focus, Select, ScrollToView?

IvanChai

Новичок
Сообщения
7
Репутация
0
Имеем рабочий пример http://autoit-script.ru/index.php?topic=23438.msg135174#msg135174:
Код:
#include "CUIAutomation2.au3"
#include "MSActiveAccessibility.au3"

Opt( "MustDeclareVars", 1 )
Global $hWnd
Global $hWindow

MainFunc()


Func MainFunc()

  $hWnd = WinWait("[CLASS:d8348ccb68a1]", "", 10)
  WinActivate($hWnd)

  Local $ct ="[CLASSNN:SysListView321]";
  $hWindow = ControlGetHandle($hWnd, "", $ct)
  If Not $hWindow Then Return

  ; Get Window object
  Local $pWindow, $oWindow
  AccessibleObjectFromWindow( $hWindow, $OBJID_CLIENT, $tIID_IAccessible, $pWindow )
  $oWindow = ObjCreateInterface( $pWindow, $sIID_IAccessible, $dtagIAccessible )
  If Not IsObj( $oWindow ) Then Return

  ; Window name
  Local $sName
  ConsoleWrite( @CRLF & "Window:" )
  ConsoleWrite( @CRLF & "-------" & @CRLF )
  PrintObjectInfo( $oWindow, $CHILDID_SELF, "" )

  ; Get children
  ConsoleWrite( "Children:" & @CRLF )
  ConsoleWrite( "---------" & @CRLF )
  WalkTreeWithAccessibleChildren( $pWindow, 0, 5 )

EndFunc


Func WalkTreeWithAccessibleChildren( $pAcc, $iLevel, $iLevels = 0 )

  If $iLevels And $iLevel = $iLevels Then Return

  ; Create object
  Local $oAcc = ObjCreateInterface( $pAcc, $sIID_IAccessible, $dtagIAccessible )
  If Not IsObj( $oAcc ) Then Return
  $oAcc.AddRef()

  Local $iChildCount, $iReturnCount, $tVarChildren

  ; Get children
  If $oAcc.get_accChildCount( $iChildCount ) Or Not $iChildCount Then Return
  If AccessibleChildren( $pAcc, 0, $iChildCount, $tVarChildren, $iReturnCount ) Then Return

  ; Indentation
  Local $sIndent = ""
  For $i = 0 To $iLevel - 1
    $sIndent &= "    "
  Next

  Local $vt, $pChildObj, $oChildObj, $iChildElem

  ; For each child
  For $i = 1 To $iReturnCount

    ; $tVarChildren is an array of VARIANTs with information about the children
    $vt = BitAND( DllStructGetData( $tVarChildren, $i, 1 ), 0xFFFF )

    If $vt = $VT_DISPATCH Then

      ; Child object
      $pChildObj = DllStructGetData( $tVarChildren, $i, 3 )
      $oChildObj = ObjCreateInterface( $pChildObj, $sIID_IAccessible, $dtagIAccessible )
      If IsObj( $oChildObj ) Then
        PrintObjectInfo( $oChildObj, $CHILDID_SELF, $sIndent )
        WalkTreeWithAccessibleChildren( $pChildObj, $iLevel + 1, $iLevels )
      EndIf

    Else ; $vt = $VT_I4

      ; Child element
      $iChildElem = DllStructGetData( $tVarChildren, $i, 3 )
      PrintObjectInfo( $oAcc, $iChildElem, $sIndent )

    EndIf

  Next

EndFunc


Func PrintObjectInfo( $oAcc, $iChild, $sIndent )
  Local $sName, $iRole, $sRole, $iRoleLen
  Local $iState, $sState, $iStateLen
  Local $sValue, $x, $y, $w, $h
  If $iChild <> $CHILDID_SELF Then _
    ConsoleWrite( $sIndent & "$iChildElem = " & $iChild & @CRLF )
    $oAcc.get_accName( $iChild, $sName )

    ConsoleWrite( $sIndent & "$sName  = " & $sName & @CRLF )

    If $oAcc.accLocation( $x, $y, $w, $h, $iChild ) = $S_OK Then _
      ConsoleWrite( $sIndent & "$x, $y, $w, $h = " & $x & ", " & $y & ", " & $w & ", " & $h & @CRLF )
    ConsoleWrite( @CRLF )
EndFunc

Возможно ли использовать полученные данные ($oWindow, $pWindow, $iChildElem, $oAcc, $pAcc или $tVarChildren) для управления элементами списка (выделение, фокус, прокрутка к элементу, вызов контекстного меню на заданном элементе) или остаётся только вариант использования стандартного Handle ($hWindow) вместе с IAccessible (который по факту нужен только для получения BoundRectangle и Name)? Если да, то каким образом?
 

InnI

AutoIT Гуру
Сообщения
4,922
Репутация
1,432
IvanChai
Используя IAccessible можно по имени узнать индекс элемента (пункта списка). Всё остальное сделает UIAutomate
Код:
#include <UIAutomate.au3>
#include "MSActiveAccessibility.au3"

Global Const $sIID_IAccessible = "{618736E0-3C3D-11CF-810C-00AA00389B71}"
Global $dtagIAccessible = "GetTypeInfoCount hresult(uint*);" & _
"GetTypeInfo hresult(uint;int;ptr*);" & _
"GetIDsOfNames hresult(struct*;wstr;uint;int;int);" & _
"Invoke hresult(int;struct*;int;word;ptr*;ptr*;ptr*;uint*);" & _
"get_accParent hresult(ptr*);" & _
"get_accChildCount hresult(long*);" & _
"get_accChild hresult(variant;idispatch*);" & _
"get_accName hresult(variant;bstr*);" & _
"get_accValue hresult(variant;bstr*);" & _
"get_accDescription hresult(variant;bstr*);" & _
"get_accRole hresult(variant;variant*);" & _
"get_accState hresult(variant;variant*);" & _
"get_accHelp hresult(variant;bstr*);" & _
"get_accHelpTopic hresult(bstr*;variant;long*);" & _
"get_accKeyboardShortcut hresult(variant;bstr*);" & _
"get_accFocus hresult(struct*);" & _
"get_accSelection hresult(variant*);" & _
"get_accDefaultAction hresult(variant;bstr*);" & _
"accSelect hresult(long;variant);" & _
"accLocation hresult(long*;long*;long*;long*;variant);" & _
"accNavigate hresult(long;variant;variant*);" & _
"accHitTest hresult(long;long;variant*);" & _
"accDoDefaultAction hresult(variant);" & _
"put_accName hresult(variant;bstr);" & _
"put_accValue hresult(variant;bstr);"

$hCtrl = ControlGetHandle("[RegexpTitle:Zello]", "", "SysListView323") ; список "Лучшие каналы"
$iIndex = _GetIndexByName($hCtrl, "Трасса") ; индекс канала "Трасса"
If Not $iIndex Then Exit MsgBox(0, "Error", "Элемент не найден", 2)

$oParent = _UIA_GetElementFromHandle($hCtrl) ; список "Лучшие каналы"
$aItems = _UIA_FindAllElements($oParent, "ControlType", $UIA_ListItemControlTypeId) ; все пункты списка
$oElement = $aItems[$iIndex] ; канал "Трасса"

; включение канала двойным кликом
_UIA_ElementScrollIntoView($oElement)
_UIA_ElementMouseClick($oElement, "", Default, Default, 2)

Sleep(2000)

; выключение канала (одна функция вместо двух предыдущих)
_UIA_ElementInvoke($oElement)

; -------------------------------------------------

Func _GetIndexByName($hWnd, $sName, $fInStr = True)
  If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
  Local $pWindow, $oWindow, $iChildCount, $sText
  AccessibleObjectFromWindow($hWnd, $OBJID_CLIENT, $tIID_IAccessible, $pWindow)
  $oWindow = ObjCreateInterface($pWindow, $sIID_IAccessible, $dtagIAccessible)
  If Not IsObj($oWindow) Then Return  SetError(2, 0, 0)
  If $oWindow.get_accChildCount($iChildCount) Or Not $iChildCount Then Return SetError(3, 0, 0)
  For $iChild = 1 To $iChildCount
    $oWindow.get_accName($iChild, $sText)
    If $fInStr Then
      If StringInStr($sText, $sName) Then Return $iChild
    Else
      If $sText = $sName Then Return $iChild
    EndIf
  Next
EndFunc

Func _UIA_ElementInvoke($oElement)
  If Not IsObj($oElement) Then Return SetError(1, __UIA_ConsoleWriteError("_UIA_ElementInvoke : параметр не является объектом"), 0)
  Local $pInvoke, $oInvoke
  $oElement.GetCurrentPattern($UIA_InvokePatternId, $pInvoke)
  $oInvoke = ObjCreateInterface($pInvoke, $sIID_IUIAutomationInvokePattern, $dtagIUIAutomationInvokePattern)
  If Not IsObj($oInvoke) Then Return SetError(2, __UIA_ConsoleWriteError("_UIA_ElementInvoke : ошибка создания объекта на основе шаблона Invoke"), 0)
  Local $ErrorCode = $oInvoke.Invoke()
  If $ErrorCode Then Return SetError(3, __UIA_ConsoleWriteError("_UIA_ElementInvoke : ошибка выполнения метода (0x" & Hex($ErrorCode) & ")"), 0)
EndFunc

И снова удивляюсь интерфейсу: DoDefaultAction не воспринимает, а Invoke работает. :stars:
 
Автор
IvanChai

IvanChai

Новичок
Сообщения
7
Репутация
0
Благодарю за исчерпывающий ответ и подробный пример :ok:
 
Верх