Gui, Add, GroupBox, hwndhctrl, test SetHoverText(hctrl, "New text") Gui, Add, Button, hwndhctrl, abc SetHoverText(hctrl, "123") Gui, Show Return GuiClose: ExitApp Return SetHoverText(CtrlHwnd, HoverText = "", msg = "", hwnd = "") { static CtrlArray := [] static WM_MOUSEMOVE := OnMessage( 0x200, "SetHoverText" ) static WM_NCMOUSELEAVE := OnMessage( 0x2A2, "SetHoverText" ) static ChangedHwnd ; Setup hover control if !msg ; Called from fuction, not OnMessage. { ControlGetText, OrigText,, ahk_id %CtrlHwnd% ; GuiControl can't get the control's text of a non-default GUI. GuiHwnd := DllCall("GetParent", "UInt", CtrlHwnd) CtrlArray[CtrlHwnd] := { OrigText: OrigText, HoverText: HoverText, GuiHwnd: GuiHwnd } SetTimer, __CheckIfMouseIsOutsideGui, 100 ; WM_NCMOUSELEAVE won't execute when mouse moving too fast. Return } MouseGetPos,,,, hwnd, 2 ; Button / Radio / Checkbox don't need this line. if CtrlArray.HasKey(hwnd) ; Mouse is over at a defined control. { if !ChangedHwnd ; Button's text only change once, when mouse moving inside the control. { GuiControl,, %hwnd%, % CtrlArray[hwnd]["HoverText"] ChangedHwnd := hwnd } } else if ChangedHwnd { GuiControl,, %ChangedHwnd%, % CtrlArray[ChangedHwnd]["OrigText"] ChangedHwnd := "" } Return __CheckIfMouseIsOutsideGui: if !ChangedHwnd Return MouseGetPos,,, hWin if ( hWin != CtrlArray[ChangedHwnd]["GuiHwnd"] ) { GuiControl,, %ChangedHwnd%, % CtrlArray[ChangedHwnd]["OrigText"] ChangedHwnd := "" } Return }