river: refactor keyboard groups implementation

This reduces the impact of keyboard groups on the Keyboard.zig
implementation and otherwise improves consistency with patterns used
elsewhere in rivers code.

There are also two small changes to the riverctl interface:

- keyboard-group-add-keyboard is renamed to keyboard-group-add
- keyboard-group-remove is added to support removing keyboards from a
group.
This commit is contained in:
Isaac Freund
2022-09-17 11:26:45 +02:00
parent 01f49bbbc1
commit e35c147cd5
10 changed files with 179 additions and 172 deletions
+34 -65
View File
@@ -25,19 +25,13 @@ const xkb = @import("xkbcommon");
const server = &@import("main.zig").server;
const util = @import("util.zig");
const KeycodeSet = @import("KeycodeSet.zig");
const Seat = @import("Seat.zig");
const InputDevice = @import("InputDevice.zig");
const KeyboardGroup = @import("KeyboardGroup.zig");
const KeycodeSet = @import("KeycodeSet.zig");
const log = std.log.scoped(.keyboard);
pub const Provider = union(enum) {
device: InputDevice,
group: *KeyboardGroup,
};
provider: Provider,
device: InputDevice,
/// Pressed keys for which a mapping was triggered on press
eaten_keycodes: KeycodeSet = .{},
@@ -46,8 +40,11 @@ key: wl.Listener(*wlr.Keyboard.event.Key) = wl.Listener(*wlr.Keyboard.event.Key)
modifiers: wl.Listener(*wlr.Keyboard) = wl.Listener(*wlr.Keyboard).init(handleModifiers),
pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
const wlr_keyboard = wlr_device.device.keyboard;
wlr_keyboard.data = @ptrToInt(self);
self.* = .{
.device = undefined,
};
try self.device.init(seat, wlr_device);
errdefer self.device.deinit();
const context = xkb.Context.new(.no_flags) orelse return error.XkbContextFailed;
defer context.unref();
@@ -57,70 +54,37 @@ pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
const keymap = xkb.Keymap.newFromNames(context, null, .no_flags) orelse return error.XkbKeymapFailed;
defer keymap.unref();
const wlr_keyboard = self.device.wlr_device.device.keyboard;
wlr_keyboard.data = @ptrToInt(self);
if (!wlr_keyboard.setKeymap(keymap)) return error.SetKeymapFailed;
self.* = .{
.provider = undefined,
};
if (wlr.KeyboardGroup.fromKeyboard(wlr_keyboard)) |grp| {
const group = @intToPtr(*KeyboardGroup, grp.data);
self.provider = .{ .group = group };
} else {
self.provider = .{ .device = undefined };
try self.provider.device.init(seat, wlr_device);
}
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
wlr_keyboard.events.key.add(&self.key);
wlr_keyboard.events.modifiers.add(&self.modifiers);
wlr_keyboard.setRepeatInfo(server.config.repeat_rate, server.config.repeat_delay);
}
pub fn deinit(self: *Self) void {
self.key.link.remove();
self.modifiers.link.remove();
switch (self.provider) {
.device => {
const wlr_keyboard = self.provider.device.wlr_device.device.keyboard;
if (wlr_keyboard.group) |group| group.removeKeyboard(wlr_keyboard);
self.provider.device.deinit();
},
.group => {},
}
self.device.deinit();
self.* = undefined;
}
/// This event is raised when a key is pressed or released.
fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboard.event.Key) void {
// This event is raised when a key is pressed or released.
const self = @fieldParentPtr(Self, "key", listener);
switch (self.provider) {
.device => {
if (self.provider.device.wlr_device.device.keyboard.group != null) return;
self.handleKeyImpl(self.provider.device.seat, self.provider.device.wlr_device, event);
},
.group => self.handleKeyImpl(self.provider.group.seat, self.provider.group.group.input_device, event),
}
}
const wlr_keyboard = self.device.wlr_device.device.keyboard;
/// Simply pass modifiers along to the client
fn handleModifiers(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
const self = @fieldParentPtr(Self, "modifiers", listener);
switch (self.provider) {
.device => {
if (self.provider.device.wlr_device.device.keyboard.group != null) return;
self.handleModifiersImpl(self.provider.device.seat, self.provider.device.wlr_device);
},
.group => self.handleModifiersImpl(self.provider.group.seat, self.provider.group.group.input_device),
}
}
// If the keyboard is in a group, this event will be handled by the group's Keyboard instance.
if (wlr_keyboard.group != null) return;
fn handleKeyImpl(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice, event: *wlr.Keyboard.event.Key) void {
const wlr_keyboard = wlr_device.device.keyboard;
self.device.seat.handleActivity();
seat.handleActivity();
seat.clearRepeatingMapping();
self.device.seat.clearRepeatingMapping();
// Translate libinput keycode -> xkbcommon
const keycode = event.keycode + 8;
@@ -137,7 +101,7 @@ fn handleKeyImpl(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice, event:
!released and
!isModifier(sym))
{
seat.cursor.hide();
self.device.seat.cursor.hide();
break;
}
}
@@ -148,11 +112,11 @@ fn handleKeyImpl(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice, event:
}
// Handle user-defined mappings
const mapped = seat.hasMapping(keycode, modifiers, released, xkb_state);
const mapped = self.device.seat.hasMapping(keycode, modifiers, released, xkb_state);
if (mapped) {
if (!released) self.eaten_keycodes.add(event.keycode);
const handled = seat.handleMapping(keycode, modifiers, released, xkb_state);
const handled = self.device.seat.handleMapping(keycode, modifiers, released, xkb_state);
assert(handled);
}
@@ -160,8 +124,8 @@ fn handleKeyImpl(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice, event:
if (!eaten) {
// If key was not handled, we pass it along to the client.
const wlr_seat = seat.wlr_seat;
wlr_seat.setKeyboard(wlr_device);
const wlr_seat = self.device.seat.wlr_seat;
wlr_seat.setKeyboard(self.device.wlr_device);
wlr_seat.keyboardNotifyKey(event.time_msec, event.keycode, event.state);
}
}
@@ -170,6 +134,17 @@ fn isModifier(keysym: xkb.Keysym) bool {
return @enumToInt(keysym) >= xkb.Keysym.Shift_L and @enumToInt(keysym) <= xkb.Keysym.Hyper_R;
}
fn handleModifiers(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void {
const self = @fieldParentPtr(Self, "modifiers", listener);
const wlr_keyboard = self.device.wlr_device.device.keyboard;
// If the keyboard is in a group, this event will be handled by the group's Keyboard instance.
if (wlr_keyboard.group != null) return;
self.device.seat.wlr_seat.setKeyboard(self.device.wlr_device);
self.device.seat.wlr_seat.keyboardNotifyModifiers(&wlr_keyboard.modifiers);
}
/// Handle any builtin, harcoded compsitor mappings such as VT switching.
/// Returns true if the keysym was handled.
fn handleBuiltinMapping(keysym: xkb.Keysym) bool {
@@ -189,9 +164,3 @@ fn handleBuiltinMapping(keysym: xkb.Keysym) bool {
else => return false,
}
}
/// Simply pass modifiers along to the client
fn handleModifiersImpl(_: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) void {
seat.wlr_seat.setKeyboard(wlr_device);
seat.wlr_seat.keyboardNotifyModifiers(&wlr_device.device.keyboard.modifiers);
}