On most browsers when you right click to open the context menu you are able to press shortcut keys to select one of the menu options. (On Internet Explorer the letter "s" will select "Save picture as")
Microsoft Edge does not support shortcut keys for the right click context menu.
This script will send a right click, wait for the context menu to open, then click on "Save picture as" or what ever you assign to the variable TextToClick
How does it work:
This script needs to know where the context menu has opened in relation to the mouse cursor. For example... Top Left, Top Right, Bottom Left, or Bottom Right
This is done by retrieving the pixel color of the context menu border. This only works on MicroSoft Edge Light and Dark Themes. As far as I know MicroSoft Edge only supports these 2 themes. I will update this post when/if more themes are added to Microsoft Edge.
Once the script knows where the context menu is, it moves the mouse in increments of 30 and retrieving the text under the mouse looking for the TextToClick variable
When it finds the TextToClick variable, it will click on it.
This script works on right click context menus on the browsing window, not the titlebar, not the address bar nor toolbars.
Credits: Thanks to jethrow and Sean.
This script uses GetTextUndeMouse code by jethrow found https://autohotkey.com/board/topic/7730 ... ntry493839
GetTextUnderMouse relies on the ACC library created by Sean. The original post be found here. https://autohotkey.com/board/topic/7730 ... -09272012/
The acc library can be downloaded from here https://autohotkey.com/boards/viewtopic.php?f=6&t=26201
I added the acc library to the bottom of this script
Code: Select all
; I used Control Space as the hotkey
; Change the variable TextToClick to what you need the click to click on
TextToClick = Save picture as
#SingleInstance,Force
^space:: ;control space
WinGetClass,class, A
if (Class = "ApplicationFrameWindow") ;Class for Microsoft Edge
{
Send {rbutton} ;open right click context menu
sleep 500 ;wait for context menu to appear
MouseGetPos,Xp1,Yp1
;Context Menu is on the BOTTOM RIGHT or the mouse position
PixelGetColor, Color, Xp1, Yp1
if ( Color = "0xCCCCCC" or Color = "0x767676" ) ;if this is true then the context menu has been found (light or dark theme)
{
TempXp1 := (Xp1 + 10)
FoundContextMenu = 1
}
;Context Menu is on the BOTTOM LEFT or the mouse position
PixelGetColor, Color, Xp1 -3, Yp1
if ( Color = "0xCCCCCC" or Color = "0x767676" ) ;if this is true then the context menu has been found (light or dark theme)
{
TempXp1 := (Xp1 - 10)
FoundContextMenu = 1
}
If FoundContextMenu = 1
{
TempYp1 := Yp1
loop 400 ;loop and move the mouse and get text under mouse
{
TempYp1 := (TempYp1 + 30)
mousemove,%TempXp1%,%TempYp1%
MouseGetPos, OutputVarX, OutputVarY, OutputVarWin, OutputVarControl,
if OutputVarControl <> ;if OutputVarControl is blank the the mouse has moved off of the context meu
{
BreakLoop = 1
Break
}
Tempvar := GetTextUnderMouse()
if Tempvar = %TextToClick%
{
Click
BreakLoop = 1
break
}
}
If BreakLoop = 1
Goto SkipRetrievingText
}
;Context Menu is on the TOP RIGHT or the mouse position
PixelGetColor, Color, Xp1 + 1, Yp1 - 1
if ( Color = "0xCCCCCC" or Color = "0x767676" )
{
TempXp1 := (Xp1 + 10)
FoundContextMenu = 1
}
;Context Menu is on the TOP LEFT or the mouse position
PixelGetColor, Color, Xp1 - 1, Yp1 - 1
if ( Color = "0xCCCCCC" or Color = "0x767676" )
{
TempXp1 := (Xp1 - 10)
FoundContextMenu = 1
}
If FoundContextMenu = 1
{
TempYp1 := Yp1
loop 400
{
TempYp1 := (TempYp1 - 30)
mousemove,%TempXp1%,%TempYp1%
MouseGetPos, OutputVarX, OutputVarY, OutputVarWin, OutputVarControl,
if OutputVarControl <> ;if OutputVarControl is blank then the mouse has moved off the context menu
Break
Tempvar := GetTextUnderMouse()
if Tempvar = %TextToClick%
{
click
break
}
}
}
}
SkipRetrievingText:
Color =
BreakLoop =
FoundContextMenu =
return
GetTextUnderMouse() {
Acc := Acc_ObjectFromPoint(child)
try value := Acc.accValue(child)
if Not value
try value := Acc.accName(child)
return value
}
;------------------------------------------------------------------------------
; 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/19/2012
;------------------------------------------------------------------------------
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
Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}
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
Return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}
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
Return ComObjEnwrap(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
}
; 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_Children(Acc) {
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)=3?child:Acc_Query(child)), ObjRelease(child)
return Children
}
error:=Exception("",-1)
MsgBox, 262420, Acc_Children Failed, % "File: " error.file "`nLine: " error.line "`n`nContinue Script?"
IfMsgBox, No
ExitApp
}
Acc_Location(Acc, ChildId=0) { ; adapted from Sean's code
try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
catch
return
return {x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")
, pos:"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 ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
^escape::
exitapp