Skip to content

Instantly share code, notes, and snippets.

@anonymous1184
Last active January 8, 2024 14:50
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save anonymous1184/58d2b141be2608a2f7d03a982e552a71 to your computer and use it in GitHub Desktop.
Save anonymous1184/58d2b141be2608a2f7d03a982e552a71 to your computer and use it in GitHub Desktop.
Acc.ahk

MSAA Library (Acc.ahk)

The versions in this Gist have the same* functionality as the original (found here). However, it has small modifications. None of them has any meaningful impact but the last one (it helps with performance inside iterations, like when recursing the accessibility tree).

* Plus small fixes, validations here and there, and early return where applicable...

Why? Because to understand what the code does, I need to be able to read it. The original library is distributed with compactness in mind, neverminding the ability to read the code and learn from it.

Also, the author of the original code base (board's user Sean) did so in a certain way; when it got extended, the contributor (forum's user jethrow) added his coding style making the thing a bit harder to grasp at first sight.

While I did my best trying not to change the library functionality, structure and outline; small bits are different yet, is a 1:1 drop-in replacement.

Modifications

#Warn compatible

It doesn't trigger warnings for undeclared variables if #Warn is enabled (as it should).

Formatting

Everything was re-written with a consistent coding style, following this guidelines. But more than anything is to keep things as simple as possible; AutoHotkey is an easy language, and there is no need to take away that by adding complex expressions.

Legacy code

Deprecated syntax was removed and used the recommended instead. While not v2-compatible straightforward, the changes made had compatibility in mind; translating into v2 syntax should be easier now.

UPDATE: It was easy all right, as proven by the small changeset.

ChildId as pure number

When talking to the IAccessible interface, it expects the ChildId parameter to be an integer; AutoHotkey v1.1 can pass integers as strings when they are not the result of an expression.

ANSI compatibility

Acc_GetRoleText() and Acc_GetStateText() are Unicode-only now. If you plan on running this in Windows 98 you can't, is safe for XP onwards though.

Acc_Location()

The Acc_Location() function bundled with the original library receives as the 3rd parameter a referenced variable while other versions in use return it as a property (for example here, see the note at the end of the answer). Now both are provided as they're not in conflict with each other.

Acc_ChildrenByRole()

The function was replaced because it was a copy of Acc_Children() with a simple filter. Rather than duplicated functionality, the filter is applied to the result of Acc_Children().

Acc_Get()

  • Small input validations.
  • Early return on errors.
  • Different error text when sending roles in the path.
  • It now re-uses Acc_Location().
  • Parent is a property and was treated as a method, always throwing an error. Now it makes use of a function already written.

Performance

oleacc.dll is not one of the libraries loaded by default, needs to be explicitly loaded/freed every time DllCall() is used. The original library already had this in mind; as an improvement, the address of each function is retrieved statically at load to have the same performance as any standard DLL.

Files

AutoHotkey v2.0

AutoHotkey v1.1

v2.0 vs v1.1

