input: Fix next/prev layout switch for grouped devices

Input devices in a seat can be grouped so that configuration changes on
one device, like the active layout, are automatically propagated to the
other devices.

The current logic for xkb_switch_layout wasn't accounting for this,
however. It was looping through all input devices and changing the
layout for each one, causing grouped devices to have their layouts
changed multiple times. This wasn't noticed when setting the layout to a
fixed index, but caused the wrong layout to be selected when using
the 'next' and 'prev' keywords.

In order to fix this issue, loop over each seat and, if the input
devices in the seat are grouped, change the layout only for the first
device in the seat.
This commit is contained in:
Nícolas F. R. A. Prado 2022-01-03 22:24:06 -05:00
parent eaeb173a4b
commit a933b4efed

View file

@ -3,6 +3,7 @@
#include "sway/config.h" #include "sway/config.h"
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "sway/input/seat.h"
#include "log.h" #include "log.h"
static void switch_layout(struct wlr_keyboard *kbd, xkb_layout_index_t idx) { static void switch_layout(struct wlr_keyboard *kbd, xkb_layout_index_t idx) {
@ -66,20 +67,30 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
relative = 0; relative = 0;
} }
struct sway_input_device *dev; struct sway_seat *seat;
wl_list_for_each(dev, &server.input->devices, link) { wl_list_for_each(seat, &server.input->seats, link) {
if (strcmp(ic->identifier, "*") != 0 && struct sway_seat_device *seat_dev;
strcmp(ic->identifier, "type:keyboard") != 0 && struct sway_input_device *dev;
strcmp(ic->identifier, dev->identifier) != 0) { wl_list_for_each(seat_dev, &seat->devices, link) {
continue; dev = seat_dev->input_device;
} if (strcmp(ic->identifier, "*") != 0 &&
if (dev->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { strcmp(ic->identifier, "type:keyboard") != 0 &&
continue; strcmp(ic->identifier, dev->identifier) != 0) {
} continue;
if (relative) { }
switch_layout_relative(dev->wlr_device->keyboard, relative); if (dev->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
} else { continue;
switch_layout(dev->wlr_device->keyboard, layout); }
if (relative) {
switch_layout_relative(dev->wlr_device->keyboard, relative);
} else {
switch_layout(dev->wlr_device->keyboard, layout);
}
// If input devices in this seat are grouped, skip the
// other devices since the layout change will already be
// propagated automatically.
if (dev->wlr_device->keyboard->group)
break;
} }
} }