Keyboard: ignore multiple presses of a key

I have managed to crash river (because the relevant assertion was wrong)
on this using fcitx5 (5.1.8) and anthy with the following sequence of
key events on a physical keyboard (every line followed by releasing
everything):
    super-; (my shortcut to enable anthy)
    shift-letter (fcitx doesn't release shift on its virtual keyboard)
    escape
    shift (fcitx sends another press event)
The failure to release shift is not the only weirdness happening, but
it's what eventually lead to the assertion failure.
This commit is contained in:
tiosgz 2024-03-18 11:17:59 +00:00 committed by Isaac Freund
parent 7ceed0d093
commit 198351794b
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11

View File

@ -59,9 +59,15 @@ pub const Pressed = struct {
keys: std.BoundedArray(Key, capacity) = .{}, keys: std.BoundedArray(Key, capacity) = .{},
fn addAssumeCapacity(pressed: *Pressed, new: Key) void { fn contains(pressed: *Pressed, code: u32) bool {
for (pressed.keys.constSlice()) |item| assert(new.code != item.code); for (pressed.keys.constSlice()) |item| {
if (item.code == code) return true;
}
return false;
}
fn addAssumeCapacity(pressed: *Pressed, new: Key) void {
assert(!pressed.contains(new.code));
pressed.keys.appendAssumeCapacity(new); pressed.keys.appendAssumeCapacity(new);
} }
@ -177,6 +183,16 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
if (!released and handleBuiltinMapping(sym)) return; if (!released and handleBuiltinMapping(sym)) return;
} }
// Some virtual_keyboard clients are buggy and press a key twice without
// releasing it in between. There is no good way for river to handle this
// other than to ignore any newer presses. No need to worry about pairing
// the correct release, as the client is unlikely to send all of them
// (and we already ignore releasing keys we don't know were pressed).
if (!released and keyboard.pressed.contains(event.keycode)) {
log.err("key pressed again without release, virtual-keyboard client bug?", .{});
return;
}
// Every sent press event, to a regular client or the input method, should have // Every sent press event, to a regular client or the input method, should have
// the corresponding release event sent to the same client. // the corresponding release event sent to the same client.
// Similarly, no press event means no release event. // Similarly, no press event means no release event.