(one more way to) open a link on a new tab and got focus as well

Post your working scripts, libraries and tools for AHK v1.1 and older
SundayProgrammer
Posts: 143
Joined: 25 Dec 2020, 12:26

(one more way to) open a link on a new tab and got focus as well

Post by SundayProgrammer » 26 Apr 2022, 01:00

keyboard + mouse: Shift+Ctrl+Click; or

mouse-only: drag&drop the link to an empty space on the tab-ribbon; or

mouse-only with this simple script running: which enabled us to drag&drop the link just a small step "up" (instead of dragging it all the way to the tab-ribbon) to make the subject matter happen.

Code: Select all

#IfWinActive, ahk_exe msedge.exe
~LButton::keyLButton()
keyLButton() {
	WinGetPos,,, ww,, A
	MouseGetPos, x, y
	If not ((v := GetFocusedElement().Value) = GetURL("A")) and SubStr(v, 1, 8) = "https://"
		If (x < ww - 25) and (y > 80) and GetKeyState(A_ThisHotkey, "P")
		{	Sleep, 500
			MouseGetPos, xx, yy
			If (Abs(yy - y) > 22 or Abs(xx - x) > 15) and GetKeyState(A_ThisHotkey, "P")
				MouseMove, ww - 171, 20
		}
}
GetFocusedElement() {	;based on the script by Descolada (https://www.autohotkey.com/boards/viewtopic.php?p=459451&sid=dde6b407875aadff59bc35e0864f63e4#p459451)
	IUIAutomation := ComObjCreate(CLSID_CUIAutomation := "{ff48dba4-60ef-4201-aa87-54103eef594e}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
	DllCall(NumGet(NumGet(IUIAutomation+0)+8*A_PtrSize), "ptr",IUIAutomation, "ptr*",element)	;IUIAutomation::GetFocusedElement
	DllCall(NumGet(NumGet(element+0)+23*A_PtrSize), "ptr", element, "ptr*", name)	;IUIAutomationElement::CurrentName
	DllCall(NumGet(NumGet(element+0)+10*A_PtrSize), "ptr", element, "uint",30045, "ptr", (VarSetCapacity(val,8+2*A_PtrSize)+NumPut(0,val,0,"short")+NumPut(0,val,8,"ptr"))*0+&val)	;IUIAutomationElement::GetCurrentPropertyValue
	ObjRelease(element)
	ObjRelease(IUIAutomation)
	Return {"Name":StrGet(name,"utf-16"), "Value":StrGet(NumGet(val,8,"ptr"),"utf-16")}
}
GetURL(wTitle*) {	;written by Descolada (https://www.autohotkey.com/boards/viewtopic.php?p=459451&sid=dde6b407875aadff59bc35e0864f63e4#p459451)
	ErrorLevel := 0
	if !(wId := WinExist(wTitle*)) {
		ErrorLevel := 1
		return
	}
	IUIAutomation := ComObjCreate(CLSID_CUIAutomation := "{ff48dba4-60ef-4201-aa87-54103eef594e}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
	DllCall(NumGet(NumGet(IUIAutomation+0)+6*A_PtrSize), "ptr", IUIAutomation, "ptr", wId, "ptr*", elementMain)   ; IUIAutomation::ElementFromHandle
	NumPut(addressbarStrPtr := DllCall("oleaut32\SysAllocString", "wstr", "Address and search bar", "ptr"),(VarSetCapacity(addressbar,8+2*A_PtrSize)+NumPut(8,addressbar,0,"short"))*0+&addressbar,8,"ptr")
	DllCall("oleaut32\SysFreeString", "ptr", addressbarStrPtr)
	if (A_PtrSize = 4) {
		DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", 30005, "int64", NumGet(addressbar, 0, "int64"), "int64", NumGet(addressbar, 8, "int64"), "ptr*", addressbarCondition)   ; IUIAutomation::CreatePropertyCondition
	} else {
		DllCall(NumGet(NumGet(IUIAutomation+0)+23*A_PtrSize), "ptr", IUIAutomation, "int", 30005, "ptr", &addressbar, "ptr*", addressbarCondition)   ; IUIAutomation::CreatePropertyCondition
	}
	DllCall(NumGet(NumGet(elementMain+0)+5*A_PtrSize), "ptr", elementMain, "int", TreeScope_Descendants := 0x4, "ptr", addressbarCondition, "ptr*", currentURLElement) ; IUIAutomationElement::FindFirst
	DllCall(NumGet(NumGet(currentURLElement+0)+10*A_PtrSize),"ptr",currentURLElement,"uint",30045,"ptr",(VarSetCapacity(currentURL,8+2*A_PtrSize)+NumPut(0,currentURL,0,"short")+NumPut(0,currentURL,8,"ptr"))*0+&currentURL) ;IUIAutomationElement::GetCurrentPropertyValue
	ObjRelease(currentURLElement)
	ObjRelease(elementMain)
	ObjRelease(IUIAutomation)
	If (theText := StrGet(NumGet(currentURL,8,"ptr"),"utf-16")) = "// // LOGGED"
		Return "_Logged_"
	return theText
}
i noticed myself doing the subject matter quite often, and mostly don't have a keyboard around, thus started to feel the distance to the tab-ribbon is a "baggage" which could be avoided. that's why this script was written. and i'm happy with the "savings" it brings me. i wondered if you may also find it useful.

it has a known drawback though. which is, it bumped the text selection when you select the text by dragging from a point upward.

2022may28 edited: improved the script, avoided the known drawback. and from now on, not only "up", any directions will do the job.
Last edited by SundayProgrammer on 28 May 2022, 06:10, edited 1 time in total.

SundayProgrammer
Posts: 143
Joined: 25 Dec 2020, 12:26

Re: (one more way to) open a link on a new tab and got focus as well

Post by SundayProgrammer » 20 May 2022, 03:54


another "one more". this one utilizes the "bigger youtube tooltip" to obtain the link (youtube video link) and opens it up on a new tab.

this is how: when the tooltip (which must contain a youtube video link) is shown, move your mouse on top of it (anywhere within the tooltip) and rest for a little while. the link will therefore be taken for the operation.

Code: Select all

var("Set:uToggle@VirtualGlobal", True)
DllCall("SetWindowsHookEx", "int", 14, "uint", RegisterCallback("MouseProc"), "uint", 0, "uint", 0)	; WH_MOUSE_LL = 14
Return

Tab & u::var("Set:uToggle@VirtualGlobal", not var("uToggle@VirtualGlobal"))	;toggle youtip() on/off
Tab & 2::var("Set:uToggle@VirtualGlobal", 2)	;set unconditional youtip()
Tab & 0::ExitApp
Tab & r::RemoveTT()	;rarely needed
	RemoveTT() {
		ControlGetText, t,, ahk_class tooltips_class32
		If StrLen(t)
			ToolTip
	}
Tab::Tab

MouseProc(nCode, wParam, lParam) {
	static mLock := False
	Critical
	If A_TickCount - mLock > 1000
	{	mLock := A_TickCount
		If wParam = 0x200	; WM_MOUSEMOVE
			YouTip(NumGet(lParam+0,0,"int"), NumGet(lParam+4,0,"int"))
		mLock := False
	}Return DllCall("CallNextHookEx", "uint", MouseHook, "int", nCode, "uint", wParam, "uint", lParam)
}
YouTip(mgpx := 0, mgpy := 0) {
	static PriorX, PriorY, Interval := 500, mTT := A_TickCount
	If mgpx + mgpy
		SetTimer, YouTip, Off
	Else
	{	CoordMode, Mouse, Screen
		MouseGetPos, mgpx, mgpy
		CoordMode, Mouse, Window
	}
	If (MouseMoved := Abs(mgpx - PriorX) + Abs(mgpy - PriorY)) and var("uToggle@VirtualGlobal") and MgpWpn() = "msedge.exe"
		Interval := YouTipSub()
	Else If MgpClass() = "tooltips_class32"
	{	ControlGetText, ttt,, ahk_class tooltips_class32
		If InStr(ttt, ".youtube.com/watch?v=")
		If MouseMoved
			mTT := A_TickCount, Interval = 100
		Else If (timelapse := A_TickCount - mTT) > 1000 and timelapse < 2000
		{	RegExMatch(ttt, ">>>\K.+?(?=<<<)", url), Clipboard := RegExReplace(url, "&(list|pageId)=.+$")
			ToolTip
			Send, ^t+^l
			Interval = 500
		}Else Interval = 100
	}Else If MouseMoved
		Interval = 500
	Else If Interval < 3000
		Interval += 500
	PriorX := mgpx, PriorY := mgpy
	SetTimer, YouTip, -%Interval%
}
YouTipSub() {
	static PriorTT := A_TickCount

	o := GetInfoFromPoint()
	If var("uToggle@VirtualGlobal") > 1 or InStr(o.Value, ".youtube.com/watch?v=") or InStr(SubStr(o.Name, -4), "view") or SubStr(o.Name, -22) = "also watch this channel"
		tt := (StrLen(o.Value) ? ">>>" o.Value "<<<" : "") "`n`n>>>" o.Name "<<<"
	Else
	{	ControlGetText, ttt,, ahk_class tooltips_class32
		If StrLen(ttt) and (ttt = PriorTT)
		{	ToolTip
			PriorTT := A_TickCount
		}Return 100
	}
	If not (tt = PriorTT)
	{	ToolTip, %tt%
		rToolTip(0xFFFF00, 0x000000)
		PriorTT := tt
	}
	Return 100
}
rToolTip(BgClr:="", FgClr:="") {	;based on the fnt lib (found in autohotkey forum)
	hTT:=WinExist("ahk_class tooltips_class32")
	if (BgClr||FgClr) {	;written by @"just me"
		if BgClr
			BgClr := ((BgClr >> 16) & 0xFF) | (BgClr & 0x00FF00) | ((BgClr & 0xFF) << 16)
		if FgClr
			FgClr := ((FgClr >> 16) & 0xFF) | (FgClr & 0x00FF00) | ((FgClr & 0xFF) << 16)
		DllCall("UxTheme.dll\SetWindowTheme", "Ptr", hTT, "Ptr", 0, "Str", "")
		VarSetCapacity(RC, 16, 0)
		NumPut(4, RC, 0, "Int"), NumPut(4, RC, 4, "Int"), NumPut(4, RC, 8, "Int"), NumPut(1, RC, 12, "Int")
		DllCall("User32.dll\SendMessage", "Ptr", hTT, "UInt", 0x041A, "Ptr", 0, "Ptr", &RC)
		if BgClr
			DllCall("User32.dll\SendMessage", "Ptr", hTT, "UInt", 0x0413, "Ptr", BgClr, "Ptr", 0)
		if FgClr
			DllCall("User32.dll\SendMessage", "Ptr", hTT, "UInt", 0x0414, "Ptr", FgClr, "Ptr", 0)
	}SendMessage,0x30,DllCall("CreateFont","Int",-22,"Int",0,"Int",0,"Int",0,"Int",400,"UInt",0,"UInt",0,"UInt",0,"UInt",1,"UInt",4,"UInt",0,"UInt",2,"UInt",0,"Str","MS Shell Dlg"),0,,ahk_id %hTT%
	SendMessage,0x41D,0,0,,ahk_id %hTT%
}
MgpWpn() {
	MouseGetPos,,, hwnd
	WinGet, wpn, ProcessName, ahk_id %hwnd%
	Return wpn
}
MgpClass() {
	MouseGetPos,,, w
	WinGetClass, name, ahk_id %w%
	Return name
}
var(name, value = "") {	;component taken from my other project
	global
	local p, a, v
	If p := InStr(name, "@")
	{	a := SubStr(name, 1, 4), v := Trim(SubStr(name, 1, p - 1)), name := Trim(SubStr(name, p + 1))
		If (a = "Set:") or (a = "Get:")
			v := Trim(SubStr(v, 5))
		Else a := StrLen(value) ? "Set:" : "Get:"
		If StrLen(v) and StrLen(name)
		{	v := a v, v .= (a = "Set:") ? "=" value : ""
			If InStr(name, ".")
				v := cnsm(name, v)
			Else v := %name%(v)
		}Else v = Error: Invalid Parameter "%v%@%name%"
	}Else
	{	a := SubStr(name, 1, 4)
		If (a = "Set:") or (a = "Get:")
			name := Trim(SubStr(name, 5))
		If InStr(name, ".")
			v := cns(a, name, value)
		Else
		{	If (a = "Set:") or StrLen(value)
				%name% := value
			v := %name%
		}
	}Return v
}
VirtualGlobal(param = "") {	;component taken from my other project
	static
	If StrLen(param)
	If IsGetSet(param, action, varname, value)
	If InStr(varname, ".")
		Return cns(action, varname, value)
	Else
	{	If (action = "Set:")
			%varname% := value
		v := %varname%
		Return v
	}
}
IsGetSet(Param, ByRef a, ByRef v, ByRef value) {	;component taken from my other project
	a := SubStr(Param, 1, 4)
	If (a = "Set:") or (a = "Get:")
	{	v := Trim((p := InStr(Param, "=")) ? (SubStr(Param, 5, p - 5), value := SubStr(Param, p + 1)) : SubStr(Param, 5))
		Return True
	}Return False
}
cns(action, varname, value) {	;component taken from my other project
	n := RegExMatch(varname, ".+\K\."), m := SubStr(varname, 1, n - 1)
	Loop, Parse, m, .
		If A_Index = 1
			a := &%A_LoopField%, o := Object(a)
		Else o := Object(a)[A_LoopField], a := &o
	If (action = "Set:")
		o[SubStr(varname, n+1)] := value
	Return o[SubStr(varname, n+1)]
}
cnsm(s, p*) {	;component taken from my other project
	n := RegExMatch(s, ".+\K\."), m := SubStr(s, 1, n - 1)
	Loop, Parse, m, .
		If A_Index = 1
			a := &%A_LoopField%, o := Object(a)
		Else o := Object(a)[A_LoopField], a := &o
	Return o[SubStr(s, n+1)](p*)
}
GetInfoFromPoint() {	;based on the script from Descolada at https://www.autohotkey.com/boards/viewtopic.php?p=459451#p459451
	CoordMode, Mouse, Screen
	MouseGetPos, x, y
	CoordMode, Mouse, Window
	IUIAutomation := ComObjCreate(CLSID_CUIAutomation := "{ff48dba4-60ef-4201-aa87-54103eef594e}", IID_IUIAutomation := "{30cbe57d-d9d0-452a-ab13-7ac5ac4825ee}")
	DllCall(NumGet(NumGet(IUIAutomation+0)+7*A_PtrSize), "ptr", IUIAutomation, "int64", x|y<<32, "ptr*", element)	;IUIAutomation::ElementFromPoint
	DllCall(NumGet(NumGet(element+0)+23*A_PtrSize), "ptr", element, "ptr*", name)	;IUIAutomationElement::CurrentName
	DllCall(NumGet(NumGet(element+0)+10*A_PtrSize), "ptr", element, "uint",30045, "ptr", (VarSetCapacity(val,8+2*A_PtrSize)+NumPut(0,val,0,"short")+NumPut(0,val,8,"ptr"))*0+&val)	;IUIAutomationElement::GetCurrentPropertyValue
	ObjRelease(element)
	ObjRelease(IUIAutomation)
	Return {"Name":StrGet(name,"utf-16"), "Value":StrGet(NumGet(val,8,"ptr"),"utf-16")}
}


Post Reply

Return to “Scripts and Functions (v1)”