[Function] FFToolTip: Flicker-Free ToolTip

Post your working scripts, libraries and tools for AHK v1.1 and older
iPhilip
Posts: 791
Joined: 02 Oct 2013, 12:21

Re: [Function] FFToolTip: Flicker-Free ToolTip

24 Jun 2021, 13:59

mstrauss2021 wrote:
24 Jun 2021, 12:12
Still using this script and loving it.
Got everything working the way I want, however...

I have the tooltip always following the mouse which is good, but now I realize the tooltip is kind of getting in the way.

I've read the comments in the script and tried altering X variable but no change.

How can I add 75 to the X position of the tooltip and which line needs to be changed?
Change all instances of MouseX + 16 to MouseX + 75
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
mstrauss2021
Posts: 30
Joined: 13 Feb 2021, 10:34

Re: [Function] FFToolTip: Flicker-Free ToolTip

24 Jun 2021, 15:02

Beautiful, thank you
SilentlyFiguring
Posts: 1
Joined: 22 Oct 2021, 13:06

Re: [Function] FFToolTip: Flicker-Free ToolTip

22 Oct 2021, 13:28

Thanks for writing this excellent code iPhilip. I've been using it for years. Unfortunately, updates made to AHK v2 (somewhere between AHK 2.0-a100-52515e2 and the current AHK 2.0-beta.2) caused the v2 versions in the original post to not work. I managed to modify the code for my own use so that it works with the current version of the AHK v2 beta and I feel I spent way too much time on it to not upload my results for others. I don't have enough of a grasp of DllCalls and Buffer objects to believe my modifications are optimal and/or fully efficient, but at least it works.

Basically, here's the code that iPhilip had labeled as "AHK v2 versions: Here is the function for single-monitor configurations:" with my modifications:

Code: Select all

