Search code examples
winformswinapiwindows-messages

How can I receive mouse events when a wrapped control has set capture?


My WndProc isn't seeing mouse-up notifications when I click with a modifier key (shift or control) pressed. I see them without the modifier key, and I see mouse-down notifications with the modifier keys.

I'm trying to track user actions in a component I didn't write, so I'm using the Windows Forms NativeWindow wrapper (wrapping the component) to get Windows messages from the WndProc() method.

I've tried tracking the notifications I do get, and I the only clue I see is WM_CAPTURECHANGED. I've tried calling SetCapture when I receive the WM_LBUTTONDOWN message, but it doesn't help.

Without modifier (skipping paint, timer and NCHITTEST messages):

WM_PARENTNOTIFY
WM_MOUSEACTIVATE
WM_MOUSEACTIVATE
WM_SETCURSOR
WM_LBUTTONDOWN
WM_SETCURSOR
WM_MOUSEMOVE
WM_SETCURSOR
WM_LBUTTONUP

With modifier (skipping paint, timer and NCHITTEST messages):

WM_KEYDOWN
WM_PARENTNOTIFY
WM_MOUSEACTIVATE
WM_MOUSEACTIVATE
WM_SETCURSOR
WM_LBUTTONDOWN
WM_SETCURSOR (repeats)
WM_KEYDOWN (repeats)
WM_KEYUP

If I hold the mouse button down for a long time, I can usually get a WM_LBUTTONUP notification, but it should be possible to make it more responsive..

Edit: I've tried control-clicking outside of the component of interest and moving the cursor into it before releasing the mouse button, and then I do get a WM_LBUTTONUP notification, so it looks like the component is capturing the mouse on mouse-down. Is there any way to receive that notification when another window has captured the mouse?

Thanks.


Solution

  • Frequently, when the mouse is clicked down on a (native) windows control, some kind of modal tracking loop is entered to manage the "drag" operation. During the duration of the modal loop messages are directly extracted from the message queue and processed - the mouse up notification would be one of the terminating conditions for the modal loop and thus typically consumed without being dispatched.

    Can you click elsewhere on the desktop, move the mouse over the window and release and see the click? That would indicate some kind of modal code is being triggered on mouse-down messages.


    I can think of four ways you can possibly get around this problem.

    • Find out what sort of drag operation the control supports - and disable it. Hopefully if the built in WindowProc knows that no modal drags are allowed it won't enter a modal loop.
    • Prevent the WindowProc finding out about the modal drag: i.e. intercept AND DON'T PASS ON any WM_LBUTTONDOWN messages to the next Windowproc in the chain.
    • Install a message hook using SetWindowsHookEx.

    All these solutions are very windows API. No idea how they translate in the managed environment.