Jump to content
Sign in to follow this  
MDCT

Make context-menu dissapear on mouse-leave

Recommended Posts

MDCT

Hello,

Now I have question regarding context-menu. I have tried to search the forum, but could find the solution.

Basically, I want to create a context-menu that disappears when the mouse is not on the context-menu. Is it possible?

Below is a simple context-menu example. To show the context-menu, run the script and hold left-mouse-button for a few seconds.

#include <Constants.au3>
#include <MenuConstants.au3>
#include <Misc.au3>
#include <WindowsConstants.au3>
;Mainloop
    While 1
            if _IsPressed("01") Then
                for $x=1 to 10
                    if not _IsPressed("01") then ExitLoop
                    Sleep(50)
                Next
                if _IsPressed("01") then showPopup()
            EndIf
    WEnd

Func showPopup()
    $hDlg = GUICreate("", 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW); Create our temporary GUI
    $cDummy = GUICtrlCreateDummy(); Create a dummy control to hang a context menu on
    $hContextMenu = GUICtrlCreateContextMenu($cDummy); Create the context menu
    $exit=GUICtrlCreateMenuItem("Exit",$hContextMenu)
    GUISetState(@SW_SHOW,$hDlg)
    $rect = MouseGetPos()
    $nResult = _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($hContextMenu), $hDlg, $rect[0]-27, $rect[1]-12, 1, 1, 2)
    If $nResult = $exit Then exit
    GUIDelete($hDlg)
EndFunc

Func _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $iX = -1, $iY = -1, $iAlignX = 1, $iAlignY = 1, $iNotify = 0, $iButtons = 0)
    Local $iFlags, $aResult

    If $iX = -1 Then $iX = _WinAPI_GetMousePosX()
    If $iY = -1 Then $iY = _WinAPI_GetMousePosY()
    Switch $iAlignX
        Case 1
            $iFlags = BitOR($iFlags, $TPM_LEFTALIGN)
        Case 2
            $iFlags = BitOR($iFlags, $TPM_RIGHTALIGN)
        Case Else
            $iFlags = BitOR($iFlags, $TPM_CENTERALIGN)
    EndSwitch
    Switch $iAlignY
        Case 1
            $iFlags = BitOR($iFlags, $TPM_TOPALIGN)
        Case 2
            $iFlags = BitOR($iFlags, $TPM_VCENTERALIGN)
        Case Else
            $iFlags = BitOR($iFlags, $TPM_BOTTOMALIGN)
    EndSwitch
    If BitAND($iNotify, 1) <> 0 Then $iFlags = BitOR($iFlags, $TPM_NONOTIFY)
    If BitAND($iNotify, 2) <> 0 Then $iFlags = BitOR($iFlags, $TPM_RETURNCMD)
    Switch $iButtons
        Case 1
            $iFlags = BitOR($iFlags, $TPM_RIGHTBUTTON)
        Case Else
            $iFlags = BitOR($iFlags, $TPM_LEFTBUTTON)
    EndSwitch
    $aResult = DllCall("User32.dll", "int", "TrackPopupMenu", "hwnd", $hMenu, "int", $iFlags, "int", $iX, "int", $iY, "int", 0, "hwnd", $hWnd, "hwnd", 0)
    Return $aResult[0]
EndFunc  ;==>_GUICtrlMenu_TrackPopupMenu

By the time it goes to "_GUICtrlMenu_TrackPopupMenu", the script is paused. I did try using Adlib, if I did not made mistake on the code, Adlib also won't work.

Any idea on how to make the context-menu disappear on mouse-leave?

Thank you.

Share this post


Link to post
Share on other sites
MrCreatoR

I am not sure that this can work with seperate menu, but here is a gui main menu example:

#include <Constants.au3>
#include <MenuConstants.au3>
#include <Misc.au3>
#include <WindowsConstants.au3>
;

GUIRegisterMsg($WM_MENUSELECT, "MENU_HANDLER")

$hDlg = GUICreate("", 200, 120, 0, 0); Create our temporary GUI

$nDummy = GUICtrlCreateLabel("", 0, -100)

$hContextMenu = GUICtrlCreateMenu("Menu"); Create the context menu
$exit = GUICtrlCreateMenuItem("Exit", $hContextMenu)
GUISetState(@SW_SHOW, $hDlg)

While GUIGetMsg() <> -3
WEnd

Func MENU_HANDLER($hWndGUI, $MsgID, $wParam, $lParam)
    Local $iItemID = BitAND($wParam, 0xFFFF)
    
    If GUICtrlRead($iItemID) = "" Then ControlClick($hWndGUI, "", $nDummy)
    
    Return "GUI_RUNDEFMSG"
