Select items in Microsoft Edge context menu

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Select items in Microsoft Edge context menu

05 Feb 2017, 01:02

Please Note: I need some people to test this on Microsoft Edge. I was only able to test it on 2 computers running windows 10. I will be using this for my SavePictureAs program, and would like it to be as bug free as possible.

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
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.
User avatar
rommmcek
Posts: 1474
Joined: 15 Aug 2014, 15:18

Re: Select items in Microsoft Edge context menu

05 Feb 2017, 04:53

I experienced, sometimes context menu appears like: See pic!
Then it doesn't work.

I am using FindText for this and it works faster!
https://autohotkey.com/boards/viewtopic ... t=findtext
Attachments
Save picture as._ACCpng.png
Save picture as._ACCpng.png (162.35 KiB) Viewed 1650 times
User avatar
DataLife
Posts: 447
Joined: 29 Sep 2013, 19:52

Re: Select items in Microsoft Edge context menu

06 Feb 2017, 15:35

rommmcek wrote:I experienced, sometimes context menu appears like: See pic!
Then it doesn't work.

I am using FindText for this and it works faster!
https://autohotkey.com/boards/viewtopic ... t=findtext
Thanks for the FindText suggestion. It works perfectly and very fast. It searches the entire screen in .57 seconds.
Check out my scripts. (MyIpChanger) (ClipBoard Manager) (SavePictureAs)
All my scripts are tested on Windows 10, AutoHotkey 32 bit Ansi unless otherwise stated.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 207 guests