How to intercept child control mouse wheen messages - winapi

I need to get mouse wheel events in frame window but they are caught by child windows. How can I redirect mouse wheel messages from all child windows to this window?

It is already done for you out of the box. Make sure you don't prevents things from rolling the usual way.
WM_MOUSEWHEEL message (Windows)
Sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.

Related

How to properly override mouse events in other apps (Windows)?

I'm trying to implement system-wide drag operation with middle mouse button. It should override middle mouse drag behavior in other programs. Currently, I am handling global mouse events with system-wide hooks.
Problem is - many programs still receive and handle same events like I did not intercept them.
Here's what I tried:
not call the next hook for mouse down event: I never receive mouse up, so I don't know where and when to stop dragging
not call the next hook for mouse move: cursor slows down tremendously
not call the next hook for mouse up: most windows in the system stop reacting to mouse events completely after my drag is finished
always call the next hook in the chain: if the control under mouse has scroll in it, most of the time it will be scrolling while my drag is in progress. Also UWP apps continue receiving mouse events during my drag, so if a link in MS Edge happens to be under cursor when it started, and mouse does not leave Edge boundary, Edge receives click event, and new tab is opened
What I need is: when user holds middle mouse and starts dragging, my drag handler should be called, and no other handlers, like file drag, scroll, etc should happen.
I ended up with somewhat hacky solution:
do not call the next hook for mouse down for middle button
record where it was pressed
when handling mouse up, if user did not drag - replay the whole mouse up + mouse down using SendInput from a separate thread (to avoid deadlock due to reentrancy)

When (and how) to lay out the children of a Win32 window in response to a resize?

Windows sends several messages when a window is resized:
WM_GETMINMAXINFO
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE
WM_NCCALCSIZE
WM_SIZING
WM_SIZE
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGED
and possibly more.
If I would like to re-position the children when my window is resized, where and how should I do so?
I'm looking for the "best" method -- i.e. the method with the fewest gotcha's and the least flicker.
My current method is to perform all the repositioning inside WM_NCCALCSIZE, using DeferWindowPos.
However, I've also tried handling it inside WM_WINDOWPOSCHANGED... but no matter where I handle it, it seems like there is always at least one "moment" when the window is painted in an in-between state, where the window's size has changed, but its contents have yet to be resized.
Another effect I would also like to avoid: moving a child after it has already moved. I don't want the user to see a control sliding down and then back up because of my change -- it should have as few transient effects as possible.
Am I doing this correctly? Is there a better place I can lay out the window's children?
You should re-position the window in the WM_SIZE message, because that is the last one that the window recieves before complete it's task...To re-position the window you can use MoveWindow

Win32 doesn't send mouse events to my window, only its parent. why?

I have a window that's a CHILD window of another window. For reasons beyond me, NC_HITTEST never gets called on it, no mouse events are called for it (but rather reach its parent window).
Why is that? I want that child window to process his own mouse clicks.
NC_HITTEST is not likely a message you want to be catching for mouse events. You want to be catching WM_MOUSEMOVE, WM_LBUTTONDOWN, etc...

Windows: Mouse Down on Window Decoration

In almost any Windows application, I notice that holding the mouse button down in a non-client area causes the painting to stop. Why is this required?
For example, I have a Managed Direct 3D application which displays a spinning cube. If I place the pointer over the title bar and hold the mouse button down, the cube ceases to spin even though I have not coded any such condition into my loop.
Why is painting halted? What are the benefits? Most importantly, how can I work around this?
When you click on the title bar, there's a brief pause while the window manager tries to determine whether or not you're clicking or beginning a drag (moving the window). If you're still holding down the button, then it's a drag: the window manager sets up its own message loop and pumps messages until you release the mouse. Your window should still be able to process messages, because they'll still be dispatched, but if your animation depends on a custom message loop then you'll be stuck 'till the modal drag loop ends.
Work around it by triggering your animation in response to messages: a timer seems like a good choice to me.

How to tell if a a mouse button has been released outside the window?

Usually, when a user holds the mouse pressed over a button, moves the mouse away from the window, and then releases it, the button can tell that the mouse has been released even though the release has actually occured outside the window.
When I inspect mouse clicks in my window, how can I imitate the same behavior?
When a mouse button being pushed down over the window I get the WM_XBUTTONDOWN message, but Windows don't treat it as if anything is logically being "clicked", so after the mouse leaves the window, no further messages will arrive at the window, which results in a "lost" WM_XBUTTONUP message.
When you receive the button down, you capture the mouse. That means that all the mouse events until releasing the capture will be reported to the window that captured the mouse.
See the documentation here. You also have a link to an example from that page.
Use the DragDetect() function.
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dragdetect?redirectedfrom=MSDN

Resources