10

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.

JoderCoder
  • 111
  • 1
  • 5
  • 2
    Look at [first answer here](http://stackoverflow.com/questions/6165136/ws-ex-transparent-what-does-it-actually-do). It suggests using WS_EX_TRANSPARENT (a window is not transparent, but mouse events fall through). If you can't afford this, then the other possible solutions are more complicated, including windows subclassing and manual forwarding mouse events from the upper window to the window beneath. – Stan Oct 25 '12 at 14:05
  • Thanks for the response. I tried WS_EX_TRANSPARENT but it didnt work for some reason, it didn't pass-through the mouse events to the window underneath. – JoderCoder Oct 26 '12 at 14:20

4 Answers4

10

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.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • Thanks for the response. I am developing an application for Remote Desktop Connection (RDC) environments where you remote into another Window 7 machine. I have a window which is a child of the RDC - composited windows - RDC window is totally another process which I have no control over. So when the mouse is moved over, clicked, double-clicked on my window, I just want to ignore it and pass it to the window beneath it. The window beneath it is RDC window which will deliver it to the right window inside the remote session. I tried both WM_NCHITTEST and WS_EX_TRANSPARENT, and neither worked. – JoderCoder Oct 26 '12 at 14:07
1

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.

JoderCoder
  • 111
  • 1
  • 5
0

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 */
kungfooman
  • 4,473
  • 1
  • 44
  • 33