Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

Discuss the future of the AutoHotkey language
User avatar
jeeswg
Posts: 5939
Joined: 19 Dec 2016, 01:58
Location: UK

Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Apr 2017, 10:42

I've attempted two-way compatible conversions. They're working on AHK v1 but AccViewer and iWB2 Learner are having problems saying 'No object to invoke' on AHK v2, although the GUI windows are displaying.

Since AccViewer and iWB2 Learner need the Gui command, I suggest to test them on AutoHotkey_2.0-a077-c2bb552.

Index of /download/2.0
https://autohotkey.com/download/2.0/

Intended filenames:
Acc (AHK1+2).ahk [a finished version might be renamed to Acc.ahk]
AccViewer (AHK1+2).ahk
Anchor (AHK1+2).ahk [a finished version might be renamed to Anchor.ahk]
iWB2 Learner (AHK1+2).ahk

==================================================

Original versions:

[installation instructions]
Acc library (MSAA) and AccViewer download links - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=26201

[Acc.ahk]
Autohotkey-scripts-.ahk/Acc.ahk at master · Drugoy/Autohotkey-scripts-.ahk · GitHub
https://github.com/Drugoy/Autohotkey-sc ... es/Acc.ahk

[AccViewer.ahk]
Autohotkey-scripts-.ahk/AccViewer.ahk at master · Drugoy/Autohotkey-scripts-.ahk · GitHub
https://github.com/Drugoy/Autohotkey-sc ... Viewer.ahk

[Anchor.ahk]
AutoHotkey-Scripts/Anchor.ahk at master · polyethene/AutoHotkey-Scripts · GitHub
https://github.com/polyethene/AutoHotke ... Anchor.ahk

[iWB2 Learner UPDATED.ahk]
iWB2.Learner.UPDATED.zip
https://github.com/ahkscript/awesome-Au ... PDATED.zip

==================================================

One query re. Acc.ahk, which is preferable:
Acc_ObjectFromWindow(hWnd, idObject = 0) ;OBJID_WINDOW := 0
Acc_ObjectFromWindow(hWnd, idObject = -4) ;OBJID_CLIENT := -4
As I have seen both versions in recent versions of Acc.ahk.

Does it affect the operation of the script?

I normally see in AccViewer's treeview hierarchies, 'window' then lower down, 'client'.

Please share any arguments for why it should be either 'window' or 'client'.
Last edited by jeeswg on 15 Apr 2017, 13:32, edited 13 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 5939
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Apr 2017, 10:42

Code: Select all

;[updated: 2017-04-15]
;updated by jeeswg to make it AHK v1/v2 two-way compatible

; http://www.autohotkey.com/board/topic/77303-acc-library-ahk-l-updated-09272012/
; https://dl.dropbox.com/u/47573473/Web%20Server/AHK_L/Acc.ahk
;------------------------------------------------------------------------------
; Acc.ahk Standard Library
; by Sean
; Updated by jethrow:
; 	Modified ComObjEnwrap params from (9,pacc) --> (9,pacc,1)
; 	Changed ComObjUnwrap to ComObjValue in order to avoid AddRef (thanks fincs)
; 	Added Acc_GetRoleText & Acc_GetStateText
; 	Added additional functions - commented below
; 	Removed original Acc_Children function
; last updated 2/25/2010
;------------------------------------------------------------------------------

Acc_Init()
{
	Static	h
	If Not	h
		h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	{
		_idChild_:=NumGet(varChild,8,"UInt")
		ObjAddRef(pacc)
		Return	ComObject(9,pacc,1)
	}
}

Acc_ObjectFromPoint(ByRef _idChild_ := "", x := "", y := "")
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	{
		_idChild_:=NumGet(varChild,8,"UInt")
		ObjAddRef(pacc)
		Return	ComObject(9,pacc,1)
	}
}

