From dd9933b6a15e415e63b52585301d9216ef57b3cf Mon Sep 17 00:00:00 2001 From: Leon Henrik Plickat Date: Wed, 3 Jan 2024 21:30:46 +0100 Subject: [PATCH] keyboard-groups: use globber for identifier matching --- doc/riverctl.1.scd | 3 ++- river/Keyboard.zig | 17 +++++++++------ river/KeyboardGroup.zig | 37 ++++++++++++++++++++++---------- river/command/keyboard_group.zig | 3 +++ 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd index 5553306..b46185d 100644 --- a/doc/riverctl.1.scd +++ b/doc/riverctl.1.scd @@ -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 diff --git a/river/Keyboard.zig b/river/Keyboard.zig index 97eae23..69c34b2 100644 --- a/river/Keyboard.zig +++ b/river/Keyboard.zig @@ -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; + } } } diff --git a/river/KeyboardGroup.zig b/river/KeyboardGroup.zig index 617c042..cf68bde 100644 --- a/river/KeyboardGroup.zig +++ b/river/KeyboardGroup.zig @@ -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); diff --git a/river/command/keyboard_group.zig b/river/command/keyboard_group.zig index 4453006..442fbdc 100644 --- a/river/command/keyboard_group.zig +++ b/river/command/keyboard_group.zig @@ -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]); }