; ===============================================================================================================================
; FFToolTip(Text:="", X:="", Y:="", WhichToolTip:=1)
; Function:       Creates a tooltip window anywhere on the screen. Unlike the built-in ToolTip function, calling this function
;                 repeatedly will not cause the tooltip window to flicker. Otherwise, it behaves the same way. Use this function
;                 without the first three parameters, i.e. FFToolTip(), in order to hide the tooltip.
; Parameters:     Text - The text to display in the tooltip. To create a multi-line tooltip, use the linefeed character (`n) in
;                    between each line, e.g. Line1`nLine2. If blank or omitted, the existing tooltip will be hidden.
;                 X - The x position of the tooltip. This position is relative to the active window, the active window's client
;                    area, or the entire screen depending on the coordinate mode (see the CoordMode function). In the default
;                    mode, the coordinates that are relative to the active window.
;                 Y - The y position of the tooltip. See the above X parameter for more information. If both the X and Y
;                    coordinates are omitted, the tooltip will be shown near the mouse cursor.
;                 WhichToolTip - A number between 1 and 20 to indicate which tooltip window to operate upon. If unspecified, the
;                    default is 1.
; Return values:  None
; Global vars:    None
; Dependencies:   None
; Tested with:    AHK 2.0-beta.2
; Tested on:      Win 7 (x64)
; Written by:     iPhilip
; ===============================================================================================================================
; MSDN Links:
; https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getcursorpos - GetCursorPos function
; https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-clienttoscreen - ClientToScreen function
; https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-movewindow - MoveWindow function
; ===============================================================================================================================

FFToolTip(Text:="", X:="", Y:="", WhichToolTip:=1) {
   static ID := [], Xo:=0, Yo:=0, W:=0, H:=0, SavedText:=""
        , PID := DllCall("GetCurrentProcessId")
        , Point := Buffer(8)
   
   if (Text = "") {  ; Hide the tooltip
      ToolTip , , , WhichToolTip
      ID.Delete(WhichToolTip)
   } else if not ID.Has(WhichToolTip) {  ; First call
      ToolTip Text, X, Y, WhichToolTip
      ID.Length := Max(ID.Length, WhichToolTip)
      ID[WhichToolTip] := WinExist("ahk_class tooltips_class32 ahk_pid " PID)
      WinGetPos , , &W, &H, "ahk_id " ID[WhichToolTip]
      SavedText := Text
   } else if (Text != SavedText) {  ; The tooltip text changed
      ToolTip Text, X, Y, WhichToolTip
      WinGetPos , , &W, &H, "ahk_id " ID[WhichToolTip]
      SavedText := Text
   } else {  ; The tooltip is being repositioned
      if (Flag := X = "" || Y = "") {
         DllCall("GetCursorPos", "Ptr", Point.Ptr, "Int")
         MouseX := NumGet(Point, 0, "Int")
         MouseY := NumGet(Point, 4, "Int")
      }
      ;
      ; Convert input coordinates to screen coordinates
      ;
      if (A_CoordModeToolTip = "Window") {
         WinGetPos &WinX, &WinY, , , "A"
         X := X = "" ? MouseX + 16 : X + WinX
         Y := Y = "" ? MouseY + 16 : Y + WinY
      } else if (A_CoordModeToolTip = "Client") {
         DllCall("ClientToScreen", "Ptr", WinExist("A"), "Ptr", Point.Ptr, "Int")
         X := X = "" ? MouseX + 16 : NumGet(Point, 0, "Int")
         Y := Y = "" ? MouseY + 16 : NumGet(Point, 4, "Int")
         
      } else {  ; A_CoordModeToolTip = "Screen"
         X := X = "" ? MouseX + 16 : X
         Y := Y = "" ? MouseY + 16 : Y
      }
      ;
      ; Deal with the bottom and right edges of the screen
      ;
      if Flag {
         X := X + W >= A_ScreenWidth  ? A_ScreenWidth  - W - 1 : X
         Y := Y + H >= A_ScreenHeight ? A_ScreenHeight - H - 1 : Y
         if (MouseX >= X && MouseX <= X + W && MouseY >= Y && MouseY <= Y + H)
            X := MouseX - W - 3, Y := MouseY - H - 3
      }
      ;
      ; If necessary, store the coordinates and move the tooltip window
      ;
      if (X != Xo || Y != Yo) {
         Xo := X, Yo := Y
         DllCall("MoveWindow", "Ptr", ID[WhichToolTip], "Int", X, "Int", Y, "Int", W, "Int", H, "Int", false, "Int")
      }
   }
}
And here's a summary of the lines I changed:

Code: Select all

static ID := [], Xo, Yo, W, H, SavedText                              -> static ID := [], Xo:=0, Yo:=0, W:=0, H:=0, SavedText:=""
, _ := VarSetCapacity(Point, 8)                                       -> , Point := Buffer(8) ; VarSetCapacity is deprecated now and instead Buffer objects must be used
} else if not ID[WhichToolTip] {  ; First call                        -> } else if not ID.Has(WhichToolTip) {  ; First call ; arrays were changed so that to check for the existence of an element, we now must use the Has function
[nothing]                                                             -> ID.Length := Max(ID.Length, WhichToolTip) ; this line is needed before "ID[WhichToolTip] := ...", since arrays were changed to require that their length be increased before a new element can be added and its value set
DllCall("GetCursorPos", "Ptr", &Point, "Int")                         -> DllCall("GetCursorPos", "Ptr", Point.Ptr, "Int") ; since Point is now a buffer object, it needs to be referenced differently
NumPut(X, Point, 0, "Int"), NumPut(Y, Point, 4, "Int")                -> ; deleted, the line was breaking the code and strangely didn't seem to affect the end result
DllCall("ClientToScreen", "Ptr", WinExist("A"), "Ptr", &Point, "Int") -> DllCall("ClientToScreen", "Ptr", WinExist("A"), "Ptr", Point.Ptr, "Int") ; since Point is now a buffer object, it needs to be referenced differently
; I also peppered the code with &'s before variable names wherever not doing so was generating errors.
Again, thanks iPhilip for the excellent code. I'm glad I was able to tweak it so I could continue using it with the current AHK v2.
User avatar
kczx3
Posts: 1640
Joined: 06 Oct 2015, 21:39

Re: [Function] FFToolTip: Flicker-Free ToolTip

22 Oct 2021, 20:56

Buffer objects can (and should) be passed directly to Ptr parameters of DllCalls. There are optimizations in place for this.
carno
Posts: 265
Joined: 20 Jun 2014, 16:48

Re: [Function] FFToolTip: Flicker-Free ToolTip

21 Nov 2021, 21:25

Great script. Works perfectly on Win 7.
LAPIII
Posts: 667
Joined: 01 Aug 2021, 06:01

Re: [Function] FFToolTip: Flicker-Free ToolTip

16 Mar 2022, 21:35

I'm learning how to implement Functions in scripts. Can you show me how to put it in:

Code: Select all

#Persistent
SetTimer, WatchCursor, 500
Return
 
WatchCursor:
  MouseGetPos, , , id, control
  WinGetTitle, title, ahk_id %id%
  WinGetClass, class, ahk_id %id%
  ControlGetFocus, ActiveWin, A
  ToolTip, Unique ID: ahk_id %id%`nTitle
         : %title%`nClass
         : ahk_class %class%`nControl
         : %control%`nActive Control
         : %ActiveWin%`n`nCTRL+WIN+T to Toggle On 
           and Off
           or `nCTRL+F12 to Copy to Clipboard
FFToolTip()           
Return
 
^#T:: 
  SetTimer, WatchCursor, % (Toggle:=!Toggle) 
                         ? "Off" : "On"
  If Toggle
    ToolTip
Return
 
^F12::ClipBoard := "Unique ID: ahk_id " . id 
                . "`r" . "Title: " . title 
                . "`r" . "Class: ahk_class" .  class 
                . "`r" . "Control: " 
                . "Active Control: " . ActiveWin
                . control . "`r" 
iPhilip
Posts: 791
Joined: 02 Oct 2013, 12:21

Re: [Function] FFToolTip: Flicker-Free ToolTip

16 Mar 2022, 21:57

Sure. Does the code below help?

Code: Select all

#Persistent
SetTimer, WatchCursor, 500
Return
 
WatchCursor:
  MouseGetPos, , , id, control
  WinGetTitle, title, ahk_id %id%
  WinGetClass, class, ahk_id %id%
  ControlGetFocus, ActiveWin, A
  FFToolTip("Unique ID: ahk_id " id "`n"
          . "Title: " title "`n"
          . "Class: ahk_class " class "`n"
          . "Control: " control "`n"
          . "Active Control: " ActiveWin "`n`n"
          . "CTRL+WIN+T to Toggle On and Off or`n"
          . "CTRL+F12 to Copy to Clipboard")           
Return
 
^#T:: 
  SetTimer, WatchCursor, % (Toggle:=!Toggle) 
                         ? "Off" : "On"
  If Toggle
    FFToolTip()
Return
 
^F12::ClipBoard := "Unique ID: ahk_id " . id 
                . "`r" . "Title: " . title 
                . "`r" . "Class: ahk_class" .  class 
                . "`r" . "Control: " 
                . "Active Control: " . ActiveWin
                . control . "`r" 

; ===============================================================================================================================
; FFToolTip(Text:="", X:="", Y:="", WhichToolTip:=1)
; Function:       Creates a tooltip window anywhere on the screen. Unlike the built-in ToolTip command, calling this function
;                 repeatedly will not cause the tooltip window to flicker. Otherwise, it behaves the same way. Use this function
;                 without the first three parameters, i.e. FFToolTip(), in order to hide the tooltip.
; Parameters:     Text - The text to display in the tooltip. To create a multi-line tooltip, use the linefeed character (`n) in
;                    between each line, e.g. Line1`nLine2. If blank or omitted, the existing tooltip will be hidden.
;                 X - The x position of the tooltip. This position is relative to the active window, the active window's client
;                    area, or the entire screen depending on the coordinate mode (see the CoordMode command). In the default
;                    mode, the coordinates that are relative to the active window.
;                 Y - The y position of the tooltip. See the above X parameter for more information. If both the X and Y
;                    coordinates are omitted, the tooltip will be shown near the mouse cursor.
;                 WhichToolTip - A number between 1 and 20 to indicate which tooltip window to operate upon. If unspecified, the
;                    default is 1.
; Return values:  None
; Global vars:    None
; Dependencies:   None
; Tested with:    AHK 1.1.30.01 (A32/U32/U64)
; Tested on:      Win 7 (x64)
; Written by:     iPhilip
; ===============================================================================================================================
; MSDN Links:
; https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getcursorpos - GetCursorPos function
; https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-clienttoscreen - ClientToScreen function
; https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-movewindow - MoveWindow function
; ===============================================================================================================================

FFToolTip(Text:="", X:="", Y:="", WhichToolTip:=1) {
   static ID := [], Xo, Yo, W, H, SavedText
        , PID := DllCall("GetCurrentProcessId")
        , _ := VarSetCapacity(Point, 8)
   
   if (Text = "") {  ; Hide the tooltip
      ToolTip, , , , WhichToolTip
      ID.Delete(WhichToolTip)
   } else if not ID[WhichToolTip] {  ; First call
      ToolTip, %Text%, X, Y, WhichToolTip
      ID[WhichToolTip] := WinExist("ahk_class tooltips_class32 ahk_pid " PID)
      WinGetPos, , , W, H, % "ahk_id " ID[WhichToolTip]
      SavedText := Text
   } else if (Text != SavedText) {  ; The tooltip text changed
      ToolTip, %Text%, X, Y, WhichToolTip
      WinGetPos, , , W, H, % "ahk_id " ID[WhichToolTip]
      SavedText := Text
   } else {  ; The tooltip is being repositioned
      if (Flag := X = "" || Y = "") {
         DllCall("GetCursorPos", "Ptr", &Point, "Int")
         MouseX := NumGet(Point, 0, "Int")
         MouseY := NumGet(Point, 4, "Int")
      }
      ;
      ; Convert input coordinates to screen coordinates
      ;
      if (A_CoordModeToolTip = "Window") {
         WinGetPos, WinX, WinY, , , A
         X := X = "" ? MouseX + 16 : X + WinX
         Y := Y = "" ? MouseY + 16 : Y + WinY
      } else if (A_CoordModeToolTip = "Client") {
         NumPut(X, Point, 0, "Int"), NumPut(Y, Point, 4, "Int")
         DllCall("ClientToScreen", "Ptr", WinExist("A"), "Ptr", &Point, "Int")
         X := X = "" ? MouseX + 16 : NumGet(Point, 0, "Int")
         Y := Y = "" ? MouseY + 16 : NumGet(Point, 4, "Int")
      } else {  ; A_CoordModeToolTip = "Screen"
         X := X = "" ? MouseX + 16 : X
         Y := Y = "" ? MouseY + 16 : Y
      }
      ;
      ; Deal with the bottom and right edges of the screen
      ;
      if Flag {
         X := X + W >= A_ScreenWidth  ? A_ScreenWidth  - W - 1 : X
         Y := Y + H >= A_ScreenHeight ? A_ScreenHeight - H - 1 : Y
         if (MouseX >= X && MouseX <= X + W && MouseY >= Y && MouseY <= Y + H)
            X := MouseX - W - 3, Y := MouseY - H - 3
      }
      ;
      ; If necessary, store the coordinates and move the tooltip window
      ;
      if (X != Xo || Y != Yo) {
         Xo := X, Yo := Y
         DllCall("MoveWindow", "Ptr", ID[WhichToolTip], "Int", X, "Int", Y, "Int", W, "Int", H, "Int", false, "Int")
      }
   }
}
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
LAPIII
Posts: 667
Joined: 01 Aug 2021, 06:01

Re: [Function] FFToolTip: Flicker-Free ToolTip

17 Mar 2022, 16:08

@iPhilip Perfect, thanks. :clap:
iPhilip
Posts: 791
Joined: 02 Oct 2013, 12:21

Re: [Function] FFToolTip: Flicker-Free ToolTip

17 Mar 2022, 16:18

You are welcome. :)
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
lexikos
Posts: 9494
Joined: 30 Sep 2013, 04:07
Contact:

Re: [Function] FFToolTip: Flicker-Free ToolTip

30 Apr 2022, 18:22

You might consider replacing all of the positioning logic with a single call to CalculatePopupWindowPosition, assuming you don't need to support Windows XP or older. It transparently supports multiple monitors, even if they have different DPI settings (which causes this script some trouble). I've demonstrated how to do it for v2 here. For v1, there's WinMoveZ by SKAN.
iPhilip
Posts: 791
Joined: 02 Oct 2013, 12:21

Re: [Function] FFToolTip: Flicker-Free ToolTip

02 May 2022, 01:27

lexikos wrote:
30 Apr 2022, 18:22
You might consider replacing all of the positioning logic with a single call to CalculatePopupWindowPosition, assuming you don't need to support Windows XP or older. It transparently supports multiple monitors, even if they have different DPI settings (which causes this script some trouble). I've demonstrated how to do it for v2 here. For v1, there's WinMoveZ by SKAN.
Thank you, @lexikos. I will look into it.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
ai877
Posts: 1
Joined: 17 Apr 2022, 11:11

Re: [Function] FFToolTip: Flicker-Free ToolTip

10 Dec 2022, 17:46

omg thanks very much for this!
finally no more flickering tooltips :dance: :bravo:

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 69 guests