seat/keyboard: support sending modifiers when not focused

This adds wlr_seat_client_notify_modifiers which sends the current
keyboard modifiers to an additional client, tracking what the client
last saw to avoid unneeded duplicates. This is useful to make actions
like "ctrl+scroll" work correctly when pointer and keyboard focus are on
distinct clients.

The tracked modifier state is also used to avoid sending unneeded
modifiers events in default_keyboard_modifiers.  No de-duplication is
performed in wlr_seat_keyboard_send_modifiers because that function is
used in cases where the protocol unconditionally requires a modifiers
event to be sent (such as after wl_keyboard_enter).
This commit is contained in:
Daniel De Graaf 2024-01-23 19:30:33 -05:00
parent 3ad4374a54
commit 8ad0c0166b
2 changed files with 65 additions and 12 deletions

View file

@ -55,6 +55,13 @@ struct wlr_seat_client {
struct wlr_serial_ringset serials;
bool needs_touch_frame;
// The client's current knowledge of the keyboard modifier state. This
// will lag behind the actual state if the client does not have
// keyboard focus; it is used by wlr_seat_client_notify_modifiers to
// allow actions like ctrl+scroll to work without sending duplicate
// events if modifiers are unchanged.
struct wlr_keyboard_modifiers tracked_modifiers;
// When the client doesn't support high-resolution scroll, accumulate deltas
// until we can notify a discrete event.
// Some mice have a free spinning wheel, making possible to lock the wheel
@ -526,6 +533,14 @@ void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time_msec,
void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers);
/**
* Update an additional client's view of the keyboard modifier state. This
* does nothing if the target has keyboard focus or if its view of the modifier
* state still matches the current modifier state.
*/
void wlr_seat_client_notify_modifiers(struct wlr_seat *seat,
struct wlr_seat_client *target);
/**
* Send a keyboard enter event to the given surface and consider it to be the
* focused surface for the keyboard. This will send a leave event to the last