EndFunc

 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites
MDCT

Thanks, it's a nice idea, but I cannot seem to make this method to work without using the GUI. Is GUICtrlCreateDummy() the only way to create GUI-less contextmenu?

Share this post


Link to post
Share on other sites
ResNullius

Don't know if this will help, but Holger made a function to show a script's TrayMenu at the current mouse position. so it sort of emulates a context menu

http://www.autoitscript.com/forum/index.ph...st&p=202661

Edit: Actually, that might help with simulating a GUI-less context menu, but the biggest problem with menus (context and tray) is that the execution of the script is paused when the menus are visible.

That means no looping to check for active window changes or the like. Hmmm...

Edited by ResNullius

Share this post


Link to post
Share on other sites
MDCT

Thanks for trying to help, ResNullius. Just like you said, when "Func ShowTrayMenu()" is executed, it shows the tray and then pauses the script.

I think it can be done by using 2 scripts. One script is to create the menu, the other is to detect mouse by getting window classname that's on the mouse position. But it's not a pretty solution.

EDIT:

Well, even it's not a pretty solution, I did it anyway.

Here's the first script that needs to be compiled and run as exe (because scite cannot execute 2 scripts).

#include <WinAPI.au3>

global const $TITLE_SENDER = '#Sender'
global const $TITLE_RECEIVER = '#Reseiver'
global const $WM_COPYDATA = 0x004A

global $sMsg, $Dummy, $Flag = 0
;_Receiver()
GUICreate($TITLE_RECEIVER)
GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')

While 1
    Sleep(50)
    if $Flag = 1 then
        $X=MouseGetPos()
        $hPoint = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $X[0], "int", $X[1])
        tooltip(_WinAPI_GetClassName($hPoint[0]),0,0)
        While _WinAPI_GetClassName($hPoint[0]) <> "#32768" 
            $X=MouseGetPos()
            $hPoint = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $X[0], "int", $X[1])
            Sleep(16)
        WEnd
        While _WinAPI_GetClassName($hPoint[0]) = "#32768" 
            $X=MouseGetPos()
            $hPoint = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $X[0], "int", $X[1])
            Sleep(16)
        WEnd
        if _WinAPI_GetClassName($hPoint[0]) <> "#32768" then msgbox(0,0,"Out")
        $Flag = 0
    endif
    Sleep(50)   
WEnd

func _WM_COPYDATA($hWnd, $msgID, $wParam, $lParam)
   
    local $tCOPYDATA = DllStructCreate('dword;dword;ptr', $lParam)
    local $tMsg = DllStructCreate('char[' & DllStructGetData($tCOPYDATA, 2) & ']', DllStructGetData($tCOPYDATA, 3))
   
    $sMsg = DllStructGetData($tMsg, 1)
   
; For Sender   
    GUICtrlSendToDummy($Dummy)
   
; For Receiver
    $Flag = 1
   
    return 0
endfunc; _WM_COPYDATA

Here is the one that can be executed by using Scite. And don't forget to hold left-mouse-button to show the contextmenu.

#include <Constants.au3>
#include <MenuConstants.au3>
#include <Misc.au3>
#include <WindowsConstants.au3>

global const $TITLE_SENDER = '#Sender'
global const $TITLE_RECEIVER = '#Reseiver'
;global const $WM_COPYDATA = 0x004A

global $sMsg, $Dummy, $Flag = 0
;Mainloop
    While 1
            Sleep(16)
            if _IsPressed("01") Then
                for $x=1 to 10
                    if not _IsPressed("01") then ExitLoop
                    Sleep(50)
                Next
                if _IsPressed("01") then
                    _SendData(WinGetHandle($TITLE_RECEIVER), "1")
                    showPopup()
                EndIf
            EndIf
            Sleep(16)
    WEnd

Func showPopup()
    $hDlg = GUICreate("", 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW); Create our temporary GUI
    $cDummy = GUICtrlCreateDummy(); Create a dummy control to hang a context menu on
    $hContextMenu = GUICtrlCreateContextMenu($cDummy); Create the context menu
    $exit=GUICtrlCreateMenuItem("Exit",$hContextMenu)
    GUISetState(@SW_SHOW,$hDlg)
    $rect = MouseGetPos()
    $nResult = _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($hContextMenu), $hDlg, $rect[0]-27, $rect[1]-12, 1, 1, 2)
    If $nResult = $exit Then exit
    GUIDelete($hDlg)
EndFunc