Acc_ObjectFromWindow(hWnd, idObject := -4)
{
	Acc_Init()
	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
	{
		ObjAddRef(pacc)
		Return	ComObject(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_SetWinEventHook(eventMin, eventMax, pCallback)
{
	Return	DllCall("SetWinEventHook", "Uint", eventMin, "Uint", eventMax, "Uint", 0, "Ptr", pCallback, "Uint", 0, "Uint", 0, "Uint", 0)
}

Acc_UnhookWinEvent(hHook)
{
	Return	DllCall("UnhookWinEvent", "Ptr", hHook)
}
/*	Win Events:

	pCallback := RegisterCallback("WinEventProc")
	WinEventProc(hHook, event, hWnd, idObject, idChild, eventThread, eventTime)
	{
		Critical
		Acc := Acc_ObjectFromEvent(_idChild_, hWnd, idObject, idChild)
		; Code Here:

	}
*/

; Written by jethrow
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_Location(Acc, ChildId:=0, byref Position:="") { ; adapted from Sean's code
	try Acc.accLocation(ComObject(0x4003,&x:=0), ComObject(0x4003,&y:=0), ComObject(0x4003,&w:=0), ComObject(0x4003,&h:=0), ChildId)
	catch
		return
	Position := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
	return	{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) { ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
	try return ComObject(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p:="") {
	static setting:=0
	return p=""?setting:setting:=p
}
Acc_Children(Acc) {
	if ComObjType(Acc,"Name") != "IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), 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.Push(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):""
			return Children.MaxIndex()?Children:""
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_ChildrenByRole(Acc, Role) {
	if ComObjType(Acc,"Name")!="IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop, % cChildren {
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
				if NumGet(varChildren,i-8)=9
					AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Push(AccChild):""
				else
					Acc_Role(Acc, child)=Role?Children.Push(child):""
			}
			ErrorLevel:=0
			return Children.MaxIndex()?Children:""
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_Get(Cmd, ChildPath:="", ChildID:=0, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="") {
	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		ChildPath := StrReplace(ChildPath, "_", A_Space)
		AccError:=Acc_Error(), Acc_Error(true)
		Loop, Parse, ChildPath, ., % A_Space
			try {
				if RegExMatch(A_LoopField, "^\d*$")
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return
			}
		Acc_Error(AccError)
		Cmd := StrReplace(Cmd, A_Space, "")
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:""
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObject(0x4003,&x:=0), ComObject(0x4003,&y:=0), ComObject(0x4003,&w:=0), ComObject(0x4003,&h:=0), ChildId)
			  , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if RegExMatch(Cmd, "^(Role|State)$")
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if RegExMatch(Cmd, "^(ChildCount|Selection|Focus)$")
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := Chr(34) Cmd Chr(34) " Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		ErrorLevel:=0
		return ret_val
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}

Code: Select all

#Include Acc (AHK1+2).ahk
#Include Anchor (AHK1+2).ahk
;[updated: 2017-04-15]
;updated by jeeswg to make it AHK v1/v2 two-way compatible

{
	WM_ACTIVATE := 0x06
	WM_KILLFOCUS := 0x08
	WM_LBUTTONDOWN := 0x201
	WM_LBUTTONUP := 0x202
	global	Border := new Outline, Stored:={}, Acc, ChildId, TVobj, Win:={}
}
{
	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, Add, Button, x160 y8 w105 h20 vShowStructure gShowStructure, Show Acc Structure
	{
		Gui, Add, Text, x10 y3 w25 h26 Border gCrossHair ReadOnly HWNDh8 Border
		CColor(h8, "White")
		Gui, Add, Text, x10 y3 w25 h4 HWNDh9 Border
		CColor(h9, "0046D5")
		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 w275 h130 vWinCtrl, Window/Control Info
		Gui, Font
		Gui, Add, Text, x7 y49 w42 h20 Right, WinTitle:
		Gui, Add, Edit, x51 y47 w221 h20 vWinTitle ,
		Gui, Add, Text, x7 y71 w42 h20 Right, Text:
		Gui, Add, Edit, x51 y69 w221 h20 vText ,
		Gui, Add, Text, x7 y93 w42 h20 Right, Hwnd:
		Gui, Add, Edit, x51 y91 w72 h20 vHwnd,
		Gui, Add, Text, x126 y93 w51 h20 vClassText Right, Class(NN):
		Gui, Add, Edit, x178 y91 w94 h20 vClass,
		Gui, Add, Text, x7 y115 w42 h20 Right, Position:
		Gui, Add, Edit, x51 y113 w72 h20 vPosition,
		Gui, Add, Text, x126 y115 w51 h20 Right, Process:
		Gui, Add, Edit, x178 y113 w94 h20 vProcess,
		Gui, Add, Text, x7 y137 w42 h20 Right, Size:
		Gui, Add, Edit, x51 y135 w72 h20 vSize,
		Gui, Add, Text, x126 y137 w51 h20 Right, Proc ID:
		Gui, Add, Edit, x178 y135 w94 h20 vProcID,
	}
	{
		Gui, Font, bold
		Gui, Add, GroupBox, x2 y165 w275 h240 vAcc, Accessible Info
		Gui, Font
		Gui, Add, Text, x7 y182 w42 h20 Right, Name:
		Gui, Add, Edit, x51 y180 w221 h20 vAccName ,
		Gui, Add, Text, x7 y204 w42 h20 Right, Value:
		Gui, Add, Edit, x51 y202 w221 h20 vAccValue ,
		Gui, Add, Text, x7 y226 w42 h20 Right, Role:
		Gui, Add, Edit, x51 y224 w72 h20 vAccRole,
		Gui, Add, Text, x126 y226 w55 h20 Right, ChildCount:
		Gui, Add, Edit, x182 y224 w90 h20 vAccChildCount,
		Gui, Add, Text, x7 y248 w42 h20 Right, State:
		Gui, Add, Edit, x51 y246 w72 h20 vAccState,
		Gui, Add, Text, x126 y248 w55 h20 Right, Selection:
		Gui, Add, Edit, x182 y246 w90 h20 vAccSelection,
		Gui, Add, Text, x7 y270 w42 h20 Right, Action:
		Gui, Add, Edit, x51 y268 w72 h20 vAccAction,
		Gui, Add, Text, x126 y270 w55 h20 Right, Focus:
		Gui, Add, Edit, x182 y268 w90 h20 vAccFocus,
		{
			Gui, Add, Text, x7 y292 w55 h20 Right vAccLocationText, Location:
			Gui, Add, Edit, x65 y290 w207 h20 vAccLocation ,
			Gui, Add, Text, x7 y314 w55 h20 Right, Description:
			Gui, Add, Edit, x65 y312 w207 h20 vAccDescription ,
			Gui, Add, Text, x7 y336 w55 h20 Right, Keyboard:
			Gui, Add, Edit, x65 y334 w207 h20 vAccKeyboard ,
			Gui, Add, Text, x7 y358 w55 h20 Right, Help:
			Gui, Add, Edit, x65 y356 w207 h20 vAccHelp ,
			Gui, Add, Text, x7 y380 w55 h20 Right, HelpTopic:
			Gui, Add, Edit, x65 y378 w207 h20 vAccHelpTopic ,
		}
	}
	{
		Gui, Add, StatusBar, gShowMainGui
		SB_SetParts(70,150)
		SB_SetText("`tshow more", 3)
	}
	{
		Gui Acc: New, ToolWindow AlwaysOnTop Resize LabelAcc HWNDhwnd, Acc Structure
		Win.Acc := hwnd
		Gui Acc: Add, TreeView, w200 h300 vTView gTreeView R17 AltSubmit
		Gui Acc: Show, Hide
	}
	GoSub, ShowMainGui
	AHKFC_WinRedraw("ahk_id" Win.Main)
	return
}
ShowMainGui:
{
	if RegExMatch(A_EventInfo, "^(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 RegExMatch(SB_Text, "Id: \K\d+", SB_Text)
			{
				ToolTip % "clipboard = " clipboard:=SB_Text
				SetTimer, RemoveToolTip, -2000
			}
	}
	else {
		Gui Main: Default
		if ShowingLess {
			SB_SetText("`tshow less", 3)
			GuiControl, Move, Acc, x2 y165 w275 h240
			GuiControl, Show, AccDescription
			GuiControl, Show, AccLocation
			GuiControl, Show, AccLocationText
			{
				height := 319
				while (height<428) {
					height += 10
					Gui, Show, % "w280 h" height
					Sleep, 20
				}
			}
			Gui, Show, w280 h428
			ShowingLess := false
		}
		else {
			if (ShowingLess != "") {
				height := 428
				while (height>319) {
					height -= 10
					Gui, Show, % "w280 h" height
					Sleep, 20
				}
			}
			Gui, Show, w280 h319
			GuiControl, Hide, AccDescription
			GuiControl, Hide, AccLocation
			GuiControl, Hide, AccLocationText
			GuiControl, Move, Acc, x2 y165 w275 h130
			SB_SetText("`tshow more", 3)
			ShowingLess := true
		}
		AHKFC_WinRedraw("ahk_id" Win.Main)
	}
return
}

#if Not Lbutton_Pressed
^/::
{
	AHKBC_SetBatchLines(-1)
	Lbutton_Pressed := true
	Stored.Chwnd := ""
	Gui Acc: Default
	GuiControl, Disable, TView
	while Lbutton_Pressed
	GetAccInfo()
	AHKBC_SetBatchLines("10ms")
	return
}
#if Lbutton_Pressed
^/::
{
	Lbutton_Pressed := false
	Gui Main: Default
	Sleep, -1
	GuiControl, , WinCtrl, % (DllCall("GetParent", Uint,Acc_WindowFromObject(Acc))? "Control":"Window") " Info"
	if Not DllCall("IsWindowVisible", "Ptr",Win.Acc) {
		Border.Hide()
		SB_SetText("Path: " GetAccPath(Acc).path, 2)
	}
	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", Uint,Acc_WindowFromObject(Acc))? "Control":"Window") " Info"
	if Not DllCall("IsWindowVisible", "Ptr",Win.Acc) {
		Border.Hide()
		SB_SetText("Path: " GetAccPath(Acc).path, 2)
	}
	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") {
		AHKBC_SetBatchLines(-1)
		Hotkey, ~LButton Up, On
		{
			GuiControl, Hide, HBar
			GuiControl, Hide, VBar
			CrossHair(CH:=false)
		}
		Lbutton_Pressed := True
		Stored.Chwnd := ""
		Gui Acc: Default
		GuiControl, Disable, TView
		while Lbutton_Pressed
			GetAccInfo()
		AHKBC_SetBatchLines("10ms")
	}
	return
}
OnExitCleanup()
{
	CrossHair(true)
	ExitApp
}
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
	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")
	TVobj := {(parent): {is_obj:true, obj:AccObj, need_children:false, childid:0, Children:[]}}
	Loop Parse, Child_Path, .
	{
		if !RegExMatch(A_LoopField, "^\d*$")
			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:
{
	Anchor(TView, "wh")
	return
}
TreeView:
{
	Gui, Submit, NoHide
	if (A_GuiEvent = "S")
		UpdateAccInfo(TVobj[A_EventInfo].obj, TVobj[A_EventInfo].childid, TVobj[A_EventInfo].obj_path)
	if (A_GuiEvent = "+") {
		GuiControl, -Redraw, TView
		TV_Expanded(A_EventInfo)
		GuiControl, +Redraw, TView
	}
	return
}
RemoveToolTip:
{
	ToolTip
	return
}
GetAccInfo() {
	global Whwnd
	static ShowButtonEnabled
	MouseGetPos, , , Whwnd
	if (Whwnd!=Win.Main and Whwnd!=Win.Acc) {
		{
			GuiControlGet, SectionLabel, , WinCtrl
			if (SectionLabel != "Window/Control Info")
				GuiControl, , WinCtrl, Window/Control Info
		}
		Acc := Acc_ObjectFromPoint(ChildId)
		Location := GetAccLocation(Acc, ChildId)
		if (Stored.Location != Location) {
			Hwnd := Acc_WindowFromObject(Acc)
			if (Stored.Hwnd != Hwnd) {
				if DllCall("GetParent", Uint,hwnd) {
					WinGetTitle, title, % "ahk_id" parent
					ControlGetText, text, , % "ahk_id" Hwnd
					class := GetClassNN(Hwnd,Whwnd)
					ControlGetPos, posX, posY, posW, posH, , % "ahk_id" Hwnd
					proc := AHKFC_WinGetProcessName("ahk_id" parent)
					procid := AHKFC_WinGetPID("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
					proc := AHKFC_WinGetProcessName("ahk_id" Hwnd)
					procid := AHKFC_WinGetPID("ahk_id" Hwnd)
				}
				{
					GuiControl, , WinTitle, % title
					GuiControl, , Text, % text
					GuiControl, , Hwnd, % "0x" Format("{:X}", Hwnd)
					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)
		}
	}
}
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_GetRoleText(Acc.accRole(ChildId))
		GuiControl, , AccState, % Acc_GetStateText(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)
	}
	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
	ClassNN := _GetClassNN.ClassNN, _GetClassNN:=""
	return, ClassNN
}
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)), 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), Parent, "bold")
			TVobj[added] := {is_obj:true, need_children:true, obj:child, childid:0, Children:[], Obj_Path:Trim(Parent_Obj_Path "," A_Index, ",")}
		}
		TVobj[Parent].Children.Push(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(ComObject(0x4003,&x:=0), ComObject(0x4003,&y:=0), ComObject(0x4003,&w:=0), ComObject(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","UInt",NULL,"Int",id,"UInt")
}
__delete() {
DllCall("DestroyCursor","Uint",this.ptr)
}
}
class Outline {
	__New(color:="red") {
		Gui, +HWNDdefault
		Loop, 4 {
			Gui, New, -Caption +ToolWindow HWNDhwnd
			Gui, Color, % color
			this[A_Index] := hwnd
		}
		this.visible := false
		this.color := color
		this.top := this[1]
		this.right := this[2]
		this.bottom := this[3]
		this.left := this[4]
		Gui, % default ": Default"
	}
	Show(x1, y1, x2, y2, sides:="TRBL") {
		Gui, +HWNDdefault
		if InStr( sides, "T" )
			Gui, % this[1] ":Show", % "NA X" x1-2 " Y" y1-2 " W" x2-x1+4 " H" 2
		Else, Gui, % this[1] ":Hide"
		if InStr( sides, "R" )
			Gui, % this[2] ":Show", % "NA X" x2 " Y" y1 " W" 2 " H" y2-y1
		Else, Gui, % this[2] ":Hide"
		if InStr( sides, "B" )
			Gui, % this[3] ":Show", % "NA X" x1-2 " Y" y2 " W" x2-x1+4 " H" 2
		Else, Gui, % this[3] ":Hide"
		if InStr( sides, "L" )
			Gui, % this[4] ":Show", % "NA X" x1-2 " Y" y1 " W" 2 " H" y2-y1
		Else, Gui, % this[3] ":Hide"
		self.visible := true
		Gui, % default ": Default"
	}
	Hide() {
		Gui, +HWNDdefault
		Loop, 4
			Gui, % this[A_Index] ": Hide"
		self.visible := false
		Gui, % default ": Default"
	}
	SetAbove(hwnd) {
		ABOVE := DllCall("GetWindow", "uint", hwnd, "uint", 3)
		Loop, 4
			DllCall(	"SetWindowPos", "uint", this[A_Index], "uint", ABOVE
					,	"int", 0, "int", 0, "int", 0, "int", 0
					,	"uint", 0x1|0x2|0x10	)
	}
	Transparent(param) {
		Loop, 4
			AHKFC_WinSetTransparent(param=1? 0:255, "ahk_id" this[A_Index])
		self.visible := !param
	}
	Color(color) {
		Gui, +HWNDdefault
		Loop, 4
			Gui, % this[A_Index] ": Color" , % color
		self.color := color
		Gui, % default ": Default"
	}
	Destroy() {
		Loop, 4
			Gui, % this[A_Index] ": Destroy"
	}
}
CColor(Hwnd, Background:="", Foreground:="") {
	return CColor_(Background, Foreground, "", Hwnd+0)
}
CColor_(Wp, Lp, Msg, Hwnd) {
	static
	static WM_CTLCOLOREDIT:=0x0133, WM_CTLCOLORLISTBOX:=0x134, WM_CTLCOLORSTATIC:=0x0138
	,LVM_SETBKCOLOR:=0x1001, LVM_SETTEXTCOLOR:=0x1024, LVM_SETTEXTBKCOLOR:=0x1026, TVM_SETTEXTCOLOR:=0x111E, TVM_SETBKCOLOR:=0x111D
	,BS_CHECKBOX:=2, BS_RADIOBUTTON:=8, ES_READONLY:=0x800
	,CLR_NONE:=-1, CSILVER:=0xC0C0C0, CGRAY:=0x808080, CWHITE:=0xFFFFFF, CMAROON:=0x80, CRED:=0x0FF, CPURPLE:=0x800080, CFUCHSIA:=0xFF00FF,CGREEN:=0x8000, CLIME:=0xFF00, COLIVE:=0x8080, CYELLOW:=0xFFFF, CNAVY:=0x800000, CBLUE:=0xFF0000, CTEAL:=0x808000, CAQUA:=0xFFFF00
	,CLASSES := "Button|ComboBox|Edit|ListBox|Static|RICHEDIT50W|SysListView32|SysTreeView32"
	If (Msg = "") {
		if !adrSetTextColor
		adrSetTextColor   := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "Gdi32.dll"), "astr", "SetTextColor")
		,adrSetBkColor   := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "Gdi32.dll"), "astr", "SetBkColor")
		,adrSetBkMode   := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "Gdi32.dll"), "astr", "SetBkMode")
		BG := !Wp ? "" : C%Wp% != "" ? C%Wp% : "0x" SubStr(WP,5,2) SubStr(WP,3,2) SubStr(WP,1,2)
		FG := !Lp ? "" : C%Lp% != "" ? C%Lp% : "0x" SubStr(LP,5,2) SubStr(LP,3,2) SubStr(LP,1,2)
		WinGetClass, class, % "ahk_id" Hwnd
		If !RegExMatch(class, "^(" CLASSES ")$")
			return A_ThisFunc "> Unsupported control class: " class
		ControlGet, style, Style, , , % "ahk_id" Hwnd
		if (class = "Edit") && (Style & ES_READONLY)
			class := "Static"
		if (class = "Button")
			if (style & BS_RADIOBUTTON) || (style & BS_CHECKBOX)
				class := "Static"
			else
				return A_ThisFunc "> Unsupported control class: " class
		if (class = "ComboBox") {
			VarSetCapacity(CBBINFO, 52, 0), NumPut(52, CBBINFO), DllCall("GetComboBoxInfo", "UInt", Hwnd, "UInt", &CBBINFO)
			hwnd := NumGet(CBBINFO, 48)
			_%hwnd%BG := BG, _%hwnd%FG := FG, _%hwnd% := BG ? DllCall("CreateSolidBrush", "UInt", BG) : -1
			(CTLCOLORLISTBOX = "") ? (CTLCOLORLISTBOX := OnMessage(WM_CTLCOLORLISTBOX, A_ThisFunc)) : ""
			If NumGet(CBBINFO,44)
				Hwnd :=  Numget(CBBINFO,44), class := "Edit"
		}
		if RegExMatch(class, "^(SysListView32|SysTreeView32)$")
		{
			m := class="SysListView32" ? "LVM" : "TVM"
			SendMessage, % %m%_SETBKCOLOR, ,% BG, ,% "ahk_id" Hwnd
			SendMessage, % %m%_SETTEXTCOLOR, ,% FG, ,% "ahk_id" Hwnd
			SendMessage, % %m%_SETTEXTBKCOLOR, ,% CLR_NONE, ,% "ahk_id" Hwnd
			return
		}
		if (class = "RICHEDIT50W")
		{
			f := "RichEdit_SetBgColor", %f%(Hwnd, -BG)
			return f
		}
		if (!CTLCOLOR%Class%)
			CTLCOLOR%Class% := OnMessage(WM_CTLCOLOR%Class%, A_ThisFunc)
		_%Hwnd%BG := BG,  _%Hwnd%FG := FG
		return _%Hwnd% := BG ? DllCall("CreateSolidBrush", "UInt", BG) : CLR_NONE
	}
	critical
	Hwnd := Lp + 0, hDC := Wp + 0
	If (_%Hwnd%) {
		DllCall(adrSetBkMode, "uint", hDC, "int", 1)
		if (_%Hwnd%FG)
			DllCall(adrSetTextColor, "UInt", hDC, "UInt", _%Hwnd%FG)
		if (_%Hwnd%BG)
			DllCall(adrSetBkColor, "UInt", hDC, "UInt", _%Hwnd%BG)
		return (_%Hwnd%)
	}
}
CrossHair(OnOff:=1) {
	static AndMask, XorMask, _s, h_cursor, IDC_CROSS := 32515, _c, _b, _h
	if (OnOff = "Init" or OnOff = "I" or _s = "") {
		_s := "_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"
		_c := StrSplit(system_cursors, ","), _b := [], _h := []
		Loop, % _c.MaxIndex()
			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")
	}
	_s := (OnOff = 0 || OnOff = "Off" || _s = "_h" && (OnOff < 0 || OnOff = "Toggle" || OnOff = "T")) ? "_b" : "_h"
	Loop, % _c.MaxIndex()
		h_cursor := DllCall( "CopyImage", "uint",%_s%[A_Index], "uint",2, "int",0, "int",0, "uint",0 )
		, DllCall( "SetSystemCursor", "uint",h_cursor, "uint",_c[A_Index] )
}

