Sign in to follow this  
Followers 0
Nikolas92

How to check is context menu under mouse?

8 posts in this topic

Hi, explorer context menu sometimes gets stuck and I would like to kill it, but I dont know how to check is context menu under mouse? Can someone show me some       example?

#NoTrayIcon
#include <Misc.au3>
#include <WinAPISys.au3>

Opt("WinWaitDelay", 0)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)
Opt("MouseClickDragDelay", 0)
Opt("SendKeyDelay", 0)
Opt("SendKeyDownDelay", 0)

Global $hNTDll = DllOpen("ntdll.dll")
Local $left, $right, $top, $bottom, $MouseX, $MouseY

While 1
   $hWnd = WinWait('[CLASS:#32768]')
   $aPos = WinGetPos($hWnd)
   Do
      _HighPrecisionSleep(0.1)
   until _WinAPI_GetAsyncKeyState(0x01) = False and _WinAPI_GetAsyncKeyState(0x02) = False
   If IsArray($aPos) Then
   While 1
      _HighPrecisionSleep(0.1)
      If _IsPressed(01) Or _IsPressed(02) Then
         Do
            _HighPrecisionSleep(0.1)
         until _WinAPI_GetAsyncKeyState(0x01) = False and _WinAPI_GetAsyncKeyState(0x02) = False
         $MousePos = MouseGetPos()
         If $aPos[0] < $MousePos[0] And $MousePos[0] < $aPos[0] + $aPos[2] And $aPos[1] < $MousePos[1] And $MousePos[1] < $aPos[1] + $aPos[3] Then
            ; Mouse cursor is still inside window.
            If not WinExists($hWnd) Then ExitLoop
         Else
            WinKill($hWnd)
            ExitLoop
         EndIf
      EndIf
   WEnd
   EndIf
WEnd

Func _HighPrecisionSleep($iMicroSeconds)
   Local $hStruct = DllStructCreate("int64 time;")
   DllStructSetData($hStruct, "time", -1 * ($iMicroSeconds * 10))
   DllCall($hNTDll, "dword", "NtDelayExecution", "int", 0, "ptr", DllStructGetPtr($hStruct))
EndFunc   ;==>_HighPrecisionSleep

 

Share this post


Link to post
Share on other sites



Dont know why I cant edit previous post, but code I posted above doesnt work correctly in case of submenus and usually kills menu when clicking on submenu item.

Share this post


Link to post
Share on other sites
MouseClick("menu")
Send("{DOWN}")
$Last = ""
While Sleep(500)
    $HighlightedMenu = GetTextFromMenuContext()
    If $HighlightedMenu <> $Last Then
        ConsoleWrite($HighlightedMenu & @CRLF)
        $Last = $HighlightedMenu
    EndIf
WEnd

Func GetTextFromMenuContext()
    Local $hWnd, $hMenu, $isMenu, $hMenuCount, $hMenuText

    $hWnd = WinGetHandle("[CLASS:#32768]")
    $hMenu = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", 0x01E1, "wparam", 0, "lparam", 0)

    $isMenu = DllCall("user32.dll", "bool", "IsMenu", "handle", $hMenu[0])
    If $isMenu[0] Then
        $hMenuCount = DllCall("user32.dll", "int", "GetMenuItemCount", "handle", $hMenu[0])
        For $iItem = 0 To $hMenuCount[0] Step +1
            $hMenuText = DllCall("user32.dll", "int", "GetMenuStringW", "handle", $hMenu[0], "uint", $iItem, "wstr", "", "int", 4096, "uint", 0x400)
            $bMenuHighlight = InfoMenu($hMenu[0], $iItem)
            If $bMenuHighlight = True Then Return $hMenuText[3]
        Next
    EndIf
EndFunc   ;==>GetTextFromMenuContext

Func InfoMenu($hMenu, $iItem)
    Local Const $MFS_HILITE = 0x00000080
    Local $tInfo = DllStructCreate("uint Size;uint Mask;uint Type;uint State;uint ID;handle SubMenu;" & _
            "handle BmpChecked;handle BmpUnchecked;ulong_ptr ItemData;ptr TypeData;uint CCH;handle BmpItem")
    DllStructSetData($tInfo, "Size", DllStructGetSize($tInfo))
    DllStructSetData($tInfo, "Mask", 0x3F)
    DllCall("user32.dll", "bool", "GetMenuItemInfo", "handle", $hMenu, "uint", $iItem, "bool", True, "struct*", $tInfo)
    $aResult = BitAND(DllStructGetData($tInfo, "State"), $MFS_HILITE) <> 0
    Return $aResult
