keyboard-groups: use globber for identifier matching

This commit is contained in:
Leon Henrik Plickat 2024-01-03 21:30:46 +01:00 committed by Isaac Freund
parent 540ca043df
commit dd9933b6a1
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
4 changed files with 41 additions and 19 deletions

View File

@ -442,7 +442,8 @@ matches everything while _\*\*_ and the empty string are invalid.
*keyboard-group-add* _group_name_ _input_device_name_
Add a keyboard to a keyboard group, identified by the keyboard's
input device name. Any currently connected and future keyboards with
the given name will be added to the group.
the given name will be added to the group. Simple globbing patterns are
supported, see the rules section for further information on globs.
*keyboard-group-remove* _group_name_ _input_device_name_
Remove a keyboard from a keyboard group, identified by the keyboard's

View File

@ -21,6 +21,7 @@ const assert = std.debug.assert;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const xkb = @import("xkbcommon");
const globber = @import("globber");
const server = &@import("main.zig").server;
const util = @import("util.zig");
@ -52,13 +53,15 @@ pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void {
// wlroots will log a more detailed error if this fails.
if (!wlr_keyboard.setKeymap(server.config.keymap)) return error.OutOfMemory;
// Add to keyboard group, if applicable.
var it = seat.keyboard_groups.first;
while (it) |node| : (it = node.next) {
if (node.data.identifiers.contains(self.device.identifier)) {
// wlroots will log an error if this fails explaining the reason.
_ = node.data.wlr_group.addKeyboard(wlr_keyboard);
break;
// Add to keyboard-group, if applicable.
var group_it = seat.keyboard_groups.first;
outer: while (group_it) |group_node| : (group_it = group_node.next) {
for (group_node.data.globs.items) |glob| {
if (globber.match(glob, self.device.identifier)) {
// wlroots will log an error if this fails explaining the reason.
_ = group_node.data.wlr_group.addKeyboard(wlr_keyboard);
break :outer;
}
}
}

View File

@ -20,6 +20,7 @@ const std = @import("std");
const assert = std.debug.assert;
const mem = std.mem;
const globber = @import("globber");
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const xkb = @import("xkbcommon");
@ -35,7 +36,7 @@ const Keyboard = @import("Keyboard.zig");
seat: *Seat,
wlr_group: *wlr.KeyboardGroup,
name: []const u8,
identifiers: std.StringHashMapUnmanaged(void) = .{},
globs: std.ArrayListUnmanaged([]const u8) = .{},
pub fn create(seat: *Seat, name: []const u8) !void {
log.debug("new keyboard group: '{s}'", .{name});
@ -63,11 +64,11 @@ pub fn destroy(group: *KeyboardGroup) void {
log.debug("destroying keyboard group: '{s}'", .{group.name});
util.gpa.free(group.name);
{
var it = group.identifiers.keyIterator();
while (it.next()) |id| util.gpa.free(id.*);
for (group.globs.items) |glob| {
util.gpa.free(glob);
}
group.identifiers.deinit(util.gpa);
group.globs.deinit(util.gpa);
group.wlr_group.destroy();
@ -77,14 +78,23 @@ pub fn destroy(group: *KeyboardGroup) void {
}
pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void {
if (group.identifiers.contains(new_id)) return;
for (group.globs.items) |glob| {
if (mem.eql(u8, glob, new_id)) return;
}
log.debug("keyboard group '{s}' adding identifier: '{s}'", .{ group.name, new_id });
const owned_id = try util.gpa.dupe(u8, new_id);
errdefer util.gpa.free(owned_id);
try group.identifiers.put(util.gpa, owned_id, {});
// Glob is validated in the command handler.
try group.globs.append(util.gpa, owned_id);
errdefer {
// Not used now, but if at any point this function is modified to that
// it may return an error after the glob pattern is added to the list,
// the list will have a pointer to freed memory in its last position.
_ = group.globs.pop();
}
// Add any existing matching keyboards to the group.
var it = server.input_manager.devices.iterator(.forward);
@ -92,7 +102,7 @@ pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void {
if (device.seat != group.seat) continue;
if (device.wlr_device.type != .keyboard) continue;
if (mem.eql(u8, new_id, device.identifier)) {
if (globber.match(device.identifier, new_id)) {
log.debug("found existing matching keyboard; adding to group", .{});
if (!group.wlr_group.addKeyboard(device.wlr_device.toKeyboard())) {
@ -108,8 +118,13 @@ pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void {
}
pub fn removeIdentifier(group: *KeyboardGroup, id: []const u8) !void {
if (group.identifiers.fetchRemove(id)) |kv| {
util.gpa.free(kv.key);
for (group.globs.items, 0..) |glob, index| {
if (mem.eql(u8, glob, id)) {
_ = group.globs.orderedRemove(index);
break;
}
} else {
return;
}
var it = server.input_manager.devices.iterator(.forward);
@ -117,7 +132,7 @@ pub fn removeIdentifier(group: *KeyboardGroup, id: []const u8) !void {
if (device.seat != group.seat) continue;
if (device.wlr_device.type != .keyboard) continue;
if (mem.eql(u8, device.identifier, id)) {
if (globber.match(device.identifier, id)) {
const wlr_keyboard = device.wlr_device.toKeyboard();
assert(wlr_keyboard.group == group.wlr_group);
group.wlr_group.removeKeyboard(wlr_keyboard);

View File

@ -17,6 +17,8 @@
const std = @import("std");
const mem = std.mem;
const globber = @import("globber");
const server = &@import("../main.zig").server;
const util = @import("../util.zig");
@ -69,6 +71,7 @@ pub fn keyboardGroupAdd(
out.* = msg;
return;
};
try globber.validate(args[2]);
try group.addIdentifier(args[2]);
}