问题
I am working on an Win32 C++ application where I want to ignore the mouse events and let is pass through to the window beneath my window. Basically the window below mine will handle the mouse event. I would prefer not to send the mouse message using SendMessage to the window beneath mine or use SetCapture. Is there a way basically to ignore the mouse event and let it pass through with Windows APIs or with styles? Note that my window is not transparent.
Thanks in advance for the help.
回答1:
So I found this question, and others, while attempting to create a music player that overlays a graphical display over the screen without impacting any other interaction, including e.g. dragging windows.
I've tried both the WM_NCHITTEST
approach, as well as simply adding WS_EX_TRANSPARENT
to my window. Neither of these approaches work -- they both seem to capture mouse click events, which is something I don't want.
However, by pure coincidence, I did manage to find a combination of flags I can pass to SetWindowLong(..., GWL_EXSTYLE, ...)
that seem to do the trick, leading to the following code:
LONG cur_style = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, cur_style | WS_EX_TRANSPARENT | WS_EX_LAYERED);
It appears that this behavior is documented here:
Hit testing of a layered window is based on the shape and transparency of the window. This means that the areas of the window that are color-keyed or whose alpha value is zero will let the mouse messages through. However, if the layered window has the WS_EX_TRANSPARENT extended window style, the shape of the layered window will be ignored and the mouse events will be passed to other windows underneath the layered window.
The extended window style documentation is also very useful. For applications such as mine, where a window is not meant to be interacted with, WS_EX_NOACTIVATE
may also be useful, as it prevents some user interactions.
For posterity's sake, I will note that the code I am using to ensure my window is always on top is the following:
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
回答2:
I would try handling WM_NCHITTEST and returning HTNOWHERE
.
I believe the approaches that use WS_EX_TRANSPARENT will have other side effects and are only useful if the underlying window is owned by the same thread. From the question, it's not clear if the underlying windows are part of the same application or any old application underneath.
回答3:
I have been testing this with 2 different RDC solutions by 2 different 3rd parties. Each solution probably creates its own window differently, with different styles etc. If I do below in WindowProc:
case WM_MOUSEMOVE:
{
std::cout << "WM_MOUSEMOVE" << std::endl;
VideoWindowWin32* window = reinterpret_cast<VideoWindowWin32*> (GetWindowLongPtr (hWnd, GWL_USERDATA));
if (window)
{
HWND rParent = GetParent(window->window);
SetCapture(window->parent);
//SendMessage(window->parent, uMsg, wParam, lParam);
}
}
break;
Everything works with one of them. But it doesn't for the other.
I would appreciate if there is anything you could suggest.
回答4:
Based on Adrian McCarthy, but actually works for me (though only when the parent owns the child window, otherwise the window will catch the mouse again):
case WM_NCHITTEST: return HTTRANSPARENT;
HTNOWHERE
just caused that the LoadCursor() for the window wasn't shown anymore.
These values seem to be possible:
#ifndef NONCMESSAGES
/*
* WM_NCHITTEST and MOUSEHOOKSTRUCT Mouse Position Codes
*/
#define HTERROR (-2)
#define HTTRANSPARENT (-1)
#define HTNOWHERE 0
#define HTCLIENT 1
#define HTCAPTION 2
#define HTSYSMENU 3
#define HTGROWBOX 4
#define HTSIZE HTGROWBOX
#define HTMENU 5
#define HTHSCROLL 6
#define HTVSCROLL 7
#define HTMINBUTTON 8
#define HTMAXBUTTON 9
#define HTLEFT 10
#define HTRIGHT 11
#define HTTOP 12
#define HTTOPLEFT 13
#define HTTOPRIGHT 14
#define HTBOTTOM 15
#define HTBOTTOMLEFT 16
#define HTBOTTOMRIGHT 17
#define HTBORDER 18
#define HTREDUCE HTMINBUTTON
#define HTZOOM HTMAXBUTTON
#define HTSIZEFIRST HTLEFT
#define HTSIZELAST HTBOTTOMRIGHT
#if(WINVER >= 0x0400)
#define HTOBJECT 19
#define HTCLOSE 20
#define HTHELP 21
#endif /* WINVER >= 0x0400 */
/*
* SendMessageTimeout values
*/
#define SMTO_NORMAL 0x0000
#define SMTO_BLOCK 0x0001
#define SMTO_ABORTIFHUNG 0x0002
#if(WINVER >= 0x0500)
#define SMTO_NOTIMEOUTIFNOTHUNG 0x0008
#endif /* WINVER >= 0x0500 */
#if(WINVER >= 0x0600)
#define SMTO_ERRORONEXIT 0x0020
#endif /* WINVER >= 0x0600 */
#if(WINVER >= 0x0602)
#endif /* WINVER >= 0x0602 */
#endif /* !NONCMESSAGES */
来源:https://stackoverflow.com/questions/13069717/letting-the-mouse-pass-through-windows-c