;==================================================

;forwards-compatibility functions
AHKFC_WinGetPID(WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	local OutputVar
	static WinGetPID := Func("WinGetPID")
	if WinGetPID
		return %WinGetPID%(WinTitle, WinText, ExcludeTitle, ExcludeText)
	WinGet, OutputVar, PID, % WinTitle, % WinText, % ExcludeTitle, % ExcludeText
	return OutputVar
}
AHKFC_WinGetProcessName(WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	local OutputVar
	static WinGetProcessName := Func("WinGetProcessName")
	if WinGetProcessName
		return %WinGetProcessName%(WinTitle, WinText, ExcludeTitle, ExcludeText)
	WinGet, OutputVar, ProcessName, % WinTitle, % WinText, % ExcludeTitle, % ExcludeText
	return OutputVar
}
WinGet(Cmd:="", WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	local OutputVar
	return OutputVar
}

AHKFC_WinRedraw(WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	static WinRedraw := Func("WinRedraw")
	if WinRedraw
		%WinRedraw%(WinTitle, WinText, ExcludeTitle, ExcludeText)
	else
		WinSet, Redraw,, % WinTitle, % WinText, % ExcludeTitle, % ExcludeText
}
AHKFC_WinSetTransparent(N, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	local Hwnd
	static WinSetTransparent := Func("WinSetTransparent")
	Hwnd := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText)
	if (!Hwnd)
		return 0
	if WinSetTransparent
		%WinSetTransparent%(N, WinTitle, WinText, ExcludeTitle, ExcludeText)
	else
		WinSet, Transparent, % N, % "ahk_id" Hwnd
	return 1
}
WinSet(Param1:="", Param2:="", WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
}

;==================================================

;backwards compatibility functions
AHKBC_SetBatchLines(Param)
{
	SetBatchLines, % Param
}
SetBatchLines(Param)
{
}

;==================================================

Code: Select all

;[updated: 2017-04-15]
;updated by jeeswg to make it AHK v1/v2 two-way compatible

/*
	Function: Anchor
		Defines how controls should be automatically positioned relative to the new dimensions of a window when resized.

	Parameters:
		cl - a control HWND, associated variable name or ClassNN to operate on
		a - (optional) one or more of the anchors: 'x', 'y', 'w' (width) and 'h' (height),
			optionally followed by a relative factor, e.g. "x h0.5"
		r - (optional) true to redraw controls, recommended for GroupBox and Button types

	Examples:
> "xy" ; bounds a control to the bottom-left edge of the window
> "w0.5" ; any change in the width of the window will resize the width of the control on a 2:1 ratio
> "h" ; similar to above but directrly proportional to height

	Remarks:
		To assume the current window size for the new bounds of a control (i.e. resetting) simply omit the second and third parameters.
		However if the control had been created with DllCall() and has its own parent window,
			the container AutoHotkey created GUI must be made default with the +LastFound option prior to the call.
		For a complete example see anchor-example.ahk.

	License:
		- Version 4.60a <http://www.autohotkey.net/~polyethene/#anchor>
		- Dedicated to the public domain (CC0 1.0) <http://creativecommons.org/publicdomain/zero/1.0/>
*/
Anchor(i, a := "", r := false) {
	static c, cs := 12, cx := 255, cl := 0, g, gs := 8, gl := 0, gpi, gw, gh, z := 0, k := 0xffff
	If (z = 0)
		VarSetCapacity(g, gs * 99, 0), VarSetCapacity(c, cs * cx, 0), z := true
	If (!WinExist("ahk_id" . i)) {
		GuiControlGet, t, Hwnd, % i
		If (ErrorLevel = 0)
			i := t
		Else ControlGet, i, Hwnd, , % i
	}
	VarSetCapacity(gi, 68, 0), DllCall("GetWindowInfo", "UInt", gp := DllCall("GetParent", "UInt", i), "UInt", &gi)
		, giw := NumGet(gi, 28, "Int") - NumGet(gi, 20, "Int"), gih := NumGet(gi, 32, "Int") - NumGet(gi, 24, "Int")
	If (gp != gpi) {
		gpi := gp
		Loop, % gl
			If (NumGet(g, cb := gs * (A_Index - 1)) == gp) {
				gw := NumGet(g, cb + 4, "Short"), gh := NumGet(g, cb + 6, "Short"), gf := 1
				Break
			}
		If (!gf)
			NumPut(gp, g, gl), NumPut(gw := giw, g, gl + 4, "Short"), NumPut(gh := gih, g, gl + 6, "Short"), gl += gs
	}
	ControlGetPos, dx, dy, dw, dh, , % "ahk_id" i
	Loop, % cl
		If (NumGet(c, cb := cs * (A_Index - 1)) == i) {
			If (a = "")
			{
				cf := 1
				Break
			}
			giw -= gw, gih -= gh, as := 1, dx := NumGet(c, cb + 4, "Short"), dy := NumGet(c, cb + 6, "Short")
				, cw := dw, dw := NumGet(c, cb + 8, "Short"), ch := dh, dh := NumGet(c, cb + 10, "Short")
			Loop, Parse, a, % "xywh"
				If (A_Index > 1)
					av := SubStr(a, as, 1), as += 1 + StrLen(A_LoopField)
						, d%av% += (InStr("yh", av) ? gih : giw) * (A_LoopField + 0 ? A_LoopField : 1)
			DllCall("SetWindowPos", "UInt", i, "Int", 0, "Int", dx, "Int", dy
				, "Int", InStr(a, "w") ? dw : cw, "Int", InStr(a, "h") ? dh : ch, "Int", 4)
			If (r != 0)
				DllCall("RedrawWindow", "UInt", i, "UInt", 0, "UInt", 0, "UInt", 0x0101) ; RDW_UPDATENOW | RDW_INVALIDATE
			Return
		}
	If (cf != 1)
		cb := cl, cl += cs
	bx := NumGet(gi, 48), by := NumGet(gi, 16, "Int") - NumGet(gi, 8, "Int") - gih - NumGet(gi, 52)
	If (cf = 1)
		dw -= giw - gw, dh -= gih - gh
	NumPut(i, c, cb), NumPut(dx - bx, c, cb + 4, "Short"), NumPut(dy - by, c, cb + 6, "Short")
		, NumPut(dw, c, cb + 8, "Short"), NumPut(dh, c, cb + 10, "Short")
	Return, true
}

