Skip to content

Instantly share code, notes, and snippets.

@tmplinshi
Last active October 31, 2023 11:48
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save tmplinshi/0fcb8655c1402a3662ac048d0d974915 to your computer and use it in GitHub Desktop.
Save tmplinshi/0fcb8655c1402a3662ac048d0d974915 to your computer and use it in GitHub Desktop.
; Accessible Info Viewer by jethrow
; https://autohotkey.com/board/topic/77888-accessible-info-viewer-alpha-release-2012-09-20/
; Modified by tmplinshi - https://gist.github.com/tmplinshi/0fcb8655c1402a3662ac048d0d974915/
#NoEnv
#SingleInstance, force
SetBatchLines, -1
{
WM_ACTIVATE := 0x06
WM_KILLFOCUS := 0x08
WM_LBUTTONDOWN := 0x201
WM_LBUTTONUP := 0x202
global Border := new Outline, Stored:={}, Acc, ChildId, TVobj, Win:={}
global g_isWindowDpiAware
global g_lastPos := {x:"", y:""}
global g_lastPath, g_skipTvEvent
}
{
DetectHiddenWindows, On
OnExit, OnExitCleanup
OnMessage(0x200,"WM_MOUSEMOVE")
ComObjError(false)
Hotkey, ~LButton Up, Off
}
{
Gui Main: New, HWNDhwnd LabelGui AlwaysOnTop, Accessible Info Viewer
Gui Main: Default
Win.Main := hwnd
; Gui, Color, White
Gui, Add, Checkbox, x70 y8 h20 gHotTracker_OnCheck vHotTrackerEnabled Checked0, HotTracking
Gui, Add, Text, x+0 hp 0x201 Disabled, (F1)
Gui, Add, Button, x+70 ggotoParentAcc vBtnParent, Parent
Gui, Add, Button, x+10 ggotoRootAcc vBtnRoot, Root
Gui, Add, Button, x+10 vShowStructure gShowStructure, Show Acc Structure
{
Gui, Add, Text, x10 y3 w25 h26 Border gCrossHair ReadOnly Border 0x6 ; SS_WHITERECT=0x6
Gui, Add, Text, x10 y3 w25 h4 Border HWNDh9 +0x4E
CreatePixel(h9, 0x0046D5)
Gui, Add, Text, x13 y17 w19 h1 Border vHBar
Gui, Add, Text, x22 y8 w1 h19 Border vVBar
}
{
Gui, Font, bold
Gui, Add, GroupBox, x2 y32 w465 h130 vWinCtrl, Window/Control Info
Gui, Font
Gui, Add, Text, x7 y49 h20, % "WinTitle:"
Gui, Add, Edit, ReadOnly x+0 y47 w401 h20 vWinTitle ,
Gui, Add, Text, x7 y71 h20, % " Text:"
Gui, Add, Edit, ReadOnly x+0 y69 w401 h20 vText ,
Gui, Add, Text, x7 y93 h20, % " Hwnd:"
Gui, Add, Edit, ReadOnly x+0 y91 w112 h20 vHwnd,
Gui, Add, Text, x+30 y93 h20 vClassText, % "Class(NN):"
Gui, Add, Edit, ReadOnly x+0 y91 w198 h20 vClass,
Gui, Add, Text, x7 y115 h20, % "Position:"
Gui, Add, Edit, ReadOnly x+0 y113 w112 h20 vPosition,
Gui, Add, Text, x+30 y115 h20, % " Process:"
Gui, Add, Edit, ReadOnly x+0 y113 w198 h20 vProcess,
Gui, Add, Text, x7 y137 h20, % " Size:"
Gui, Add, Edit, ReadOnly x+0 y135 w112 h20 vSize,
Gui, Add, Text, x+30 y137 h20, % " Proc ID:"
Gui, Add, Edit, ReadOnly x+0 y135 w198 h20 vProcID,
}
{
Gui, Font, bold
Gui, Add, GroupBox, x2 y165 w465 h290 vAcc, Accessible Info
Gui, Font
Gui, Add, Text, x7 y182 w42 h20 Right, Name:
Gui, Add, Edit, ReadOnly x51 y180 w411 h20 vAccName ,
Gui, Add, Text, x7 y204 w42 h20 Right, Value:
Gui, Add, Edit, ReadOnly x51 y202 w225 h20 vAccValue ,
Gui, Add, Button, x+0 hp gModifyAccValue vModifyAccValue Default Disabled, Modify
Gui, Add, Text, x+20 y204 h20, % "ChildCount:"
Gui, Add, Edit, ReadOnly x+0 y202 w55 h20 vAccChildCount,
Gui, Add, Text, x7 y226 w42 h20 Right, Role:
Gui, Add, Edit, ReadOnly x51 y224 w411 h20 vAccRole,
Gui, Add, Text, x7 y248 w42 h20 Right, State:
Gui, Add, Edit, ReadOnly x51 y246 w411 h50 -Wrap vAccState,
Gui, Add, Button, xp y+0 h22 w100 vStateSelect gSelectAcc Disabled, Select
Gui, Add, Text, x7 y320 w42 h20 Right, Action:
Gui, Add, Edit, ReadOnly x51 y318 w142 h20 vAccAction,
Gui, Add, Button, x+0 gDoDefaultAction hp vExecute Disabled, Execute
Gui, Add, Text, x+30 y320 h20, % " Focus:"
Gui, Add, Edit, ReadOnly x+0 y318 w120 h20 vAccFocus,
{
Gui, Add, Text, x7 y342 w75 h20 Right vAccLocationText, Location:
Gui, Add, Edit, ReadOnly x+0 y340 w380 h20 vAccLocation ,
Gui, Add, Text, x7 y364 w75 h20 Right, Description:
Gui, Add, Edit, ReadOnly x+0 y362 w380 h20 vAccDescription ,
Gui, Add, Text, x7 y386 w75 h20 Right, Keyboard:
Gui, Add, Edit, ReadOnly x+0 y384 w380 h20 vAccKeyboard ,
Gui, Add, Text, x7 y408 w75 h20 Right, Help:
Gui, Add, Edit, ReadOnly x+0 y406 w380 h20 vAccHelp ,
Gui, Add, Text, x7 y430 w75 h20 Right, HelpTopic:
Gui, Add, Edit, ReadOnly x+0 y428 w380 h20 vAccHelpTopic ,
Gui, Add, Text, x7 y+8 w75 Right, Selection:
Gui, Add, Edit, ReadOnly x+0 yp-3 w380 h20 vAccSelection,
}
}
{
Gui, Add, StatusBar, gShowMainGui
SB_SetParts(110, 180, 100)
; SB_SetText("get full path", 3)
SB_SetText("`tshow more", 4)
}
{
Gui Acc: New, ToolWindow Resize LabelAcc HWNDhwnd, Acc Structure
Gui, Margin, 0, 0
Gui, Font,, Microsoft YaHei
Gui, Add, TreeView, w300 h357 vTView gTreeView R17 AltSubmit HWNDhTV 0x200 ;BackgroundF0F0F0
Gui, Show, Hide
Win.Acc := hwnd
DllCall("UxTheme.dll\SetWindowTheme", "ptr", hTV, "str", "Explorer", "ptr", 0)
}
GoSub, ShowMainGui
WinSet, Redraw, , % "ahk_id" Win.Main
return
}
TempMenu_CopyCode:
TempMenu_CopyCodeSingle:
TempMenu_CopyCodeParameters:
defaultGui := A_DefaultGui
Gui, % Win.Main ":Default"
SB_SetText("", 2)
SB_SetText("Searching..", 3)
codeType := (A_ThisLabel = "TempMenu_CopyCodeSingle") ? "single"
: (A_ThisLabel = "TempMenu_CopyCodeParameters") ? "parameters"
: "full"
fullPath := GetAccFullPath(outCode, codeType)
g_lastPath := fullpath
Clipboard := outCode
SB_SetText("Path: " fullPath, 2)
SB_SetText("get full path", 3)
Gui, % defaultGui ":Default"
ToolTip("Copied",,,, 2000)
Return
; ToolTip("Test",,,, 3000)
ToolTip(Text := "", X := "", Y := "", WhichToolTip := 1, Timeout := "") {
ToolTip, % Text, X, Y, WhichToolTip
If (Timeout) {
RemoveToolTip := Func("ToolTip").Bind(,,, WhichToolTip)
SetTimer, % RemoveToolTip, % -Timeout
}
}
ShowMainGui:
{
if (A_GuiEvent = "RightClick" && A_EventInfo = 3) {
preTDpi := DllCall("SetThreadDpiAwarenessContext", "int", -4)
Menu, TempMenu, Add, Copy Code, TempMenu_CopyCode
Menu, TempMenu, Add, Copy Code (Single line), TempMenu_CopyCodeSingle
Menu, TempMenu, Add, Copy Code (Parameters), TempMenu_CopyCodeParameters
Menu, TempMenu, Show
Menu, TempMenu, DeleteAll
DllCall("SetThreadDpiAwarenessContext", "int", preTDpi)
return
}
if A_EventInfo in 1,2
{
WM_MOUSEMOVE()
StatusBarGetText, SB_Text, %A_EventInfo%, % "ahk_id" Win.Main
if SB_Text
if (A_EventInfo=2 and SB_Text:=SubStr(SB_Text,7))
or if RegExMatch(SB_Text, "Id: \K\d+", SB_Text) {
SB_Text := StrReplace(SB_Text, ",", ".")
if (A_EventInfo = 2 && childId)
Clipboard := """" SB_Text """, " childId
else
Clipboard := SB_Text
preTDpi := DllCall("SetThreadDpiAwarenessContext", "int", -4)
ToolTip % "clipboard = " clipboard
DllCall("SetThreadDpiAwarenessContext", "int", preTDpi)
SetTimer, RemoveToolTip, -2000
}
}
else if (A_EventInfo = 3)
{
SB_SetText("", 2)
SB_SetText("Searching..", 3)
fullPath := GetAccFullPath()
g_lastPath := fullPath
SB_SetText("Path: " fullPath, 2)
SB_SetText("get full path", 3)
}
else {
preTDpi := DllCall("SetThreadDpiAwarenessContext", "int", -4)
Gui Main: Default
if ShowingLess {
SB_SetText("`tshow less", 4)
GuiControl, Move, Acc, x2 y165 w465 h315
GuiControl, Show, AccDescription
GuiControl, Show, AccLocation
GuiControl, Show, AccLocationText
{
height := 369
while height<503 {
height += 10
Gui, Show, w470 h%height%
Sleep, 20
}
}
Gui, Show, w470 h503
ShowingLess := false
}
else {
if (ShowingLess != "") {
height := 503
while height>369 {
height -= 10
Gui, Show, w470 h%height%
Sleep, 20
}
}
Gui, Show, w470 h369
GuiControl, Hide, AccDescription
GuiControl, Hide, AccLocation
GuiControl, Hide, AccLocationText
GuiControl, Move, Acc, x2 y165 w465 h180
SB_SetText("`tshow more", 4)
ShowingLess := true
}
WinSet, Redraw, , % "ahk_id" Win.Main
DllCall("SetThreadDpiAwarenessContext", "int", preTDpi)
}
return
}
HotTracker_OnCheck:
GuiControlGet, HotTrackerEnabled
if HotTrackerEnabled
SetTimer, Enable_HotTracker, -1
else
SetTimer, Disable_HotTracker, -1
return
#if Not Lbutton_Pressed
Enable_HotTracker:
f1::
{
Lbutton_Pressed := true
GuiControl, Main:, HotTrackerEnabled, 1
Stored.Chwnd := ""
SB_SetText("", 3)
Gui Acc: Default
GuiControl, Disable, TView
while, Lbutton_Pressed
{
GetAccInfo()
Sleep, 30 ;5
}
DllCall("SetThreadDpiAwarenessContext", "int", -4)
SB_SetText("get full path", 3)
RestoreCursors()
ToolTip
g_lastPos := ""
return
}
#if Lbutton_Pressed
Disable_HotTracker:
f1::
{
Lbutton_Pressed := false
GuiControl, Main:, HotTrackerEnabled, 0
Gui Main: Default
Sleep, -1
GuiControl, , WinCtrl, % (DllCall("GetParent", "ptr",Acc_WindowFromObject(Acc))? "Control":"Window") " Info"
if Not DllCall("IsWindowVisible", "Ptr",Win.Acc) {
Border.Hide()
SB_SetText("Path: " GetAccPath(Acc).path, 2)
SB_SetText("get full path", 3)
}
else {
Gui Acc: Default
BuildTreeView()
GuiControl, Enable, TView
; WinActivate, % "ahk_id" Win.Acc
PostMessage, %WM_LBUTTONDOWN%, , , SysTreeView321, % "ahk_id" Win.Acc
}
return
}
#if
~Lbutton Up::
{
Hotkey, ~LButton Up, Off
Lbutton_Pressed := False
Gui Main: Default
if Not CH {
GuiControl, Show, HBar
GuiControl, Show, VBar
CrossHair(CH:=true)
}
Sleep, -1
GuiControl, , WinCtrl, % (DllCall("GetParent", "ptr",Acc_WindowFromObject(Acc))? "Control":"Window") " Info"
if Not DllCall("IsWindowVisible", "Ptr",Win.Acc) {
Border.Hide()
SB_SetText("Path: " (g_lastPath:=GetAccPath(Acc).path), 2)
SB_SetText("get full path", 3)
}
else {
Gui Acc: Default
BuildTreeView()
GuiControl, Enable, TView
WinActivate, % "ahk_id" Win.Acc
PostMessage, %WM_LBUTTONDOWN%, , , SysTreeView321, % "ahk_id" Win.Acc
}
return
}
CrossHair:
{
if (A_GuiEvent = "Normal") {
Hotkey, ~LButton Up, On
{
GuiControl, Hide, HBar
GuiControl, Hide, VBar
CrossHair(CH:=false)
}
Lbutton_Pressed := True
Stored.Chwnd := ""
SB_SetText("", 3)
Gui Acc: Default
GuiControl, Disable, TView
while, Lbutton_Pressed
{
GetAccInfo()
Sleep, 30 ;5
}
DllCall("SetThreadDpiAwarenessContext", "int", -4)
RestoreCursors()
SB_SetText("get full path", 3)
ToolTip
g_lastPos := ""
}
return
}
OnExitCleanup:
{
; CrossHair(true) ;???
RestoreCursors()
GuiClose:
ExitApp
}
ShowStructure:
{
ControlFocus, Static1, % "ahk_id" Win.Main
if DllCall("IsWindowVisible", "Ptr",Win.Acc) {
PostMessage, %WM_LBUTTONDOWN%, , , SysTreeView321, % "ahk_id" Win.Acc
return
}
WinGetPos, x, y, w, , % "ahk_id" Win.Main
WinGetPos, , , AccW, AccH, % "ahk_id" Win.Acc
WinMove, % "ahk_id" Win.Acc,
, (x+w+AccW > A_ScreenWidth? x-AccW-10:x+w+10)
, % y+5, %AccW%, %AccH%
WinShow, % "ahk_id" Win.Acc
if ComObjType(Acc, "Name") = "IAccessible"
BuildTreeView()
if Lbutton_Pressed
GuiControl, Disable, TView
else
GuiControl, Enable, TView
PostMessage, %WM_LBUTTONDOWN%, , , SysTreeView321, % "ahk_id" Win.Acc
TV_Modify(TV_GetSelection(), "VisFirst")
return
}
BuildTreeView()
{
r := GetAccPath(Acc)
AccObj:=r.AccObj, Child_Path:=r.Path, r:=""
Gui Acc: Default
TV_Delete()
GuiControl, -Redraw, TView
; parent := TV_Add(Acc_Role(AccObj), "", "Bold Expand")
parent := TV_Add(Acc_Role(AccObj), "", "Expand")
TVobj := {(parent): {is_obj:true, obj:AccObj, need_children:false, childid:0, Children:[]}}
Loop Parse, Child_Path, .
{
if A_LoopField is not Digit
TVobj[parent].Obj_Path := Trim(TVobj[parent].Obj_Path "," A_LoopField, ",")
else {
StoreParent := parent
parent := TV_BuildAccChildren(AccObj, parent, "", A_LoopField)
TVobj[parent].need_children := false
TV_Expanded(StoreParent)
TV_Modify(parent,"Expand")
AccObj := TVobj[parent].obj
}
}
if Not ChildId {
TV_BuildAccChildren(AccObj, parent)
TV_Modify(parent, "Select")
}
else
TV_BuildAccChildren(AccObj, parent, ChildId)
TV_Expanded(parent)
GuiControl, +Redraw, TView
}
AccClose:
{
Border.Hide()
Gui Acc: Hide
TV_Delete()
Gui Main: Default
GuiControl, Enable, ShowStructure
return
}
AccSize:
{
if (A_EventInfo != 1)
GuiControl, Move, TView, w%A_GuiWidth% h%A_GuiHeight%
return
}
TreeView:
{
if g_skipTvEvent
return
Gui, Submit, NoHide
if (A_GuiEvent = "S") {
ToggleThreadDpiAwareness( AccWindowFromObject(TVobj[A_EventInfo].obj) )
UpdateAccInfo(TVobj[A_EventInfo].obj, TVobj[A_EventInfo].childid, TVobj[A_EventInfo].obj_path)
acc := TVobj[A_EventInfo].obj
childid := TVobj[A_EventInfo].childid
EnableButtons()
SB_SetText("get full path", 3)
}
if (A_GuiEvent = "+") {
GuiControl, -Redraw, TView
TV_Expanded(A_EventInfo)
GuiControl, +Redraw, TView
}
return
}
RemoveToolTip:
{
ToolTip
return
}
GetClassName(hwnd) {
static init, className
if !init {
init := true
VarSetCapacity(className, 256, 0)
}
DllCall("GetClassName", "ptr", hwnd, "str", className, "int", 256)
return className
}
GetAccInfo(oInput := "") {
global Whwnd
static ShowButtonEnabled
if oInput
Whwnd := oInput.hwnd
else
{
MouseGetPos, x, y, Whwnd, Chwnd, 2
if (x = g_lastPos.x && y = g_lastPos.y) {
; _log("///////////return")
return
}
g_lastPos := {x: x, y: y}
}
if (Whwnd = Win.Main || Whwnd = Win.Acc)
return
GuiControlGet, SectionLabel, , WinCtrl
if (SectionLabel != "Window/Control Info")
GuiControl, , WinCtrl, Window/Control Info
if oInput
Acc := oInput.Acc, ChildId := 0
else
Acc := __Acc_ObjectFromPoint(ChildId), switchToVisibleParent()
static lastAcc, lastChildId
if Border.isVisible && isSameAcc(Acc, ChildId, lastAcc, lastChildId) {
return
}
lastAcc := Acc, lastChildId := ChildId
; enable acc in chrome
static WM_GETOBJECT := 0x003D
if (GetClassName(whwnd) = "Chrome_WidgetWin_1") {
SendMessage, WM_GETOBJECT, 0, 1, , % "ahk_id" (Chwnd ? Chwnd : Whwnd)
}
;ToolTip, % SubStr(acc.accName(ChildId), 1, 100) . (StrLen(acc.accName(ChildId))>100 ? " ..." : "")
Location := GetAccLocation(Acc, ChildId)
; if Stored.Location != Location {
; if 1 {
Hwnd := Acc_WindowFromObject(Acc)
if Stored.Hwnd != Hwnd {
if DllCall("GetParent", ptr,hwnd) {
WinGetTitle, title, ahk_id %parent%
ControlGetText, text, , ahk_id %Hwnd%
class := GetClassNN(Hwnd,Whwnd)
ControlGetPos, posX, posY, posW, posH, , ahk_id %Hwnd%
WinGet, proc, ProcessName, ahk_id %parent%
WinGet, procid, PID, ahk_id %parent%
}
else {
WinGetTitle, title, ahk_id %Hwnd%
WinGetText, text, ahk_id %Hwnd%
WinGetClass, class, ahk_id %Hwnd%
WinGetPos, posX, posY, posW, posH, ahk_id %Hwnd%
WinGet, proc, ProcessName, ahk_id %Hwnd%
WinGet, procid, PID, ahk_id %Hwnd%
}
{
GuiControl, , WinTitle, %title%
GuiControl, , Text, %text%
SetFormat, IntegerFast, H
GuiControl, , Hwnd, % Hwnd+0
SetFormat, IntegerFast, D
GuiControl, , Class, %class%
GuiControl, , Position, x%posX% y%posY%
GuiControl, , Size, w%posW% h%posH%
GuiControl, , Process, %proc%
GuiControl, , ProcId, %procid%
}
Stored.Hwnd := Hwnd
}
UpdateAccInfo(Acc, ChildId)
; }
}
isSameAcc(acc1, chidId1, acc2, childId2) {
if (chidId1 = childId2)
&& (acc1.accRole(chidId1) = acc2.accRole(childId2))
&& (acc1.accName(chidId1) = acc2.accName(childId2))
&& (acc1.accState(chidId1) = acc2.accState(childId2))
&& (acc1.accValue(chidId1) = acc2.accValue(childId2))
&& (acc1.accChildCount = acc2.accChildCount)
&& (acc1.accDefaultAction(chidId1) = acc2.accDefaultAction(childId2))
&& (acc1.accDescription(chidId1) = acc2.accDescription(childId2))
&& (acc1.accHelp(chidId1) = acc2.accHelp(childId2))
&& (acc1.accKeyboardShortcut(chidId1) = acc2.accKeyboardShortcut(childId2))
&& (Acc_LocationStr(acc1) = Acc_LocationStr(acc2))
return true
}
isAccInvisible() {
static STATE_SYSTEM_INVISIBLE := 0x8000
return acc.accState(childId) & STATE_SYSTEM_INVISIBLE
}
switchToVisibleParent() {
while isAccInvisible()
acc := Acc_Parent(acc)
}
DoDefaultAction() {
acc.accDoDefaultAction(ChildId)
GuiControl,, AccAction, % Acc.accDefaultAction(ChildId)
GuiControl,, AccState, % Acc_GetStateTextEx2(Acc.accState(ChildId))
}
ModifyAccValue() {
GuiControlGet, AccValue
Acc.accValue(ChildId) := AccValue
GuiControl, +cRed +Redraw, AccValue
}
EnableModifyAccValue() {
b := (Acc.accRole(ChildId) = 42) ;ROLE_SYSTEM_TEXT
GuiControl, % (b ? "-" : "+" ) . "ReadOnly", AccValue
GuiControl, % "Enable" b, ModifyAccValue
GuiControl, +cDefault, AccValue
}
EnableButtons() {
EnableModifyAccValue()
EnableBtnSelect()
GuiControl, % "Enable" (Acc.accDefaultAction(ChildId) != ""), Execute
}
UpdateAccInfo(Acc, ChildId, Obj_Path="") {
global Whwnd
Gui Main: Default
Location := GetAccLocation(Acc, ChildId, x, y, w, h)
{
GuiControl,, AccName, % Acc.accName(ChildId)
GuiControl,, AccValue, % Acc.accValue(ChildId)
GuiControl,, AccRole, % Acc_GetRoleInfo(Acc, ChildId)
GuiControl,, AccState, % Acc_GetStateTextEx2(Acc.accState(ChildId))
GuiControl,, AccAction, % Acc.accDefaultAction(ChildId)
GuiControl,, AccChildCount, % ChildId ? "N/A" : Acc.accChildCount
GuiControl,, AccSelection, % ChildId ? "N/A" : Acc.accSelection
GuiControl,, AccFocus, % ChildId ? "N/A" : Acc.accFocus
GuiControl,, AccLocation, % Location
GuiControl,, AccDescription, % Acc.accDescription(ChildId)
GuiControl,, AccKeyboard, % Acc.accKeyboardShortCut(ChildId)
Guicontrol,, AccHelp, % Acc.accHelp(ChildId)
GuiControl,, AccHelpTopic, % Acc.accHelpTopic(ChildId)
SB_SetText(ChildId? "Child Id: " ChildId:"Object")
SB_SetText(DllCall("IsWindowVisible", "Ptr",Win.Acc)? "Path: " Obj_Path:"", 2)
g_lastPath := Obj_Path
EnableButtons()
}
; Border.Transparent(true)
Border.show(x, y, x+w, y+h)
Border.setabove(Whwnd)
; Border.Transparent(false)
Stored.Location := Location
}
GetClassNN(Chwnd, Whwnd) {
global _GetClassNN := {}
_GetClassNN.Hwnd := Chwnd
Detect := A_DetectHiddenWindows
WinGetClass, Class, ahk_id %Chwnd%
_GetClassNN.Class := Class
DetectHiddenWindows, On
EnumAddress := RegisterCallback("GetClassNN_EnumChildProc")
DllCall("EnumChildWindows", "uint",Whwnd, "uint",EnumAddress)
DetectHiddenWindows, %Detect%
return, _GetClassNN.ClassNN, _GetClassNN:=""
}
GetClassNN_EnumChildProc(hwnd, lparam) {
static Occurrence
global _GetClassNN
WinGetClass, Class, ahk_id %hwnd%
if _GetClassNN.Class == Class
Occurrence++
if Not _GetClassNN.Hwnd == hwnd
return true
else {
_GetClassNN.ClassNN := _GetClassNN.Class Occurrence
Occurrence := 0
return false
}
}
TV_Expanded(TVid) {
For Each, TV_Child_ID in TVobj[TVid].Children
if TVobj[TV_Child_ID].need_children
TV_BuildAccChildren(TVobj[TV_Child_ID].obj, TV_Child_ID)
}
TV_BuildAccChildren(AccObj, Parent, Selected_Child="", Flag="") {
TVobj[Parent].need_children := false
Parent_Obj_Path := Trim(TVobj[Parent].Obj_Path, ",")
for wach, child in Acc_Children(AccObj) {
if Not IsObject(child) {
added := TV_Add("[" A_Index "] " Acc_GetRoleText(AccObj.accRole(child)) " " AccObj.accName(child), Parent)
TVobj[added] := {is_obj:false, obj:Acc, childid:child, Obj_Path:Parent_Obj_Path}
if (child = Selected_Child)
TV_Modify(added, "Select")
}
else {
; added := TV_Add("[" A_Index "] " Acc_Role(child) " " child.accName(0), Parent, "bold")
added := TV_Add("[" A_Index "] " Acc_Role(child) " " child.accName(0), Parent, "")
TVobj[added] := {is_obj:true, need_children:true, obj:child, childid:0, Children:[], Obj_Path:Trim(Parent_Obj_Path "," A_Index, ",")}
}
TVobj[Parent].Children.Insert(added)
if (A_Index = Flag)
Flagged_Child := added
}
return Flagged_Child
}
GetAccPath(Acc, byref hwnd="") {
hwnd := Acc_WindowFromObject(Acc)
WinObj := Acc_ObjectFromWindow(hwnd)
WinObjPos := Acc_Location(WinObj).pos
while Acc_WindowFromObject(Parent:=Acc_Parent(Acc)) = hwnd {
t2 := GetEnumIndex(Acc) "." t2
if Acc_Location(Parent).pos = WinObjPos
return {AccObj:Parent, Path:SubStr(t2,1,-1)}
Acc := Parent
}
while Acc_WindowFromObject(Parent:=Acc_Parent(WinObj)) = hwnd
t1.="P.", WinObj:=Parent
return {AccObj:Acc, Path:t1 SubStr(t2,1,-1)}
}
GetEnumIndex(Acc, ChildId=0) {
if Not ChildId {
ChildPos := Acc_Location(Acc).pos
For Each, child in Acc_Children(Acc_Parent(Acc))
if IsObject(child) and Acc_Location(child).pos=ChildPos
return A_Index
}
else {
ChildPos := Acc_Location(Acc,ChildId).pos
For Each, child in Acc_Children(Acc)
if Not IsObject(child) and Acc_Location(Acc,child).pos=ChildPos
return A_Index
}
}
GetAccLocation(AccObj, Child=0, byref x="", byref y="", byref w="", byref h="") {
AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), Child)
return "x" (x:=NumGet(x,0,"int")) " "
. "y" (y:=NumGet(y,0,"int")) " "
. "w" (w:=NumGet(w,0,"int")) " "
. "h" (h:=NumGet(h,0,"int"))
}
WM_MOUSEMOVE() {
static hCurs := new Cursor(32649)
MouseGetPos,,,,ctrl
if (ctrl = "msctls_statusbar321")
DllCall("SetCursor","ptr",hCurs.ptr)
}
class Cursor {
__New(id) {
this.ptr := DllCall("LoadCursor", "ptr", 0, "Int", id, "ptr")
}
__delete() {
DllCall("DestroyCursor", "ptr", this.ptr)
}
}
class Outline {
__New(color="red") {
static WS_EX_TRANSPARENT := 0x20, WS_EX_LAYERED := 0x00080000
preDefaultGui := A_DefaultGui
this.hwnds := {}
Loop, 4 {
Gui, New, -Caption +ToolWindow HWNDhwnd -DPIScale +E%WS_EX_TRANSPARENT% +E%WS_EX_LAYERED%
Gui, Color, %color%
this[A_Index] := hwnd
DllCall("SetLayeredWindowAttributes", "ptr", hwnd, uint, 0, "uchar", 255, "int", 2)
}
this.isVisible := false
this.color := color
this.top := this[1]
this.right := this[2]
this.bottom := this[3]
this.left := this[4]
Gui, %preDefaultGui%: Default
}
MoveTogether(arrHwnd, arrPos) {
hDWP := DllCall("BeginDeferWindowPos", "int", arrHwnd.Length(), "ptr")
for i, v in arrPos {
DllCall("DeferWindowPos", "ptr", hDWP, "ptr", arrHwnd[i], "ptr", 0
, "int", v[1], "int", v[2], "int", v[3], "int", v[4]
, "uint", 0x54) ; SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_NOZORDER
}
DllCall("EndDeferWindowPos", "ptr", hDWP)
}
Show(x1, y1, x2, y2) {
b := g_isWindowDpiAware ? Round(2*(A_ScreenDPI/96)) : 2
arrHwnd := [this.1, this.2, this.3, this.4]
arrPos := [ [x1-b, y1-b, x2-x1+b*2, b]
, [x2, y1, b, y2-y1]
, [x1-b, y2, x2-x1+b*2, b]
, [x1-b, y1, b, y2-y1] ]
this.MoveTogether(arrHwnd, arrPos)
; this.GuiShow("top", x1-b, y1-b, x2-x1+b*2, b)
; this.GuiShow("right", x2, y1, b, y2-y1)
; this.GuiShow("bottom", x1-b, y2, x2-x1+b*2, b)
; this.GuiShow("left", x1-b, y1, b, y2-y1)
this.isVisible := true
}
GuiShow(name, x, y, w, h) {
Gui, % this[name] ":Show", % "NA x" x " y" y " w" w " h" h
}
Hide() {
Loop, 4
Gui, % this[A_Index] ": Hide"
this.isVisible := false
}
SetAbove(hwnd) {
ABOVE := DllCall("GetWindow", "ptr", hwnd, "uint", 3, "ptr")
Loop, 4
DllCall( "SetWindowPos", "ptr", this[A_Index], "ptr", ABOVE
, "int", 0, "int", 0, "int", 0, "int", 0
, "uint", 0x1|0x2|0x10 )
}
Transparent(param) {
Loop, 4
WinSet, Transparent, % param=1? 0:255, % "ahk_id" this[A_Index]
this.isVisible := !param
}
Color(color) {
Gui, +HWNDdefault
Loop, 4
Gui, % this[A_Index] ": Color" , %color%
this.color := color
Gui, %default%: Default
}
Destroy() {
Loop, 4
Gui, % this[A_Index] ": Destroy"
}
}
CreatePixel(hwnd, Color) {
VarSetCapacity(BMBITS, 4, 0), Numput(Color, &BMBITS, 0, "UInt")
hBM := DllCall("CreateBitmap", "Int", 1, "Int", 1, "UInt", 1, "UInt", 24, "Ptr", 0, "Ptr")
hBM := DllCall("CopyImage", "Ptr", hBM, "UInt", 0, "Int", 0, "Int", 0, "UInt", 0x2008, "Ptr")
DllCall("SetBitmapBits", "Ptr", hBM, "UInt", 3, "Ptr", &BMBITS)
DllCall("SendMessage", "Ptr", hwnd, "UInt", 0x172, "Ptr", 0, "Ptr", hBM)
}
CrossHair(OnOff=1) {
static AndMask, XorMask, $, h_cursor, IDC_CROSS := 32515
,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13
, b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13
, h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13
if (OnOff = "Init" or OnOff = "I" or $ = "") {
$ := "h"
, VarSetCapacity( h_cursor,4444, 1 )
, VarSetCapacity( AndMask, 32*4, 0xFF )
, VarSetCapacity( XorMask, 32*4, 0 )
, system_cursors := "32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650"
StringSplit c, system_cursors, `,
Loop, %c0%
h_cursor := DllCall( "LoadCursor", "uint",0, "uint",c%A_Index% )
, h%A_Index% := DllCall( "CopyImage", "uint",h_cursor, "uint",2, "int",0, "int",0, "uint",0 )
, b%A_Index% := DllCall("LoadCursor", "Uint", "", "Int", IDC_CROSS, "Uint")
}
$ := (OnOff = 0 || OnOff = "Off" || $ = "h" && (OnOff < 0 || OnOff = "Toggle" || OnOff = "T")) ? "b" : "h"
Loop, %c0%
h_cursor := DllCall( "CopyImage", "uint",%$%%A_Index%, "uint",2, "int",0, "int",0, "uint",0 )
, DllCall( "SetSystemCursor", "uint",h_cursor, "uint",c%A_Index% )
}
ToggleThreadDpiAwareness(hwnd) {
if !g_isWindowDpiAware := _isWindowDpiAware(hwnd)
val := -1
else if (g_isWindowDpiAware=2 && WinGetClass(hwnd)="#32768")
|| (g_isWindowDpiAware=1 && A_PtrSize=8 && WinGetClass(hwnd)="#32768")
val := -1, g_isWindowDpiAware := 0, getCursorAgain := true
else
val := -4
if (A_OSVersion >= "10.0.14393")
DllCall("SetThreadDpiAwarenessContext", "int", val)
return getCursorAgain
}
WinGetClass(hwnd) {
WinGetClass, class, ahk_id %hwnd%
return class
}
{ ; Acc Library
__Acc_AutoInit() {
static _ := DllCall("LoadLibrary", "Str", "oleacc.dll", "Ptr")
}
Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild) {
If DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}
__Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "") {
if (x = "" || y = "") {
DllCall("GetPhysicalCursorPos", "Int64P", pt)
hwnd := DllCall("WindowFromPoint", "int64", pt)
if ToggleThreadDpiAwareness(hwnd)
DllCall("GetPhysicalCursorPos", "Int64P", pt)
} else {
pt := x & 0xFFFFFFFF | y << 32
}
If DllCall("oleacc\AccessibleObjectFromPoint", "Int64", pt, "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_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_GetStateText(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_Role(Acc, ChildId=0) {
try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_State(Acc, ChildId=0) {
try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetStateText(Acc.accState(ChildId)):"invalid object"
}
Acc_Children(Acc) { ; from https://github.com/serzh82saratov/AhkSpy
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 : ""
}
}
}
Acc_Location(Acc, ChildId=0) {
try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
catch
return
return {x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")
, pos:"x" NumGet(x,0,"int")" y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")}
}
Acc_Parent(Acc) {
try parent := Acc.accParent
return parent ? Acc_Query(parent) : ""
}
Acc_Child(Acc, ChildId=0) {
try child := Acc.accChild(ChildId)
return child ? Acc_Query(child) : ""
}
Acc_Query(Acc) {
try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
; https://docs.microsoft.com/zh-cn/windows/desktop/WinAuto/object-state-constants
Acc_GetStateTextEx(nState) {
static states := [ 0x0,0x1,0x10,0x100,0x10000,0x100000,0x1000000,0x2,0x20,0x200,0x2000
, 0x20000,0x200000,0x2000000,0x20000000,0x4,0x40,0x400,0x4000,0x40000
, 0x400000,0x40000000,0x8,0x80,0x800,0x8000,0x80000,0x800000 ]
for i, n in states
{
if (nState & n)
out .= Acc_GetStateText(n) ","
}
return RTrim(out, ",")
}
Acc_GetStateTextEx2(nState) {
static oState := { ANIMATED:0x4000, BUSY:0x800, CHECKED:0x10, COLLAPSED:0x400, DEFAULT:0x100, EXPANDED:0x200, EXTSELECTABLE:0x2000000
, FOCUSABLE:0x100000, FOCUSED:0x4, HASPOPUP:0x40000000, HOTTRACKED:0x80, INVISIBLE:0x8000, OFFSCREEN:0x10000, LINKED:0x400000
, MARQUEED:0x2000, MIXED:0x20, MOVEABLE:0x40000, MULTISELECTABLE:0x1000000, NORMAL:0x0, PRESSED:0x8, PROTECTED:0x20000000
, READONLY:0x40, SELECTABLE:0x200000, SELECTED:0x2, SELFVOICING:0x80000, SIZEABLE:0x20000, TRAVERSED:0x800000, UNAVAILABLE:0x1 }
for k, v in oState
{
if (nState & v) {
v_hex := Format("{:#x}", v)
out .= Acc_GetStateText(v) " (STATE_SYSTEM_" k " := " v_hex ")`n"
}
}
return RTrim(out, "`n")
}
Acc_GetRoleConstName(nRole) {
static arr := [ "TITLEBAR","MENUBAR","SCROLLBAR","GRIP","SOUND","CURSOR","CARET","ALERT","WINDOW","CLIENT","MENUPOPUP","MENUITEM","TOOLTIP"
, "APPLICATION","DOCUMENT","PANE","CHART","DIALOG","BORDER","GROUPING","SEPARATOR","TOOLBAR","STATUSBAR","TABLE","COLUMNHEADER","ROWHEADER"
, "COLUMN","ROW","CELL","LINK","HELPBALLOON","CHARACTER","LIST","LISTITEM","OUTLINE","OUTLINEITEM","PAGETAB","PROPERTYPAGE","INDICATOR"
, "GRAPHIC","STATICTEXT","TEXT","PUSHBUTTON","CHECKBUTTON","RADIOBUTTON","COMBOBOX","DROPLIST","PROGRESSBAR","DIAL","HOTKEYFIELD","SLIDER"
, "SPINBUTTON","DIAGRAM","ANIMATION","EQUATION","BUTTONDROPDOWN","BUTTONMENU","BUTTONDROPDOWNGRID","WHITESPACE"
, "PAGETABLIST","CLOCK","SPLITBUTTON","IPADDRESS","OUTLINEBUTTON" ]
return (s := arr[nRole]) ? "ROLE_SYSTEM_" s : ""
}
Acc_GetRoleInfo(Acc, ChildId) {
nRole := Acc.accRole(ChildId)
return Acc_GetRoleText(nRole) " (" Acc_GetRoleConstName(nRole) " := " nRole ")"
}
}
_isWindowDpiAware(hwnd) {
static last := {}
if (hwnd = last.hwnd)
return last.val
DllCall("GetWindowThreadProcessId", "ptr", hwnd, "int*", pid)
if (pid = last.pid)
return last.val, last.hwnd := hwnd
return val := GetProcessDpiAwareness(pid)
, last := {pid: pid, hwnd: hwnd, val: val}
}
GetProcessDpiAwareness(pid) {
static h := DllCall("LoadLibrary", "str", "Shcore.dll", "ptr")
static GetProcessDpiAwareness := DllCall("GetProcAddress", "ptr", h, "astr", "GetProcessDpiAwareness", "ptr")
if hProcess := DllCall("OpenProcess", "uint", 0x0400, "int", false, "uint", pid, "ptr")
{
DllCall(GetProcessDpiAwareness, "ptr", hProcess, "int*", PROCESS_DPI_AWARENESS)
DllCall("CloseHandle", "ptr", hProcess)
return PROCESS_DPI_AWARENESS
}
}
SelectAcc() {
; https://docs.microsoft.com/en-us/windows/win32/winauto/selflag
; SELFLAG_TAKESELECTION = 0x2
Acc.accSelect(0x2, ChildId)
GuiControl, Disable, % A_GuiControl
GuiControl,, AccState, % Acc_GetStateTextEx2(Acc.accState(ChildId))
}
EnableBtnSelect() {
static STATE_SYSTEM_SELECTABLE := 0x200000
static STATE_SYSTEM_SELECTED := 0x2
b := (Acc.accState(ChildId) & STATE_SYSTEM_SELECTABLE)
&& !(Acc.accState(ChildId) & STATE_SYSTEM_SELECTED)
static last := 0
if (b != last) {
GuiControl, % "Enable" b, StateSelect
last := b
}
}
RestoreCursors() {
static SPI_SETCURSORS := 0x57
DllCall("SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0)
}
; ====================================================================
#If WinActive("ahk_id " Win.Acc) || WinActive("ahk_id " Win.Main)
^g::gotoPath()
; ^BackSpace::gotoParentAcc()
; ^Home::gotoRootAcc()
#If
_InputBox(Title:="", oParam := "")
{
preTDPI := DllCall("SetThreadDpiAwarenessContext", "int", -4)
Gui, % Win.Main ":+OwnDialogs -AlwaysOnTop"
InputBox, v, %Title%,,,, % oParam.Height,,,,, % oParam.Default
CancelPressed := ErrorLevel
Gui, % Win.Main ":+AlwaysOnTop"
DllCall("SetThreadDpiAwarenessContext", "int", preTDPI)
return CancelPressed ? "" : v
}
_error(title, text) {
preTDPI := DllCall("SetThreadDpiAwarenessContext", "int", -4)
Gui, % Win.Main ":+OwnDialogs -AlwaysOnTop"
MsgBox, 48, %title%, %text%
Gui, % Win.Main ":+AlwaysOnTop"
DllCall("SetThreadDpiAwarenessContext", "int", preTDPI)
}
gotoPath() {
if !inputPath := _InputBox( "Go to path", {height:110, default:g_lastPath} )
Return
inputPath := StrReplace(inputPath, ",", ".")
inputPath := Trim(inputPath, ".")
if !(inputPath ~= "^\d+(\.\d+)*$")
return _error("Go to path", "path invalid")
parentElement := GetRootAcc(acc)
try {
Loop, Parse, inputPath, .
{
parentElement := AccChildren(parentElement)[A_LoopField]
if !parentElement.accRole(0)
return
}
Acc := parentElement, childId := 0
UpdateAccInfo(Acc, childId)
BuildTreeView()
}
}
gotoParentAcc() {
if !isRootAcc(Acc)
__updateAcc( Acc_Parent(Acc) )
}
gotoRootAcc() {
__updateAcc( GetRootAcc(Acc) )
}
__updateAcc(newAcc, childId := 0) {
if !AccChildren(newAcc)
return
acc := newAcc
ToggleThreadDpiAwareness( AccWindowFromObject(acc) )
GetAccInfo( {hwnd: Acc_WindowFromObject(acc), acc:acc} )
; UpdateAccInfo(Acc, childId)
; SB_SetText("Path: " (g_lastPath:=GetAccPath(Acc).path), 2)
g_skipTvEvent := true
BuildTreeView()
g_skipTvEvent := false
}
; isRootAcc(acc) {
; static GA_ROOT := 2
; hWnd := Acc_WindowFromObject(acc)
; hWndRoot := DllCall("GetAncestor", "ptr", hwnd, "uint", GA_ROOT, "ptr")
; return (hWnd = hWndRoot)
; }
isRootAcc(acc) {
static DesktopHwnd := DllCall("GetDesktopWindow", "ptr")
try {
return (Acc_WindowFromObject(Acc_Parent(acc)) = DesktopHwnd)
}
}
GetRootAcc(acc) {
static GA_ROOT := 2
hwnd := Acc_WindowFromObject(acc)
hRoot := DllCall("GetAncestor", "ptr", hwnd, "uint", GA_ROOT, "ptr")
return AccObjectFromWindow(hRoot)
}
GetAccFullPath2(ByRef outCode := "", codeType := "full") {
params := { Value: acc.AccValue(childId)
, Name: acc.AccName(childId)
, Role: acc.accRole(childId)
, State: acc.accState(childId)
, ChildCount: acc.accChildCount
, hWnd: AccWindowFromObject(Acc) }
if SearchElement(accRoot:=GetRootAcc(acc), params, childId, inOutPath, inOutRole)
{
if IsByRef(outCode)
createSearchCode(outCode, codeType, accRoot, params, childId, inOutPath, inOutRole)
return inOutPath
}
}
GetAccPath_Full(Acc) {
static DesktopHwnd := DllCall("GetDesktopWindow", "ptr")
while idx := GetEnumIndex2(Acc) {
ParentAcc := Acc_Parent(Acc)
if !(hwnd := Acc_WindowFromObject(ParentAcc)) || (hwnd = DesktopHwnd)
break
path := idx "." path
role .= Acc.accRole(0) "."
Acc := ParentAcc
}
return {AccObj:Acc, Path: RTrim(path, ".")}
}
GetAccFullPath(ByRef outCode := "", codeType := "full") {
local path, role
static DesktopHwnd := DllCall("GetDesktopWindow", "ptr")
rootHwnd := DllCall("GetAncestor", "ptr", Acc_WindowFromObject(Acc), "uint", GA_ROOT:=2, "ptr")
thisAcc := Acc
while idx := GetEnumIndex2(thisAcc) {
parentAcc := Acc_Parent(thisAcc)
if !(hwnd := Acc_WindowFromObject(parentAcc)) || (hwnd = DesktopHwnd)
break
path := idx "." path
role .= thisAcc.accRole(0) "."
thisAcc := parentAcc
}
path := Trim(path, ".")
if (Acc_WindowFromObject(thisAcc) != rootHwnd) {
return GetAccFullPath2(outCode, codeType)
}
if IsByRef(outCode) {
Sort, role, U D.
role := Trim(role, ".")
params := { Name: Acc.AccName(childId), Role: Acc.accRole(childId) }
createSearchCode(outCode, codeType, thisAcc, params, childId, path, role)
}
return path
}
GetEnumIndex2(Acc) {
For Each, child in Acc_Children(p:=Acc_Parent(Acc))
{
if IsObject(child)
&& (child.accRole(0) = Acc.accRole(0))
&& (child.accName(0) = Acc.accName(0))
&& (child.accState(0) = Acc.accState(0))
&& (child.accValue(0) = Acc.accValue(0))
&& (child.accChildCount = Acc.accChildCount)
&& (Acc_LocationStr(child) = Acc_LocationStr(Acc))
&& (child.accDefaultAction(0) = Acc.accDefaultAction(0))
&& (child.accDescription(0) = Acc.accDescription(0))
&& (child.accHelp(0) = Acc.accHelp(0))
&& (child.accKeyboardShortcut(0) = Acc.accKeyboardShortcut(0))
return A_Index
}
}
Acc_LocationStr(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")
}
; teadrinker
SearchElement(parentElement, params, childId:=0, ByRef inOutPath:="", ByRef inOutRole:="", _allowRole:="")
{
if inOutPath {
_accBackup := parentElement
Loop, Parse, inOutPath, `,., %A_Space%%A_Tab%
parentElement := AccChildren(parentElement)[A_LoopField]
}
found := true
for k, v in params {
try {
switch k {
case "ChildCount": (parentElement.accChildCount != v && found := false)
case "State": (!(parentElement.accState(childId) & v) && found := false)
case "hWnd": (AccWindowFromObject(parentElement) != v && found := false)
default: (parentElement["acc" . k](childId) != v && found := false)
}
}
catch
found := false
} until !found
if found
Return parentElement
if _accBackup {
parentElement := _accBackup
}
if inOutRole {
_allowRole := {}
Loop, Parse, inOutRole, `,., %A_Space%%A_Tab%
_allowRole[A_LoopField] := 1
}
inOutPath := inOutRole := ""
for k, v in AccChildren(parentElement)
{
b := !_allowRole || _allowRole.HasKey(v.accRole(0))
if b && (obj := SearchElement(v, params, childId, inOutPath, inOutRole, _allowRole))
{
if IsByRef(inOutPath)
inOutPath := k . (inOutPath ? "." : "") . inOutPath
if IsByRef(inOutRole) && !(inOutRole ~= "\b" v.accRole(0) "\b")
inOutRole := v.accRole(0) . (inOutRole ? "." : "") . inOutRole
Return obj
}
}
}
AccObjectFromWindow(hWnd, idObject = 0) {
static IID_IDispatch := "{00020400-0000-0000-C000-000000000046}"
, IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
, OBJID_NATIVEOM := 0xFFFFFFF0, VT_DISPATCH := 9, F_OWNVALUE := 1
, h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
VarSetCapacity(IID, 16), idObject &= 0xFFFFFFFF
DllCall("ole32\CLSIDFromString", "Str", idObject = OBJID_NATIVEOM ? IID_IDispatch : IID_IAccessible, "Ptr", &IID)
if DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject, "Ptr", &IID, "PtrP", pAcc) = 0
Return ComObject(VT_DISPATCH, pAcc, F_OWNVALUE)
}
AccWindowFromObject(Acc) {
DllCall("oleacc\WindowFromAccessibleObject", "Ptr", ComObjValue(Acc), "Ptr*", hWnd)
return hWnd
}
AccChildren(Acc) {
static VT_DISPATCH := 9
Loop 1 {
if ComObjType(Acc, "Name") != "IAccessible" {
error := "Invalid IAccessible Object"
break
}
try cChildren := Acc.accChildCount
catch
Return ""
Children := []
VarSetCapacity(varChildren, cChildren*(8 + A_PtrSize*2), 0)
res := DllCall("oleacc\AccessibleChildren", "Ptr", ComObjValue(Acc), "Int", 0
, "Int", cChildren, "Ptr", &varChildren, "IntP", cChildren)
if (res != 0) {
error := "AccessibleChildren DllCall Failed"
break
}
Loop % cChildren {
i := (A_Index - 1)*(A_PtrSize*2 + 8)
child := NumGet(varChildren, i + 8)
Children.Push( (b := NumGet(varChildren, i) = VT_DISPATCH) ? AccQuery(child) : child )
( b && ObjRelease(child) )
}
}
if error
ErrorLevel := error
else
Return Children.MaxIndex() ? Children : ""
}
AccQuery(Acc) {
static IAccessible := "{618736e0-3c3d-11cf-810c-00aa00389b71}", VT_DISPATCH := 9, F_OWNVALUE := 1
try Return ComObject(VT_DISPATCH, ComObjQuery(Acc, IAccessible), F_OWNVALUE)
}
; =================================================================
createSearchCode(ByRef outCode, codeType, parentElement, params, childId, inOutPath, inOutRole) {
if !(codeType ~= "i)full|single|parameters")
throw
WinGetTitle, title, % "ahk_id " (hWnd := Acc_WindowFromObject(parentElement))
WinGet, exeName, ProcessName, ahk_id %hWnd%
WinGetClass, class, ahk_id %hWnd%
for k, v in params {
if !(k ~= "i)State|ChildCount|hWnd|Value") {
q := (k ~= "i)Name|Value") ? """" : ""
v := (k = "Role") ? "(" Acc_GetRoleConstName(v) ":=" v ")" : v
strParams .= k ":" q StrReplace(v, "`n", "``n") q ", "
}
}
strParams := "{" RTrim(strParams, ", ") "}"
if (codeType = "single") {
outCode = accFound := SearchElement(accParent, %strParams%, %childId%, "%inOutPath%", "%inOutRole%")
return
}
if (codeType = "parameters") {
outCode = %strParams%, %childId%, "%inOutPath%", "%inOutRole%"
return
}
if (a := acc.accDefaultAction(childId))
code_DoDefaultAction = accFound.accDoDefaultAction(%childId%) `;%a%
if (class = "Chrome_WidgetWin_1")
code_WM_GETOBJECT := "SendMessage, 0x003D, 0, 1 `;WM_GETOBJECT"
code_part1 =
(LTrim Join`r`n
#NoEnv
SetBatchLines, -1
if !hwnd := WinExist("%title% ahk_exe %exeName% ahk_class %class%")
%A_Tab%throw "window not found"
%code_WM_GETOBJECT%
accRoot := AccObjectFromWindow(hwnd)
if !accFound := SearchElement(accRoot, %strParams%, %childId%, "%inOutPath%", "%inOutRole%")
%A_Tab%throw "element not found"
MsgBox, `% accFound.accName(%childId%)
%code_DoDefaultAction%
Return
)
code_part2 =
(% Join`r`n
SearchElement(parentElement, params, childId:=0, ByRef inOutPath:="", ByRef inOutRole:="")
{
_inOutRole := inOutRole
if accFound := _SearchElement(parentElement, params, childId, inOutPath, inOutRole)
return accFound
if _inOutRole
return _SearchElement(parentElement, params, childId, inOutPath, inOutRole := "")
}
_SearchElement(parentElement, params, childId:=0, ByRef inOutPath:="", ByRef inOutRole:="", _allowRole:="")
{
if inOutPath {
_accBackup := parentElement
Loop, Parse, inOutPath, `,., %A_Space%%A_Tab%
parentElement := AccChildren(parentElement)[A_LoopField]
}
found := true
for k, v in params {
try {
switch k {
case "ChildCount": (parentElement.accChildCount != v && found := false)
case "State": (!(parentElement.accState(childId) & v) && found := false)
case "NameRegEx": (!(parentElement.accName(childId) ~= v) && found := false)
default: (parentElement["acc" . k](childId) != v && found := false)
}
}
catch
found := false
} until !found
if found
Return parentElement
if _accBackup {
parentElement := _accBackup
}
if inOutRole {
_allowRole := {}
Loop, Parse, inOutRole, `,., %A_Space%%A_Tab%
_allowRole[A_LoopField] := 1
}
inOutPath := inOutRole := ""
for k, v in AccChildren(parentElement)
{
b := !_allowRole || _allowRole.HasKey(v.accRole(0))
if b && (obj := _SearchElement(v, params, childId, inOutPath, inOutRole, _allowRole))
{
if IsByRef(inOutPath)
inOutPath := k . (inOutPath ? "." : "") . inOutPath
if IsByRef(inOutRole) && !(inOutRole ~= "\b" v.accRole(0) "\b")
inOutRole := v.accRole(0) . (inOutRole ? "." : "") . inOutRole
Return obj
}
}
}
AccObjectFromWindow(hWnd, idObject = 0) {
static IID_IDispatch := "{00020400-0000-0000-C000-000000000046}"
, IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
, OBJID_NATIVEOM := 0xFFFFFFF0, VT_DISPATCH := 9, F_OWNVALUE := 1
, h := DllCall("LoadLibrary", "Str", "oleacc", "Ptr")
VarSetCapacity(IID, 16), idObject &= 0xFFFFFFFF
DllCall("ole32\CLSIDFromString", "Str", idObject = OBJID_NATIVEOM ? IID_IDispatch : IID_IAccessible, "Ptr", &IID)
if DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject, "Ptr", &IID, "PtrP", pAcc) = 0
Return ComObject(VT_DISPATCH, pAcc, F_OWNVALUE)
}
AccChildren(Acc) {
static VT_DISPATCH := 9
Loop 1 {
if ComObjType(Acc, "Name") != "IAccessible" {
error := "Invalid IAccessible Object"
break
}
try cChildren := Acc.accChildCount
catch
Return ""
Children := []
VarSetCapacity(varChildren, cChildren*(8 + A_PtrSize*2), 0)
res := DllCall("oleacc\AccessibleChildren", "Ptr", ComObjValue(Acc), "Int", 0
, "Int", cChildren, "Ptr", &varChildren, "IntP", cChildren)
if (res != 0) {
error := "AccessibleChildren DllCall Failed"
break
}
Loop % cChildren {
i := (A_Index - 1)*(A_PtrSize*2 + 8)
child := NumGet(varChildren, i + 8)
Children.Push( (b := NumGet(varChildren, i) = VT_DISPATCH) ? AccQuery(child) : child )
( b && ObjRelease(child) )
}
}
if error
ErrorLevel := error
else
Return Children.MaxIndex() ? Children : ""
}
AccQuery(Acc) {
static IAccessible := "{618736e0-3c3d-11cf-810c-00aa00389b71}", VT_DISPATCH := 9, F_OWNVALUE := 1
try Return ComObject(VT_DISPATCH, ComObjQuery(Acc, IAccessible), F_OWNVALUE)
}
)
outCode := code_part1 . code_part2
outCode := StrReplace(outCode, "`r`n`r`n`r`n", "`r`n",, 1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment