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

@ -10,6 +10,11 @@
#include "types/wlr_data_device.h"
#include "types/wlr_seat.h"
static void seat_keyboard_send_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers,
struct wlr_seat_client *client,
bool force);
static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
const struct wlr_keyboard_modifiers *modifiers) {
@ -27,7 +32,7 @@ static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab,
static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
const struct wlr_keyboard_modifiers *modifiers) {
wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
seat_keyboard_send_modifiers(grab->seat, modifiers, NULL, false);
}
static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
@ -195,34 +200,67 @@ static void seat_keyboard_handle_surface_destroy(struct wl_listener *listener,
wlr_seat_keyboard_clear_focus(state->seat);
}
void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers) {
struct wlr_seat_client *client = seat->keyboard_state.focused_client;
static void seat_keyboard_send_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers,
struct wlr_seat_client *client,
bool force) {
const struct wlr_keyboard_modifiers empty = {};
struct wl_resource *resource;
if (client == NULL) {
client = seat->keyboard_state.focused_client;
}
if (client == NULL) {
return;
}
if (modifiers == NULL) {
modifiers = ∅
}
struct wlr_keyboard_modifiers *tracked = &client->tracked_modifiers;
if (!force && tracked->depressed == modifiers->depressed &&
tracked->latched == modifiers->latched &&
tracked->locked == modifiers->locked &&
tracked->group == modifiers->group) {
return;
}
uint32_t serial = wlr_seat_client_next_serial(client);
struct wl_resource *resource;
*tracked = *modifiers;
wl_resource_for_each(resource, &client->keyboards) {
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;
}
if (modifiers == NULL) {
wl_keyboard_send_modifiers(resource, serial, 0, 0, 0, 0);
} else {
wl_keyboard_send_modifiers(resource, serial,
modifiers->depressed, modifiers->latched,
modifiers->locked, modifiers->group);
}
wl_keyboard_send_modifiers(resource, serial,
modifiers->depressed, modifiers->latched,
modifiers->locked, modifiers->group);
}
}
void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
const struct wlr_keyboard_modifiers *modifiers) {
seat_keyboard_send_modifiers(seat, modifiers, NULL, true);
}
void wlr_seat_client_notify_modifiers(struct wlr_seat *seat,
struct wlr_seat_client *target) {
struct wlr_seat_client *focused = seat->keyboard_state.focused_client;
if (target == NULL || target == focused) {
return;
}
struct wlr_keyboard_modifiers *modifiers = &seat->keyboard_state.keyboard->modifiers;
seat_keyboard_send_modifiers(seat, modifiers, target, false);
}
void seat_client_send_keyboard_leave_raw(struct wlr_seat_client *seat_client,
struct wlr_surface *surface) {
uint32_t serial = wlr_seat_client_next_serial(seat_client);
struct wl_resource *resource;
const struct wlr_keyboard_modifiers unset = {};
seat_client->tracked_modifiers = unset;
wl_resource_for_each(resource, &seat_client->keyboards) {
if (seat_client_from_keyboard_resource(resource) == NULL) {
continue;