Code: Select all

#Include Acc (AHK1+2).ahk
#Include Anchor (AHK1+2).ahk
;[updated: 2017-04-15]
;updated by jeeswg to make it AHK v1/v2 two-way compatible

; Dragable Cursor is now Drawn In, rather than using external images
; Text Insert Point will not stay on edit control when clicked (unless highlighted)
; Updated to use New Realease of Sean's ComUtils

; To Do: Allow Text/HTML Pop-out for Viewing
; To Do: Make ChildNodes a complete tree
; Considering: Change from Click-to-Copy to Right-Click>>Copy Data

{ ; CONSTANTS/PARAMETERS
	WM_ACTIVATE := 0x06
	WM_KILLFOCUS := 0x08
	WM_LBUTTONDOWN := 0x201
	WM_LBUTTONUP := 0x202
	Stored := object(	"AppName",		"iWB2 Learner"
					,	"TextLabel",	"InnerText"		) ; hold stored/global values throughout script
}
{ ; DIRECTIVES
	;#NoEnv
	#NoTrayIcon
	DetectHiddenWindows,on
	SetTitleMatchMode,slow
	SetTitleMatchMode,2
}
{ ; AUTOEXEC
	ComObjError(false)
	OnMessage(WM_LBUTTONDOWN, "HandleMessage")
	OnExit("OnExitCleanup")

	; Main GUI
	Menu, Main, Add, Show Parent Structure, ParentStructure
	Gui, Menu, Main
	Gui, Add, Edit, x61 y5 w255 h20 hwndTitleHwnd vTitle HWNDh1,
	Gui, Add, Edit, x61 y30 w255 h20 vURLL HWNDh2,
	Gui, Add, Edit, x36 y55 w50 h20 vEleIndex HWNDh3,
	Gui, Add, Edit, x120 y55 w90 h20 vEleName HWNDh4,
	Gui, Add, Edit, x226 y55 w90 h20 vEleIDs HWNDh5,
	Gui, Add, ListView, x6 y82 w310 h60 -LV0x10 AltSubmit vVarListView gSubListView NoSortHdr, % "Frame.#|index|name|id|"
	LV_ModifyCol(1, 65), LV_ModifyCol(2,49), LV_ModifyCol(3,87), LV_ModifyCol(4,87), LV_ModifyCol(2,"Center")
	Gui, Add, Edit, x11 y160 w302 h40 vhtml_text HWNDh6,
	Gui, Add, Edit, x10 y217 w302 h40 vhtml_value HWNDh7,
	Gui, Add, Text, x35 y7 w25 h20 +Center, Title
	Gui, Add, Text, x37 y33 w23 h20 +Center, Url
	Gui, Add, Text, x1 y56 w34 h20 +Center, Index
	Gui, Add, Text, x89 y57 w30 h21 +Center, Name
	Gui, Add, Text, x212 y58 w13 h20 +Center, ID
	Gui, Add, GroupBox, x6 y145 w310 h119 vText, InnerText
	Gui, Add, GroupBox, x6 y201 w310 h63 , OuterHTML

	; CrossHair Control
	Gui, Add, Text, x5 y3 w25 h26 Border gCrossHair ReadOnly HWNDh8 Border
	CColor(h8, "White")
	Gui, Add, Text, x5 y3 w25 h4 HWNDh9 Border
	CColor(h9, "0046D5")
	Gui, Add, Text, x8 y17 w19 h1 Border vHBar
	Gui, Add, Text, x17 y8 w1 h19 Border vVBar
	Gui, Font, S6
	Gui, Add, Text, x1 y32 w35 h26 +Center, DRAG CURSOR

	Gui, +AlwaysOnTop +Delimiter`n
	Gui, Show, Center  h270 w322, % Stored.AppName
	Gui, +LastFoundExist
	AHKFC_WinRedraw("ahk_id" GuiWinHWND:=WinExist())
	ControlFocus, Static7, % "ahk_id" GuiWinHWND

	; Parental Structure GUI
	Gui 2: +ToolWindow +AlwaysOnTop +Resize
	Gui 2: Add, TreeView, vTView R17
	Gui 2: Show, Hide, Parent Structure
	WinGetPos, , , _2GuiW, _2GuiH, % "ahk_id"
	. Stored.2GUIhwnd := WinExist("Parent Structure ahk_class AutoHotkeyGUI")
	Menu, RClickMenu, Add ; Ensure RClickMenu Exists

	outline := Outline() ; create "Outline" object
	Hotkey, ~LButton Up, Off ; "~LButton Up" Hotkey only active when LButton is pressed
	return
}

#s::
{ ; Speak the Text of the Element
	ComObjCreate("SAPI.SpVoice").Speak(Stored.textOfObj)
	return
}
~Lbutton Up::
{ ; Handle LButton Being Released
	Hotkey, ~LButton Up, Off
	Lbutton_Pressed := False
	if IsObject(Stored.BColor) ; Restore Element Background Color
		Stored.BColor := ""
	else if Not CH { ; Reset CrossHair
        GuiControl, Show, HBar
        GuiControl, Show, VBar
		CrossHair(CH:=true)
	}
	RemoveFocus()
	return
}
HandleMessage( p_w, p_l, p_m, p_hw ) { ; Handle LButton Being Pressed (for "WM_LBUTTONDOWN")
	Gui, Submit, NoHide
	if (A_GuiControl = "VarListView") { ; Get Column Number - if clicked on ListView
		global column_num ; http://www.autohotkey.com/forum/viewtopic.php?t=6414
		VarSetCapacity( htinfo, 20 )
		, DllCall( "RtlFillMemory", "uint", &htinfo, "uint", 1, "uchar", p_l & 0xFF )
		, DllCall( "RtlFillMemory", "uint", &htinfo+1, "uint", 1, "uchar", ( p_l >> 8 ) & 0xFF )
		, DllCall( "RtlFillMemory", "uint", &htinfo+4, "uint", 1, "uchar", ( p_l >> 16 ) & 0xFF )
		, DllCall( "RtlFillMemory", "uint", &htinfo+5, "uint", 1, "uchar", ( p_l >> 24 ) & 0xFF )
		SendMessage, % 0x1000+57, 0, % &htinfo,, % "ahk_id" p_hw
		If ( ErrorLevel = -1 )
			Return
		column_num := ( *( &htinfo+8 ) & 1 ) ? False : 1+*( &htinfo+16 )
	}
	else if (%A_GuiControl% != "") {
			temp := clipboard := %A_GuiControl%
			ToolTip, % "clipboard= " (StrLen(temp) > 40 ? SubStr(temp,1,40) "..." : temp)
			SetTimer, RemoveToolTip, 1000
	}
	else if (A_GuiControl = "TView") { ; if clicked on TreeView (parent structure)
		Acc_ObjectFromPoint(child).accSelect(0x3, child)
		Hotkey, ~LButton Up, On
		global Stored
		if TV_GetParent(TVsel:=TV_GetSelection()) {
			TV_GetText(text, TVsel)
			RegExMatch(text, "\d+", child)
			clicked := Stored.pelt.childNodes[child]
		}
		else {
			clicked := Stored.pelt
			Loop, % TV_GetDiffCount(Stored.TVitem, TVsel)
				clicked := clicked.parentNode
		}
		Stored.BColor := BCobj(clicked, "silver")
	}
	RemoveFocus()
}
IE_HtmlElement() { ; get the parent windows & coord from the element
	static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}", IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}"
	CoordMode, Mouse
	MouseGetPos, xpos, ypos,, hCtl, 3
	WinGetClass, sClass, % "ahk_id" hCtl
	If Not (sClass == "Internet Explorer_Server")
		|| Not pdoc := ComObject(9,ComObjQuery(Acc_ObjectFromWindow(hCtl), IID_IHTMLWindow2, IID_IHTMLWindow2),1).document ; document property will fail if no valie com object
			Return
	global outline, Stored, Frame := {} ; store frames & hold "Frame" Coords & stored values
	pwin := ComObject(9,ComObjQuery(pdoc, IID_IHTMLWindow2, IID_IHTMLWindow2),1)
	iWebBrowser2 := ComObject(9,ComObjQuery(pwin,IID_IWebBrowserApp,IID_IWebBrowserApp),1)

	if pelt := pwin.document.elementFromPoint( xpos-xorg:=pwin.screenLeft, ypos-yorg:=pwin.screenTop ) {
		Stored.LV := object() ; hold frame info for ListView
		while (type:=pelt.tagName)="IFRAME" || type="FRAME" {
			selt .=   A_Index ") **[sourceIndex]=" pelt.sourceindex " **[Name]= " pelt.name " **[ID]= " pelt.id "`n"
			, Stored.LV[A_Index, "C1"] := type "." A_Index
			, Stored.LV[A_Index, "C2"] := pelt.sourceindex
			, Stored.LV[A_Index, "C3"] := pelt.name
			, Stored.LV[A_Index, "C4"] := pelt.id
			, Frame[A_Index] := pelt ; store frames
			, pwin :=	ComObject(9,ComObjQuery(pbrt:=pelt.contentWindow, IID_IHTMLWindow2, IID_IHTMLWindow2),1)
			, pdoc :=	pwin.document
			, Stored.LV[A_Index, "URL"] := pdoc.url
			, pbrt :=	pdoc.elementFromPoint(	xpos-xorg+=pelt.getBoundingClientRect().left
											,	ypos-yorg+=pelt.getBoundingClientRect().top	)
			, pelt :=	pbrt
		}
		pbrt :=   pelt.getBoundingClientRect()
		, l  :=   pbrt.left
		, t  :=   pbrt.top
		, r  :=   pbrt.right
		, b  :=   pbrt.bottom

		if Not outline.visible ; if the element has changed
			|| (Stored.pelt.sourceIndex != pelt.sourceIndex) {
			; (Stored["x1"] <> l+xorg || Stored["y1"] <> t+yorg || Stored["x2"] <> r+xorg || Stored["y2"] <> b+yorg) {
			if selt ; if the element is in a frame, get frame dimensions
				Frect := Frame[Frame.maxIndex()].getBoundingClientRect() ; get the Frame Rectangle
				, Frame.x1 := xorg ; set the frame Coordinates
				, Frame.y1 := yorg
				, Frame.x2 := FRect.right+xorg
				, Frame.y2 := FRect.bottom+yorg
			else,
				Frame.x1:=Frame.y1:=Frame.x2:=Frame.y2:= "NA" ; if there isn't any frames, assign frame coords "NA"

			; Change outline display
			outline.transparent(true)
			, outline.hide()
			, coord := GetCoord(	Stored.x1 := l+xorg
								, 	Stored.y1 := t+yorg
								,	Stored.x2 := r+xorg
								,	Stored.y2 := b+yorg
								,	iWebBrowser2.HWND	)
			, outline.show(coord.x1, coord.y1, coord.x2, coord.y2, coord.sides)
			, outline.setAbove( iWebBrowser2.HWND )
			, outline.transparent( false )
		}

		Sleep, 1 ; make sure Controls Update
		if (Stored.selt != selt) {
			LV_Delete()
			Loop, % Stored.LV.MaxIndex()
				LV_Add(	""	,	Stored.LV[A_Index].C1
							,	Stored.LV[A_Index].C2
							,	Stored.LV[A_Index].C3
							,	Stored.LV[A_Index].C4	)
			Stored.selt := selt
		}
		Stored.pelt := pelt
		, Stored.LocationName := iWebBrowser2.LocationName
		, Stored.LocationURL := iWebBrowser2.LocationURL
		GoSub, UpdateGuiControls
		Gui, Show, NA, % Stored.AppName " :: <" Stored.pelt.tagName ">"
	}
}

