Winit: [Wayland] No ModifiersChanged event send when window doesn't have keyboard focus, but at least has pointer focus, on modifer release

Created on 5 Jan 2020  路  13Comments  路  Source: rust-windowing/winit

For e.g. if you open a URL in Alacritty holding some modifier your keyboard focus will move to your browser, but pointer could be still over Alacritty and will highlight URL even if you release all your modifiers. So to sync your modifiers you should bring keyboard focus back to the window.

I feel like winit can't do anything about it, knowing some Wayland security concerns, however it's better to keep this issue around, maybe there's something can be done.

cc @chrisduerr

Wayland needs investigation bug

All 13 comments

(this is actually a Wayland issue @goddessfreya)

@cole-h Thanks. I was looking at other macOS issues (#1361 & #1360) and must've gotten confused.

Overall, the common wisdom on Wayland is that whenever the keyboard focus is lost, the client should behave as if all keys and modifiers were released. The server re-advertizes them when focus is gained.

Winit should probably emulate these key press & release events.

Sending a ModifiersChanged(empty) when leaving and then just sending ModifiersChanged(...) again when focus is regained would work fine for us.

Actually it's only okay if holding shift and clicking the window doesn't remove keyboard focus from the window when the mouse moves outside. It obviously shouldn't stop terminal selection when the mouse leaves the window. But I think Wayland should keep window focus in that case?

Actually it's only okay if holding shift and clicking the window doesn't remove keyboard focus from the window when the mouse moves outside. It obviously shouldn't stop terminal selection when the mouse leaves the window. But I think Wayland should keep window focus in that case?

That would be compositor-dependent, so winit cannot really enforce anything there. But generally compositors behave in a sane way : the focus would not be lost until the mouse button is released, or even until the user actually clicks on an other window.

Sending a ModifiersChanged(empty) when leaving and then just sending ModifiersChanged(...) again when focus is regained would work fine for us.

If we're doing that, does it make sense to make ModifiersChanged a member of WindowEvent and send events to the window that currently has keyboard focus? DeviceEvent is supposed to be used for raw, unfiltered events directly from the device, and doing additional filtering on ModifiersChanged violates that. I think it's a bit weird from an API design standpoint to have ModifiersChanged in DeviceEvent anyway, since it's mainly useful for GUI input and GUI input events are delivered through WindowEvent.

ModifiersChanged is actually the only DeviceEvent that Alacritty handles currently. So I do feel like a WindowEvent would probably be more appropriate.

@Osspial IIRC ModifiersChanged was a WindowEvent at some point, however it was breaking some things on X11/Xwayland, so it was changed to DeviceEvent. I think @murarth should have a better explanation on why things are the way they are right now, however I could be completely wrong.

Oh, right. The problem is that this event needs to arrive before the KeyboardInput event the modifier change is associated to. I think that's why it was changed iirc.

The full discussion is here: #1259. I didn't read through the issue at the time since it was X11-specific, but it looks like with #1279 implemented there isn't much of a reason to require the event be a device event now.

On X11, it makes the most sense for ModifiersChanged to be a DeviceEvent. Modifiers state is a global state, it is generated mainly by events that are not related to any window, it can be generated even if a process does not currently have an open window, and it is generated only once even if a process has multiple open windows.

However, it could be moved to WindowEvent with the following changes:

  • winit would generate ModifiersChanged(empty) immediately before Focused(false), if the current modifiers set is not empty.
  • winit would generate ModifiersChanged(modifiers) immediately after Focused(true), if the current modifiers set is not empty.
  • winit would track the currently focused window ID and send this with the ModifiersChanged event. As a result, applications would no longer receive ModifiersChanged events when no window belonging to the process is in focus.

If none of these changes are a major issue for applications, then I have no objection to moving ModifiersChanged back to WindowEvent.

I've submitted PR #1381 to move the ModifiersChanged variant back to WindowEvent.

It includes the change for X11 and Wayland, plus fixing the original issue on Wayland described here. It's missing implementations for Mac and Windows because I don't know whether those platforms also require the same window focus workaround.

It's missing implementations for Mac and Windows because I don't know whether those platforms also require the same window focus workaround.

@murarth This has just been reported in Alacritty to also be buggy on macOS: https://github.com/alacritty/alacritty/issues/3188. I can't say something about Windows, but macOS definitely seems to need it. So for consistency, it probably would make sense to do this on all platforms?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

francesca64 picture francesca64  路  4Comments

francesca64 picture francesca64  路  5Comments

coderhwz picture coderhwz  路  3Comments

chrisduerr picture chrisduerr  路  3Comments

alexheretic picture alexheretic  路  4Comments