AutoHotkey Community

It is currently May 26th, 2012, 4:28 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 24 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: March 25th, 2009, 12:51 pm 
Offline

Joined: December 3rd, 2008, 5:37 am
Posts: 158
Location: chennai,india
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.....


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 12:43 am 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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 March 26th, 2009, 2:01 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 7:41 am 
Offline

Joined: December 3rd, 2008, 5:37 am
Posts: 158
Location: chennai,india
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 9:58 am 
Offline

Joined: March 26th, 2009, 9:50 am
Posts: 2
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 1:57 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 2:03 pm 
Offline

Joined: December 3rd, 2008, 5:37 am
Posts: 158
Location: chennai,india
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 2:12 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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 March 26th, 2009, 2:43 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 2:43 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 2:49 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
Search for MN_GETHMENU.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 3:06 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 3:16 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
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
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 3:39 pm 
Offline

Joined: November 4th, 2008, 9:23 am
Posts: 1045
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 26th, 2009, 4:44 pm 
Offline

Joined: December 3rd, 2008, 5:37 am
Posts: 158
Location: chennai,india
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


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 27th, 2009, 12:19 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 27th, 2009, 12:22 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
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.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 24 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: BrandonHotkey, SKAN, tterB and 16 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group