CrossHair:
{ ; allow dragable Cross-Hair when clicked
	if (A_GuiEvent = "Normal") {
		AHKBC_SetBatchLines(-1)
		Hotkey, ~LButton Up, On
		{ ; Set CrossHair Cursor & Hide in GUI
			GuiControl, Hide, HBar
			GuiControl, Hide, VBar
			CrossHair(CH:=false)
		}
		Lbutton_Pressed := True
		while Lbutton_Pressed
			IE_HtmlElement()
		outline.hide()
		if (Stored.pelt.tagName != "")
			Gui, Show, NA, % Stored.AppName " :: <" Stored.pelt.tagName "> [" GetTagIndex(Stored.pelt) "]"
		if WinVisible("ahk_id" Stored.2GUIhwnd)
			GoSub, ParentStructure
		AHKBC_SetBatchLines("10ms")
	}
	return
}
OnExitCleanup()
{ ; Cleanup when the Script Exits
	CrossHair(true)
	ExitApp
}
GuiClose:
	ExitApp
UpdateGuiControls:
{ ; Update the Main GUI with the New Element Info
	AHKBC_SetBatchLines(-1)
	Gui, 1: Default
	textOfObj := inpt(Stored.pelt)
	GuiControl, , Title, % Stored.LocationName
	GuiControl, , URLL, % Stored.LocationURL ; Edit2
	GuiControl, , EleIndex, % Stored.pelt.sourceindex ; Edit3
	GuiControl, , EleName, % Stored.pelt.name ; Edit4
	GuiControl, , EleIDs, %	Stored.pelt.id ; Edit5
	if (Stored.textOfObj != textOfObj)
		GuiControl, , html_text, % Stored.textOfObj:=textOfObj ; Edit6
	if (Stored.outerHTML != (val:=Stored.pelt.outerHTML) )
		GuiControl, , html_value, % Stored.outerHTML:=val ; Edit7
	textOfObj:=val:=""
	RemoveFocus()
}
SubListView:
{ ; When the Frames ListView is clicked
	if (A_GuiEvent = "Normal") { ; if Right Clicked
		if (column_num = 1)
			LVselection := Stored.LV[A_EventInfo].url
		else,
			LV_GetText(LVselection, A_EventInfo, column_num)
		if LVselection { ; if listview item contains data
			clipboard := LVSelection
			ToolTip, % "clipboard= " (StrLen(LVSelection) > 40 ? SubStr(LVSelection,1,40) "..." : LVSelection)
			SetTimer, RemoveToolTip, 1000
		}
	}
	Return
}
RemoveToolTip:
{
	SetTimer, RemoveToolTip, off
	ToolTip
	return
}
ParentStructure:
{ ; "Parent Structure" Menu Item Labels
	{
		AHKBC_SetBatchLines(-1)
		if Not Stored.pelt.tagName
			return
		nodes := object()
		elem := Stored.pelt
		Gui 2: Default
		TV_Delete()
		Loop {
			if (A_Index != 1)
				elem := elem.parentNode
			nodes.InsertAt( 1, elem.tagName
					.	(elem.id!=""? " id= " Chr(34) elem.id Chr(34):"")
					.	(elem.name!=""? "  name= " Chr(34) elem.name Chr(34):"") )
		} Until, elem.tagName = "html"

		GuiControl, -Redraw, TView
		For, Each, item in nodes
			Stored.TVitem := TV_Add(item)

		nodes := Stored.pelt.childNodes
		Loop, % nodes.length {
			elem := nodes.item(A_Index-1)
			TV_Add("[" A_Index-1 "] " elem.tagName
				.	(elem.id!=""? " id= " Chr(34) elem.id Chr(34):"")
				.	(elem.name!=""? "  name= " Chr(34) elem.name Chr(34):"")
			, Stored.TVitem	)
		}
		nodes:=elem:=""
		GuiControl, +Redraw, TView
		TV_Modify(Stored.TVitem, "Select Bold")
		if Not WinVisible("ahk_id" Stored.2GUIhwnd) {
			WinGetPos, x, y, w, , % "ahk_id" GuiWinHWND
			WinMove, % "ahk_id" Stored.2GUIhwnd,
				, % (x+w+_2GuiW > A_ScreenWidth? x-_2GuiW-5:x+w+5)
				, % y, % _2GuiW, % _2GuiH
			WinShow, % "ahk_id" Stored.2GUIhwnd
			temp:=""
		}
		return
	}
	2GuiClose:
	{
		Gui 2: Hide
		Gui 1: Default
		Stored.TVitem := ""
		return
	}
	2GuiSize:
	{
		Anchor(TView, "wh")
		return
	}
	2GuiContextMenu:
	{
		if (A_GuiControl = "TView") {
			Acc_ObjectFromPoint(child).accSelect(0x3, child)
			Menu, RClickMenu, DeleteAll
			TV_GetText(text, TV_GetSelection())
			if RegExMatch(text, "id= " Chr(34) "\K[^" Chr(34) "]+", ElemID)
				Menu, RClickMenu, Add, Copy ID, RClick
			if RegExMatch(text, "name= " Chr(34) "\K[^" Chr(34) "]+", ElemName)
				Menu, RClickMenu, Add, Copy Name, RClick
			Menu, RClickMenu, Add, Use Element, RClick
			Menu, RClickMenu, Show
		}
		return
	}
	RClick:
	{
		Gui, 2: +OwnDialogs
		if (A_ThisMenuItem = "Copy ID")
			clipboard := ElemID
		else if (A_ThisMenuItem = "Copy Name")
			clipboard := ElemName
		else if (A_ThisMenuItem = "Use Element") {
			temp := Stored.pelt
			Gui, 2: Default
			if TV_GetParent(TVsel:=TV_GetSelection()) {
				TV_GetText(text, TVsel)
				RegExMatch(text, "\d+", child)
				Stored.pelt := Stored.pelt.childNodes[child]
			}
			else,
				Loop, % TV_GetDiffCount(Stored.TVitem, TVsel)
					Stored.pelt := Stored.pelt.parentNode
			if Not Stored.pelt.sourceIndex {
				MsgBox, 262160, Selection Error, Cannot access this element.
				Stored.pelt := temp
			}
			else {
				Gui, 1: Default
				Gui, Show, NA, % Stored.AppName " :: <" Stored.pelt.tagName ">"
					. (Stored.pelt.tagName="HTML"? "":" [" GetTagIndex(Stored.pelt) "]")
				GoSub, UpdateGuiControls
				if WinVisible("ahk_id" Stored.2GUIhwnd)
					GoSub, ParentStructure
			}
		}
		ElemName:=ElemID:=TVsel:=child:=temp:=""
		return
	}
}

