 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
chandru155
Joined: 03 Dec 2008 Posts: 158 Location: chennai,india
|
Posted: Wed Mar 25, 2009 11:51 am Post subject: How to get PopUp menu Items |
|
|
| I want to write a program which tell whenever a new pop up menu is created in our computer and also tells the PopUp menu items present in that PopUp menu. For eg, if we right click means, iwe ll get some popup menu. My program have to tell that one pop up menu is appeared and also it has to tell the items present in that popup menu. Any help plz..... |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Wed Mar 25, 2009 11:43 pm Post subject: |
|
|
Is the menu created by your AHK script - or just any menu?
If the menu in created by your script, that's an easier task (see below code). Whenever you open the menu, you can iterate through it's contents with the below code.
If the menu isn't created by your script, I'm not sure of how to do it.
| Code: | #NoEnv ;I have no idea why this is required, but it is
;Iterates through an AHK menu
MenuName := "tray"
hMenu := MI_getMenuHandle(MenuName)
Loop, % DllCall("GetMenuItemCount", "uint", hMenu)
{
itemText := Menu_getMenuString(hMenu, A_Index)
MsgBox, % MenuName . " -> Item" . A_Index . ": " itemText
}
;Copied directly from Lexikos' Menu Icons
; Gets a menu handle from a menu name.
; Adapted from Shimanov's Menu_AssignBitmap()
; http://www.autohotkey.com/forum/topic7526.html
MI_GetMenuHandle(menu_name)
{
static h_menuDummy
; v2.2: Check for !h_menuDummy instead of h_menuDummy="" in case init failed last time.
If !h_menuDummy
{
Menu, menuDummy, Add
Menu, menuDummy, DeleteAll
Gui, 99:Menu, menuDummy
; v2.2: Use LastFound method instead of window title. [Thanks animeaime.]
Gui, 99:+LastFound
h_menuDummy := DllCall("GetMenu", "uint", WinExist())
Gui, 99:Menu
Gui, 99:Destroy
; v2.2: Return only after cleaning up. [Thanks animeaime.]
if !h_menuDummy
return 0
}
Menu, menuDummy, Add, :%menu_name%
h_menu := DllCall( "GetSubMenu", "uint", h_menuDummy, "int", 0 )
DllCall( "RemoveMenu", "uint", h_menuDummy, "uint", 0, "uint", 0x400 )
Menu, menuDummy, Delete, :%menu_name%
return h_menu
}
;copied directly from my menu wrapper library (with slight modifications)
Menu_getMenuString(hMenu, Position)
{
;implemented specifically for getting the MenuItemName for a menu item
static alreadyDone, ReturnValue
;260 is the largest size a menu item can be
if (!alreadyDone)
{
alreadyDone := true
VarSetCapacity(ReturnValue, 260)
}
if Position is integer
{
;convert from one-based to zero-based index
Position--
ByPosition := 0x400 ;MF_BYPOSITION
}
else
return
DllCall("GetMenuString"
, "uInt", hMenu
, "uInt", Position
, "uInt", &ReturnValue
, "int", 261 ;260 (max size) + 1 (for null terminator)
, "uInt", ByPosition)
return ReturnValue
}
|
_________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts.
Last edited by animeaime on Thu Mar 26, 2009 1:01 pm; edited 1 time in total |
|
| Back to top |
|
 |
chandru155
Joined: 03 Dec 2008 Posts: 158 Location: chennai,india
|
Posted: Thu Mar 26, 2009 6:41 am Post subject: |
|
|
| Thanks. But i want to get non ahk menu text. Anyway, thanks for you code. I want this because, i am doing windows narrator like program. |
|
| Back to top |
|
 |
