Aviod trigger OnMouseLeave when Gui Menu shows

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
zcooler
Posts: 455
Joined: 11 Jan 2014, 04:59

Aviod trigger OnMouseLeave when Gui Menu shows

01 Oct 2017, 04:23

Wondering if it might be possible to somehow aviod triggering OnMouseLeave when Gui Menu (with tooltips) is activated?
In other words treating the menu as part of the Gui with msg "Mouse entered gui" and when mouse leaves gui and menu (+tooltips) triggers "Mouse left gui".

This is a combo script of Helgef OnMouseLeave and just me (iPhilips) Menu Tooltip

Code: Select all

#NoEnv
SetBatchLines, -1
CoordMode, ToolTip, Screen ; Required for ShowMenuCheckCursorPosition()

OnMessage(0x200, "OnMouseMove")

gui, +hwndguiId

; This doesn't work on 64 bit
/*
typedef struct tagTRACKMOUSEEVENT {
  DWORD cbSize;
  DWORD dwFlags;
  HWND  hwndTrack;
  DWORD dwHoverTime;
} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT;
*/

WM_MOUSELEAVE:=0x2A3
cbSize:=A_PtrSize=4?16:24
TME_LEAVE:=0x00000002
dwFlags:=TME_LEAVE


VarSetCapacity(TRACKMOUSEEVENT, cbSize,0)
NumPut(cbSize, TRACKMOUSEEVENT, 0, "Uint")
NumPut(dwFlags, TRACKMOUSEEVENT, 4, "Uint")
NumPut(guiId, TRACKMOUSEEVENT, 8, "Ptr")
; NumPut(0, TRACKMOUSEEVENT, 8+A_PtrSize, "Uint") ; Not needed

if !DllCall("User32.dll\TrackMouseEvent", "Ptr", &TRACKMOUSEEVENT)
	Msgbox fail
else
	OnMessage(WM_MOUSELEAVE, "WM_MOUSELEAVE")
	
Menu, MyMenu, Add, Item 1, MenuHandler
Menu, MyMenu, Add, Item 2, MenuHandler
   Menu, MySubMenu3, Add, Item 3.1, MenuHandler
   Menu, MySubMenu3, Add, Item 3.2, MenuHandler
   Menu, MySubMenu3, Add, Item 3.3, MenuHandler
   Menu, MySubMenu3, Add, Item 3.4, MenuHandler
   Menu, MySubMenu3, Add, Item 3.5, MenuHandler
Menu, MyMenu, Add, Item 3, :MySubMenu3
Menu, MyMenu, Add, Item 4, MenuHandler
   Menu, MySubMenu5, Add, Item 5.1, MenuHandler
   Menu, MySubMenu5, Add, Item 5.2, MenuHandler
      Menu, MySubMenu5.3, Add, Item 5.3.1, MenuHandler
      Menu, MySubMenu5.3, Add, Item 5.3.2, MenuHandler
      Menu, MySubMenu5.3, Add, Item 5.3.3, MenuHandler
      Menu, MySubMenu5.3, Add, Item 5.3.4, MenuHandler
      Menu, MySubMenu5.3, Add, Item 5.3.5, MenuHandler
   Menu, MySubMenu5, Add, Item 5.3, :MySubMenu5.3
   Menu, MySubMenu5, Add, Item 5.4, MenuHandler
   Menu, MySubMenu5, Add, Item 5.5, MenuHandler
Menu, MyMenu, Add, Item 5, :MySubMenu5	

gui, show, w200 h200

global ToolTipText := {}
AssignToolTipTexts("MyMenu")
AssignToolTipTexts("MySubMenu3")
AssignToolTipTexts("MySubMenu5")
AssignToolTipTexts("MySubMenu5.3")
Return

AssignToolTipTexts(MenuName) {
   HMENU := MenuGetHandle(MenuName)
   ToolTipText[HMENU] := []
   Loop, % Menu_GetItemCount(HMENU)
      ToolTipText[HMENU][A_Index] := MenuName " - Item " A_Index
}

GuiClose:
ExitApp

GuiContextMenu:
ShowMenu(MenuGetHandle("MyMenu"), , , 3)
Return

MenuHandler:
   MsgBox, 0, %A_ThisLabel%, %A_ThisMenu% - %A_ThisMenuItem%
   Menu_CheckRadioGroup(MenuGetHandle(A_ThisMenu), A_ThisMenuItemPos, 1)
