Keve Posted September 23, 2020 Share Posted September 23, 2020 Hello Forum, The best way to utilise one of the autoit scripts I am about to write would be to add one or two extra options to the content sensitive menu that shows up when you right-click something. What I did before was to create suitable menu items for the toolbar icon of my autoit application. This time however, I would prefer not to always move my mouse to the bottom of the screen to click the toolbar icon and bring up the available menu items. I would prefer to just right-click something on my screen, and see my autoit option in that list. Is this something doable with autoit? Can I add items to the right-click menu? Pointers or suggestions are appreciated! Regards, Keve Link to comment Share on other sites More sharing options...
zeenmakr Posted September 23, 2020 Share Posted September 23, 2020 not a true menu, but i'm thinking _IsPressed() check if it is at a specific location with get control position ControlGetPos(), then open a new gui with always ontop with options Link to comment Share on other sites More sharing options...
Keve Posted September 24, 2020 Author Share Posted September 24, 2020 Checking for a particular screen location may not be an efficient solution. The is no way to know in advance, where the object(s) I am interested in would show up on the screen, so there is no reference I could compare coordinates to. But the rest of your suggestion is promising. If I find no way to inject my menu items into the standard right-click menu, I can create my own little GUI menu, trigger it for a specific input combination (say Ctrl+Alt+RightClick) and display it at the current location of the mouse pointer. Regardless of what screen object is at that mouse pointer location at the time. I still hope somebody will point me towards extending the right-click menu. But if that does not happen, this is a good reserve-solution. Thanks! Link to comment Share on other sites More sharing options...
Popular Post LarsJ Posted September 24, 2020 Popular Post Share Posted September 24, 2020 It's not that hard. Here is an example with the context menu in Notepad. Run the code in SciTE with F5. Only tested in Windows 7. Should also work in Windows 10. expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y Opt( "MustDeclareVars", 1 ) #include <Misc.au3> #include <GuiMenu.au3> #include <WindowsConstants.au3> Example() Func Example() ; Open Notepad Run( "notepad.exe" ) WinWait( "[CLASS:Notepad]" ) ; Open context menu Send( "{APPSKEY}" ) WinWait( "[CLASS:#32768]" ) ; Get menu handle Local $hMenu = GetMenuHandle() If Not $hMenu Then Return ConsoleWrite( "$hMenu ERR" & @CRLF ) ConsoleWrite( "$hMenu OK" & @CRLF ) ; Add new menu item Local $iItem = _GUICtrlMenu_AddMenuItem( $hMenu, "My new menu item" ) If Not $iItem Then Return ConsoleWrite( "$iItem ERR" & @CRLF ) ConsoleWrite( "$iItem OK" & @CRLF ) ; Show all menu items Local $iCount = _GUICtrlMenu_GetItemCount( $hMenu ), $sText For $i = 0 To $iCount - 1 $sText = _GUICtrlMenu_GetItemText( $hMenu, $i ) If $sText <> "" Then ConsoleWrite( "$sText = " & $sText & @CRLF ) ConsoleWrite( "$iIndex = " & $i & @CRLF ) EndIf Next ; Detect menu item click While Sleep(10) And Not _IsPressed( "01", "user32.dll" ) WEnd $iItem = _GUICtrlMenu_MenuItemFromPointEx( 0, $hMenu ) ; Works in both 32 and 64 bit code ConsoleWrite( "Clicked item = " & $iItem & @CRLF ) If $iItem <> $iCount - 1 Then Return ConsoleWrite( "My new menu item NOT clicked" & @CRLF ) ConsoleWrite( "My new menu item clicked" & @CRLF ) EndFunc Func GetMenuHandle() Local $hDesktop = _WinAPI_GetDesktopWindow(), $i = 0 Local $hChild = _WinAPI_GetWindow( $hDesktop, $GW_CHILD ) While $hChild And $i < 50 If _WinAPI_GetClassName( $hChild ) = "#32768" Then ExitLoop $hChild = _WinAPI_GetWindow( $hChild, $GW_HWNDNEXT ) $i += 1 WEnd If $i = 50 Then Return 0 Local $hMenu = _SendMessage( $hChild, $MN_GETHMENU ) If $hMenu > 0 Then Return $hMenu Return 0 EndFunc Func _GUICtrlMenu_MenuItemFromPointEx( $hWnd, $hMenu, $iX = -1, $iY = -1 ) If $iX = -1 Then $iX = _WinAPI_GetMousePosX() If $iY = -1 Then $iY = _WinAPI_GetMousePosY() Local $tPOINT = DllStructCreate( "long;long" ) DllStructSetData( $tPOINT, 1, $iX ) DllStructSetData( $tPOINT, 2, $iY ) Local $tPOINT64 = DllStructCreate( "int64", DllStructGetPtr( $tPOINT ) ) Local $aResult = DllCall("user32.dll", "int", "MenuItemFromPoint", "hwnd", $hWnd, "handle", $hMenu, "int64", DllStructGetData( $tPOINT64, 1 ) ) If @error Then Return SetError(@error, @extended, -1) Return $aResult[0] EndFunc SciTE output: $hMenu OK $iItem OK $sText = &Undo $iIndex = 0 $sText = Cu&t $iIndex = 2 $sText = &Copy $iIndex = 3 $sText = &Paste $iIndex = 4 $sText = &Delete $iIndex = 5 $sText = Select &All $iIndex = 7 $sText = &Right to left Reading order $iIndex = 9 $sText = &Show Unicode control characters $iIndex = 10 $sText = &Insert Unicode control character $iIndex = 11 $sText = &Open IME $iIndex = 13 $sText = &Reconversion $iIndex = 14 $sText = My new menu item ; <<<<<<<< $iIndex = 15 Clicked item = 15 My new menu item clicked ; <<<<<<<< Once the new menu item is clicked, you can either execute a menu function directly, or you can open your own context menu with several items and possibly submenus. Both with straightforward AutoIt code. Keve, pixelsearch, mLipok and 2 others 3 2 Controls,  File Explorer,  ROT objects,  UI Automation,  Windows Message MonitorCompiled code: Accessing AutoIt variables,  DotNet.au3 UDF,  Using C# and VB codeShell menus: The Context menu,  The Favorites menu. Shell related: Control Panel,  System Image ListsGraphics related: Rubik's Cube,  OpenGL without external libraries,  Navigating in an image,  Non-rectangular selectionsListView controls: Colors and fonts,  Multi-line header,  Multi-line items,  Checkboxes and icons,  Incremental searchListView controls: Virtual ListViews,  Editing cells,  Data display functions Link to comment Share on other sites More sharing options...
mikell Posted September 24, 2020 Share Posted September 24, 2020 Depending on the OS this maybe needs to be adapted but a simple way to add an entry to the Windows context menu is to add a registry key key : HKEY_CLASSES_ROOT\*\shell\my_script\command REG_SZ value : C:\my_script.exe "%1" and to use $CmdLine[1] in your script 'my_script.exe' Â pixelsearch 1 Link to comment Share on other sites More sharing options...
Keve Posted September 24, 2020 Author Share Posted September 24, 2020 Lars, I believe you gave me exactly what I was after. I will play around with your example code. Mikell, that is an option I did not consider. Thanks for pointing it out! In general, I prefer not to mess around in the registry, hence such a solution eluded my thoughts. Link to comment Share on other sites More sharing options...
zeenmakr Posted September 25, 2020 Share Posted September 25, 2020 (edited) 14 hours ago, LarsJ said: It's not that hard. for you to say lol, this is neat, thanks @Keve just mashed up this to call some funcs concept, let me know what else you came up with. btw, so far it doesnt work on chrome, vlc expandcollapse popup#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y ; ---------------------------------------------------------- ; concept: Right-Click anywhere with popup Context Menu ; it it known that not all context menus are ; detectable and able to add new menu item. ; (e.g chrome, vlc and perhaps other apps) ; ---------------------------------------------------------- #include <Misc.au3> #include <GuiMenu.au3> #include <WindowsConstants.au3> #include <array.au3> Opt( "MustDeclareVars", 1 ) HotKeySet('{F1}', '_Exit') Func _Exit() Exit EndFunc Global $hMenu Global $sItemNames = "Added_xNew|Added_xOpen|Added_xCopy|Added_xPaste|Added_xSelect|Added_xClose" Global $aItemNames = StringSplit($sItemNames, '|', 2) Func Added_xNew($str) MsgBox(0, @ScriptLineNumber&': Added_xNew', $str,1) MsgBox(0, @ScriptLineNumber&': Added_xNew', $str) EndFunc Func Added_xOpen($str) MsgBox(0, @ScriptLineNumber&': Added_xOpen', $str,1) MsgBox(0, @ScriptLineNumber&': Added_xOpen', $str) EndFunc Func Added_xCopy($str) MsgBox(0, @ScriptLineNumber&': Added_xCopy', $str,1) MsgBox(0, @ScriptLineNumber&': Added_xCopy', $str) EndFunc Func Added_xPaste($str) MsgBox(0, @ScriptLineNumber&': Added_xPaste', $str,1) MsgBox(0, @ScriptLineNumber&': Added_xPaste', $str) EndFunc Func Added_xSelect($str) MsgBox(0, @ScriptLineNumber&': Added_xSelect', $str,1) MsgBox(0, @ScriptLineNumber&': Added_xSelect', $str) EndFunc Func Added_xClose($str) MsgBox(0, @ScriptLineNumber&': Added_xSelect', $str,1) MsgBox(0, @ScriptLineNumber&': Added_xSelect', $str) EndFunc MsgBox(0, @ScriptLineNumber&': Ready?', 'Right Click anywhere with a Popup Context Menu') While 1 ; wait for Right-Click to occur While Sleep(10) And Not _IsPressed( "02", "user32.dll" ) ;01=primary, 02=secondary mouse button WEnd _popup_contextMenuDetectionAndSelection() WEnd ; concept to call func based on newly added menu item selected Func _popup_contextMenuDetectionAndSelection() Local $timeout = 3 Local $init Local $iIsItem Local $iCount Local $jCount Local $iItem Local $jItem Local $sFuncName Local $aPos ConsoleWrite('!>!'&@ScriptLineNumber&': 1st Right-Clicked - Context Menu Pop-Up'&''&@CRLF) ;Read/Brown $aPos = MouseGetPos() ToolTip('Wait '&$timeout&'secs for New Context Menus to populate)', $aPos[0]-3, $aPos[1]-30) ; $timeout seconds to locate popup context menu existence $init = TimerInit() While TimerDiff($init) < ($timeout * 1000) $hMenu = GetMenuHandle() If $hMenu Then ExitLoop sleep(10) WEnd ConsoleWrite('+>+'&@ScriptLineNumber&': $hMenu - '&$hMenu&''&@CRLF) ;Green/Grey If Not $hMenu Then ToolTip('') Send('{ESC}') Local $sMsg = 'Note: doesnt work in Chrome/VLC'&@CRLF&@CRLF& _ 'Press Ok then Right-Click to try again' MsgBox(0, @ScriptLineNumber&': Error', $sMsg, 1) MsgBox(0, @ScriptLineNumber&': Error', $sMsg, 1) MsgBox(0, @ScriptLineNumber&': Error', $sMsg, 1) MsgBox(0, @ScriptLineNumber&': Error', $sMsg, 1) Else ; $timeout seconds to get inital menu items $init = TimerInit() While TimerDiff($init) < ($timeout * 1000) $iCount = _GUICtrlMenu_GetItemCount($hMenu) If $iCount Then ExitLoop sleep(10) WEnd ConsoleWrite('-->'&@ScriptLineNumber&': $iCount '&$iCount&''&@CRLF) ;Yellow/Orange $iIsItem = _AddMenuItem_toRightClickContextMenu() ConsoleWrite('-->'&@ScriptLineNumber&': $iIsItem '&$iIsItem&''&@CRLF) ;Yellow/Orange If Not $iIsItem Then ToolTip('>>> Fails to add NEW Menu - Click anywhere to continue then Right-Click to try again <<<', $aPos[0]-3, $aPos[1]-30) Else ToolTip('>>> Now select a NEW Menu below if every added correctly <<<', $aPos[0]-3, $aPos[1]-30) ; waiting for Left-Click (click a menu item) While Sleep(10) And Not _IsPressed( "01", "user32.dll" ) ;01=primary, 02=secondary mouse button WEnd ConsoleWrite('!>!'&@ScriptLineNumber&': 2nd Left-Clicked - Item Selected'&''&@CRLF) ;Read/Brown ToolTip('') ; $timeout seconds get total menu items (old + newly added) $init = TimerInit() While TimerDiff($init) < ($timeout * 1000) $jCount = _GUICtrlMenu_GetItemCount($hMenu) If $jCount Then ExitLoop sleep(10) WEnd ConsoleWrite('!>!'&@ScriptLineNumber&': $jCount - '&$jCount&''&@CRLF) ;Read/Brown If $jCount > 0 Then $iItem = _GUICtrlMenu_MenuItemFromPointEx( 0, $hMenu ) $jItem = $jCount - $iItem - 1 ConsoleWrite('-->'&@ScriptLineNumber&': $jItem '&$jItem&' = '&$jCount& ' - '& $iItem &@CRLF) ;Yellow/Orange ; only detect newly added menu items If $jItem <= UBound($aItemNames)-1 Then _ArrayReverse($aItemNames) $sFuncName = $aItemNames[$jCount - $iItem - 1] Call($sFuncName, '(init: '&$iCount-1& ') + (new: '& UBound($aItemNames) &') + (dividers: 2) = [totalMenus: '& $jCount-1 &']' &@CRLF&@CRLF& _ 'you selected item #'&$iItem &'/'& $jCount-1 &@CRLF&@CRLF& _ 'which executes func: ' &$sFuncName & '() that clicked on'&@CRLF&@CRLF& _ 'clicked: '& $jItem&' <= '& UBound($aItemNames)-1 &' :total custom menus') _ArrayReverse($aItemNames) EndIf Else MsgBox(0, @ScriptLineNumber&': Fails', 'No menu item was Clicked', 1) MsgBox(0, @ScriptLineNumber&': Fails', 'No menu item was Clicked', 1) EndIf EndIf EndIf EndFunc Func _AddMenuItem_toRightClickContextMenu() If Not $hMenu Then Return False Local $iItemNot = True If $hMenu Then ; Add new menu item Local $iItem $iItem = _GUICtrlMenu_AddMenuItem( $hMenu, '') ;add new divider If Not $iItem Then $iItemNot = False $iItem = _GUICtrlMenu_AddMenuItem( $hMenu, '') ;add new divider If Not $iItem Then $iItemNot = False For $i=0 To UBound($aItemNames)-1 $iItem = _GUICtrlMenu_AddMenuItem( $hMenu, StringReplace($aItemNames[$i], '_', ' ')) If Not $iItem Then $iItemNot = False Next EndIf Return $iItemNot EndFunc Func GetMenuHandle() Local $hDesktop = _WinAPI_GetDesktopWindow(), $i = 0 Local $hChild = _WinAPI_GetWindow( $hDesktop, $GW_CHILD ) While $hChild And $i < 50 If _WinAPI_GetClassName( $hChild ) = "#32768" Then ExitLoop $hChild = _WinAPI_GetWindow( $hChild, $GW_HWNDNEXT ) $i += 1 WEnd If $i = 50 Then Return 0 Local $hMenu = _SendMessage( $hChild, $MN_GETHMENU ) If $hMenu > 0 Then Return $hMenu Return 0 EndFunc Func _GUICtrlMenu_MenuItemFromPointEx( $hWnd, $hMenu, $iX = -1, $iY = -1 ) If $iX = -1 Then $iX = _WinAPI_GetMousePosX() If $iY = -1 Then $iY = _WinAPI_GetMousePosY() Local $tPOINT = DllStructCreate( "long;long" ) DllStructSetData( $tPOINT, 1, $iX ) DllStructSetData( $tPOINT, 2, $iY ) Local $tPOINT64 = DllStructCreate( "int64", DllStructGetPtr( $tPOINT ) ) Local $aResult = DllCall("user32.dll", "int", "MenuItemFromPoint", "hwnd", $hWnd, "handle", $hMenu, "int64", DllStructGetData( $tPOINT64, 1 ) ) If @error Then Return SetError(@error, @extended, -1) Return $aResult[0] EndFunc  here is an anomaly, right-click on SciTE title bar resulted in retaining added menu items. even after exited the code  Edited September 25, 2020 by zeenmakr updated w/anomaly Keve 1 Link to comment Share on other sites More sharing options...
zeenmakr Posted September 25, 2020 Share Posted September 25, 2020 12 hours ago, LarsJ said: ; Get menu handle Local $hMenu = GetMenuHandle() If Not $hMenu Then Return ConsoleWrite( "$hMenu ERR" & @CRLF ) do you know why it often fail to get $hMenu? giving extra 3 seconds for the context menu to fully populate before look for the handle doesn't help Link to comment Share on other sites More sharing options...
LarsJ Posted September 25, 2020 Share Posted September 25, 2020 Come on. It's a very small function. It must be possible to debug it. I had no errors. Controls,  File Explorer,  ROT objects,  UI Automation,  Windows Message MonitorCompiled code: Accessing AutoIt variables,  DotNet.au3 UDF,  Using C# and VB codeShell menus: The Context menu,  The Favorites menu. Shell related: Control Panel,  System Image ListsGraphics related: Rubik's Cube,  OpenGL without external libraries,  Navigating in an image,  Non-rectangular selectionsListView controls: Colors and fonts,  Multi-line header,  Multi-line items,  Checkboxes and icons,  Incremental searchListView controls: Virtual ListViews,  Editing cells,  Data display functions Link to comment Share on other sites More sharing options...
zeenmakr Posted September 25, 2020 Share Posted September 25, 2020 (edited) 5 hours ago, LarsJ said: I had no errors. it narrowed down to here, although class '#32768 is found' sometimes menu handle returns other time not, see screenshot expandcollapse popup; ;... ; While 1 ; wait for Right-Click to occur _MouseWaitPressed(02) _MouseWaitReleased(02) $hMenu = GetMenuHandle() Global $aPos = MouseGetPos() ToolTip($hMenu > 0 ? 'OK - '&$hMenu : 'ERROR - '&$hMenu, $aPos[0]-3, $aPos[1]-30) Local $sPrefix = @ScriptLineNumber&': $hMenu = '&$hMenu&' - ' ConsoleWrite($hMenu > 0 ? '>->'& $sPrefix &' OK' &@CRLF : '!>!'& $sPrefix &' ERROR' &@CRLF) ;Red/Brown ;~ _popup_contextMenuDetectionAndSelection() WEnd ; wait for key pressed Func _MouseWaitPressed($btn=01) ;01=primary, 02=secondary mouse button While Sleep(10) And Not _IsPressed($btn, "user32.dll" ) WEnd EndFunc ; wait for key to depress Func _MouseWaitReleased($btn=01) ;01=primary, 02=secondary mouse button While Sleep(250) And _IsPressed($btn, "user32.dll") WEnd EndFunc ;_EvenOrOdd Func _IsEven($n) If NOT Mod($n ,2) Then Return 1 ;even Else Return 0 ;odd EndIf EndFunc ; ;... ; Func GetMenuHandle() ConsoleWrite('!>!'&@ScriptLineNumber&':'&' ------------------------------------ '&@CRLF) ;Read/Brown Local $hDesktop = _WinAPI_GetDesktopWindow(), $i = 0 Local $hChild = _WinAPI_GetWindow( $hDesktop, $GW_CHILD ) While $hChild And $i < 100 Local $hMenuTmp = _SendMessage( $hChild, $MN_GETHMENU ) Local $clChild = _WinAPI_GetClassName( $hChild ) ;debuging If _IsEven($i) Then ConsoleWrite('>->'&@ScriptLineNumber&': 3-'&$i&' | parent - '&$hDesktop& _ ' | $hChild - '&$hChild&' = '&$clChild& _ ' <---$hMenuTmp ['&$hMenuTmp&']'& @CRLF) ;Blue/Cyan Else ConsoleWrite('-->'&@ScriptLineNumber&': 3-'&$i&' | parent - '&$hDesktop& _ ' | $hChild - '&$hChild&' = '&$clChild& _ ' <---$hMenuTmp ['&$hMenuTmp&']'& @CRLF) ;Yellow/Orange EndIf ; is context menu? If _WinAPI_GetClassName( $hChild ) = "#32768" Then ExitLoop $hChild = _WinAPI_GetWindow( $hChild, $GW_HWNDNEXT ) $i += 1 WEnd If $i = 100 Then Return 0 ; $timeout seconds - get $hMenu Local $timeout = 3 Local $init = TimerInit() While TimerDiff($init) < ($timeout * 1000) Local $hMenu = _SendMessage( $hChild, $MN_GETHMENU ) ; <--- found menu class #32768 but couldn retrieve the handle If $hMenu > 0 Then ExitLoop WEnd Local $sPrefix = @ScriptLineNumber&': 4-'&$i&' | '&_WinAPI_GetClassName( $hChild )&' = '& $hMenu ConsoleWrite($hMenu > 0 ? ' '& $sPrefix &' <<<=== WINNER ===' &@CRLF : '!>!'& $sPrefix &' <<<=== NO CONTEXT MENU ===' &@CRLF) ;Red/Brown If $hMenu > 0 Then Return $hMenu Return 0 EndFunc  Edited September 25, 2020 by zeenmakr Link to comment Share on other sites More sharing options...
LarsJ Posted September 25, 2020 Share Posted September 25, 2020 You can try if you can identify the menus with UI Automation code in Menus.7z in this post. The 7z file contains all necessary code. Run Example.au3 in SciTE with F5. zeenmakr 1 Controls,  File Explorer,  ROT objects,  UI Automation,  Windows Message MonitorCompiled code: Accessing AutoIt variables,  DotNet.au3 UDF,  Using C# and VB codeShell menus: The Context menu,  The Favorites menu. Shell related: Control Panel,  System Image ListsGraphics related: Rubik's Cube,  OpenGL without external libraries,  Navigating in an image,  Non-rectangular selectionsListView controls: Colors and fonts,  Multi-line header,  Multi-line items,  Checkboxes and icons,  Incremental searchListView controls: Virtual ListViews,  Editing cells,  Data display functions Link to comment Share on other sites More sharing options...
Keve Posted October 17, 2020 Author Share Posted October 17, 2020 Zeenmakr & Lars, you may have provided me with more than what I was looking for. I am still digesting it. But I find it very valuable. Very much appreciated! Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now