Func _GUICtrlMenu_TrackPopupMenu($hMenu, $hWnd, $iX = -1, $iY = -1, $iAlignX = 1, $iAlignY = 1, $iNotify = 0, $iButtons = 0)
    Local $iFlags, $aResult

    If $iX = -1 Then $iX = _WinAPI_GetMousePosX()
    If $iY = -1 Then $iY = _WinAPI_GetMousePosY()
    Switch $iAlignX
        Case 1
            $iFlags = BitOR($iFlags, $TPM_LEFTALIGN)
        Case 2
            $iFlags = BitOR($iFlags, $TPM_RIGHTALIGN)
        Case Else
            $iFlags = BitOR($iFlags, $TPM_CENTERALIGN)
    EndSwitch
    Switch $iAlignY
        Case 1
            $iFlags = BitOR($iFlags, $TPM_TOPALIGN)
        Case 2
            $iFlags = BitOR($iFlags, $TPM_VCENTERALIGN)
        Case Else
            $iFlags = BitOR($iFlags, $TPM_BOTTOMALIGN)
    EndSwitch
    If BitAND($iNotify, 1) <> 0 Then $iFlags = BitOR($iFlags, $TPM_NONOTIFY)
    If BitAND($iNotify, 2) <> 0 Then $iFlags = BitOR($iFlags, $TPM_RETURNCMD)
    Switch $iButtons
        Case 1
            $iFlags = BitOR($iFlags, $TPM_RIGHTBUTTON)
        Case Else
            $iFlags = BitOR($iFlags, $TPM_LEFTBUTTON)
    EndSwitch
    $aResult = DllCall("User32.dll", "int", "TrackPopupMenu", "hwnd", $hMenu, "int", $iFlags, "int", $iX, "int", $iY, "int", 0, "hwnd", $hWnd, "hwnd", 0)
    Return $aResult[0]
EndFunc ;==>_GUICtrlMenu_TrackPopupMenu

func _SendData($hWnd, $sData)
   
    local $tCOPYDATA, $tMsg
   
    $tMsg = DllStructCreate('char[' & StringLen($sData) + 1 & ']')
    DllStructSetData($tMsg, 1, $sData)
    $tCOPYDATA = DllStructCreate('dword;dword;ptr')
    DllStructSetData($tCOPYDATA, 2, StringLen($sData) + 1)
    DllStructSetData($tCOPYDATA, 3, DllStructGetPtr($tMsg))
    $Ret = DllCall('user32.dll', 'lparam', 'SendMessage', 'hwnd', $hWnd, 'int', $WM_COPYDATA, 'wparam', 0, 'lparam', DllStructGetPtr($tCOPYDATA))
    if (@error) or ($Ret[0] = -1) then
        return 0
    endif
    return 1
endfunc; _SendData

Basically, the second script will send message to the first script after it creates context-menu. the first script will detect the window class on mouse over.

Anyone has other idea?

Edited by MDCT

Share this post


Link to post
Share on other sites
MrCreatoR

Try this:

#include <Constants.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <GUIMenu.au3>
#include <Misc.au3>
#include <Timers.au3>
;

Global $hUser32Dll = DllOpen("User32.dll")
Global $iHideMenuDelay = 10

While 1
    If _IsPressed("01", $hUser32Dll) Then
        For $x = 1 To 10
            If Not _IsPressed("01", $hUser32Dll) Then ExitLoop
            Sleep(50)
        Next
        
        If _IsPressed("01", $hUser32Dll) Then _ShowPopupMenu_Proc()
    Else
        Sleep(100)
    EndIf
WEnd

Func _ShowPopupMenu_Proc()
    Local $hDlg, $cDummy, $nContextMenu, $hContextMenu, $nHide_MItem, $nExit_MItem, $hTimer, $aMousePos, $nResult
    
    $hDlg = GUICreate("", 1, 1, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW); Create our temporary GUI
    
    $cDummy = GUICtrlCreateDummy(); Create a dummy control to hang a context menu on
    
    $nContextMenu = GUICtrlCreateContextMenu($cDummy); Create the context menu
    $hContextMenu = GUICtrlGetHandle($nContextMenu)
    
    $nHide_MItem = GUICtrlCreateMenuItem("Hide", $nContextMenu)
    $nShowMsg_MItem = GUICtrlCreateMenuItem("Show some message", $nContextMenu)
    GUICtrlCreateMenuItem("", $nContextMenu)
    $nExit_MItem = GUICtrlCreateMenuItem("Exit", $nContextMenu)
    
    GUISetState(@SW_SHOW, $hDlg)
    
    $hTimer = _Timer_SetTimer($hDlg, $iHideMenuDelay, "_CheckHoverMenu_Proc")
    
    $aMousePos = MouseGetPos()
    $nResult = _GUICtrlMenu_TrackPopupMenu($hContextMenu, $hDlg, $aMousePos[0] - 27, $aMousePos[1] - 12, 1, 1, 2)
    
    _Timer_KillTimer($hDlg, $hTimer)
    
    Switch $nResult
        Case $nShowMsg_MItem
            MsgBox(64, 'Title', 'My Message')
        Case $nHide_MItem
            ;hm... it's already hidden :D 
        Case $nExit_MItem
            DllClose($hUser32Dll)
            Exit
    EndSwitch
    
    GUIDelete($hDlg)