EndFunc   ;==>InfoMenu

Or better: _GUICtrlMenu_GetItemHighlighted

Share this post


Link to post
Share on other sites

Hi ThioFoX, thanks for answering, but it looks that there is no need to check for what context menu item is under mouse since this seems to work:

; www.autoitscript.com/forum/topic/114628-capture-the-windows-events/
; www.autoitscript.com/forum/topic/56536-easy-shell-hooking-example/?page=2

#NoTrayIcon
#include<WinAPISys.au3>
#include <Misc.au3>

Opt("WinWaitDelay", 0)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)
Opt("MouseClickDragDelay", 0)
Opt("SendKeyDelay", 0)
Opt("SendKeyDownDelay", 0)
Opt("WinTitleMatchMode", 3)

Global $ContextMenu = ''
Global $hGUI = GUICreate('')
GUIRegisterMsg(_WinAPI_RegisterWindowMessage('SHELLHOOK'), 'WM_SHELLHOOK')
_WinAPI_RegisterShellHookWindow($hGUI)
$hHookFunc = DllCallbackRegister('_WinEventProc', 'none', 'ptr;uint;hwnd;int;int;uint;uint')
$hWinHook = _WinAPI_SetWinEventHook($EVENT_SYSTEM_MENUPOPUPSTART, $EVENT_SYSTEM_DIALOGSTART, DllCallbackGetPtr($hHookFunc))

While 1
   Sleep(1000)
WEnd

Func WM_SHELLHOOK($hWnd, $iMsg, $wParam, $lParam)
   If $wParam = $HSHELL_WINDOWACTIVATED Or $wParam = $HSHELL_RUDEAPPACTIVATED Then
      $WindowHandle = $lParam
      $WindowClass = _WinAPI_GetClassName($WindowHandle)
      If $WindowClass = '#32768' Then
         $ContextMenu = $WindowHandle
      ElseIf $WindowClass <> '#32768' And $ContextMenu <> '' And (_IsPressed(01) Or _IsPressed(02)) Then
         WinKill($ContextMenu)
      EndIf
   EndIf
EndFunc

Func _WinEventProc($hHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iEventThread, $imsEventTime)
   $WindowHandle = $hWnd
   $WindowClass = _WinAPI_GetClassName($WindowHandle)
   If $WindowClass = '#32768' Then
      $ContextMenu = $WindowHandle
   ElseIf $WindowClass <> '#32768' And $ContextMenu <> '' And (_IsPressed(01) Or _IsPressed(02)) Then
      WinKill($ContextMenu)
   EndIf
EndFunc

 

Share this post


Link to post
Share on other sites
; www.autoitscript.com/forum/topic/114628-capture-the-windows-events/
; www.autoitscript.com/forum/topic/56536-easy-shell-hooking-example/?page=2
; www.autoitscript.com/forum/topic/185055-how-to-check-is-context-menu-under-mouse/

#NoTrayIcon
#include<WinAPISys.au3>
#include <Misc.au3>
#Include <SendMessage.au3>
#include <GuiMenu.au3>
#include <WindowsConstants.au3>

Opt("WinWaitDelay", 0)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)
Opt("MouseClickDragDelay", 0)
Opt("SendKeyDelay", 0)
Opt("SendKeyDownDelay", 0)
Opt("WinTitleMatchMode", 3)

If WinExists('[CLASS:#32768]') Then
   Global $ContextMenu = WinGetHandle('[CLASS:#32768]')
Else
   Global $ContextMenu = ''
EndIf
$hHookFunc = DllCallbackRegister('_WinEventProc', 'none', 'ptr;uint;hwnd;int;int;uint;uint')
$hWinHook = _WinAPI_SetWinEventHook($EVENT_SYSTEM_FOREGROUND, $EVENT_SYSTEM_CAPTURESTART, DllCallbackGetPtr($hHookFunc))

While 1
   Sleep(1000)
WEnd

Func _WinEventProc($hHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iEventThread, $imsEventTime)
   If $iEvent = $EVENT_SYSTEM_FOREGROUND or $iEvent = $EVENT_SYSTEM_MENUPOPUPSTART or $iEvent = $EVENT_SYSTEM_CAPTURESTART Then
      $Submenu = 'No'
      $WindowHandle = $hWnd
      $WindowClass = _WinAPI_GetClassName($WindowHandle)
      If $WindowClass = '#32768' Then
         $hMenu = _SendMessage($ContextMenu, $MN_GETHMENU, 0, 0)
         $MenuCount = _GUICtrlMenu_GetItemCount($hMenu)
         For $i = $MenuCount to 0 Step -1
            $tInfo = _GUICtrlMenu_GetItemInfo($hMenu, $i)
            If BitAND(DllStructGetData($tInfo, "State"), $MFS_HILITE) <> 0 Then
               $Submenu = 'yes'
               ExitLoop
            EndIf
         Next
         If $ContextMenu <> '' and $ContextMenu <> $WindowHandle and $Submenu = 'No' Then WinKill($ContextMenu)
         $ContextMenu = $WindowHandle
      ElseIf $ContextMenu <> '' And (_IsPressed(01) Or _IsPressed(02)) Then
         WinKill($ContextMenu)
      EndIf
   EndIf
