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:
+34
-65
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user