#Requires AutoHotkey v2.0
; Version: 2023.09.22.1
; https://gist.github.com/58d2b141be2608a2f7d03a982e552a71
; Private
Acc_Init(Function) {
static hModule := DllCall("LoadLibrary", "Str", "oleacc.dll", "Ptr")
return DllCall("GetProcAddress", "Ptr", hModule, "AStr", Function, "Ptr")
}
Acc_ObjectFromEvent(&ChildIdOut, hWnd, ObjectId, ChildId) {
static STATUS_SUCCESS := 0, address := Acc_Init("AccessibleObjectFromEvent")
child := Buffer(A_PtrSize * 2 + 8, 0)
pAcc := 0
NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "UInt", ChildId, "Ptr*", &pAcc, "Ptr", child, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Error("AccessibleObjectFromEvent() failed.", -1, OsError().Message)
}
ChildIdOut := NumGet(child, 8, "UInt")
return ComValue(9, pAcc, 1)
}
Acc_ObjectFromPoint(&ChildIdOut := "", x := 0, y := 0) {
static STATUS_SUCCESS := 0, address := Acc_Init("AccessibleObjectFromPoint")
point := x & 0xFFFFFFFF | y << 32
if (point = 0) {
DllCall("GetCursorPos", "Int64*", &point)
}
pAcc := 0
child := Buffer(A_PtrSize * 2 + 8, 0)
NTSTATUS := DllCall(address, "Int64", point, "Ptr*", &pAcc, "Ptr", child, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Error("AccessibleObjectFromPoint() failed.", -1, OsError().Message)
}
ChildIdOut := NumGet(child, 8, "UInt")
return ComValue(9, pAcc, 1)
}
/* ObjectId
OBJID_WINDOW := 0x00000000 ; 0
OBJID_SYSMENU := 0xFFFFFFFF ; -1
OBJID_TITLEBAR := 0xFFFFFFFE ; -2
OBJID_MENU := 0xFFFFFFFD ; -3
OBJID_CLIENT := 0xFFFFFFFC ; -4
OBJID_VSCROLL := 0xFFFFFFFB ; -5
OBJID_HSCROLL := 0xFFFFFFFA ; -6
OBJID_SIZEGRIP := 0xFFFFFFF9 ; -7
OBJID_CARET := 0xFFFFFFF8 ; -8
OBJID_CURSOR := 0xFFFFFFF7 ; -9
OBJID_ALERT := 0xFFFFFFF6 ; -10
OBJID_SOUND := 0xFFFFFFF5 ; -11
OBJID_QUERYCLASSNAMEIDX := 0xFFFFFFF4 ; -12
OBJID_NATIVEOM := 0xFFFFFFF0 ; -13
*/
Acc_ObjectFromWindow(hWnd, ObjectId := -4) {
static STATUS_SUCCESS := 0, address := Acc_Init("AccessibleObjectFromWindow")
ObjectId &= 0xFFFFFFFF
IID := Buffer(16, 0)
addr := ObjectId = 0xFFFFFFF0 ? 0x0000000000020400 : 0x11CF3C3D618736E0
rIID := NumPut("Int64", addr, IID)
addr := ObjectId = 0xFFFFFFF0 ? 0x46000000000000C0 : 0x719B3800AA000C81
rIID := NumPut("Int64", addr, rIID) - 16
pAcc := 0
NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "Ptr", rIID, "Ptr*", &pAcc, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Error("AccessibleObjectFromWindow() failed.", -1, OsError().Message)
}
return ComValue(9, pAcc, 1)
}
Acc_WindowFromObject(oAcc) {
static STATUS_SUCCESS := 0, address := Acc_Init("WindowFromAccessibleObject")
if (!IsObject(oAcc)) {
throw Error("Not an object.", -1, oAcc)
}
pAcc := ComObjValue(oAcc)
hWnd := 0
NTSTATUS := DllCall(address, "Ptr", pAcc, "Ptr*", &hWnd, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Error("WindowFromAccessibleObject() failed.", -1, OsError().Message)
}
return hWnd
}
Acc_GetRoleText(nRole) {
static address := Acc_Init("GetRoleTextW")
size := DllCall(address, "UInt", nRole, "Ptr", 0, "UInt", 0, "UInt")
if (!size) {
throw Error("GetRoleText() failed.", -1, OsError().Message)
}
size := VarSetStrCapacity(&role, size + 1)
size := DllCall(address, "UInt", nRole, "Str", &role, "UInt", size, "UInt")
if (!size) {
throw Error("GetRoleText() failed.", -1, OsError().Message)
}
return role
}
Acc_GetStateText(nState) {
static address := Acc_Init("GetStateTextW")
size := DllCall(address, "UInt", nState, "Ptr", 0, "UInt", 0, "UInt")
if (!size) {
throw Error("GetStateText() failed.", -1, OsError().Message)
}
size := VarSetStrCapacity(&state, size + 1)
size := DllCall(address, "UInt", nState, "Str", &state, "UInt", size, "UInt")
if (!size) {
throw Error("GetStateText() failed.", -1, OsError().Message)
}
return state
}
Acc_SetWinEventHook(EventMin, EventMax, Callback) {
return DllCall("SetWinEventHook", "UInt", EventMin, "UInt", EventMax, "Ptr", 0, "Ptr", Callback, "UInt", 0, "UInt", 0, "UInt", 0, "Ptr")
}
Acc_UnhookWinEvent(hHook) {
return DllCall("UnhookWinEvent", "Ptr", hHook, "Int")
}
/* Win Events
Callback := CallbackCreate("WinEventProc")
WinEventProc(hHook, Event, hWnd, ObjectId, ChildId, EventThread, EventTime) {
Critical
oAcc := Acc_ObjectFromEvent(ChildIdOut, hWnd, ObjectId, ChildId)
; Code Here
}
*/
; Written by jethrow
Acc_Role(oAcc, ChildId := 0) {
out := "invalid object"
try {
role := oAcc.accRole(ChildId)
out := Acc_GetRoleText(role)
}
return out
}
Acc_State(oAcc, ChildId := 0) {
out := "invalid object"
try {
state := oAcc.accState(ChildId)
out := Acc_GetStateText(state)
}
return out
}
Acc_Location(oAcc, ChildId := 0, &Position := "") {
static VT_BYREF := 16384, VT_I4 := 3, varType := VT_BYREF | VT_I4
x := Buffer(4, 0)
y := Buffer(4, 0)
w := Buffer(4, 0)
h := Buffer(4, 0)
xPtr := ComValue(varType, x.Ptr, 1)
yPtr := ComValue(varType, y.Ptr, 1)
wPtr := ComValue(varType, w.Ptr, 1)
hPtr := ComValue(varType, h.Ptr, 1)
Position := "ERROR"
out := { x: 0, y: 0, w: 0, h: 0, Pos: Position }
try {
oAcc.accLocation(xPtr, yPtr, wPtr, hPtr, ChildId)
x := NumGet(x, 0, "Int")
y := NumGet(y, 0, "Int")
w := NumGet(w, 0, "Int")
h := NumGet(h, 0, "Int")
Position := "x" x " y" y " w" w " h" h
out := { x: x, y: y, w: w, h: h, Pos: Position }
}
return out
}
Acc_Parent(oAcc) {
try {
return Acc_Query(oAcc.accParent)
}
}
Acc_Child(oAcc, ChildId := 0) {
try {
child := oAcc.AccChild(ChildId)
return Acc_Query(child)
}
}
; Private
Acc_Query(oAcc) {
try {
query := ComObjQuery(oAcc, "{618736E0-3C3D-11CF-810C-00AA00389B71}")
return ComValue(9, query, 1)
}
}
; Private, deprecated
Acc_Error(Previous := "") {
static setting := 0
if (StrLen(Previous)) {
setting := Previous
}
return setting
}
Acc_Children(oAcc) {
static address := Acc_Init("AccessibleChildren")
if (ComObjType(oAcc, "Name") != "IAccessible") {
throw Error("Invalid IAccessible Object", -1, oAcc)
}
pAcc := ComObjValue(oAcc)
size := A_PtrSize * 2 + 8
accChildren := Buffer(oAcc.accChildCount * size, 0)
obtained := 0
NTSTATUS := DllCall(address, "Ptr", pAcc, "Int", 0, "Int", oAcc.accChildCount, "Ptr", accChildren, "Int*", &obtained, "UInt")
if (NTSTATUS != 0) {
throw Error("AccessibleChildren() failed.", -1, OsError().Message)
}
children := []
loop (obtained) {
i := (A_Index - 1) * size
child := NumGet(accChildren, i + 8, "Int64")
if (NumGet(accChildren, i, "Int64") = 9) {
accChild := Acc_Query(child)
children.Push(accChild)
ObjRelease(child)
} else {
children.Push(child)
}
}
return children
}
Acc_ChildrenByRole(oAcc, RoleText) {
children := []
for _, child in Acc_Children(oAcc) {
if (Acc_Role(child) = RoleText) {
children.Push(child)
}
}
return children
}
/* Commands:
- Aliases:
Action -> DefaultAction
DoAction -> DoDefaultAction
Keyboard -> KeyboardShortcut
- Properties:
Child
ChildCount
DefaultAction
Description
Focus
Help
HelpTopic
KeyboardShortcut
Name
Parent
Role
Selection
State
Value
- Methods:
DoDefaultAction
Location
- Other:
Object
*/
Acc_Get(Command, ChildPath, ChildId := 0, Target*) {
if (Command ~= "i)^(HitTest|Navigate|Select)$") {
throw Error("Command not implemented", -1, Command)
}
ChildPath := StrReplace(ChildPath, "_", " ")
if (IsObject(Target[1])) {
oAcc := Target[1]
} else {
hWnd := WinExist(Target*)
oAcc := Acc_ObjectFromWindow(hWnd, 0)
}
if (ComObjType(oAcc, "Name") != "IAccessible") {
throw Error("Cannot access an IAccessible Object", -1, oAcc)
}
ChildPath := StrSplit(ChildPath, ".")
for level, item in ChildPath {
RegExMatch(item, "S)(?<Role>\D+)(?<Index>\d*)", &match)
if (match) {
item := match.Index ? match.Index : 1
children := Acc_ChildrenByRole(oAcc, match.Role)
} else {
children := Acc_Children(oAcc)
}
if (children.Has(item)) {
oAcc := children[item]
continue
}
extra := match.Role
? "Role: " match.Role ", Index: " item
: "Item: " item ", Level: " level
throw Error("Cannot access ChildPath Item", -1, extra)
}
switch (Command) { ; Expand aliases
case "Action": Command := "DefaultAction"
case "DoAction": Command := "DoDefaultAction"
case "Keyboard": Command := "KeyboardShortcut"
case "Object": return oAcc
}
switch (Command) {
case "Location": out := Acc_Location(oAcc, ChildId).pos
case "Parent": out := Acc_Parent(oAcc)
case "Role", "State": out := Acc_%Command%(oAcc, ChildId)
case "ChildCount", "Focus", "Selection": out := oAcc.acc%Command%
default: out := oAcc.acc%Command%(ChildId)
}
return out
}
#Requires AutoHotkey v1.1
; Version: 2023.09.22.1
; https://gist.github.com/58d2b141be2608a2f7d03a982e552a71
; Private
Acc_Init(Function) {
static hModule := DllCall("LoadLibrary", "Str", "oleacc.dll", "Ptr")
return DllCall("GetProcAddress", "Ptr", hModule, "AStr", Function, "Ptr")
}
Acc_ObjectFromEvent(ByRef ChildIdOut, hWnd, ObjectId, ChildId) {
static STATUS_SUCCESS := 0, address := Acc_Init("AccessibleObjectFromEvent")
VarSetCapacity(child, A_PtrSize * 2 + 8, 0)
pAcc := 0
NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "UInt", ChildId, "Ptr*", pAcc, "Ptr", &child, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Exception("AccessibleObjectFromEvent() failed.", -1, A_LastError)
}
ChildIdOut := NumGet(child, 8, "UInt")
return ComObj(9, pAcc, 1)
}
Acc_ObjectFromPoint(ByRef ChildIdOut := "", x := 0, y := 0) {
static STATUS_SUCCESS := 0, address := Acc_Init("AccessibleObjectFromPoint")
point := x & 0xFFFFFFFF | y << 32
if (point = 0) {
DllCall("GetCursorPos", "Int64*", point)
}
pAcc := 0
VarSetCapacity(child, A_PtrSize * 2 + 8, 0)
NTSTATUS := DllCall(address, "Int64", point, "Ptr*", pAcc, "Ptr", &child, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Exception("AccessibleObjectFromPoint() failed.", -1, A_LastError)
}
ChildIdOut := NumGet(child, 8, "UInt")
return ComObj(9, pAcc, 1)
}
/* ObjectId
OBJID_WINDOW := 0x00000000 ; 0
OBJID_SYSMENU := 0xFFFFFFFF ; -1
OBJID_TITLEBAR := 0xFFFFFFFE ; -2
OBJID_MENU := 0xFFFFFFFD ; -3
OBJID_CLIENT := 0xFFFFFFFC ; -4
OBJID_VSCROLL := 0xFFFFFFFB ; -5
OBJID_HSCROLL := 0xFFFFFFFA ; -6
OBJID_SIZEGRIP := 0xFFFFFFF9 ; -7
OBJID_CARET := 0xFFFFFFF8 ; -8
OBJID_CURSOR := 0xFFFFFFF7 ; -9
OBJID_ALERT := 0xFFFFFFF6 ; -10
OBJID_SOUND := 0xFFFFFFF5 ; -11
OBJID_QUERYCLASSNAMEIDX := 0xFFFFFFF4 ; -12
OBJID_NATIVEOM := 0xFFFFFFF0 ; -13
*/
Acc_ObjectFromWindow(hWnd, ObjectId := -4) {
static STATUS_SUCCESS := 0, address := Acc_Init("AccessibleObjectFromWindow")
ObjectId &= 0xFFFFFFFF
VarSetCapacity(IID, 16, 0)
addr := ObjectId = 0xFFFFFFF0 ? 0x0000000000020400 : 0x11CF3C3D618736E0
rIID := NumPut(addr, IID, "Int64")
addr := ObjectId = 0xFFFFFFF0 ? 0x46000000000000C0 : 0x719B3800AA000C81
rIID := NumPut(addr, rIID + 0, "Int64") - 16
pAcc := 0
NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "Ptr", rIID, "Ptr*", pAcc, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Exception("AccessibleObjectFromWindow() failed.", -1, A_LastError)
}
return ComObj(9, pAcc, 1)
}
Acc_WindowFromObject(oAcc) {
static STATUS_SUCCESS := 0, address := Acc_Init("WindowFromAccessibleObject")
if (!IsObject(oAcc)) {
throw Exception("Not an object.", -1, oAcc)
}
pAcc := ComObjValue(oAcc)
hWnd := 0
NTSTATUS := DllCall(address, "Ptr", pAcc, "Ptr*", hWnd, "UInt")
if (NTSTATUS != STATUS_SUCCESS) {
throw Exception("WindowFromAccessibleObject() failed.", -1, A_LastError)
}
return hWnd
}
Acc_GetRoleText(nRole) {
static address := Acc_Init("GetRoleTextW")
size := DllCall(address, "UInt", nRole, "Ptr", 0, "UInt", 0, "UInt")
if (!size) {
throw Exception("GetRoleText() failed.", -1, A_LastError)
}
size := VarSetCapacity(role, size * 2, 0)
size := DllCall(address, "UInt", nRole, "Str", role, "UInt", size, "UInt")
if (!size) {
throw Exception("GetRoleText() failed.", -1, A_LastError)
}
return role
}
Acc_GetStateText(nState) {
static address := Acc_Init("GetStateTextW")
size := DllCall(address, "UInt", nState, "Ptr", 0, "UInt", 0, "UInt")
if (!size) {
throw Exception("GetStateText() failed.", -1, A_LastError)
}
size := VarSetCapacity(state, size * 2, 0)
size := DllCall(address, "UInt", nState, "Str", state, "UInt", size, "UInt")
if (!size) {
throw Exception("GetStateText() failed.", -1, A_LastError)
}
return state
}
Acc_SetWinEventHook(EventMin, EventMax, Callback) {
return DllCall("SetWinEventHook", "UInt", EventMin, "UInt", EventMax, "Ptr", 0, "Ptr", Callback, "UInt", 0, "UInt", 0, "UInt", 0, "Ptr")
}
Acc_UnhookWinEvent(hHook) {
return DllCall("UnhookWinEvent", "Ptr", hHook, "Int")
}
/* Win Events
Callback := RegisterCallback("WinEventProc")
WinEventProc(hHook, Event, hWnd, ObjectId, ChildId, EventThread, EventTime) {
Critical
oAcc := Acc_ObjectFromEvent(ChildIdOut, hWnd, ObjectId, ChildId)
; Code Here
}
*/
; Written by jethrow
Acc_Role(oAcc, ChildId := 0) {
out := "invalid object"
try {
role := oAcc.accRole(ChildId + 0)
out := Acc_GetRoleText(role)
}
return out
}
Acc_State(oAcc, ChildId := 0) {
out := "invalid object"
try {
state := oAcc.accState(ChildId + 0)
out := Acc_GetStateText(state)
}
return out
}
Acc_Location(oAcc, ChildId := 0, ByRef Position := "") {
static VT_BYREF := 16384, VT_I4 := 3, varType := VT_BYREF | VT_I4
VarSetCapacity(x, 4, 0)
VarSetCapacity(y, 4, 0)
VarSetCapacity(w, 4, 0)
VarSetCapacity(h, 4, 0)
xPtr := ComObj(varType, &x, 1)
yPtr := ComObj(varType, &y, 1)
wPtr := ComObj(varType, &w, 1)
hPtr := ComObj(varType, &h, 1)
Position := "ERROR"
out := { x: 0, y: 0, w: 0, h: 0, Pos: Position }
try {
oAcc.accLocation(xPtr, yPtr, wPtr, hPtr, ChildId + 0)
x := NumGet(x, 0, "Int")
y := NumGet(y, 0, "Int")
w := NumGet(w, 0, "Int")
h := NumGet(h, 0, "Int")
Position := "x" x " y" y " w" w " h" h
out := { x: x, y: y, w: w, h: h, Pos: Position }
}
return out
}
Acc_Parent(oAcc) {
try {
return Acc_Query(oAcc.accParent)
}
}
Acc_Child(oAcc, ChildId := 0) {
try {
child := oAcc.AccChild(ChildId + 0)
return Acc_Query(child)
}
}
; Private
Acc_Query(oAcc) {
try {
query := ComObjQuery(oAcc, "{618736E0-3C3D-11CF-810C-00AA00389B71}")
return ComObj(9, query, 1)
}
}
; Private, deprecated
Acc_Error(Previous := "") {
static setting := 0
if (StrLen(Previous)) {
setting := Previous
}
return setting
}
Acc_Children(oAcc) {
static address := Acc_Init("AccessibleChildren")
if (ComObjType(oAcc, "Name") != "IAccessible") {
throw Exception("Invalid IAccessible Object", -1, oAcc)
}
pAcc := ComObjValue(oAcc)
size := A_PtrSize * 2 + 8
VarSetCapacity(accChildren, oAcc.accChildCount * size, 0)
obtained := 0
NTSTATUS := DllCall(address, "Ptr", pAcc, "Int", 0, "Int", oAcc.accChildCount, "Ptr", &accChildren, "Int*", obtained, "UInt")
if (NTSTATUS != 0) {
throw Exception("AccessibleChildren() failed.", -1, A_LastError)
}
children := []
loop % obtained {
i := (A_Index - 1) * size
child := NumGet(accChildren, i + 8, "Int64")
if (NumGet(accChildren, i, "Int64") = 9) {
accChild := Acc_Query(child)
children.Push(accChild)
ObjRelease(child)
} else {
children.Push(child)
}
}
return children
}
Acc_ChildrenByRole(oAcc, RoleText) {
children := []
for _, child in Acc_Children(oAcc) {
if (Acc_Role(child) = RoleText) {
children.Push(child)
}
}
return children
}
/* Commands:
- Aliases:
Action -> DefaultAction
DoAction -> DoDefaultAction
Keyboard -> KeyboardShortcut
- Properties:
Child
ChildCount
DefaultAction
Description
Focus
Help
HelpTopic
KeyboardShortcut
Name
Parent
Role
Selection
State
Value
- Methods:
DoDefaultAction
Location
- Other:
Object
*/
Acc_Get(Command, ChildPath, ChildId := 0, Target*) {
if (Command ~= "i)^(HitTest|Navigate|Select)$") {
throw Exception("Command not implemented", -1, Command)
}
ChildPath := StrReplace(ChildPath, "_", " ")
if (IsObject(Target[1])) {
oAcc := Target[1]
} else {
hWnd := WinExist(Target*)
oAcc := Acc_ObjectFromWindow(hWnd, 0)
}
if (ComObjType(oAcc, "Name") != "IAccessible") {
throw Exception("Cannot access an IAccessible Object", -1, oAcc)
}
ChildPath := StrSplit(ChildPath, ".")
for level, item in ChildPath {
RegExMatch(item, "OS)(?<Role>\D+)(?<Index>\d*)", match)
if (match) {
item := match.Index ? match.Index : 1
children := Acc_ChildrenByRole(oAcc, match.Role)
} else {
children := Acc_Children(oAcc)
}
if (children.HasKey(item)) {
oAcc := children[item]
continue
}
extra := match.Role
? "Role: " match.Role ", Index: " item
: "Item: " item ", Level: " level
throw Exception("Cannot access ChildPath Item", -1, extra)
}
switch (Command) { ; Expand aliases
case "Action": Command := "DefaultAction"
case "DoAction": Command := "DoDefaultAction"
case "Keyboard": Command := "KeyboardShortcut"
case "Object": return oAcc
}
switch (Command) {
case "Location": out := Acc_Location(oAcc, ChildId).pos
case "Parent": out := Acc_Parent(oAcc)
case "Role", "State": out := Acc_%Command%(oAcc, ChildId)
case "ChildCount", "Focus", "Selection": out := oAcc["acc" Command]
default: out := oAcc["acc" Command](ChildId + 0)
}
return out
}
--- Acc.ahk
+++ Acc1.ahk
@@ -1 +1 @@
-#Requires AutoHotkey v2.0
+#Requires AutoHotkey v1.1
@@ -12 +12 @@
-Acc_ObjectFromEvent(&ChildIdOut, hWnd, ObjectId, ChildId) {
+Acc_ObjectFromEvent(ByRef ChildIdOut, hWnd, ObjectId, ChildId) {
@@ -14 +14 @@
- child := Buffer(A_PtrSize * 2 + 8, 0)
+ VarSetCapacity(child, A_PtrSize * 2 + 8, 0)
@@ -16 +16 @@
- NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "UInt", ChildId, "Ptr*", &pAcc, "Ptr", child, "UInt")
+ NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "UInt", ChildId, "Ptr*", pAcc, "Ptr", &child, "UInt")
@@ -18 +18 @@
- throw Error("AccessibleObjectFromEvent() failed.", -1, OsError().Message)
+ throw Exception("AccessibleObjectFromEvent() failed.", -1, A_LastError)
@@ -21 +21 @@
- return ComValue(9, pAcc, 1)
+ return ComObj(9, pAcc, 1)
@@ -24 +24 @@
-Acc_ObjectFromPoint(&ChildIdOut := "", x := 0, y := 0) {
+Acc_ObjectFromPoint(ByRef ChildIdOut := "", x := 0, y := 0) {
@@ -28 +28 @@
- DllCall("GetCursorPos", "Int64*", &point)
+ DllCall("GetCursorPos", "Int64*", point)
@@ -31,2 +31,2 @@
- child := Buffer(A_PtrSize * 2 + 8, 0)
- NTSTATUS := DllCall(address, "Int64", point, "Ptr*", &pAcc, "Ptr", child, "UInt")
+ VarSetCapacity(child, A_PtrSize * 2 + 8, 0)
+ NTSTATUS := DllCall(address, "Int64", point, "Ptr*", pAcc, "Ptr", &child, "UInt")
@@ -34 +34 @@
- throw Error("AccessibleObjectFromPoint() failed.", -1, OsError().Message)
+ throw Exception("AccessibleObjectFromPoint() failed.", -1, A_LastError)
@@ -37 +37 @@
- return ComValue(9, pAcc, 1)
+ return ComObj(9, pAcc, 1)
@@ -59 +59 @@
- IID := Buffer(16, 0)
+ VarSetCapacity(IID, 16, 0)
@@ -61 +61 @@
- rIID := NumPut("Int64", addr, IID)
+ rIID := NumPut(addr, IID, "Int64")
@@ -63 +63 @@
- rIID := NumPut("Int64", addr, rIID) - 16
+ rIID := NumPut(addr, rIID + 0, "Int64") - 16
@@ -65 +65 @@
- NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "Ptr", rIID, "Ptr*", &pAcc, "UInt")
+ NTSTATUS := DllCall(address, "Ptr", hWnd, "UInt", ObjectId, "Ptr", rIID, "Ptr*", pAcc, "UInt")
@@ -67 +67 @@
- throw Error("AccessibleObjectFromWindow() failed.", -1, OsError().Message)
+ throw Exception("AccessibleObjectFromWindow() failed.", -1, A_LastError)
@@ -69 +69 @@
- return ComValue(9, pAcc, 1)
+ return ComObj(9, pAcc, 1)
@@ -75 +75 @@
- throw Error("Not an object.", -1, oAcc)
+ throw Exception("Not an object.", -1, oAcc)
@@ -79 +79 @@
- NTSTATUS := DllCall(address, "Ptr", pAcc, "Ptr*", &hWnd, "UInt")
+ NTSTATUS := DllCall(address, "Ptr", pAcc, "Ptr*", hWnd, "UInt")
@@ -81 +81 @@
- throw Error("WindowFromAccessibleObject() failed.", -1, OsError().Message)
+ throw Exception("WindowFromAccessibleObject() failed.", -1, A_LastError)
@@ -90 +90 @@
- throw Error("GetRoleText() failed.", -1, OsError().Message)
+ throw Exception("GetRoleText() failed.", -1, A_LastError)
@@ -92,2 +92,2 @@
- size := VarSetStrCapacity(&role, size + 1)
- size := DllCall(address, "UInt", nRole, "Str", &role, "UInt", size, "UInt")
+ size := VarSetCapacity(role, size * 2, 0)
+ size := DllCall(address, "UInt", nRole, "Str", role, "UInt", size, "UInt")
@@ -95 +95 @@
- throw Error("GetRoleText() failed.", -1, OsError().Message)
+ throw Exception("GetRoleText() failed.", -1, A_LastError)
@@ -104 +104 @@
- throw Error("GetStateText() failed.", -1, OsError().Message)
+ throw Exception("GetStateText() failed.", -1, A_LastError)
@@ -106,2 +106,2 @@
- size := VarSetStrCapacity(&state, size + 1)
- size := DllCall(address, "UInt", nState, "Str", &state, "UInt", size, "UInt")
+ size := VarSetCapacity(state, size * 2, 0)
+ size := DllCall(address, "UInt", nState, "Str", state, "UInt", size, "UInt")
@@ -109 +109 @@
- throw Error("GetStateText() failed.", -1, OsError().Message)
+ throw Exception("GetStateText() failed.", -1, A_LastError)
@@ -123 +123 @@
-Callback := CallbackCreate("WinEventProc")
+Callback := RegisterCallback("WinEventProc")
@@ -136 +136 @@
- role := oAcc.accRole(ChildId)
+ role := oAcc.accRole(ChildId + 0)
@@ -145 +145 @@
- state := oAcc.accState(ChildId)
+ state := oAcc.accState(ChildId + 0)
@@ -151 +151 @@
-Acc_Location(oAcc, ChildId := 0, &Position := "") {
+Acc_Location(oAcc, ChildId := 0, ByRef Position := "") {
@@ -153,8 +153,8 @@
- x := Buffer(4, 0)
- y := Buffer(4, 0)
- w := Buffer(4, 0)
- h := Buffer(4, 0)
- xPtr := ComValue(varType, x.Ptr, 1)
- yPtr := ComValue(varType, y.Ptr, 1)
- wPtr := ComValue(varType, w.Ptr, 1)
- hPtr := ComValue(varType, h.Ptr, 1)
+ VarSetCapacity(x, 4, 0)
+ VarSetCapacity(y, 4, 0)
+ VarSetCapacity(w, 4, 0)
+ VarSetCapacity(h, 4, 0)
+ xPtr := ComObj(varType, &x, 1)
+ yPtr := ComObj(varType, &y, 1)
+ wPtr := ComObj(varType, &w, 1)
+ hPtr := ComObj(varType, &h, 1)
@@ -164 +164 @@
- oAcc.accLocation(xPtr, yPtr, wPtr, hPtr, ChildId)
+ oAcc.accLocation(xPtr, yPtr, wPtr, hPtr, ChildId + 0)
@@ -183 +183 @@
- child := oAcc.AccChild(ChildId)
+ child := oAcc.AccChild(ChildId + 0)
@@ -192 +192 @@
- return ComValue(9, query, 1)
+ return ComObj(9, query, 1)
@@ -208 +208 @@
- throw Error("Invalid IAccessible Object", -1, oAcc)
+ throw Exception("Invalid IAccessible Object", -1, oAcc)
@@ -212 +212 @@
- accChildren := Buffer(oAcc.accChildCount * size, 0)
+ VarSetCapacity(accChildren, oAcc.accChildCount * size, 0)
@@ -214 +214 @@
- NTSTATUS := DllCall(address, "Ptr", pAcc, "Int", 0, "Int", oAcc.accChildCount, "Ptr", accChildren, "Int*", &obtained, "UInt")
+ NTSTATUS := DllCall(address, "Ptr", pAcc, "Int", 0, "Int", oAcc.accChildCount, "Ptr", &accChildren, "Int*", obtained, "UInt")
@@ -216 +216 @@
- throw Error("AccessibleChildren() failed.", -1, OsError().Message)
+ throw Exception("AccessibleChildren() failed.", -1, A_LastError)
@@ -219 +219 @@
- loop (obtained) {
+ loop % obtained {
@@ -271 +271 @@
- throw Error("Command not implemented", -1, Command)
+ throw Exception("Command not implemented", -1, Command)
@@ -281 +281 @@
- throw Error("Cannot access an IAccessible Object", -1, oAcc)
+ throw Exception("Cannot access an IAccessible Object", -1, oAcc)
@@ -285 +285 @@
- RegExMatch(item, "S)(?<Role>\D+)(?<Index>\d*)", &match)
+ RegExMatch(item, "OS)(?<Role>\D+)(?<Index>\d*)", match)
@@ -292 +292 @@
- if (children.Has(item)) {
+ if (children.HasKey(item)) {
@@ -299 +299 @@
- throw Error("Cannot access ChildPath Item", -1, extra)
+ throw Exception("Cannot access ChildPath Item", -1, extra)
@@ -311,2 +311,2 @@
- case "ChildCount", "Focus", "Selection": out := oAcc.acc%Command%
- default: out := oAcc.acc%Command%(ChildId)
+ case "ChildCount", "Focus", "Selection": out := oAcc["acc" Command]
+ default: out := oAcc["acc" Command](ChildId + 0)
@Gewerd-Strauss
Copy link

Gewerd-Strauss commented Nov 13, 2021

just a quick heads-up that the link in this string

following this guidelines

is not at all pointing to your reddit post "Autohotkey coding style/guidelines"-post that a hover-over suggests. It's pointing to an imgur-gif, but I am not sure if that is intended.

@anonymous1184
Copy link
Author

I know, haven't had the chance to write them. That''s why the link is in strike-through text and the actual link is the John Travolta meme from Pulp Fiction (cross over from A New Hope).

But basically are just the Linux kernel coding style with the Microsoft naming conventions as AHK is more akin to C# rather than plain C and of course is Windows-based rather than *NIX-based. Also a big difference is Allman over K&R because AHK can't handle consistently K&R (damn you specialized loops).

Hopefully one of this days I have the time to write and explain the why on each decision, as I like to think they are not based solely on preference but rather on experience. For example, I really dislike Allman but in order to achieve consistency I have to use it.

@Gewerd-Strauss
Copy link

Heh, the neverending quest for the best Identation style. I learned Allman-Style implicitly when starting out with coding in MatLab, because that's entirely formatted in Allman. Never liked K&R or 1TB, but to each their own. First exposure it was for me :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment