Movable ToolTip

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Movable ToolTip

01 Jan 2018, 09:38

Lately I'm often using ToolTip to display data, enlarged with ToolTipAll to be readable from a distance.
Bigger ToolTip is more likely to cover some important part of the screen, so I needed it to be movable.

Code: Select all

#NoEnv
OnMessage(0x201, "WM_LBUTTONDOWN")

Global tClass:="SysShadow,Alternate Owner,tooltips_class32,DummyDWMListenerWindow,EdgeUiInputTopWndClass,ApplicationFrameWindow,TaskManagerWindow,Qt5QWindowIcon,Windows.UI.Core.CoreWindow,WorkerW,Progman,Internet Explorer_Hidden,Shell_TrayWnd" ; HH Parent

WinGetActiveTitle, aWin
ToolTip,
(
Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
), 0, 0
return

WM_LBUTTONDOWN(wParam, lParam, msg, hwnd) {
	PostMessage, 0xA1, 2 ; WM_NCLBUTTONDOWN
	KeyWait, LButton, U
	Loop { ; adapted from https://autohotkey.com/board/topic/32171-how-to-get-the-id-of-the-next-or-previous-window-in-z-order/
        ; GetWindow() returns a decimal value, so we have to convert it to hex
        ; GetWindow() processes even hidden windows, so we move down the z oder until the next visible window is found
        hwnd := Format("0x{:x}", DllCall("GetWindow", UPtr,hwnd, UInt,2) ) ; 2 = GW_HWNDNEXT
        if DllCall("IsWindowVisible", UPtr,hwnd) {
            WinGet, Ex, ExStyle, ahk_id %hwnd%
            ;if ( IsWindowCloaked(hwnd) || Ex & (0x8 | 0x80 | 0x8000000) ) ;WS_EX_TOPMOST, WS_EX_TOOLWINDOW, WS_EX_NOACTIVATE
            if (IsWindowCloaked(hwnd) || Ex & 0x8000088) ;WS_EX_TOPMOST, WS_EX_TOOLWINDOW, WS_EX_NOACTIVATE
		Continue
            WinGetClass, cClass, ahk_id %hwnd%
            if InStr(tClass, cClass, 1) ; if cClass in %tClass%
                Continue
            else break
        }
    }   WinActivate, ahk_id %hwnd%
}

IsWindowCloaked(hwnd) {
    return DllCall("dwmapi\DwmGetWindowAttribute", "ptr",hwnd, "int",14, "int*",cloaked, "int",4) >= 0
        && cloaked
}

Esc::exitapp
First Post
Last edited by rommmcek on 16 Oct 2019, 21:47, edited 7 times in total.
User avatar
Delta Pythagorean
Posts: 627
Joined: 13 Feb 2017, 13:44
Location: Somewhere in the US
Contact:

Re: Movable ToolTip

01 Jan 2018, 14:22

Huh. Neat.

[AHK]......: v2.0.12 | 64-bit
[OS].......: Windows 11 | 23H2 (OS Build: 22621.3296)
[GITHUB]...: github.com/DelPyth
[PAYPAL]...: paypal.me/DelPyth
[DISCORD]..: tophatcat

burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: Movable ToolTip

02 Jan 2018, 16:13

:thumbup:
Very nice.
Regards,
burque505
lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Movable ToolTip

12 Oct 2019, 20:39

I was looking for any information about the DummyDWMListenerWindow window class (not specifically on the forum) and found this.

This list of window class checks could be optimized considerably. You could:
  • Use a window group. AutoHotkey looping through the group internally should be much more efficient than evaluating a long list of sub-expressions.
  • Use if var in MatchList or even InStr.
  • Use an associative array with class names as keys (however, I'm fairly certain class names are case-sensitive and keys are not).
Actually, you might like to know that some of those windows can be excluded more efficiently: several of them are "cloaked" rather than hidden. Some of them can (also) be excluded via the presence of the WS_EX_TOOLWINDOW ExStyle (which prevents them from having a taskbar button unless WS_EX_APPWINDOW is present) or WS_EX_NOACTIVATE.
User avatar
elModo7
Posts: 217
Joined: 01 Sep 2017, 02:38
Location: Spain
Contact:

Re: Movable ToolTip

13 Oct 2019, 11:18

Might find some use for it, thanks for sharing!
User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Re: Movable ToolTip

15 Oct 2019, 02:19

Thanks for suggestions! First part is here not so important (accept for the embellishing the code), but the second part is very useful (not finished yet), even if there was some strange (seems no where documented) ExStyle to be found (thanks to svArtist's work).
Anyway, I posted it in OP.
lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Movable ToolTip

15 Oct 2019, 03:55

Code: Select all

IsWindowCloaked(hwnd) {
    return DllCall("dwmapi\DwmGetWindowAttribute", "ptr",hwnd, "int",14, "int*",cloaked, "int",4) ;>= 0
        ;&& cloaked
}
Your modified version of the function will not tell you if the window is cloaked. It will return 0 (success) on Windows 8 and later if the HWND is valid, or a negative value otherwise.
if (Ex = 0x108) ; || IsWindowCloaked || Ex = 0x80 || Ex = 0x8000000) ;0x108???, WS_EX_TOOLWINDOW, WS_EX_NOACTIVATE
Styles are a combination of bit flags, and can be tested with bitwise-and (e.g. (style & 0x100)). You should rarely, if ever, compare the style value directly with the equality operator. 0x108 is a combination of the very much documented styles WS_EX_WINDOWEDGE and WS_EX_TOPMOST.

Why post these changes before they are finished?
User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Re: Movable ToolTip

15 Oct 2019, 12:13

Thanks again!
- I modified your function because I did not understand it converts retrieved "cloaked" value to true or false, what I believe now.
- I noticed in msdn that some styles are defined multiple times, but I mixed up bitwise "add" with RegEx "or" (what a blunder!)
- I posted the code because it prevents e.g. Window spy to pop up even if it was minimized.

Now the code is finished, but not extensively tested yet! (Update in OP)
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Movable ToolTip

15 Oct 2019, 12:42

might not be finished just yet ;)
rommmcek wrote:
01 Jan 2018, 09:38

Code: Select all

if (Ex&0x8=0x8 || IsWindowCloaked || Ex&0x80=0x80 || Ex&0x8000000=0x8000000)
i'm not sure if those bitwise ANDs should also have = operators, at least i've never seen it done like that before

and it doesn't look like you're calling the function either. shouldn't it be:

Code: Select all

if (Ex&0x8 || IsWindowCloaked(hwnd) || ...

User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Re: Movable ToolTip

15 Oct 2019, 15:12

Thank You!
First fault was due to very little experience, but tested and it was working.
Second was pure typo and after update just being not attentive when doing copy paste.
Updated OP.

Off Topic:
Now I'll try to cloak a window, and hope, you'll be still around to commet my probably not working attempt...
Looks like Dll is dealing with structures, from which I can barely read, but not write into it...
Spoiler
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: Movable ToolTip

15 Oct 2019, 20:21

your code above doesn't work for me on win10. does it work for you? the gui is still visible for me.

the only example i could find from microsoft on how to use this is here:
https://docs.microsoft.com/en-us/windows/win32/directcomp/how-to--animate-the-bitmap-of-a-layered-child-window

Code: Select all

BOOL fCloak = TRUE;
DwmSetWindowAttribute(pDemoApp->m_hwndLayeredChild,
    DWMWA_CLOAK,
    &fCloak,
    sizeof(fCloak));
DWMWA_CLOAK is 13 so that is correct, then i guess we need to pass a boolean true/false, but MSDN for SetWindowAttribute says we need to pass a pointer. you passed 1, but probably we need to pass the address of a var containing 1.

this works for me:

Code: Select all

SetWindowCloaked(hwnd) {
  static DWMWA_CLOAK := 13
  myBoolSize := VarSetCapacity(myBool, 4)
  ;msgbox myBoolSize=%myBoolSize%     ; shows 6 for me, not 4, strange
  myBool := true
  Return DllCall("Dwmapi\DwmSetWindowAttribute", Ptr, hwnd, UInt, DWMWA_CLOAK, UInt, &myBool, UInt, myBoolSize)
}

lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Movable ToolTip

16 Oct 2019, 03:45

guest3456 wrote:i'm not sure if those bitwise ANDs should also have = operators, at least i've never seen it done like that before
It may be done in languages where int is not implicitly convertible to bool, or in other languages just for clarity. One may also want to test whether multiple bits are all set or all not set, or some specific combination. For instance, (Ex & 0x8000088) = 0x8000088 would tell us whether all three of the styles 0x8000000, 0x80 and 0x8 are set. In this case we probably just want to know if any of the three are set, so (Ex & 0x8000088) will suffice (it will be non-zero if any of the three styles are set, and zero if none of them are set). You can also write (Ex & 0x8000088) != 0 for clarity (or to get a proper boolean result), or (Ex & 0x8000088) = 0 if you want to know that none of them are set.

I recently used this code to determine whether a window is either hidden (lacks WS_VISIBLE) or disabled (has WS_DISABLED):

Code: Select all

if ((style & (WS_VISIBLE | WS_DISABLED)) != WS_VISIBLE)
Spoiler
User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Re: Movable ToolTip

16 Oct 2019, 07:53

OMG! This was very instructive to me!
@guest3456 No, my code didn't work for me (Win10). You probably interpreted the struck line as a negation of the second part of the sentence. In fact it was vice versa! I.e. I gave up.
I was both, so near to success and to the other side so far away! As lexikos explained, sometimes DllCall() requires profound understanding of the struct. Experienced guys like you can get around it (your code works) others (like me) obviously not!
Here is my final "cloak" example
For me it is important to learn and that the code works (now tested with cloaked window too)!
Mistery revealed thanks to svArtist with a "little" help of lexikos and active interest of guest3456!
Thanks to all of you!

P.s.: Updated OP, (Edit: Fixed unfortunate copy paste typo in OP; Edit2: Removing HH Parent from the tClass list in the OP)

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 71 guests