EndFunc

 

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

You are just making it complicated with event hook, you should have just added in your loop what thiofox told you:

; www.unknowncheats.me/forum/1265891-post1.html
; www.autoitscript.com/forum/topic/183986-how-to-hide-focus-rectangle-for-any-control/
; www.autoitscript.com/forum/topic/185055-how-to-check-is-context-menu-under-mouse/

#NoTrayIcon
#include <Misc.au3>
#include <WinAPISys.au3>
#Include <SendMessage.au3>
#include <GuiMenu.au3>
#include <WindowsConstants.au3>

Opt("WinWaitDelay", 0)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)
Opt("MouseClickDragDelay", 0)
Opt("SendKeyDelay", 0)
Opt("SendKeyDownDelay", 0)
Opt("WinTitleMatchMode", 3)

Global $hNTDll = DllOpen("ntdll.dll")
Global $MenuItemHighlighted, $left, $right, $top, $bottom, $MouseX, $MouseY

While 1
   $MenuItemHighlighted = 'No'
   $hWnd = WinWait('[CLASS:#32768]')
   $hMenu = _SendMessage($hWnd, $MN_GETHMENU, 0, 0)
   $MenuCount = _GUICtrlMenu_GetItemCount($hMenu)
   Do
      _HighPrecisionSleep(0.1)
   until _WinAPI_GetAsyncKeyState(0x01) = False and _WinAPI_GetAsyncKeyState(0x02) = False
   $aPos = WinGetPos($hWnd)
   If IsArray($aPos) Then
   While 1
      _HighPrecisionSleep(0.1)
      If _IsPressed(01) Or _IsPressed(02) Then
         $MousePos = MouseGetPos()
         For $i = 0 to $MenuCount - 1
            $tInfo = _GUICtrlMenu_GetItemInfo($hMenu, $i)
            If BitAND(DllStructGetData($tInfo, "State"), $MFS_HILITE) <> 0 Then
               $MenuItemHighlighted = 'yes'
               ExitLoop
            EndIf
         Next
         If $MenuItemHighlighted = 'yes' or ($aPos[0] < $MousePos[0] And $MousePos[0] < $aPos[0] + $aPos[2] And $aPos[1] < $MousePos[1] And $MousePos[1] < $aPos[1] + $aPos[3]) Then
            ; Mouse cursor is still inside window.
            If not WinExists($hWnd) Then ExitLoop
         Else
            WinKill($hWnd)
            ExitLoop
         EndIf
      EndIf
   WEnd
   EndIf
WEnd

Func _HighPrecisionSleep($iMicroSeconds)
   Local $hStruct = DllStructCreate("int64 time;")
   DllStructSetData($hStruct, "time", -1 * ($iMicroSeconds * 10))
   DllCall($hNTDll, "dword", "NtDelayExecution", "int", 0, "ptr", DllStructGetPtr($hStruct))
EndFunc   ;==>_HighPrecisionSleep

 

Edited by kosamja

Share this post


Link to post
Share on other sites

Hi kosamja, I tried that already, but it still doesnt work correctly on submenus. I currently trying this code, so it would be nice if you or anyone else could look in this code and help me find if there are any error in it

 

; www.autoitscript.com/forum/topic/114628-capture-the-windows-events/
; www.autoitscript.com/forum/topic/56536-easy-shell-hooking-example/?page=2
; www.autoitscript.com/forum/topic/185055-how-to-check-is-context-menu-under-mouse/

#NoTrayIcon
#include<WinAPISys.au3>
#include <Misc.au3>
#Include <SendMessage.au3>
#include <GuiMenu.au3>
#include <WindowsConstants.au3>

Opt("WinWaitDelay", 0)
Opt("MouseClickDelay", 0)
Opt("MouseClickDownDelay", 0)
Opt("MouseClickDragDelay", 0)
Opt("SendKeyDelay", 0)
Opt("SendKeyDownDelay", 0)
Opt("WinTitleMatchMode", 3)