R1688R
Joined: 26 Mar 2009 Posts: 2
|
Posted: Thu Mar 26, 2009 8:58 am Post subject: |
|
|
I am finding the answer too.
Can we use "control" or "send message" method to get the same effect like click the popup menu item or press the hotkey ect. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 26, 2009 12:57 pm Post subject: |
|
|
If you can retrieve the hwnd for the menu, then the same loop can be used. Here is a link to the Menu API. Instead of the using the HWND for an AHK menu, use the context menu's HWND. However, I don't know how to retrieve the context menu's HWND.
Here is another iterate script. It iterates through the file menu in notepad - maybe it will spark an idea.
| Code: | #NoEnv ;I have no idea why this is required, but it is
;Iterates through a menu
Run, Notepad.exe
WinWait, Untitled - Notepad
WinWaitActive
;stores the menu bar
hMenuBar := DllCall("GetMenu", "uint", WinExist())
MsgBox, % "Number of menus on Menu bar: " . DllCall("GetMenuItemCount", "uint", hMenuBar)
;sub menu to iterate
SubMenuIndex := 1
MenuName := Menu_getMenuString(hMenuBar, SubMenuIndex)
;the menu (really a submenu of the menu bar) to iterate
;-1 converts position from one-based to zero-based index
hMenu := DllCall("GetSubMenu", "uint", hMenuBar, "int", SubMenuIndex - 1)
Loop, % DllCall("GetMenuItemCount", "uint", hMenu)
{
itemText := Menu_getMenuString(hMenu, A_Index)
MsgBox, % MenuName . " -> Item" . A_Index . ": " itemText
}
return
;copied directly from my menu wrapper library (with slight modifications)
Menu_getMenuString(hMenu, Position)
{
;implemented specifically for getting the MenuItemName for a menu item
static alreadyDone, ReturnValue
;260 is the largest size a menu item can be
if (!alreadyDone)
{
alreadyDone := true
VarSetCapacity(ReturnValue, 260)
}
if Position is integer
{
;convert from one-based to zero-based index
Position--
ByPosition := 0x400 ;MF_BYPOSITION
}
else
return
DllCall("GetMenuString"
, "uInt", hMenu
, "uInt", Position
, "uInt", &ReturnValue
, "int", 261 ;260 (max size) + 1 (for null terminator)
, "uInt", ByPosition)
return ReturnValue
}
|
_________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
chandru155
Joined: 03 Dec 2008 Posts: 158 Location: chennai,india
|
Posted: Thu Mar 26, 2009 1:03 pm Post subject: |
|
|
| Can you give me a example program to get text of pop up menu, when ever the user right click. Because windows pop up menu will appear whenever we right click the mouse. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 26, 2009 1:12 pm Post subject: |
|
|
I'm not sure how to get the menu handle (hMenu) for the context menu... if you can find someone that's knows how to get it, the above code will work. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts.
Last edited by animeaime on Thu Mar 26, 2009 1:43 pm; edited 2 times in total |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 26, 2009 1:43 pm Post subject: |
|
|
| R1688R wrote: | I am finding the answer too.
Can we use "control" or "send message" method to get the same effect like click the popup menu item or press the hotkey ect. |
This example clicks File -> Open in Notepad.
Replace the hMenu with the handle for the context menu (not sure how to retrieve it, though).
| Code: | ; #NoEnv ;I have no idea why this is required, but it is
;Iterates through a menu
Run, Notepad.exe
WinWait, Untitled - Notepad
WinWaitActive
;stores the unique ID (HWND) for the window (used later)
WinGet, WinHWND, ID
;stores the menu bar
hMenuBar := DllCall("GetMenu", "uint", WinExist())
;sub menu to iterate
SubMenuIndex := 1 ;the file menu
;the menu (really a submenu of the menu bar) to iterate
;-1 converts position from one-based to zero-based index
hMenu := DllCall("GetSubMenu", "uint", hMenuBar, "int", SubMenuIndex - 1)
MenuItemIndex := 2 ;Open
;retrieves the menu item handle for the desired item
hMenuItem := DllCall("GetMenuItemID", "uint", hMenu, "int", MenuItemIndex - 1)
;"Select" File -> Open
PostMessage, 0x111, %hMenuItem% ,0,, ahk_id %WinHWND% ; 0x111 is WM_COMMAND
return |
Or, you could use the arrow keys to select an item.
This example clicks the "paste" option, fourth in the context menu (excluding separators). It pastes "Hello World!" Don't worry, the previous clipboard is restored.
| Code: | ;clicks the "paste" option on the context menu (option 4 - excluding the separators)
Position := 4
Run, Notepad.exe
WinWait, Untitled - Notepad
;it doesn't use the last found window here (for me, at least)
WinWaitActive, Untitled - Notepad
;taken from the ClipboardAll example (see http://www.autohotkey.com/docs/misc/Clipboard.htm#ClipboardAll)
; Save the entire clipboard to a variable of your choice.
ClipSaved := ClipboardAll
; ... here make temporary use of the clipboard, such as for pasting Unicode text via Transform Unicode ...
Clipboard := "Hello World!"
;open the context menu
;(no control is listed - sent to the top level)
;(makes use of the last found window)
ControlClick, , , , Right
;press the down arrow until we have the item (Position times)
;so Position = 1 will press the down arrow 1 time (to select the first item)
Send, {Down %Position%}
;wait before making the selection (for demonstration)
Sleep, 2000
;Press Enter
Send, {Enter}
; Restore the original clipboard. Note the use of Clipboard (not ClipboardAll).
Clipboard := ClipSaved
; Free the memory in case the clipboard was very large.
; not necessary because the program is about to close (and it will be freed automatically then)
; ClipSaved =
|
_________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Mar 26, 2009 1:49 pm Post subject: |
|
|
| Search for MN_GETHMENU. |
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 26, 2009 2:06 pm Post subject: |
|
|
It's not working for me - MN_GETHMENU.
| Code: | Run, Notepad.exe
WinWait, Untitled - Notepad
WinWaitActive
;stores the unique ID (HWND) for the window (used later)
WinGet, WinHWND, ID
;Send the message to the control
ControlGet, Edit1_HWND, hwnd, , Edit1
;MN_GETHMENU = 0x1E1
SendMessage, 0x1E1, 0, 0, , ahk_id %Edit1_HWND%
hMenuTry1 := ErrorLevel
;Send the message to the window
;MN_GETHMENU = 0x1E1
SendMessage, 0x1E1, 0, 0, , ahk_id %WinHWND%
hMenuTry2 := ErrorLevel
;Send to the window (via Last Found Window)
;MN_GETHMENU = 0x1E1
SendMessage, 0x1E1, 0, 0
hMenuTry3 := ErrorLevel
MsgBox, % hMenuBar . " " . hMenuTry1 . " " . hMenuTry2 . " " . hMenuTry3 |
_________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Mar 26, 2009 2:16 pm Post subject: |
|
|
I meant search in the forum. For example, this is the code written by me. Just bring up any menu then dismiss it.
| Code: | #SingleInstance, Force
SetBatchLInes, -1
WinWait, ahk_class #32768
SendMessage, 0x1E1, 0, 0 ; MN_GETHMENU
hMenu := ErrorLevel
sContents := GetMenu(hMenu)
WinWaitClose
MsgBox, % sContents
GetMenu(hMenu)
{
Loop, % DllCall("GetMenuItemCount", "Uint", hMenu)
{
idx := A_Index - 1
idn := DllCall("GetMenuItemID", "Uint", hMenu, "int", idx)
nSize++ := DllCall("GetMenuString", "Uint", hMenu, "int", idx, "Uint", 0, "int", 0, "Uint", 0x400)
VarSetCapacity(sString, nSize)
DllCall("GetMenuString", "Uint", hMenu, "int", idx, "str", sString, "int", nSize, "Uint", 0x400) ;MF_BYPOSITION
If !sString
sString := "---------------------------------------"
sContents .= idx . " : " . idn . A_Tab . A_Tab . sString . "`n"
If (idn = -1) && (hSubMenu := DllCall("GetSubMenu", "Uint", hMenu, "int", idx))
sContents .= GetMenu(hSubMenu)
}
Return sContents
}
|
|
|
| Back to top |
|
 |
animeaime
Joined: 04 Nov 2008 Posts: 1045
|
Posted: Thu Mar 26, 2009 2:39 pm Post subject: |
|
|
Wow! Nice.
So the context menu has it's own window? How do you get the hwnd for the context menu window of an external program... I tried in Notepad and checked Window Spy, but the ControlNN nor the Window change when over a context menu versus the window. _________________ As always, if you have any further questions, don't hesitate to ask.
Add OOP to your scripts via the Class Library. Check out my scripts. |
|
| Back to top |
|
 |
chandru155
Joined: 03 Dec 2008 Posts: 158 Location: chennai,india
|
Posted: Thu Mar 26, 2009 3:44 pm Post subject: |
|
|
| Thanks sean. Your code is super. One more small HELP. Can you change your code, so that it records the all menu items(not sub menu items) in a text file when it is appeared. And also, it should record in another text file whenever a sub menu is created |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Mar 26, 2009 11:19 pm Post subject: |
|
|
| animeaime wrote: | | So the context menu has it's own window? How do you get the hwnd for the context menu window of an external program... | #32768 is the class name of the Windows standard menu. BTW, it implies that this technique will only work with Windows standard menus, but not with non-standard menus like the ones of firefox etc. |
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Thu Mar 26, 2009 11:22 pm Post subject: |
|
|
| chandru155 wrote: | | Can you change your code, so that it records the all menu items(not sub menu items) in a text file when it is appeared. | You can tweak it as whatever you like. Although I can imagine a potential problem to filter out already shown menus, I suppose it's not unsurmountable. The simplest solution may be to use SKAN's ShellHook code. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|