rust-windowing / winit

Window handling library in pure Rust
https://docs.rs/winit/
Apache License 2.0
4.84k stars 902 forks source link

`CursorEntered` and `CursorLeft` events not getting sent if entered a second window while holding the mouse button down #3908

Open noemu opened 2 months ago

noemu commented 2 months ago

CursorEntered and CursorLeft works perfectly only for the window you start the drag and drop gesture. While holding the mouse button the events are not fired in another window.

How to reproduce:

Expected Result:

Actual Result:

I've tested it only on windows. I'm not sure if it is related to windows or the following fixed bug Issue #3153

madsmtm commented 2 months ago

On macOS, if I click and hold the cursor from window A to B, I get the following sequence:

Window A: MouseInput { state: Pressed, ... }
Window A: CursorLeft
Window A: MouseInput { state: Released, ... }
Window B: CursorEntered

I have no idea what the desired is, but I'm not sure we really have the ability to influence this in Winit, at least not without a lot of hacks?

noemu commented 1 month ago

On Windows: FileHovered, FileDropped and FilesHoveredLeft is also affected by this Issue. I started a File-Drag with drag-rs from Window A. Window B doesn't fire any events until the mouse is released.

The whole event-loop of window B isn't running as long as the mouse button is pressed. Switching to window B with Alt-Tab while holding the mouse button, seems to enable the event-loop of B. Maybe switching the focus could be a workaround for my implementation.

noemu commented 1 month ago

I finally figured out, why it's behaving like that.

It's basically because of capture_mouse / SetCapture(window).

WM_LBUTTONDOWN => {
            ...
            unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
            ...
        },

As long as the mouse is captured by a window, all events are forwarded to its event loop.

The workaround for me is to check in MouseMove if I entered another window. And in that case I would switch the SetCapture to the window under the cursor.

daxpedda commented 1 month ago

AFAIK capturing is necessary for "pointer focus" to work correctly. This is the concept of having mouse events continue to be sent to the window where the input was started.

@madsmtm on most backends I believe you don't receive a CursorEnter/CursorLeave on other windows during pointer focus, so I think MacOS should be adjusted.

Whatever comes out of this, I believe we should make sure all backends behave the same, barring any platform-specific dangers coming up.