WebWriter - By Tank
Posted: 17 Oct 2019, 13:06
This still has alot of work to go as to writing a script with frames and dealing with anything that isnt clickable
Hopefully you find it really helpful. basically what it does is allows you to click a web object and it then attempts to build a css selector and write a script using my iwebBrowser2 class.
this code is a prototype and should at this ALPHA stage only be used with great care.
If it helps you please feel free to help me out while i am out of work
Help me out
version .03 Alpha
Corrected tag siblings and other minor corrections
version .02 alpha posted in op
corrected issue identified by gregster
added methods for
Hopefully you find it really helpful. basically what it does is allows you to click a web object and it then attempts to build a css selector and write a script using my iwebBrowser2 class.
this code is a prototype and should at this ALPHA stage only be used with great care.
If it helps you please feel free to help me out while i am out of work
Help me out
version .03 Alpha
Corrected tag siblings and other minor corrections
Code: Select all
#NoEnv
winactivate ahk_class IEFrame
^esc:: ExitApp
#IfWinActive, ahk_class IEFrame
F1::click() ;; click
F2::value() ;;text or value
F3::src() ;; image or frame src URI
F4::checked() ;; is checked true false or blank
#IfWinActive
elementUnderMouse(ByRef ele){
getQuerySelector := getQuerySelector(ele := elementFromMouse())
getQuerySelector = %getQuerySelector%
return getQuerySelector
}
writeScript(event){
WinGetActiveTitle, winTitle
winTitle := RegExReplace(winTitle, "[^\w\s\-]")
scriptFile := A_WorkingDir "\" winTitle ".ahk"
if !FileExist(scriptFile)
FileAppend,
( LTrim
#Include, lib\iWebBrowser2.ahk
ie := new iWebBrowser2()
pwb:=ie.pwb
while pwb.busy
`tSleep, 500
sleep 2000
;; auto generated code below
), %scriptFile%
;; end if
if event
FileAppend, %event%, %scriptFile%
}
value(){
ret := "", variable := "hovertext" A_Now, cssSelector := elementUnderMouse(ele), element := new IE_HtmlElement(ele), attribute := element.attribute, txt := element.text
if cssSelector && element && attribute
ret =
( LTrim
;; hovered over "%txt%"
%variable% := ie.pdoc().querySelector("%cssSelector%").%attribute% ;; should be a string
)
ObjRelease(ele), ObjRelease(element), writeScript(ret)
}
src(){
ret := "", variable := "Source" A_Now
if cssSelector := elementUnderMouse(ele)
&& element := new IE_HtmlElement(ele)
&& element.getSrc()
&& tagName := element.tag
ret =
( LTrim
;; get source of an %tagName% tag
%variable% := ie.pdoc().querySelector("%cssSelector%").src ;; should be a URI
)
ObjRelease(ele), ObjRelease(element), writeScript(ret)
}
checked(){
ret := "", variable := "isChecked" A_Now
if cssSelector := elementUnderMouse(ele)
&& element := new IE_HtmlElement(ele)
&& InStr(element.getType(), "checkbox:radio")
&& txt := element.element.parentNode.innerText
ret =
( LTrim
/*
is input checked near
"txt"
*/
%variable% := ie.pdoc().querySelector("%cssSelector%").checked ;; -1 means checked 0 means not checked
)
ObjRelease(ele), ObjRelease(element), writeScript(ret)
}
click(){
ret := "", variable := isChecked A_Now
if (cssSelector := elementUnderMouse(ele))
&& (element := new IE_HtmlElement(ele))
&& (txt := element.text)
ret =
( LTrim
;; clicked "%txt%"
ie.pdoc().querySelector("%cssSelector%").click() ;; execute the click event
;; wait for any results to settle
Sleep, 1000
while pwb.busy
`tSleep, 500
Sleep, 1000
)
ObjRelease(ele), ObjRelease(element), writeScript(ret)
}
getQuerySelector(ele){
static iterCount := 0
try id := ele.id
if (iterCount++ < 10 && !id)
path := getQuerySelector(ele.parentNode)
else iterCount := 0
return path getTagName(ele)
}
getTagName(ele){
try tagName := ele.tagName, id := ele.id
return !id ? siblingList(ele, tagName) : tagName "#" id " "
}
siblingList(ele, tagName){
tag := tagName
while ele := ele.previousSibling
tag .= " + " tagName
return tag " "
}
elementFromMouse(){
try
If (hWnd := hWNDunderMouse(xpos, ypos)) && (pwin := $AccessibleObjectFromWindow(hWnd))
&& (pelt := pwin.document.elementFromPoint(xpos-(xorg:=pwin.screenLeft), ypos-(yorg:=pwin.screenTop)))
While isFrame(pelt){
ObjRelease(pwin), pwin := ComObj( 9, ComObjQuery( cw := pelt.contentwindow, $IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}", $IHTMLWindow2 ), 1 ), ObjRelease(cw)
, xorg+=pelt.getBoundingClientRect.left, yorg+=pelt.getBoundingClientRect.top, ObjRelease(pelt), pelt := pwin.document.elementFromPoint(xpos-xorg, ypos-yorg)
}
ObjRelease(pwin)
Return pelt
}
hWNDunderMouse( ByRef xpos, ByRef ypos){
CoordMode, Mouse
MouseGetPos, xpos, ypos,, hWnd, 3
return hWnd
}
$AccessibleObjectFromWindow(hIESrv){
IID_IAccessible := "{618736E0-3C3D-11CF-810C-00AA00389B71}", VarSetCapacity( GUID, 16, 0 ), DllCall("LoadLibrary", "str", "oleacc.dll")
DllCall( "ole32\CLSIDFromString"
, "wstr", IID_IAccessible
, "ptr", &GUID )
DllCall( "oleacc\AccessibleObjectFromWindow"
, "Uint", hIESrv
, "int", -4
, "ptr", &GUID
, "UintP", pacc)
pacc:=ComObj( 9, pacc, 1 )
pwin := ComObj( 9, ComObjQuery( pacc, $IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}", $IHTMLWindow2 ), 1 )
ObjRelease( pacc ), DllCall("FreeLibrary", "str", "oleacc.dll")
return pwin
}
isFrame(ele){
return ele.tagName="IFRAME" || ele.tagName="FRAME"
}
class iWebBrowser2 {
__new( ByRef sURL = "", ByRef sTitle = "", ByRef iHWND = "", ByRef sHTML = "" , bVisible = true )
{ ;; returns an iwebbrowser2 object
if !(this.pwb := this.oIE_get(sTitle,iHWND,sURL,sHTML))
{
this.pwb := this.oIE_new(sURL,sTitle,iHWND,sHTML,bVisible)
this.pwb.Navigate(sURL)
}
return this
}
oIE_new(ByRef sURL = "about:blank", ByRef sTitle = "", ByRef iHWND = "", ByRef sHTML = "", bVisible = true)
{
this.isInstalled()
this.pwb := ComObjCreate("internetexplorer.application")
this.pwb.Visible := bVisible
if sURL
this.pwb.Navigate(sURL)
return this.pwb
}
oIE_get( ByRef sTitle = "", ByRef iHWND = "", ByRef sURL = "", ByRef sHTML = "" )
{
this.isInstalled()
;~ this function is pointless if no instance of IE is open
;~ one edit you might make is to have this function open IE and maybe go to the home page
if ( !winexist( "ahk_class IEFrame" ) )
return false
if sTitle
this.clean_IE_Title( sTitle )
;; ok this function should look at all the existing IE instances and build a reference object
; List all open Explorer and Internet Explorer windows:
oIE := Object()
matches := 0
for window,k in ComObjCreate("Shell.Application").Windows
if ( "Internet Explorer" = window.Name)
{
possiblematch := true
try pdoc := window.document
Catch, e
while window.busy
Sleep, 500
if !window.document
Continue
if ( possiblematch && sTitle && !instr( pdoc.title, sTitle ) )
possiblematch := false
if ( possiblematch && sHTML && !instr( pdoc.documentelement.outerhtml, sHTML ) )
possiblematch := false
if ( possiblematch && sURL && !instr( pdoc.url, sURL ) )
possiblematch := false
if ( possiblematch && iHWND > 0 && window.HWND != iHWND )
possiblematch := false
if ( possiblematch )
{
;~ windowsList .= k " => " ( clipboard := window.FullName ) " :: " pdoc.title " :: " pdoc.url "`n"
matches++
sTitle := pdoc.title
sURL := pdoc.url
iHWND := window.HWND
sHTML := pdoc.documentelement.outerhtml
oIE := window
}
ObjRelease( pdoc )
}
if ( matches > 1 )
{
MsgBox, 4112, Too many Matches , Please modify your criteria or close some tabs/windows and retry
return false
}
return this.pwb := oIE
}
FindbyText(needle)
{ ;; returns the element with the text in it
try rng:=this.pdoc().body.createTextRange()
try rng.findText(needle)
return try rng.parentElement()
}
Activate(pwb)
{
DllCall("LoadLibrary", "str", "oleacc.dll")
HWND:=pwb.HWND
DetectHiddenWindows, On
WinActivate,% "ahk_id " HWND
WinWaitActive,% "ahk_id " HWND,,5
ControlGet, hTabBand, hWnd,, TabBandClass1, ahk_class IEFrame
ControlGet, hTabUI , hWnd,, DirectUIHWND1, ahk_id %hTabBand%
VarSetCapacity(CLSID, 16)
nSize=38
wString := sString := "{618736E0-3C3D-11CF-810C-00AA00389B71}"
if(nSize = "")
nSize:=DllCall("kernel32\MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sString, "int", -1, "Uint", 0, "int", 0)
VarSetCapacity(wString, nSize * 2 + 1)
DllCall("kernel32\MultiByteToWideChar", "Uint", 0, "Uint", 0, "Uint", &sString, "int", -1, "Uint", &wString, "int", nSize + 1)
DllCall("ole32\CLSIDFromString", "Uint",&wString , "Uint", &CLSID)
If hTabUI && DllCall("oleacc\AccessibleObjectFromWindow", "Uint", hTabUI, "Uint",-4, "Uint", &CLSID , "UintP", pacc)=0
{
pacc := ComObject(9, pacc, 1), ObjAddRef(pacc)
Loop, % pacc.accChildCount
If paccChild:=pacc.accChild(A_Index)
If paccChild.accRole(0+0) = 0x3C
{
paccTab:=paccChild
Break
}
Else ObjRelease(paccChild)
ObjRelease(pacc)
}
If pacc:=paccTab
{
Loop, % pacc.accChildCount
If paccChild:=pacc.accChild(A_Index)
If paccChild.accName(0+0) = sTitle
{
ObjRelease(pwb)
paccChild.accDoDefaultAction(0)
ObjRelease(paccChild)
Break
}
Else ObjRelease(paccChild)
ObjRelease(pacc)
}
WinActivate,% sTitle
}
isInstalled()
{
Static IE_path
;; find where windows believes IE is installed
;; certain corp installs may have this in other than expected folders
if !IE_path
RegRead, IE_path, HKLM, SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\IEXPLORE.EXE
;~ MsgBox % IE_path
;; Perhaps policies prevent reading this key
if ( ErrorLevel || !IE_path )
IE_path := "C:\Program Files\Internet Explorer\iexplore.exe"
;; make sure it installed
if !FileExist( IE_path )
{
MsgBox, 4112, Internet Explorer Not Found, IE does not appear to be installed`nCannot continue `nClick OK to Exit!!!
ExitApp
}
}
pDoc()
{
return this.IHTMLWindow2_from_IWebDOCUMENT( this.pwb.document ).document
}
clean_IE_Title( ByRef sTitle = "" )
{
return sTitle := RegExReplace( sTitle ? sTitle : this.active_IE_Title(), this.IE_Suffix() "$", "" )
}
IE_Suffix()
{
static sIE_Suffix
if !sIE_Suffix
{
;; HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main
RegRead, sIE_Suffix, HKCU, Software\Microsoft\Internet Explorer\Main, Window Title ;, Windows Internet Explorer,
sIE_Suffix := " - " sIE_Suffix
}
return sIE_Suffix
}
active_IE_Title() ;; returns the title of the topmost browser if exists from the stack
{
sTitle := "NO IE Window Open"
if winexist( "ahk_class IEFrame" )
{
titlematchMode := A_TitleMatchMode
titlematchSpeed := A_TitleMatchModeSpeed
SetTitleMatchMode, 2
SetTitleMatchMode, Slow
WinGetTitle, sTitle, %sIE_Suffix% ahk_class IEFrame
SetTitleMatchMode, %titlematchMode%
SetTitleMatchMode, %titlematchSpeed%
}
return RegExReplace( sTitle, this.IE_Suffix() "$", "" )
}
IHTMLWindow2_from_IWebDOCUMENT( IWebDOCUMENT )
{
static IID_IHTMLWindow2 := "{332C4427-26CB-11D0-B483-00C04FD90119}" ; IID_IHTMLWindow2
return ComObj(9,ComObjQuery( IWebDOCUMENT, IID_IHTMLWindow2, IID_IHTMLWindow2),1)
}
IWebDOCUMENT_from_IWebDOCUMENT( IWebDOCUMENT ) ;bypasses certain security issues
{
return this.IHTMLWindow2_from_IWebDOCUMENT( IWebDOCUMENT ).document
}
IWebBrowserApp_from_IWebDOCUMENT( IWebDOCUMENT )
{
static IID_IWebBrowserApp := "{0002DF05-0000-0000-C000-000000000046}" ; IID_IWebBrowserApp
return ComObj(9,ComObjQuery( this.IHTMLWindow2_from_IWebDOCUMENT( IWebDOCUMENT ), IID_IWebBrowserApp, IID_IWebBrowserApp),1)
}
IWebBrowserApp_from_Internet_Explorer_Server_HWND( hwnd, Svr#=1 )
{ ;// based on ComObjQuery docs
static msg := DllCall( "RegisterWindowMessage", "str", "WM_HTML_GETOBJECT" )
, IID_IWebDOCUMENT := "{332C4425-26CB-11D0-B483-00C04FD90119}"
SendMessage msg, 0, 0, Internet Explorer_Server%Svr#%, ahk_id %hwnd%
if (ErrorLevel != "FAIL")
{
lResult := ErrorLevel
VarSetCapacity( GUID, 16, 0 )
if DllCall( "ole32\CLSIDFromString", "wstr", IID_IWebDOCUMENT, "ptr", &GUID ) >= 0
{
DllCall( "oleacc\ObjectFromLresult", "ptr", lResult, "ptr", &GUID, "ptr", 0, "ptr*", IWebDOCUMENT )
return this.IWebBrowserApp_from_IWebDOCUMENT( IWebDOCUMENT )
}
}
}
}
class IE_HtmlElement {
__new(ele){
this.element := ele
this.tag := this.getTag()
this.type := this.getType()
this.checked := this.getChecked()
this.text := this.getText()
this.src := this.getSrc()
}
getText(){
if (instr(this.getTag(), "input:"))
txt := this.element.value, this.attribute := "value"
else if (instr(this.getTag(), "select:"))
txt := this.element.selectedText, this.attribute := "selectedText"
else txt := this.element.innerText, this.attribute := "innerText"
ToolTip, %txt%
return txt
}
getTag(){
return this.element.tagname
}
getType(){
if (instr(this.getTag(), "input:"))
return this.element.type
}
getChecked(){
if (instr(this.getType(), "checkbox:radio"))
return this.element.checked
}
getSrc(){
if (instr(this.getTag(), "image:frame"))
return this.element.src
}
setText(txt){
}
}
version .02 alpha posted in op
corrected issue identified by gregster
added methods for
- click
- get text that works on both inputs and regular elements
- get status clicked or not of radio and checkbox
- get source of images and frames
Spoiler
v0.01
Spoiler