Last active
October 31, 2023 11:48
-
-
Save tmplinshi/0fcb8655c1402a3662ac048d0d974915 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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