EndFunc

Func _CheckHoverMenu_Proc($hWnd, $Msg, $iIDTimer, $dwTime)
    Local $stPoint = DllStructCreate("int X;int Y")
    Local $aMousePos = MouseGetPos()
    
    DllStructSetData($stPoint, "X", $aMousePos[0])
    DllStructSetData($stPoint, "Y", $aMousePos[1])
    
    Local $hWndFromPoint = _WinAPI_WindowFromPoint($stPoint)
    
    If _WinAPI_GetClassName($hWndFromPoint) <> "#32768" Then Send("{ESC}")
EndFunc
Edited by MrCreatoR

 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites
MDCT

Try this:

This is brilliant, MrCreatoR. It works very nice and efficient, just what I wanted. Thank you again for your help.

EDIT:

I don't understand about $iHideMenuDelay, it doesn't seem to affect the context-menu. Whatever it is, I'm happy with the function. Thanks.

Edited by MDCT

Share this post


Link to post
Share on other sites
MrCreatoR

I don't understand about $iHideMenuDelay, it doesn't seem to affect the context-menu

It affects on the time that needed before next function call (to check the menu hovering). In other words - It's a delay before menu will dissapear :D

 

Spoiler

Using OS: Win 7 Professional, Using AutoIt Ver(s): 3.3.6.1 / 3.3.8.1

AutoIt_Rus_Community.png AutoIt Russian Community

My Work...

Spoiler

AutoIt_Icon_small.pngProjects: ATT - Application Translate Tool {new}| BlockIt - Block files & folders {new}| SIP - Selected Image Preview {new}| SISCABMAN - SciTE Abbreviations Manager {new}| AutoIt Path Switcher | AutoIt Menu for Opera! | YouTube Download Center! | Desktop Icons Restorator | Math Tasks | KeyBoard & Mouse Cleaner | CaptureIt - Capture Images Utility | CheckFileSize Program

AutoIt_Icon_small.pngUDFs: OnAutoItErrorRegister - Handle AutoIt critical errors {new}| AutoIt Syntax Highlight {new}| Opera Library! | Winamp Library | GetFolderToMenu | Custom_InputBox()! | _FileRun UDF | _CheckInput() UDF | _GUIInputSetOnlyNumbers() UDF | _FileGetValidName() UDF | _GUICtrlCreateRadioCBox UDF | _GuiCreateGrid() | _PathSplitByRegExp() | _GUICtrlListView_MoveItems - UDF | GUICtrlSetOnHover_UDF! | _ControlTab UDF! | _MouseSetOnEvent() UDF! | _ProcessListEx - UDF | GUICtrl_SetResizing - UDF! | Mod. for _IniString UDFs | _StringStripChars UDF | _ColorIsDarkShade UDF | _ColorConvertValue UDF | _GUICtrlTab_CoverBackground | CUI_App_UDF | _IncludeScripts UDF | _AutoIt3ExecuteCode | _DragList UDF | Mod. for _ListView_Progress | _ListView_SysLink | _GenerateRandomNumbers | _BlockInputEx | _IsPressedEx | OnAutoItExit Handler | _GUICtrlCreateTFLabel UDF | WinControlSetEvent UDF | Mod. for _DirGetSizeEx UDF
 
AutoIt_Icon_small.pngExamples: 
ScreenSaver Demo - Matrix included | Gui Drag Without pause the script | _WinAttach()! | Turn Off/On Monitor | ComboBox Handler Example | Mod. for "Thinking Box" | Cool "About" Box | TasksBar Imitation Demo

Like the Projects/UDFs/Examples? Please rate the topic (up-right corner of the post header: Rating AutoIt_Rating.gif)

* === My topics === *

==================================================
My_Userbar.gif
==================================================

 

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Share this post


Link to post
Share on other sites
MDCT

It affects on the time that needed before next function call (to check the menu hovering). In other words - It's a delay before menu will dissapear :D

Okay, got that. I tried it between 10 and 100, no wonder it doesn't show any difference.

Thanks a lot, man.

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.