{ ; OUTLINE OBJECT DEFINITION
Outline(color:="red") { ; uses GUI 95-99
	self := object(	"base",	object(	"show",			"Outline_Show"
								,	"hide",			"Outline_Hide"
								,	"setAbove",		"Outline_SetAbove"
								,	"transparent",	"Outline_Transparent"
								,	"color",		"Outline_Color"
								,	"destroy",		"Outline_Destroy"
								,	"__delete",		"Object_Delete"	)	)
	Loop, 4 {
		Gui, % A_Index+95 ": -Caption +ToolWindow"
		Gui, % A_Index+95 ": Color", % color
		Gui, % A_Index+95 ": Show", NA h0 w0, % "outline" A_Index
		self[A_Index] := WinExist("outline" A_Index " ahk_class AutoHotkeyGUI")
	}
	self.visible := false
	, self.color := color
	, self.top := self[1]
	, self.right := self[2]
	, self.bottom := self[3]
	, self.left := self[4]
	Return, self
}
	Outline_Show(self, x1, y1, x2, y2, sides:="TRBL") { ; show outline at coords
		if InStr( sides, "T" )
			Gui, 96:Show, % "NA X" x1-2 " Y" y1-2 " W" x2-x1+4 " H" 2,outline1
		Else, Gui, 96: Hide
		if InStr( sides, "R" )
			Gui, 97:Show, % "NA X" x2 " Y" y1 " W" 2 " H" y2-y1,outline2
		Else, Gui, 97: Hide
		if InStr( sides, "B" )
			Gui, 98:Show, % "NA X" x1-2 " Y" y2 " W" x2-x1+4 " H" 2,outline3
		Else, Gui, 98: Hide
		if InStr( sides, "L" )
			Gui, 99:Show, % "NA X" x1-2 " Y" y1 " W" 2 " H" y2-y1,outline4
		Else, Gui, 99: Hide
		self.visible := true
	}
	Outline_Hide(self) { ; hide outline
		Loop, 4
			Gui, % A_Index+95 ": Hide"
		self.visible := false
	}
	Outline_SetAbove(self, hwnd) { ; set Z-Order one above "hwnd"
		ABOVE := DllCall("GetWindow", "uint", hwnd, "uint", 0x3) ; get window directly above "hwnd"
		Loop, 4  ; set 4 "outline" GUI's directly below "hwnd_above"
			DllCall(	"SetWindowPos", "uint", self[ A_Index ], "uint", ABOVE
					,	"int", 0, "int", 0, "int", 0, "int", 0
					,	"uint", 0x1|0x2|0x10	) ; NOSIZE | NOMOVE | NOACTIVATE
	}
	Outline_Transparent(self, param) { ; set Transparent ( different from hiding )
		Loop, 4
			AHKFC_WinSetTransparent(param=1? 0:255, "ahk_id" self[A_Index])
		self.visible := !param
	}
	Outline_Color(self, color) { ; set Color of Outline GUIs
		Loop, 4
			Gui, % A_Index+95 ": Color" , % color
		self.color := color
	}
	Outline_Destroy(self) { ; Destroy Outline
		VarSetCapacity(self, 0)
	}
	Object_Delete() { ; Destroy "outline GUIs" when object is deleted
		Loop, 4
			Gui, % A_Index+95 ": Destroy"
	}
}

; OTHER FUNCTIONS
CrossHair(OnOff:=1) {  ; Change Cursor to Cross-Hair
    ; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others
	static AndMask, XorMask, _s, h_cursor, IDC_CROSS := 32515
        ,_c ; system cursors
        ,_b   ; blank cursors
        ,_h   ; handles of default cursors
    if (OnOff = "Init" or OnOff = "I" or _s = "") {      ; init when requested or at first call
        _s := "_h"                                          ; active default cursors
        , 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"
	_c := StrSplit(system_cursors, ",")
        Loop, % _c.MaxIndex()
            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")
    }
    _s := (OnOff = 0 || OnOff = "Off" || _s = "_h" && (OnOff < 0 || OnOff = "Toggle" || OnOff = "T")) ? "_b" : "_h"

    Loop, % _c.MaxIndex()
        h_cursor := DllCall( "CopyImage", "uint",%_s%[A_Index], "uint",2, "int",0, "int",0, "uint",0 )
        , DllCall( "SetSystemCursor", "uint",h_cursor, "uint",_c[A_Index] )
; http://www.autohotkey.com/docs/commands/DllCall.htm
; http://www.autohotkey.com/forum/topic4570.html#75609
}
inpt(i) { ; return the Text of the Element
	global Stored
	tag	:=	i.tagName
	if RegExMatch(tag, "^(BUTTON|INPUT|OPTION|SELECT|TEXTAREA)$")
	{
		if (Stored.TextLabel = "InnerText")
			GuiControl, , Text, % Stored.TextLabel:="Value"
		return, i.value
	}
	if (Stored.TextLabel = "Value")
		GuiControl, , Text, % Stored.TextLabel:="InnerText"
	return, i.innerText
}

GetCoord( x1,y1,x2,y2, WinHWND ) { ; get the coordinates for the outline
	global Frame, outline
	WinGetPos, Wx, Wy, , , % "ahk_id" WinHWND
	ControlGetPos, Cx1, Cy1, Cw, Ch, Internet Explorer_Server1, % "ahk_id" WinHWND
	Cx1+=Wx  ; set "Internet Explorer_Server1" dimensions
	, Cy1+=Wy
	, Cx2:=Cx1+Cw
	, Cy2:=Cy1+Ch

	; Example return: object( "x1", 150, "y1", 200, "x2", 250, "y2", 300, "sides", "TRBL" )
	Return, object(	"x1",		Value( x1,Cx1,Frame["x1"], ">" )
				,	"y1",		Value( y1,Cy1,Frame["y1"], ">" )
				,	"x2",		Value( x2,Cx2,Frame["x2"], "<" )
				,	"y2",		Value( y2,Cy2,Frame["y2"], "<" )
				,	"sides",	( ElemCoord( y1,Cy1,Frame["y1"], ">" ) ? "T" : "" )
							.	( ElemCoord( x2,Cx2,Frame["x2"], "<" ) ? "R" : "" )
							.	( ElemCoord( y2,Cy2,Frame["y2"], "<" ) ? "B" : "" )
							.	( ElemCoord( x1,Cx1,Frame["x1"], ">" ) ? "L" : "" )	)
}
Value( E,C,F, option:=">" ) { ; returns the value of the Greatest (or smallest) value
	return,	F+0=""? (option=">"? (E>=C? E:C) : (E<=C? E:C))
		:	(option=">"? (E>=C? (E>=F? E:F) : (C>=F? C:F)) : (E<=C? (E<=F? E:F) : (C<=F? C:F)))
}
ElemCoord( E,C,F, option:=">" ) { ; returns true if the Element value is the Greatest (or smallest)
	return,	F+0=""? (option=">"? (E>=C? 1:0):(E<=C? 1:0))
		:	(option=">"? (E>=C && E>=F? 1:0):(E<=C && E<=F? 1:0))
}

GetTagIndex(element) { ; return the Index in the Tag Collection
	if IsMemberOf(element, "sourceIndex")
	and (index:=element.sourceIndex)
	and (tags:=element.ownerDocument.all.tags(element.tagName))
	and (top:=tags.length, bottom:=0)
		Loop {
			test := Floor( (top+bottom)/2 )
			i := tags[test].sourceIndex
			if (index < i)
				top := test
			else if (index > i)
				bottom := test
			else,
				return, test
		}
}
IsMemberOf(obj, name) { ; http://www.autohotkey.com/forum/topic63827.html
   p := ComObjValue(obj), ObjAddRef(p)
   return,  DllCall(NumGet(NumGet(1*p)+A_PtrSize*5)
        ,	"Ptr",  p
        ,	"Ptr",  VarSetCapacity(iid,16,0)*0+&iid
        ,	"Ptr*", &name
        ,	"UInt", 1
        ,	"UInt", 1024
        ,	"Int*", dispID)=0
        && dispID+1, ObjRelease(p)
}
TV_GetDiffCount(p1, p2) {
	count := 0
	while (p1 != p2)
		p1 := TV_GetPrev(p1)
		, count++
	return, count
}
WinVisible(WinTitle) {
	temp := A_DetectHiddenWindows
	DetectHiddenWindows, Off
	out := WinExist(WinTitle)
	DetectHiddenWindows, % temp
	return, out
}
BCobj(elem, color) { ; highlight Element Background
	static	base := object("__delete","BCobj_Delete")
	return,	object("elem",elem, "color",elem.style.backgroundColor, "base",base)
		,	elem.style.backgroundColor := color
}
BCobj_Delete(self) {
	self.elem.style.backgroundColor := self.color
}
RemoveFocus() { ; Handle LButton Being Release over Main GUI
	global GuiWinHWND
	ControlGetFocus, focus, % "ahk_id" GuiWinHWND
	if (SubStr(focus,1,4) == "Edit") {
		ControlGet, text, Selected, , % focus, % "ahk_id" GuiWinHWND
		if Not text
			ControlFocus, Static7, % "ahk_id" GuiWinHWND
	}
}

