Seat: avoid leaking eaten keys to client on focus
Until now, Seat.setFocusRaw sent all pressed keys to the client, including ones that should be eaten. (Try e.g. changing focus to a nested wlroots compositor with a terminal open to easily see it.) However, only filtering out the eaten keys is not enough; they were eaten only once all mappings had been executed. Therefore, the original function had to be split into one looking up mappings and another executing them.
This commit is contained in:
parent
6d6646febe
commit
1e3b8ed161
@ -17,6 +17,7 @@
|
|||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
const wlr = @import("wlroots");
|
const wlr = @import("wlroots");
|
||||||
const wl = @import("wayland").server.wl;
|
const wl = @import("wayland").server.wl;
|
||||||
const xkb = @import("xkbcommon");
|
const xkb = @import("xkbcommon");
|
||||||
@ -61,6 +62,7 @@ pub fn init(self: *Self, seat: *Seat, input_device: *wlr.InputDevice) !void {
|
|||||||
defer keymap.unref();
|
defer keymap.unref();
|
||||||
|
|
||||||
const wlr_keyboard = self.input_device.device.keyboard;
|
const wlr_keyboard = self.input_device.device.keyboard;
|
||||||
|
wlr_keyboard.data = @ptrToInt(self);
|
||||||
|
|
||||||
if (!wlr_keyboard.setKeymap(keymap)) return error.SetKeymapFailed;
|
if (!wlr_keyboard.setKeymap(keymap)) return error.SetKeymapFailed;
|
||||||
|
|
||||||
@ -111,9 +113,14 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa
|
|||||||
if (!released and handleBuiltinMapping(sym)) return;
|
if (!released and handleBuiltinMapping(sym)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle user-defined mapping
|
// Handle user-defined mappings
|
||||||
const mapped = self.seat.handleMapping(keycode, modifiers, released, xkb_state);
|
const mapped = self.seat.hasMapping(keycode, modifiers, released, xkb_state);
|
||||||
if (mapped and !released) self.eaten_keycodes.add(event.keycode);
|
if (mapped) {
|
||||||
|
if (!released) self.eaten_keycodes.add(event.keycode);
|
||||||
|
|
||||||
|
const handled = self.seat.handleMapping(keycode, modifiers, released, xkb_state);
|
||||||
|
assert(handled);
|
||||||
|
}
|
||||||
|
|
||||||
const eaten = if (released) self.eaten_keycodes.remove(event.keycode) else mapped;
|
const eaten = if (released) self.eaten_keycodes.remove(event.keycode) else mapped;
|
||||||
|
|
||||||
|
@ -50,3 +50,8 @@ pub fn remove(self: *Self, old: u32) bool {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes other's contents from self (if present)
|
||||||
|
pub fn subtract(self: *Self, other: Self) void {
|
||||||
|
for (other.items[0..other.len]) |item| _ = self.remove(item);
|
||||||
|
}
|
||||||
|
@ -31,6 +31,7 @@ const DragIcon = @import("DragIcon.zig");
|
|||||||
const Cursor = @import("Cursor.zig");
|
const Cursor = @import("Cursor.zig");
|
||||||
const InputManager = @import("InputManager.zig");
|
const InputManager = @import("InputManager.zig");
|
||||||
const Keyboard = @import("Keyboard.zig");
|
const Keyboard = @import("Keyboard.zig");
|
||||||
|
const KeycodeSet = @import("KeycodeSet.zig");
|
||||||
const Switch = @import("Switch.zig");
|
const Switch = @import("Switch.zig");
|
||||||
const Mapping = @import("Mapping.zig");
|
const Mapping = @import("Mapping.zig");
|
||||||
const LayerSurface = @import("LayerSurface.zig");
|
const LayerSurface = @import("LayerSurface.zig");
|
||||||
@ -253,12 +254,20 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
|||||||
|
|
||||||
// Send keyboard enter/leave events and handle pointer constraints
|
// Send keyboard enter/leave events and handle pointer constraints
|
||||||
if (target_surface) |wlr_surface| {
|
if (target_surface) |wlr_surface| {
|
||||||
if (self.wlr_seat.getKeyboard()) |keyboard| {
|
if (self.wlr_seat.getKeyboard()) |wlr_keyboard| {
|
||||||
|
var keycodes = KeycodeSet{
|
||||||
|
.items = wlr_keyboard.keycodes,
|
||||||
|
.len = wlr_keyboard.num_keycodes,
|
||||||
|
};
|
||||||
|
|
||||||
|
const keyboard = @intToPtr(*Keyboard, wlr_keyboard.data);
|
||||||
|
keycodes.subtract(keyboard.eaten_keycodes);
|
||||||
|
|
||||||
self.wlr_seat.keyboardNotifyEnter(
|
self.wlr_seat.keyboardNotifyEnter(
|
||||||
wlr_surface,
|
wlr_surface,
|
||||||
&keyboard.keycodes,
|
&keycodes.items,
|
||||||
keyboard.num_keycodes,
|
keycodes.len,
|
||||||
&keyboard.modifiers,
|
&wlr_keyboard.modifiers,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
self.wlr_seat.keyboardNotifyEnter(wlr_surface, null, 0, null);
|
self.wlr_seat.keyboardNotifyEnter(wlr_surface, null, 0, null);
|
||||||
@ -349,8 +358,25 @@ pub fn handleViewUnmap(self: *Self, view: *View) void {
|
|||||||
if (self.focused == .view and self.focused.view == view) self.focus(null);
|
if (self.focused == .view and self.focused.view == view) self.focus(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is there a user-defined mapping for passed keycode, modifiers and keyboard state?
|
||||||
|
pub fn hasMapping(
|
||||||
|
self: *Self,
|
||||||
|
keycode: xkb.Keycode,
|
||||||
|
modifiers: wlr.Keyboard.ModifierMask,
|
||||||
|
released: bool,
|
||||||
|
xkb_state: *xkb.State,
|
||||||
|
) bool {
|
||||||
|
const modes = &server.config.modes;
|
||||||
|
for (modes.items[self.mode_id].mappings.items) |*mapping| {
|
||||||
|
if (mapping.match(keycode, modifiers, released, xkb_state)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle any user-defined mapping for passed keycode, modifiers and keyboard state
|
/// Handle any user-defined mapping for passed keycode, modifiers and keyboard state
|
||||||
/// Returns true if the key was handled
|
/// Returns true if at least one mapping was run
|
||||||
pub fn handleMapping(
|
pub fn handleMapping(
|
||||||
self: *Self,
|
self: *Self,
|
||||||
keycode: xkb.Keycode,
|
keycode: xkb.Keycode,
|
||||||
@ -359,7 +385,7 @@ pub fn handleMapping(
|
|||||||
xkb_state: *xkb.State,
|
xkb_state: *xkb.State,
|
||||||
) bool {
|
) bool {
|
||||||
const modes = &server.config.modes;
|
const modes = &server.config.modes;
|
||||||
// In case more than on mapping matches, all of them are activated
|
// In case more than one mapping matches, all of them are activated
|
||||||
var handled = false;
|
var handled = false;
|
||||||
for (modes.items[self.mode_id].mappings.items) |*mapping| {
|
for (modes.items[self.mode_id].mappings.items) |*mapping| {
|
||||||
if (mapping.match(keycode, modifiers, released, xkb_state)) {
|
if (mapping.match(keycode, modifiers, released, xkb_state)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user