Short version: The code below finds out the URL of the current (active) browser tab for most of the modern browsers.
Long version:
How to get the URL of the browser tab I'm using? The problem is quite common and there have been scripts to tackle it here and in the old forum.
The best solution for quite sometime (IMHO) was Sean's DDE code but unfortunately Google Chrome doesn't support DDE. Recent changes to Chrome invalidated the Chrome_OmniboxView workaround so I didn't knew how to get it until I saw uname's use of the ACC library (Sean strikes again ). uname's code depended on the language used in Windows (I use Win7 x64 in Spanish) but I found out a workaround. I even managed to extend my solution to cover most of the Chromium-based browsers (all but Vivaldi), and even got it to work in Maxthon.
Anyway, the code below finds out the URL of the current (active) browser tab. I've tested successfully (on Win7 x64 Spanish) with the following browsers:
- Google Chrome
- Mozilla Firefox
- Internet Explorer 11
- Opera
- Microsoft Edge
- Opera 12
- Maxthon
- Iron
- Coowon
- Slimjet
- Vivaldi (if run with the --force-renderer-accessibility switch)
Code: Select all
; AutoHotkey Version: AutoHotkey 1.1
; Language: English
; Platform: Win7 SP1 / Win8.1 / Win10
; Author: Antonio Bueno <user atnbueno of Google's popular e-mail service>
; Short description: Gets the URL of the current (active) browser tab for most modern browsers
; Last Mod: 2016-05-19
Menu, Tray, Icon, % A_WinDir "\system32\netshell.dll", 86 ; Shows a world icon in the system tray
ModernBrowsers := "ApplicationFrameWindow,Chrome_WidgetWin_0,Chrome_WidgetWin_1,Maxthon3Cls_MainFrm,MozillaWindowClass,Slimjet_WidgetWin_1"
LegacyBrowsers := "IEFrame,OperaWindowClass"
^+!u::
nTime := A_TickCount
sURL := GetActiveBrowserURL()
WinGetClass, sClass, A
If (sURL != "")
MsgBox, % "The URL is """ sURL """`nEllapsed time: " (A_TickCount - nTime) " ms (" sClass ")"
Else If sClass In % ModernBrowsers "," LegacyBrowsers
MsgBox, % "The URL couldn't be determined (" sClass ")"
Else
MsgBox, % "Not a browser or browser not supported (" sClass ")"
Return
GetActiveBrowserURL() {
global ModernBrowsers, LegacyBrowsers
WinGetClass, sClass, A
If sClass In % ModernBrowsers
Return GetBrowserURL_ACC(sClass)
Else If sClass In % LegacyBrowsers
Return GetBrowserURL_DDE(sClass) ; empty string if DDE not supported (or not a browser)
Else
Return ""
}
; "GetBrowserURL_DDE" adapted from DDE code by Sean, (AHK_L version by maraskan_user)
; Found at http://autohotkey.com/board/topic/17633-/?p=434518
GetBrowserURL_DDE(sClass) {
WinGet, sServer, ProcessName, % "ahk_class " sClass
StringTrimRight, sServer, sServer, 4
iCodePage := A_IsUnicode ? 0x04B0 : 0x03EC ; 0x04B0 = CP_WINUNICODE, 0x03EC = CP_WINANSI
DllCall("DdeInitialize", "UPtrP", idInst, "Uint", 0, "Uint", 0, "Uint", 0)
hServer := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", sServer, "int", iCodePage)
hTopic := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "WWW_GetWindowInfo", "int", iCodePage)
hItem := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "0xFFFFFFFF", "int", iCodePage)
hConv := DllCall("DdeConnect", "UPtr", idInst, "UPtr", hServer, "UPtr", hTopic, "Uint", 0)
hData := DllCall("DdeClientTransaction", "Uint", 0, "Uint", 0, "UPtr", hConv, "UPtr", hItem, "UInt", 1, "Uint", 0x20B0, "Uint", 10000, "UPtrP", nResult) ; 0x20B0 = XTYP_REQUEST, 10000 = 10s timeout
sData := DllCall("DdeAccessData", "Uint", hData, "Uint", 0, "Str")
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hServer)
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hTopic)
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hItem)
DllCall("DdeUnaccessData", "UPtr", hData)
DllCall("DdeFreeDataHandle", "UPtr", hData)
DllCall("DdeDisconnect", "UPtr", hConv)
DllCall("DdeUninitialize", "UPtr", idInst)
csvWindowInfo := StrGet(&sData, "CP0")
StringSplit, sWindowInfo, csvWindowInfo, `" ;"; comment to avoid a syntax highlighting issue in autohotkey.com/boards
Return sWindowInfo2
}
GetBrowserURL_ACC(sClass) {
global nWindow, accAddressBar
If (nWindow != WinExist("ahk_class " sClass)) ; reuses accAddressBar if it's the same window
{
nWindow := WinExist("ahk_class " sClass)
accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindow))
}
Try sURL := accAddressBar.accValue(0)
If (sURL == "") {
WinGet, nWindows, List, % "ahk_class " sClass ; In case of a nested browser window as in the old CoolNovo (TO DO: check if still needed)
If (nWindows > 1) {
accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindows2))
Try sURL := accAddressBar.accValue(0)
}
}
If ((sURL != "") and (SubStr(sURL, 1, 4) != "http")) ; Modern browsers omit "http://"
sURL := "http://" sURL
If (sURL == "")
nWindow := -1 ; Don't remember the window if there is no URL
Return sURL
}
; "GetAddressBar" based in code by uname
; Found at http://autohotkey.com/board/topic/103178-/?p=637687
GetAddressBar(accObj) {
Try If ((accObj.accRole(0) == 42) and IsURL(accObj.accValue(0)))
Return accObj
Try If ((accObj.accRole(0) == 42) and IsURL("http://" accObj.accValue(0))) ; Modern browsers omit "http://"
Return accObj
For nChild, accChild in Acc_Children(accObj)
If IsObject(accAddressBar := GetAddressBar(accChild))
Return accAddressBar
}
IsURL(sURL) {
Return RegExMatch(sURL, "^(?<Protocol>https?|ftp)://(?<Domain>(?:[\w-]+\.)+\w\w+)(?::(?<Port>\d+))?/?(?<Path>(?:[^:/?# ]*/?)+)(?:\?(?<Query>[^#]+)?)?(?:\#(?<Hash>.+)?)?$")
}
; The code below is part of the Acc.ahk Standard Library by Sean (updated by jethrow)
; Found at http://autohotkey.com/board/topic/77303-/?p=491516
Acc_Init()
{
static h
If Not h
h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromWindow(hWnd, idObject = 0)
{
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
Return ComObjEnwrap(9,pacc,1)
}
Acc_Query(Acc) {
Try Return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
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.Insert(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"
}
}
- Faster in Chromium browsers: After the first use, successive queries are instantaneous (faster than DDE!) Thanks to XeroByte for the nudge
- Improved error messages in the hotkey example
- Tested without problems in all AutoHotkey versions (U32, A32, U64) and also in Windows 8.1
EDIT 2015-10-18:
- Now it works with Microsoft Edge (only tested via VM) and Slimjet (both suggestions by Kudos)
- Better URL detection (thanks LarryC for the feedback)
- Added workaround for runtime errors suggested by Kipp a year ago
- Removed support for Google's failed Origin Chip experiment
EDIT 2016-05-15:
- Better support for Microsoft Edge
- DDE is now used only for legacy browsers (specifically, Internet Explorer and Opera 12)
- Identified two browsers where the script doesn't work (it can't reach the address bar): Pale Moon and Vivaldi
EDIT 2016-05-19:
- Better detection of the address bar
- Vivaldi now supported as long as is run with the --force-renderer-accessibility switch on (and optional, but recommended, check the option "Address Bar/Show Full URL")
- Pale Moon won't be supported as they explicitly disabled the accessibility features: https://www.palemoon.org/technical.shtml#features (thanks qwerty12 for the info)
Regards from Spain,
Antonio