CColor(Hwnd, Background:="", Foreground:="") {
	; http://www.autohotkey.com/forum/viewtopic.php?t=39055
	return CColor_(Background, Foreground, "", Hwnd+0)
}
CColor_(Wp, Lp, Msg, Hwnd) {
	static
	static WM_CTLCOLOREDIT:=0x0133, WM_CTLCOLORLISTBOX:=0x134, WM_CTLCOLORSTATIC:=0x0138
		,LVM_SETBKCOLOR:=0x1001, LVM_SETTEXTCOLOR:=0x1024, LVM_SETTEXTBKCOLOR:=0x1026, TVM_SETTEXTCOLOR:=0x111E, TVM_SETBKCOLOR:=0x111D
		,BS_CHECKBOX:=2, BS_RADIOBUTTON:=8, ES_READONLY:=0x800
		,CLR_NONE:=-1, CSILVER:=0xC0C0C0, CGRAY:=0x808080, CWHITE:=0xFFFFFF, CMAROON:=0x80, CRED:=0x0FF, CPURPLE:=0x800080, CFUCHSIA:=0xFF00FF,CGREEN:=0x8000, CLIME:=0xFF00, COLIVE:=0x8080, CYELLOW:=0xFFFF, CNAVY:=0x800000, CBLUE:=0xFF0000, CTEAL:=0x808000, CAQUA:=0xFFFF00
		,CLASSES := "Button|ComboBox|Edit|ListBox|Static|RICHEDIT50W|SysListView32|SysTreeView32"

	If (Msg = "") {
		if !adrSetTextColor
			adrSetTextColor   := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "Gdi32.dll"), "astr", "SetTextColor")
			,adrSetBkColor   := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "Gdi32.dll"), "astr", "SetBkColor")
			,adrSetBkMode   := DllCall("GetProcAddress", "ptr", DllCall("GetModuleHandle", "str", "Gdi32.dll"), "astr", "SetBkMode")

		;Set the colors (RGB -> BGR)
		BG := !Wp ? "" : C%Wp% != "" ? C%Wp% : "0x" SubStr(WP,5,2) SubStr(WP,3,2) SubStr(WP,1,2)
		FG := !Lp ? "" : C%Lp% != "" ? C%Lp% : "0x" SubStr(LP,5,2) SubStr(LP,3,2) SubStr(LP,1,2)

		;Activate message handling with OnMessage() on the first call for a class
		WinGetClass, class, % "ahk_id" Hwnd
		If !RegExMatch(class, "^(" CLASSES ")$")
			return A_ThisFunc "> Unsupported control class: " class

		ControlGet, style, Style, , , % "ahk_id" Hwnd
		if (class = "Edit") && (Style & ES_READONLY)
			class := "Static"

		if (class = "Button")
			if (style & BS_RADIOBUTTON) || (style & BS_CHECKBOX)
				class := "Static"
			else return A_ThisFunc "> Unsupported control class: " class

		if (class = "ComboBox") {
			VarSetCapacity(CBBINFO, 52, 0), NumPut(52, CBBINFO), DllCall("GetComboBoxInfo", "UInt", Hwnd, "UInt", &CBBINFO)
			hwnd := NumGet(CBBINFO, 48)      ;hwndList
			%hwnd%BG := BG, %hwnd%FG := FG, %hwnd% := BG ? DllCall("CreateSolidBrush", "UInt", BG) : -1

			(CTLCOLORLISTBOX = "") ? (CTLCOLORLISTBOX := OnMessage(WM_CTLCOLORLISTBOX, A_ThisFunc)) : ""

			If NumGet(CBBINFO,44)   ;hwndEdit
				Hwnd :=  Numget(CBBINFO,44), class := "Edit"
		}

		if RegExMatch(class, "^(SysListView32|SysTreeView32)$")
		{
			 m := class="SysListView32" ? "LVM" : "TVM"
			 SendMessage, % %m%_SETBKCOLOR, ,% BG, ,% "ahk_id" Hwnd
			 SendMessage, % %m%_SETTEXTCOLOR, ,% FG, ,% "ahk_id" Hwnd
			 SendMessage, % %m%_SETTEXTBKCOLOR, ,% CLR_NONE, ,% "ahk_id" Hwnd
			 return
		}

		if (class = "RICHEDIT50W")
		{
			f := "RichEdit_SetBgColor", %f%(Hwnd, -BG)
			return f
		}

		if (!CTLCOLOR%Class%)
			CTLCOLOR%Class% := OnMessage(WM_CTLCOLOR%Class%, A_ThisFunc)

		_%Hwnd%BG := BG,  _%Hwnd%FG := FG
		return _%Hwnd% := BG ? DllCall("CreateSolidBrush", "UInt", BG) : CLR_NONE
	}

	; Message handler
	critical               ;its OK, always in new thread.

	Hwnd := Lp + 0, hDC := Wp + 0
	If (_%Hwnd%) {
	DllCall(adrSetBkMode, "uint", hDC, "int", 1)
	if (_%Hwnd%FG)
		DllCall(adrSetTextColor, "UInt", hDC, "UInt", _%Hwnd%FG)
	if (_%Hwnd%BG)
		DllCall(adrSetBkColor, "UInt", hDC, "UInt", _%Hwnd%BG)
	return (_%Hwnd%)
	}
}

;==================================================

;backwards compatibility functions
AHKBC_SetBatchLines(Param)
{
	SetBatchLines, % Param
}
SetBatchLines(Param)
{
}

;==================================================

;forwards-compatibility functions
AHKFC_WinRedraw(WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	static WinRedraw := Func("WinRedraw")
	if WinRedraw
		%WinRedraw%(WinTitle, WinText, ExcludeTitle, ExcludeText)
	else
		WinSet, Redraw,, % WinTitle, % WinText, % ExcludeTitle, % ExcludeText
}
AHKFC_WinSetTransparent(N, WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
	local Hwnd
	static WinSetTransparent := Func("WinSetTransparent")
	Hwnd := WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText)
	if (!Hwnd)
		return 0
	if WinSetTransparent
		%WinSetTransparent%(N, WinTitle, WinText, ExcludeTitle, ExcludeText)
	else
		WinSet, Transparent, % N, % "ahk_id" Hwnd
	return 1
}
WinSet(Param1:="", Param2:="", WinTitle:="", WinText:="", ExcludeTitle:="", ExcludeText:="")
{
}

;==================================================
Last edited by jeeswg on 16 May 2017, 09:34, edited 3 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
just me
Posts: 5953
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Apr 2017, 11:24

jeeswg wrote:One query re. Acc.ahk, which is preferable ...

Code: Select all

#define     OBJID_WINDOW        ((LONG)0x00000000)
#define     OBJID_SYSMENU       ((LONG)0xFFFFFFFF)
#define     OBJID_TITLEBAR      ((LONG)0xFFFFFFFE)
#define     OBJID_MENU          ((LONG)0xFFFFFFFD)
#define     OBJID_CLIENT        ((LONG)0xFFFFFFFC) // -4 (added)
#define     OBJID_VSCROLL       ((LONG)0xFFFFFFFB)
#define     OBJID_HSCROLL       ((LONG)0xFFFFFFFA)
#define     OBJID_SIZEGRIP      ((LONG)0xFFFFFFF9)
#define     OBJID_CARET         ((LONG)0xFFFFFFF8)
#define     OBJID_CURSOR        ((LONG)0xFFFFFFF7)
#define     OBJID_ALERT         ((LONG)0xFFFFFFF6)
#define     OBJID_SOUND         ((LONG)0xFFFFFFF5)
#define     OBJID_QUERYCLASSNAMEIDX ((LONG)0xFFFFFFF4)
#define     OBJID_NATIVEOM      ((LONG)0xFFFFFFF0)
User avatar
jeeswg
Posts: 5939
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Apr 2017, 11:59

Cheers just me.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 5939
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

16 May 2017, 09:53

I corrected some variable/object names on the conversions for AccViewer and iWB2 Learner. AccViewer's crosshair now works, although iWB2 Learner's crosshair is not working (in AHK v1 or v2).

==================================================

I understand now about the 'No object to invoke.' error.

Error: No object to invoke - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=37&t=3818

Code: Select all

q:: ;'No object to invoke.' tests
;MsgBox % obj.1 ;No object to invoke.

obj := {}
obj[1,2] := "hello"
MsgBox % obj.1.2 ;hello

obj := {}
obj.1 := "hello"
MsgBox % obj.1.2 ;No object to invoke.

obj := {}
obj.1 := {}
MsgBox % obj.1.2 ;blank

;MsgBox % obj.1.2 ;No object to invoke.
return
==================================================

I see now that there has been a change to NumGet:

NumGet
https://autohotkey.com/docs/commands/NumGet.htm

NumGet
https://lexikos.github.io/v2/docs/commands/NumGet.htm
If the variable contains a pure number, that number is assumed to be an address.
==================================================

I would be grateful to anyone who would like to test AccViewer and iWB2 Learner, to give me some hints on debugging the problems. Including: what is causing 'Parameter list too small.', which based on the source code, I believe refers to passing parameters to a function, but it signals 'Return, 0' ('Return, false') as being the problem line.

When I add ampersands to NumGet in AccViewer, there still seems to be a problem.

Basically I keep discovering new and surprising error messages each time I fix or try to fix the 2 scripts to work in AHK v2, and I'm going round in circles trying to correct the script. (The 2 scripts both work in AHK v1.)
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
sancarn
Posts: 212
Joined: 01 Mar 2016, 14:52

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Jul 2017, 06:59

Might want to add just me's Acc_Selection function

Code: Select all

; ----------------------------------------------------------------------------------------------------------------------------------
; Retrieves the selected children of this object. All objects that support selection must support this property
; ----------------------------------------------------------------------------------------------------------------------------------
Acc_Selection(Acc) {
   Selection := []
   Try
      Selected := Acc.accSelection
   Catch E
      Return Acc_Error(A_ThisFunc, E)
   If IsObject(Selected) {
      If (Name := ComObjType(Selected, "Name")) {
         If (Name = "IAccessible")
            Selection.Push(Selected)
         Else If (IA := Acc_Query(Selected))
            Selection.Push(IA)
      }
      Else {
         While Selected.Next(Value, VarType)
            Selection.Push(Value)
      }
   }
   Else If (Selected <> "")
      Selection.Push(Selected)
   Return (Selection.Length() ? Selection : "")
}
Also see qwerty12345's OnAlertSound script

Also sinkfaze made some cool things on the previous forum (IMPORTANT: These will not work in all cases)

Finally, does anyone know how to get the desktop window? I assume Acc_ObjectFromWindow(WinExist(),0).accParent works, but haven't tested it and am not sure it is the 'correct' method...
Last edited by sancarn on 15 Jul 2017, 20:15, edited 1 time in total.
sancarn
Posts: 212
Joined: 01 Mar 2016, 14:52

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Jul 2017, 16:59

Might also want to add these enums:

Code: Select all

;https://msdn.microsoft.com/en-us/library/windows/desktop/dd373606(v=vs.85).aspx
class ACC_OBJID{
	static	WINDOW        		:=	0x00000000
	static	SYSMENU       		:=	0xFFFFFFFF
	static	TITLEBAR      		:=	0xFFFFFFFE
	static	MENU          		:=	0xFFFFFFFD
	static	CLIENT        		:=	0xFFFFFFFC
	static	VSCROLL       		:=	0xFFFFFFFB
	static	HSCROLL       		:=	0xFFFFFFFA
	static	SIZEGRIP      		:=	0xFFFFFFF9
	static	CARET         		:=	0xFFFFFFF8
	static	CURSOR        		:=	0xFFFFFFF7
	static	ALERT         		:=	0xFFFFFFF6
	static	SOUND         		:=	0xFFFFFFF5
	static	QUERYCLASSNAMEIDX 	:=	0xFFFFFFF4
	static	NATIVEOM			:=	0xFFFFFFF0
}