$MenuNumber = WinList('[CLASS:#32768]')
If $MenuNumber[0][0] = 0 Then
   Global $ContextMenu = ''
   Global $SubMenu = ''
Else
   If $MenuNumber[0][0] = 1 Then
      Global $ContextMenu = $MenuNumber[1][1]
      Global $SubMenu = ''
   Else
      $match = ''
      For $j = 1 to 2
         $WindowHandle = $MenuNumber[$j][1]
         $hMenu = _SendMessage($WindowHandle, $MN_GETHMENU, 0, 0)
         $MenuCount = _GUICtrlMenu_GetItemCount($hMenu)
         For $i = 0 to $MenuCount - 1
            $tInfo = _GUICtrlMenu_GetItemInfo($hMenu, $i)
            $SubMenuHandle = _GUICtrlMenu_GetItemSubMenu($hMenu, $i)
            If BitAND(DllStructGetData($tInfo, "State"), $MFS_HILITE) <> 0 And $SubMenuHandle <> 0 Then
               Global $ContextMenu = $WindowHandle
               If $j = 1 Then
                  Global $SubMenu = $MenuNumber[2][1]
               Else
                  Global $SubMenu = $MenuNumber[1][1]
               EndIf
               $match = 'found'
               ExitLoop
            EndIf
         Next
         If $match <> '' Then ExitLoop
      Next
      If $match = '' Then
         Global $ContextMenu = $MenuNumber[1][1]
         Global $SubMenu = ''
      EndIf
      For $i = 1 to $MenuNumber[0][0]
         If $ContextMenu <> $MenuNumber[$i][1] And $SubMenu <> $MenuNumber[$i][1] Then WinKill($MenuNumber[$i][1])
      Next
   EndIf
EndIf
$hHookFunc = DllCallbackRegister('_WinEventProc', 'none', 'ptr;uint;hwnd;int;int;uint;uint')
$hWinHook = _WinAPI_SetWinEventHook($EVENT_SYSTEM_FOREGROUND, $EVENT_SYSTEM_CAPTURESTART, DllCallbackGetPtr($hHookFunc))

While 1
   Sleep(1000)
WEnd

Func _WinEventProc($hHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iEventThread, $imsEventTime)
   If $iEvent = $EVENT_SYSTEM_FOREGROUND or $iEvent = $EVENT_SYSTEM_MENUPOPUPSTART or $iEvent = $EVENT_SYSTEM_CAPTURESTART Then
      $WindowHandle = $hWnd
      $WindowClass = _WinAPI_GetClassName($WindowHandle)
      If $WindowClass = '#32768' Then
         $hMenu = _SendMessage($ContextMenu, $MN_GETHMENU, 0, 0)
         $MenuCount = _GUICtrlMenu_GetItemCount($hMenu)
         For $i = 0 to $MenuCount - 1
            $tInfo = _GUICtrlMenu_GetItemInfo($hMenu, $i)
            If BitAND(DllStructGetData($tInfo, "State"), $MFS_HILITE) <> 0 Then
               If $SubMenu = '' or not WinExists($SubMenu) Then $SubMenu = $WindowHandle
               ExitLoop
            EndIf
         Next
         If $ContextMenu <> '' and $ContextMenu <> $WindowHandle and $SubMenu <> $WindowHandle and WinExists($WindowHandle) Then
            If $SubMenu <> '' Then
               WinKill($SubMenu)
               $SubMenu = ''
            EndIf
            WinKill($ContextMenu)
            $ContextMenu = $WindowHandle
         EndIf
      ElseIf $ContextMenu <> '' And (_IsPressed(01) Or _IsPressed(02)) Then
         If $SubMenu <> '' Then
            WinKill($SubMenu)
            $SubMenu = ''
         EndIf
         WinKill($ContextMenu)
      EndIf
   EndIf
EndFunc

 

Share this post


Link to post
Share on other sites
;Kill any Context Menu if the window active isn't the PID of the context menu
While Sleep(500)
    $hWnd = WinGetHandle("[CLASS:#32768]")
    $ContextMenuPID = WinGetProcess($hWnd)
    $WinActivePID = WinGetProcess(WinActive(""))
    ConsoleWrite("Context Menu PID: " & $ContextMenuPID & @TAB & "Active Window PID: " & $WinActivePID & @CRLF)

    If $WinActivePID <> $ContextMenuPID And $ContextMenuPID <> -1 Then
        ConsoleWrite("Context Menu " & $hWnd & " was killed!" & @CRLF)
        WinKill($hWnd)
        ;ExitLoop ; If you want!
    EndIf
WEnd

 

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  
Followers 0