Re: AHK: Замена "Window Spy"
Никак.
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Никак.
Malcev
А какой тогда смысл, если нет возможности использовать данные из этого Spy?
user7256, этот инструмент не для программного использования. С его помощью вы можете визуально ознакомиться со структурой окна, и скопировать какие-либо данные в буфер обмена.
Плохо. Большинство - хочет строить свою логику на основе выдаваемых данных, а не просто скопировать в буфер.
Почему плохо? Просто эта программа не для этого. Вы можете посмотреть в коде, какие методы используются, и применять их отдельно. Либо спросить здесь, если чего-то не понимаете.
user7256
Какой смысл использовать огромный кусок кода для своих мелких поделок? Не легче разобраться как оно устроено и сделать свою версию?
Библиотека Acc настолько сложна и забагованна, что без обертки пользоваться ей невозможно.
То тут, то там возникают ошибки.
Яркий тому пример - протухшая библиотека AccV2.ahk на гитхабе.
Хорошие программисты всегда стремились к понижению сложности.
Для уменьшения затрат на программирование практикуется code reuse, разбивка на модули и много других техник.
У вас ничего этого нет. Все в кучу на 8 тыс строк на 280 кб.
Вы предлагаете выдирать отдельные функции из вашего скрипта для использования в моих скриптах.
Но логичнее было бы один раз создать библиотеку Acc.ahk, и подключать к вашему AhkSpy.ahk где была бы только рисовалка формы с выводом данных в нее.
Это и было бы настоящим code reuse и разбивкой на модули на практике.
Так чтобы другие могли ей пользоваться, а не только трое программистов на свете, участвовавших в разработке.
Вы потратили столько времени на скрипт, это похвально.
Но ваш код очень быстро придет в негодность как только исчезнет желание его поддерживать.
И все сотни часов разработки окажутся потрачены зря, как у того самого юзера sancarn на гите.
Вот я выдрал все процедуры и хочу получить адрес бар из firefox с помощью GetBrowserURL()
Вот что получаю в результате:
ComObjError(false)
Global WS_EX_APPWINDOW := 0x40000, WS_CHILDWINDOW := 0x40000000, WS_EX_LAYERED := 0x80000
, WS_EX_TRANSPARENT := 0x20, WS_POPUP := 0x80000000, WS_EX_NOACTIVATE := 0x8000000
#NoEnv
#UseHook
#KeyHistory 0
SetBatchLines, -1
ListLines, Off
DetectHiddenWindows, On
CoordMode, Pixel
CoordMode, Menu
oOther.anchor := {}, oOther.CurrentProcessId := DllCall("GetCurrentProcessId")
; If MemoryAnchor
; {
; If oOther.anchor["Win_text"] := IniRead("Win_Anchor")
; oOther.anchor["Win"] := 1
; If oOther.anchor["Control_text"] := IniRead("Control_Anchor")
; oOther.anchor["Control"] := 1
; }
SeDebugPrivilege()
oBody := oDoc.body
oJScript := oDoc.Script
oJScript.WordWrap := WordWrap
oJScript.MoveTitles := MoveTitles
ComObjConnect(oDoc, Events)
url := GetBrowserURL()
OutputDebug, url: %url%
GetBrowserURL()
{
WinGet, hw, ID, ahk_exe firefox.exe
AccAccFocus(hw, name, value, role, irole)
OutputDebug, value: %value%
return value
}
SeDebugPrivilege() {
Static PROCESS_QUERY_INFORMATION := 0x400, TOKEN_ADJUST_PRIVILEGES := 0x20, SE_PRIVILEGE_ENABLED := 0x2
hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION, Int, false, UInt, oOther.CurrentProcessId, Ptr)
DllCall("Advapi32\OpenProcessToken", Ptr, hProc, UInt, TOKEN_ADJUST_PRIVILEGES, PtrP, token)
DllCall("Advapi32\LookupPrivilegeValue", Ptr, 0, Str, "SeDebugPrivilege", Int64P, luid)
VarSetCapacity(TOKEN_PRIVILEGES, 16, 0)
NumPut(1, TOKEN_PRIVILEGES, "UInt")
NumPut(luid, TOKEN_PRIVILEGES, 4, "Int64")
NumPut(SE_PRIVILEGE_ENABLED, TOKEN_PRIVILEGES, 12, "UInt")
DllCall("Advapi32\AdjustTokenPrivileges", Ptr, token, Int, false, Ptr, &TOKEN_PRIVILEGES, UInt, 0, Ptr, 0, Ptr, 0)
res := A_LastError
DllCall("CloseHandle", Ptr, token)
DllCall("CloseHandle", Ptr, hProc)
Return res ;; в случае удачи 0
}
AccWindowFromObject(pacc) {
If DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc) ? ComObjValue(pacc) : pacc, "Ptr*", hWnd) = 0
Return hWnd
}
;; http://forum.script-coding.com/viewtopic.php?pid=130762#p130762
AccAccFocus(hWnd, byref name, byref value, byref role, byref irole) {
Acc := Acc_ObjectFromWindow(hWnd)
While IsObject(Acc.accFocus)
Acc := Acc.accFocus
try
{
child := Acc.accFocus
name := Acc.accName(child)
value := Acc.accValue(child)
role := AccRole(Acc, child)
irole := Acc.accRole(0)
}
}
AccRole(Acc, ChildId=0) {
Return ComObjType(Acc, "Name") = "IAccessible" ? AccGetRoleText(Acc.accRole(ChildId)) : ""
}
AccGetRoleText(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
}
AccGetStateText(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_GetPath(byref arr) {
Static DesktopHwnd := DllCall("User32.dll\GetDesktopWindow", "ptr")
If oPubObj.Acc.CLOAKED
Return 0
Acc := Object(oPubObj.Acc.AccObj)
arr := []
While Hwnd := Acc_WindowFromObject(Parent := Acc_Parent(Acc)) {
If (DesktopHwnd != Hwnd)
t1 := GetEnumIndex(Acc)
If t1 = -1
Return arr := ""
If (PrHwnd != "" && Hwnd != PrHwnd)
{
PrHwnd := Format("0x{:06X}", PrHwnd)
WinGetClass, WinClass, ahk_id %PrHwnd%
WinGet, ProcessName, ProcessName, ahk_id %PrHwnd%
arr.InsertAt(1, {Hwnd: PrHwnd, Path: SubStr(t2, 1, -1), WinClass: WinClass, ProcessName: ProcessName})
}
if (t1 = "" || Hwnd = DesktopHwnd)
break
t2 := t1 "." t2
PrHwnd := Hwnd
Acc := Parent
}
Return arr.Count()
}
GetEnumIndex(Acc) {
If oPubObj.Acc.CLOAKED
Return -1
For Each, child in Acc_Children(Acc_Parent(Acc))
{
if CompareAcc(child, Acc)
return A_Index
}
}
CompareAcc(Acc1, Acc2) {
if IsObject(Acc1) && IsObject(Acc2)
&& (Acc_Location(Acc1) = Acc_Location(Acc2))
&& (Acc1.accDefaultAction(0) = Acc2.accDefaultAction(0))
&& (Acc1.accDescription(0) = Acc2.accDescription(0))
&& (Acc1.accHelp(0) = Acc2.accHelp(0))
&& (Acc1.accKeyboardShortcut(0) = Acc.accKeyboardShortcut(0))
&& (Acc1.accChildCount = Acc2.accChildCount)
&& (Acc1.accName(0) = Acc2.accName(0))
&& (Acc1.accRole(0) = Acc2.accRole(0))
&& (Acc1.accState(0) = Acc2.accState(0))
&& (Acc1.accValue(0) = Acc2.accValue(0))
return 1
}
Acc_Children(Acc) {
if ComObjType(Acc, "Name") != "IAccessible"
return
else
{
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 : ""
}
}
}
AccGetLocation(Acc, ChildId=0) {
Static x := 0, y := 0, w := 0, h := 0
try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
AccCoord[1]:=NumGet(x,0,"int"), AccCoord[2]:=NumGet(y,0,"int"), AccCoord[3]:=NumGet(w,0,"int"), AccCoord[4]:=NumGet(h,0,"int")
}
Acc_Location(Acc, ChildId=0) {
Static x := 0, y := 0, w := 0, h := 0
try Acc.accLocation(ComObj(0x4003,&x), ComObj(0x4003,&y), ComObj(0x4003,&w), ComObj(0x4003,&h), ChildId)
return "x" NumGet(x, 0, "int") " y" NumGet(y, 0, "int") " w" NumGet(w, 0, "int") " h" NumGet(h, 0, "int")
}
Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "") {
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 = 0) {
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_Parent(Acc) {
try parent := Acc.accParent
return parent ? Acc_Query(parent) : ""
}
Acc_Query(Acc) {
try return ComObj(9, ComObjQuery(Acc, "{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
static setting:=0
return p=""?setting:setting:=p
}
Acc_Role(Acc, ChildId=0) {
try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
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_ChildrenByRole(Acc, Role) {
if ComObjType(Acc,"Name")!="IAccessible"
ErrorLevel := "Invalid IAccessible Object"
else {
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
}
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)
}
AccUnderMouse(WinID, ByRef child) {
Static h
If Not h
h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
If DllCall("oleacc\AccessibleObjectFromPoint"
, "Int64", 0 * DllCall("GetCursorPos", "Int64*", pt) + pt, "Ptr*", pacc
, "Ptr", VarSetCapacity(varChild, 8 + 2 * A_PtrSize, 0) * 0 + &varChild) = 0
Acc := ComObjEnwrap(9, pacc, 1)
If IsObject(Acc)
Return Acc, child := NumGet(varChild, 8, "UInt")
}
Библиотека Acc настолько сложна и забагованна, что без обертки пользоваться ей невозможно.
Пока я багов не обнаружил и по сравнению с UIA ничуть не сложна.
user7256, думаю, не стоит в этой теме обсуждать неудачные попытки использования выдранного наугад кода. Эта тема предназначена для обсуждения AhkSpy. Создайте свою тему со внятным заголовком, напишите, что пытались сделать, задайте конкретный вопрос.
serzh82saratov, у меня последняя версия не подсвечивает acc-элементы на семёрке, на десятке работает.
У меня нет семёрки, а координаты и размер правильно определяет?
Отбой, я просто не включил режим Control.
Такой вопрос на гитхабе задали:
Is it possible to retrieve the caret position in edit fields? I know this is possible in standard Win32 control edits, but I wonder if UIA allows this.
тоже интересно.
Через UIA нельзя.
Только через MSAA.
У тебя есть что то работающее?
Хотя через uia можно наверное так:
https://docs.microsoft.com/en-us/window … caretrange
Работающего нету. Но на нашем форуме через iaccessible это обсуждалось.
IUIAutomationTextPattern2 тоже смотрел, нигде не нашёл примеров.
на нашем форуме
Ссылки нет?
IUIAutomationTextPattern2 тоже смотрел, нигде не нашёл примеров.
Не думаю, что в этом будет толк, так как контрол должен поддерживать text pattern, а это далеко не всегда.
Ссылки нет?
Но если уж так хочется потестировать text pattern, то можешь добавить его в класс от jethrow, как я сделал тут:
https://www.autohotkey.com/boards/viewtopic.php?t=69627
Либо самому вызывать, как я сделал тут:
https://www.autohotkey.com/boards/viewt … p?p=329332
Это работает http://forum.script-coding.com/viewtopi … 940#p97940, нашёл сразу.
как я сделал тут
Так сразу не сообразишь, какой именно там код?
Я даже не знаю какой из способов мне проще адаптировать к UIASub в AhkSpy.
f11::
if !hVolume
{
ControlGet, hVolume, hwnd,, ToolbarWindow323, ahk_class Shell_TrayWnd
IUIAutomation := ComObjCreate(CLSID_CUIAutomation := "{ff48dba4-60ef-4201-aa87-54103eef594e}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
DllCall(NumGet(NumGet(IUIAutomation+0)+6*A_PtrSize), "ptr", IUIAutomation, "ptr", hVolume, "ptr*", tray) ; IUIAutomation::ElementFromHandle
VOLUME_GUID := DllCall("oleaut32\SysAllocString", "str", "{7820AE73-23E3-4229-82C1-E41CB67D5B9C}", "ptr")
VarSetCapacity(variant, 8+A_PtrSize*2, 0)
NumPut(VT_BSTR := 8, variant, 0, "ushort")
NumPut(VOLUME_GUID, variant, 8, "ptr")
if (A_PtrSize = 4)
DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", UIA_AutomationIdPropertyId := 30011, "int64", NumGet(variant, 0, "int64"), "int64", NumGet(variant, 8, "int64"), "ptr*", condition) ; IUIAutomation::CreatePropertyCondition
else
DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", UIA_AutomationIdPropertyId := 30011, "ptr", &variant, "ptr*", condition) ; IUIAutomation::CreatePropertyCondition
DllCall("oleaut32\SysFreeString", "ptr", VOLUME_GUID)
}
DllCall(NumGet(NumGet(tray+0)+5*A_PtrSize), "ptr", tray, "int", TreeScope_Descendants := 0x4, "ptr", condition, "ptr*", element) ; IUIAutomationElement::FindFirst
DllCall(NumGet(NumGet(element+0)+16*A_PtrSize), "ptr", element, "int", UIA_InvokePatternId := 10000, "ptr*", invoke) ; IUIAutomationElement::GetCurrentPattern
DllCall(NumGet(NumGet(invoke+0)+3*A_PtrSize), "ptr", invoke) ; IInvokeProvider::Invoke
ObjRelease(element)
ObjRelease(invoke)
Ладно, долго разбираться, асс пойдёт.
Ну и правильно.
Например в адресной строке у фаерфокса положение каретки через UIA не получить, так как textpattrern не поддерживается.
А через ACC получается без проблем.
Думаю не очень правильно, или ты считаешь что не может быть такого, когда UIA работает а MSAA нет.
Да, и как ты узнал что UIA не работает, в inspect не нашёл такого.
или ты считаешь что не может быть такого, когда UIA работает а MSAA нет.
Утверждать такого не буду, но я проверил на пару программах и пока таких случаев не обнаружил.
В inspect надо смотреть IsTextPattern2Available: true/false.
Спасибо.
Добавил в 4.70.
Accessible > Caret position relative.
Looking forward to the retrieval of the caret position index in the text field.
Теперь такое хотят.
Ты можешь открыть донат и выполнять подобные хотелки за пожертвования.
Malcev
Следующая версия будет вся напичкана рекламой того, что может реализовать автор программы. Придётся искать Adblock.ahk для использования.
Зачем напичкана?
Я бы сделал обычное стандартное меню у программы и в меню help прописал бы donate.
Как это сделано, например, у WinSCP.
Вопрос сам по себе интересный. Так понимаю в MSAA этого нет, в IUIAutomationTextPattern2 не знаю.
4.71 добавил в Buttton тест ControlSend из определённого перед этим контрола, если такого нет то окна.
Вопрос сам по себе интересный
Ну если уж такой интересный, то так вызывается.
ЗЫ Освобождать ресурсы не интересно (лень).
f11::
IUIAutomation := ComObjCreate(CLSID_CUIAutomation8 := "{e22ad333-b25f-460c-83d0-0581107395c9}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
DllCall(NumGet(NumGet(IUIAutomation+0)+7*A_PtrSize), "ptr", IUIAutomation, "int64", 0*DllCall("GetCursorPos","Int64*",pt)+pt, "ptr*", ElementFromPoint) ; IUIAutomation::ElementFromPoint
DllCall(NumGet(NumGet(ElementFromPoint+0)+16*A_PtrSize), "ptr", ElementFromPoint, "int", UIA_TextPattern2Id := 10024, "ptr*", ITextProvider2) ; IUIAutomationElement::GetCurrentPattern
DllCall(NumGet(NumGet(ITextProvider2+0)+7*A_PtrSize), "ptr", ITextProvider2, "ptr*", ITextRangeProvider_DocumentRange) ; ITextProvider2::get_DocumentRange
DllCall(NumGet(NumGet(ITextProvider2+0)+10*A_PtrSize), "ptr", ITextProvider2, "int*", isActive, "ptr*", ITextRangeProvider_CaretRange) ; ITextProvider2::GetCaretRange
DllCall(NumGet(NumGet(ITextRangeProvider_CaretRange+0)+5*A_PtrSize), "ptr", ITextRangeProvider_CaretRange, "int", TextPatternRangeEndpoint_Start := 0, "ptr", ITextRangeProvider_DocumentRange, "int", TextPatternRangeEndpoint_Start := 0, "uint*", caretPos) ; ITextRangeProvider2::CompareEndpoints
msgbox % caretPos
Пока ничего не понятно, но жутко интересно. Можешь ещё раз вкратце объяснить, где ты берёшь смещения и Id.
ITextProvider2 это не IUIAutomationTextPattern2?
На первый взгляд действительно бесполезная штука, показывает только в обычном блокноте. Если isActive = 0, то нет смысла пробовать другие интерфейсы UIA?
Я взял код отсюда:
https://stackoverflow.com/questions/613 … on-not-the
Создал IUIAutomation2 интерфейс:
IUIAutomation := ComObjCreate(CLSID_CUIAutomation8 := "{e22ad333-b25f-460c-83d0-0581107395c9}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
https://docs.microsoft.com/en-us/previo … 6(v=vs.85)
После чего взял код получения элемента под курсором мыши
DllCall(NumGet(NumGet(IUIAutomation+0)+7*A_PtrSize), "ptr", IUIAutomation, "int64", 0*DllCall("GetCursorPos","Int64*",pt)+pt, "ptr*", ElementFromPoint) ; IUIAutomation::ElementFromPoint
отсюда
https://github.com/jethrow/UIA_Interfac … ce.ahk#L72
После чего нам надо получить нужный нам паттерн элемента через IUIAutomationElement::GetCurrentPattern
DllCall(NumGet(NumGet(ElementFromPoint+0)+16*A_PtrSize), "ptr", ElementFromPoint, "int", UIA_TextPattern2Id := 10024, "ptr*", ITextProvider2) ; IUIAutomationElement::GetCurrentPattern
Заходишь по этой ссылке, смотришь, что надо вписывать:
https://docs.microsoft.com/en-us/window … entpattern
PATTERNID
The identifier of the control pattern. For a list of control pattern IDs, see Control Pattern Identifiers.
Там видишь, что UIA_TextPattern2Id = 10024.
Дальше идешь в самый низ метода и видишь что интерфейс расписан в
Header uiautomationclient.h (include UIAutomation.h)
Гуглишь его - выходишь на гитхаб
https://github.com/tpn/winsdk-10/blob/m … onClient.h
Вбиваешь там в поиск GetCurrentPattern.
Получаешь
https://github.com/tpn/winsdk-10/blob/m … nt.h#L1766
После чего считаешь какой он идет по счету.
Получаешь 16.
И так далее.
ITextProvider2 это не IUIAutomationTextPattern2?
Не, это разные интерфейсы. Нам правильней использовать IUIAutomationTextPattern2.
Это я названия попутал.
На первый взгляд действительно бесполезная штука, показывает только в обычном блокноте. Если isActive = 0, то нет смысла пробовать другие интерфейсы UIA?
Не понял, а при чем тут isActive = 0?
При isActive = 0 в блокноте всё-равно показывает.
Спасибо, всё понятно, тебе надо в педагоги.
Не понял, а при чем тут isActive = 0?
Спутал её с проверкой наличия у элемента TextPattern.
Предлагаю всегда вставлять в Acc Do Default Action, так как оно может быть прописано, даже когда не определено.
если свойство DefaultAction у элемента не определено, то применив к этому элементу метод DoDefaultAction в результате может дать нажатие на этот элемент.
Не совсем правильно.
DoDefaultAction убираем.
Если возвращает пустоту, но ошибки нету, значит пишем в Action
[null] ▪ Execute
Если же возвращает ошибку, то пишем в defaultaction
[Error: hr=0x80020003 - Member not found.] без Execute
Malcev
Забыл там уже всё, можешь кусок кода показать?
Это убираем:
id='acc_DoDefaultAction2'>
А вот сюда
id='acc_DoDefaultAction'>
вставляем если нету ошибки и ничему не равно, то
[null] ▪ Execute
или если есть ошибка, то
[Error: hr=0x80020003 - Member not found.] без Execute.
[Error: hr=0x0001 - Does not have a default action.] без Execute.
[Error: hr=0x80070057 - An argument is not valid.] без Execute.
То есть проверяем, что возвращает IAccessible::get_accDefaultAction.
https://docs.microsoft.com/en-us/window … aultaction
Посмотрю обязательно, сейчас время нет.
Баг в проверке acc пути.
На броузере vivaldi при дефалтных установках путь для получения адресной строки должен быть таким
4.1.2.1.1.1.1.1.2.1.2.3.1.1
AhkSpy же выводит
4.1.1.1.2.1.2.3.1.1
Так же если есть желание, то можно добавить нахождение пути в буквенной форме через role properties.
Обнаружил баг в функции Acc_ObjectFromWindow.
Если ей предоставить хендл окна в uint64, типа такого hwnd := 0xffffffff80400b6c, то iaccessible интерфейс не возвращается.
Лень копаться в математике функции, решил добавить просто:
varsetcapacity(var, 8, 0)
numput(hwnd, var, 0, "uint64")
hwnd := numget(var, 0, "uint")
Acc_ObjectFromWindow(hWnd, idObject = -4)
{
Acc_Init()
varsetcapacity(var, 8, 0)
numput(hwnd, var, 0, "uint64")
hwnd := numget(var, 0, "uint")
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)
}
Кстати, надо бы проверить, может достаточно hwnd, как uint указывать в dllcall.
Проверил - если просто uint указать не помогает.
Если ей предоставить хендл окна в uint64, типа такого hwnd := 0xffffffff80400b6c
Насколько я знаю, хэндлы окон не превышают UInt.
Написал в баг-репорт.
https://www.autohotkey.com/boards/viewt … 79#p402579
Я так понял, lexikos не хочет исправлять это в исходном коде.
Причина, лично мне, непонятна.
Я тоже не понял, какие-то проблемы с обратной совместимостью.
Игнорирует.
Наверное лень переписывать.
Когда система начинает давать такие хендлы окнам, то автохотки превращается в один сплошной баг.
Например ahk_spy не запускается, так как там видно в гуи прописано обращение к дочерним и родительскому окну, хендлы которых не распознаются.
В общем грустно.
Что делать, придётся использовать костыли.