;https://msdn.microsoft.com/en-us/library/windows/desktop/dd373609(v=vs.85).aspx
class ACC_STATE {
	static	NORMAL 					:=		0					
	static	UNAVAILABLE 			:=		0x1                    
	static	SELECTED 				:=		0x2                    
	static	FOCUSED 				:=		0x4                    
	static	PRESSED 				:=		0x8                    
	static	CHECKED 				:=		0x10                   
	static	MIXED 					:=		0x20                   
	static	INDETERMINATE 			:=		this.MIXED			
	static	READONLY 				:=		0x40                   
	static	HOTTRACKED 				:=		0x80                   
	static	DEFAULT 				:=		0x100                  
	static	EXPANDED 				:=		0x200                  
	static	COLLAPSED 				:=		0x400                  
	static	BUSY 					:=		0x800                  
	static	FLOATING 				:=		0x1000                 
	static	MARQUEED 				:=		0x2000                 
	static	ANIMATED 				:=		0x4000                 
	static	INVISIBLE 				:=		0x8000                 
	static	OFFSCREEN 				:=		0x10000                
	static	SIZEABLE 				:=		0x20000                
	static	MOVEABLE 				:=		0x40000                
	static	SELFVOICING 			:=		0x80000                
	static	FOCUSABLE 				:=		0x100000               
	static	SELECTABLE 				:=		0x200000               
	static	LINKED 					:=		0x400000               
	static	TRAVERSED 				:=		0x800000               
	static	MULTISELECTABLE 		:=		0x1000000              
	static	EXTSELECTABLE 			:=		0x2000000              
	static	ALERT_LOW 				:=		0x4000000              
	static	ALERT_MEDIUM 			:=		0x8000000              
	static	ALERT_HIGH 				:=		0x10000000             
	static	PROTECTED 				:=		0x20000000             
	static	VALID 					:=		0x7fffffff			
}

;https://msdn.microsoft.com/en-us/library/windows/desktop/dd373608(v=vs.85).aspx
class ACC_ROLE {
	static	TITLEBAR 				:=		0x1	
	static	MENUBAR 				:=		0x2 
	static	SCROLLBAR 				:=		0x3 
	static	GRIP 					:=		0x4 
	static	SOUND 					:=		0x5 
	static	CURSOR 					:=		0x6 
	static	CARET 					:=		0x7 
	static	ALERT 					:=		0x8 
	static	WINDOW 					:=		0x9 
	static	CLIENT 					:=		0xa 
	static	MENUPOPUP 				:=		0xb 
	static	MENUITEM 				:=		0xc 
	static	TOOLTIP 				:=		0xd 
	static	APPLICATION 			:=		0xe 
	static	DOCUMENT 				:=		0xf 
	static	PANE 					:=		0x10
	static	CHART 					:=		0x11
	static	DIALOG 					:=		0x12
	static	BORDER 					:=		0x13
	static	GROUPING 				:=		0x14
	static	SEPARATOR 				:=		0x15
	static	TOOLBAR 				:=		0x16
	static	STATUSBAR 				:=		0x17
	static	TABLE 					:=		0x18
	static	COLUMNHEADER 			:=		0x19
	static	ROWHEADER 				:=		0x1a
	static	COLUMN 					:=		0x1b
	static	ROW 					:=		0x1c
	static	CELL 					:=		0x1d
	static	LINK 					:=		0x1e
	static	HELPBALLOON 			:=		0x1f
	static	CHARACTER 				:=		0x20
	static	LIST 					:=		0x21
	static	LISTITEM 				:=		0x22
	static	OUTLINE 				:=		0x23
	static	OUTLINEITEM 			:=		0x24
	static	PAGETAB 				:=		0x25
	static	PROPERTYPAGE 			:=		0x26
	static	INDICATOR 				:=		0x27
	static	GRAPHIC 				:=		0x28
	static	STATICTEXT 				:=		0x29
	static	TEXT 					:=		0x2a
	static	PUSHBUTTON 				:=		0x2b
	static	CHECKBUTTON 			:=		0x2c
	static	RADIOBUTTON 			:=		0x2d
	static	COMBOBOX 				:=		0x2e
	static	DROPLIST 				:=		0x2f
	static	PROGRESSBAR 			:=		0x30
	static	DIAL 					:=		0x31
	static	HOTKEYFIELD 			:=		0x32
	static	SLIDER 					:=		0x33
	static	SPINBUTTON 				:=		0x34
	static	DIAGRAM 				:=		0x35
	static	ANIMATION 				:=		0x36
	static	EQUATION 				:=		0x37
	static	BUTTONDROPDOWN 			:=		0x38
	static	BUTTONMENU 				:=		0x39
	static	BUTTONDROPDOWNGRID 		:=		0x3a
	static	WHITESPACE 				:=		0x3b
	static	PAGETABLIST 			:=		0x3c
	static	CLOCK 					:=		0x3d
	static	SPLITBUTTON 			:=		0x3e
	static	IPADDRESS 				:=		0x3f
	static	OUTLINEBUTTON 			:=		0x40
}

;https://msdn.microsoft.com/en-us/library/windows/desktop/dd373600(v=vs.85).aspx
class ACC_NAVDIR {
	static	MIN 		:=	0x0
	static	UP 			:=	0x1
	static	DOWN 		:=	0x2
	static	LEFT 		:=	0x3
	static	RIGHT 		:=	0x4
	static	NEXT 		:=	0x5
	static	PREVIOUS	:=	0x6
	static	FIRSTCHILD 	:=	0x7
	static	LASTCHILD 	:=	0x8
	static	MAX 		:=	0x9
}

;https://msdn.microsoft.com/en-us/library/windows/desktop/dd373634(v=vs.85).aspx
class ACC_SELECTIONFLAG {
	static	NONE 				:= 0x0	
	static	TAKEFOCUS 			:= 0x1 
	static	TAKESELECTION 		:= 0x2 
	static	EXTENDSELECTION 	:= 0x4 
	static	ADDSELECTION 		:= 0x8 
	static	REMOVESELECTION 	:= 0x10
	static	VALID 				:= 0x1f
}
User avatar
jeeswg
Posts: 5939
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Jul 2017, 18:15

- Although qwerty12's OnAlertSound script looks interesting, it's not necessarily something I would incorporate into AccViewer or an AccViewer alternative, although if you can provide a good argument, I might consider it.
- sinkfaze's scripts re. menus are good, but invoking a menu item seems like a good use of the Acc library, rather than a good feature for AccViewer, also, the information retrieved via 'WinGet', is information that AccViewer can already retrieve I believe.
- From your comments you strike me as having good ambition and vision for either AccViewer or an alternative/mod, so I would encourage you to work on an alternative and submit it, written in AHK v2 or AHK v1, whichever you prefer.
- I'm not against including the Acc_Selection function or the constants per se, they strike me as being potentially worthwhile, but I think I would like to see how you would incorporate them, one of the reasons for my comment above.
- Overall I'm actually quite happy with AccViewer and iWB2 Learner, I want 2 features: hotkeys to retrieve the window/control/object under the cursor for AccViewer, and any % zoom support for iWB2 Learner, plus to simply have AHK v2 compatible versions. I've already done all of the hard work for this, however the scripts are so fiddly to alter, that I plan to recreate them instead. So my most honest answer would be further encouragement for you to pursue your own script.

This script could be a good base from which to develop an AccViewer upgrade/alternative:
AccViewer Basic - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=32039

The functionality I would like to incorporate into iWB2 Learner:
Internet Explorer get element under cursor (show borders, show text) (any zoom percentage) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=29458

I have been having a lot of trouble trying to make even simple updates to AccViewer and iWB2 Learner, so I plan to recreate them from scratch ... *when I can* ... which could be months away, even if I then went back and worked on the original scripts, from experience, it would still be faster to try and recreate the scripts first. Note: I haven't done any work with AHK v2 GUI functions, so if anyone has any good template code, that would expedite things.

In trying to convert the two scripts for AHK v2, I have kept running into unusual errors that I don't get in AHK v1, that I am unfamiliar with, thus if someone familiar enough with AHK v2 felt motivated to do it, it would be useful for those scripts to be fully debugged. This is a key reason for me to start again from scratch, I might then be able to to understand the scripts better and anticipate what was causing the errors, and resolve them all myself. Although I think the scripts would benefit from a rewrite anyway.

==================================================

Re. getting access to Desktop.

This may or may not be helpful:
get full paths of selected files on Desktop and Common File Dialogs - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 36#p154836

Also:
WinGet, hWnd, ID, ahk_class Progman

I'd be interested as to whether FindWindowSW be used for Explorer folder windows as well as Desktop, or whether a WBGet equivalent (WBGet is for Internet Explorer) can be made for Explorer folder windows, and Desktop. I.e. one method for both Desktop and folder windows.

WBGet:
Basic Webpage Controls with JavaScript / COM - Tutorial - Tutorials - AutoHotkey Community
https://autohotkey.com/board/topic/4705 ... -tutorial/
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
sancarn
Posts: 212
Joined: 01 Mar 2016, 14:52

Re: Acc / AccViewer / iWB2 Learner / Anchor conversion attempts

15 Jul 2017, 20:11

Oh no, I wasn't suggesting changing AccViewer or IWBLearner. IWBLearner doesn't really concern me at all personally. The only thing I could add to AccViewer would be an acc event viewer - though I have no idea how to do that as I haven't studied acc events... Bear in mind that I still believe inspect.exe is a far better viewer than AccViewer if you have access to it:

Image

Rather I believe these scripts should be put into acc.ahk itself. I know you're not the only one working with acc.ahk but a more up-to-date/feature-rich version of acc.ahk would be nice.

For example Sean's Acc_State() function lacks a huge amount of functionality and it would be better to use accObj.accState with the enums I have provided in class ACC_STATE as these are more feature rich.

Similarly functions like just me's Acc_Selection should absolutely be in the library, as libraries are meant to be general purpose and this just makes obj.accSelection actually usable.

Return to “AutoHotkey v2 Development”

Who is online

Users browsing this forum: No registered users and 11 guests