Return

OnMouseMove(){
	global TRACKMOUSEEVENT
	OnMessage(0x200, "OnMouseMove", 0)
	DllCall("User32.dll\TrackMouseEvent", "Ptr", &TRACKMOUSEEVENT)
	ToolTip % "Mouse entered gui @ " A_TickCount,0,0
}

WM_MOUSELEAVE(){
	ToolTip, % "Mouse left gui @ " A_TickCount,0,0
	OnMessage(0x200, "OnMouseMove")
}

; ==================================================================================================================================
; Shows a user-defined menu without blocking the script.
; Parameters:
;     HMENU          -  name or handle of a user-defined menu. This menu must not be the 'Tray' menu.
;     X              -  x-position of the upper-left corner of the menu in screen coordinates.
;                       Default: -1 - current cursor position.
;     Y              -  y-position of the upper-left corner of the menu in screen coordinates.
;                       Default: -1 - current cursor position.
;     WhichToolTip   -  Tooltip window to operate upon (1-20)
;                       Default: 1
; Return value:
;     True if the menu could be shown, otherwise False.
; Remarks:
;     Parts of code adapted from script_menu.cpp -> UserMenu::Display
;     Because the function prevents the default AHK handling of menues there might be unwanted side-effects.
; ==================================================================================================================================
ShowMenu(HMENU, X := -1, Y := -1, WhichToolTip := 1) {
   If !DllCall("IsMenu", "Ptr", HMENU) && !(HMENU := MenuGetHandle(HMENU))
      Return False
   If (MenuGetName(HMENU) = "Tray")
      Return False
   ; Determine the display position
   If (X = -1) || (Y = -1) {
      VarSetCapacity(PT, 8, 0)
      DllCall("GetCursorPos", "Ptr", &PT)
      If (X = -1)
         X := NumGet(PT, 0, "Int")
      If (Y = -1)
         Y := NumGet(PT, 4, "Int")
   }
   ; Set the AHK main window as the foreground window, if needed
   ThisTID := DllCall("GetCurrentThreadId", "UInt")
   ForeWin := DllCall("GetForegroundWindow", "UPtr")
   If (ChangeFore := !(ForeWin) || (DllCall("GetWindowThreadProcessId", "Ptr", ForeWin, "Ptr", 0, "UInt") <> ThisTID))
      While !DllCall("SetForegroundWindow", "Ptr", A_ScriptHwnd, "UInt")
         DllCall("Sleep", "UInt", 10)
   ; Activate the message handler
   MsgFunc := Func("ShowMenuEnterMenuLoop")
   OnMessage(0x0211, MsgFunc, -1) ; WM_ENTERMENULOOP
   ; Activate the timer
   TimerFunc := Func("ShowMenuCheckCursorPosition").Bind(HMENU, WhichToolTip)
   SetTimer, %TimerFunc%, 10
   Result := DllCall("TrackPopupMenuEx", "Ptr", HMENU, "UInt", 0, "Int", X, "Int", Y, "Ptr", A_ScriptHwnd, "Ptr", 0, "UInt")
   ; Deactivate the timer
   SetTimer, %TimerFunc%, Delete
   ; Remove the ToolTip, if any
   ToolTip, , , , WhichToolTip
   ; Deactivate the message handler
   OnMessage(0x0211, MsgFunc, 0) ; WM_ENTERMENULOOP
   ; Reset the timer's static variables
   ShowMenuCheckCursorPosition(0, WhichToolTip)
   ; Restore the foreground window, if needed
   If (ChangeFore) && (ForeWin) && (DllCall("GetForegroundWindow", "UPtr") = A_ScriptHwnd)
      DllCall("SetForegroundWindow", "Ptr", ForeWin, "UInt")
   Return Result
}
; ==================================================================================================================================
ShowMenuEnterMenuLoop() {
   Return 0 ; prevents AHK menu processing
}
; ==================================================================================================================================
ShowMenuCheckCursorPosition(HMENU, WhichToolTip) {
   Static PrevItem := 0, ThisMenu := 0, Menus := []
   If (HMENU = 0) {
      PrevItem := 0, ThisMenu := 0, Menus := []
      Return
   }
   If !Menus.MaxIndex()
      Menus.Push(ThisMenu := HMENU)
   DllCall("GetCursorPos", "Int64P", PT)
   If (Item := DllCall("MenuItemFromPoint", "Ptr", 0, "Ptr", ThisMenu, "Int64", PT, "Int") + 1) {
      If (Item <> PrevItem) {
         Pos := Menu_GetItemRect(ThisMenu, Item)
         ToolTip, % ToolTipText[ThisMenu][Item], Pos.right, (Pos.top + Pos.bottom)//2, WhichToolTip ; Requires CoordMode, ToolTip, Screen
      }
   }
   Else If (HSUBMENU := DllCall("GetSubMenu", "Ptr", ThisMenu, "Int", PrevItem-1))
      Menus.Push(ThisMenu := HSUBMENU)
   Else {
      If (Menus.MaxIndex() > 1 && (DllCall("MenuItemFromPoint", "Ptr", 0, "Ptr", Menus[Menus.MaxIndex()-1], "Int64", PT, "Int") + 1)) {
         Menus.Pop()
         ThisMenu := Menus[Menus.MaxIndex()]
      }
      ToolTip, , , , WhichToolTip
   }
   PrevItem := Item
}
; ==================================================================================================================================
; GetItemRect     Retrieves the bounding rectangle for the specified menu item.
; Return values:  If the function succeeds, the return value is an array containing the coordinates of the bounding rectangle of the
;                 specified menu item expressed in screen coordinates.
;                 If the function fails, the return value is null.
; ==================================================================================================================================
Menu_GetItemRect(hMenu, Item) {
   VarSetCapacity(RECT, 16, 0)
   if DllCall("GetMenuItemRect", "Ptr", 0, "Ptr", hMenu, "UInt", Item-1, "Ptr", &RECT)
      Return {left:NumGet(RECT,0),top:NumGet(RECT,4),right:NumGet(RECT,8),bottom:NumGet(RECT,12)}
}
; ==================================================================================================================================
; CheckRadioGroup Checks a specified menu item and makes it a radio item. At the same time, the function clears
;                 all other menu items in the associated group and clears the radio-item type flag for those items.
;                 If the specified menu item is the same as the previous one, the menu item is cleared.
; Parameters:     First -  The 1-based position of the first menu item in the group.
;                          Default: 0 = no radio group.
;                 Last  -  The 1-based position of the last menu item in the group.
;                          Default: 0 = last menu item.
; Return values:  If the function succeeds, the return value is nonzero; otherwise it is zero (False).
; Note:           To uncheck all items in the group specify 0 for Pos, 1 for First, and 0 for Last.
;                 To treat all items in the menu as a group pass 1 for First and 0 for Last.
;                 To check/uncheck the item inidividually use the menu command.
;
; ==================================================================================================================================
Menu_CheckRadioGroup(HMENU, Pos, First := 0, Last := 0) {
   Static PrevHMENU, PrevPos
   If (First < 1)
      First := Last := Pos
   If (Last < 1)
      Last := Menu_GetItemCount(HMENU)
   If (HMENU = PrevHMENU && Pos = PrevPos) ; If selecting the previous menu item, clear it and return
      Return DllCall("CheckMenuRadioItem", "Ptr", HMENU, "UInt", 0, "UInt", Menu_GetItemCount(HMENU) - 1, "UInt", -1, "UInt", 0x0400, "UInt") ; MF_BYPOSITION = 0x0400
   If (HMENU <> PrevHMENU) ; if the specified menu is different than the previous one, clear the all the items in the previous menu
      DllCall("CheckMenuRadioItem", "Ptr", PrevHMENU, "UInt", 0, "UInt", Menu_GetItemCount(PrevHMENU) - 1, "UInt", -1, "UInt", 0x0400, "UInt") ; MF_BYPOSITION = 0x0400
   PrevHMENU := HMENU, PrevPos := Pos
   Return DllCall("CheckMenuRadioItem", "Ptr", HMENU, "UInt", First - 1, "UInt", Last - 1, "UInt", Pos - 1, "UInt", 0x0400, "UInt") ; MF_BYPOSITION = 0x0400
}
; ==================================================================================================================================
; GetItemCount    Determines the number of items in the specified menu.
; Return values:  If the function succeeds, the return value specifies the number of items in the menu.
;                 If the function fails, the return value is -1
; ==================================================================================================================================
Menu_GetItemCount(HMENU) {
   Return DllCall("GetMenuItemCount", "Ptr", HMENU, "Int")
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Anput, DiegoSouto, mikeyww, robnicholson, Rohwedder, Swiftly9767 and 368 guests