aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--completions/bash/riverctl3
-rw-r--r--completions/fish/riverctl.fish7
-rw-r--r--completions/zsh/_riverctl3
-rw-r--r--doc/riverctl.1.scd20
-rw-r--r--river/InputDevice.zig39
-rw-r--r--river/Keyboard.zig99
-rw-r--r--river/KeyboardGroup.zig108
-rw-r--r--river/Seat.zig20
-rw-r--r--river/command.zig7
-rw-r--r--river/command/keyboard_group.zig45
10 files changed, 179 insertions, 172 deletions
diff --git a/completions/bash/riverctl b/completions/bash/riverctl
index c0b0bbd..9793b6f 100644
--- a/completions/bash/riverctl
+++ b/completions/bash/riverctl
@@ -5,7 +5,8 @@ function __riverctl_completion ()
OPTS=" \
keyboard-group-create \
keyboard-group-destroy \
- keyboard-group-add-keyboard \
+ keyboard-group-add \
+ keyboard-group-remove \
csd-filter-add \
exit \
float-filter-add \
diff --git a/completions/fish/riverctl.fish b/completions/fish/riverctl.fish
index 4b81ef1..aabf99c 100644
--- a/completions/fish/riverctl.fish
+++ b/completions/fish/riverctl.fish
@@ -62,9 +62,10 @@ complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'set-repeat'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'set-cursor-warp' -d 'Set the cursor warp mode.'
complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'xcursor-theme' -d 'Set the xcursor theme'
# Keyboardgroups
-complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-create' -d 'Create a keyboard group.'
-complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-destroy' -d 'Destroy a keyboard group.'
-complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-add-keyboard' -d 'Add a keyboard to a keyboard group.'
+complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-create' -d 'Create a keyboard group.'
+complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-destroy' -d 'Destroy a keyboard group.'
+complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-add' -d 'Add a keyboard to a keyboard group.'
+complete -c riverctl -x -n '__fish_riverctl_complete_arg 1' -a 'keyboard-group-remove' -d 'Remove a keyboard from a keyboard group.'
# Subcommands
complete -c riverctl -x -n '__fish_seen_subcommand_from focus-output' -a 'next previous'
diff --git a/completions/zsh/_riverctl b/completions/zsh/_riverctl
index 3250b50..f5cd125 100644
--- a/completions/zsh/_riverctl
+++ b/completions/zsh/_riverctl
@@ -58,7 +58,8 @@ _riverctl_subcommands()
# Keyboard groups
'keyboard-group-create:Create a keyboard group'
'keyboard-group-destroy:Destroy a keyboard group'
- 'keyboard-group-add-keyboard:Add a keyboard to a keyboard group'
+ 'keyboard-group-add:Add a keyboard to a keyboard group'
+ 'keyboard-group-remove:Remove a keyboard from a keyboard group'
# Input
'input:Configure input devices'
'list-inputs:List all input devices'
diff --git a/doc/riverctl.1.scd b/doc/riverctl.1.scd
index 38ac669..d98aafe 100644
--- a/doc/riverctl.1.scd
+++ b/doc/riverctl.1.scd
@@ -330,26 +330,30 @@ A complete list may be found in _/usr/include/linux/input-event-codes.h_
*list-input-configs*
List all input configurations.
-*keyboard-group-create* _keyboard_group_name_
+*keyboard-group-create* _group_name_
Create a keyboard group. A keyboard group collects multiple keyboards in
a single logical keyboard. This means that all state, like the active
modifiers, is shared between the keyboards in a group.
-*keyboard-group-destroy* _keyboard_group_name_
- Destroy the keyboard group of the given name. All attached keyboards
+*keyboard-group-destroy* _group_name_
+ Destroy the keyboard group with the given name. All attached keyboards
will be released, making them act as seperate devices again.
-*keyboard-group-add-keyboard* _keyboard_group_name_ _input_device_identifier_
- Add a keyboard to a keyboard group, identified by the keyboards input
- device identifier. Any currently connected and future keyboards matching
- the identifier will be added to the group.
+*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.
+
+*keyboard-group-remove* _group_name_ _input_device_name_
+ Remove a keyboard from a keyboard group, identified by the keyboard's
+ input device name.
The _input_ command can be used to create a configuration rule for an input
device identified by its _name_.
The _name_ of an input device consists of its type, its numerical vendor id,
its numerical product id and finally its self-advertised name, separated by -.
-A list of all device properties that can be configured maybe found below.
+A list of all device properties that can be configured may be found below.
However note that not every input device supports every property.
*input* _name_ *events* *enabled*|*disabled*|*disabled-on-external-mouse*
diff --git a/river/InputDevice.zig b/river/InputDevice.zig
index 3b4e117..83da4ed 100644
--- a/river/InputDevice.zig
+++ b/river/InputDevice.zig
@@ -50,6 +50,12 @@ pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !vo
else => @tagName(wlr_device.type),
};
+ // wlroots 0.15 leaves wlr_input_device->name NULL for keyboard groups.
+ // This wart has been cleaned up in 0.16, so just work around it until that is released.
+ // TODO(wlroots): Remove this hack
+
+ const name = if (isKeyboardGroup(wlr_device)) "wlr_keyboard_group" else wlr_device.name;
+
const identifier = try std.fmt.allocPrint(
util.gpa,
"{s}-{}-{}-{s}",
@@ -57,7 +63,7 @@ pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !vo
device_type,
wlr_device.vendor,
wlr_device.product,
- mem.trim(u8, mem.span(wlr_device.name), &ascii.spaces),
+ mem.trim(u8, mem.span(name), &ascii.spaces),
},
);
errdefer util.gpa.free(identifier);
@@ -77,15 +83,19 @@ pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !vo
wlr_device.events.destroy.add(&device.destroy);
- // Apply any matching input device configuration.
- for (server.input_manager.configs.items) |*input_config| {
- if (mem.eql(u8, input_config.identifier, identifier)) {
- input_config.apply(device);
+ // Keyboard groups are implemented as "virtual" input devices which we don't want to expose
+ // in riverctl list-inputs as they can't be configured.
+ if (!isKeyboardGroup(wlr_device)) {
+ // Apply any matching input device configuration.
+ for (server.input_manager.configs.items) |*input_config| {
+ if (mem.eql(u8, input_config.identifier, identifier)) {
+ input_config.apply(device);
+ }
}
- }
- server.input_manager.devices.append(device);
- seat.updateCapabilities();
+ server.input_manager.devices.append(device);
+ seat.updateCapabilities();
+ }
log.debug("new input device: {s}", .{identifier});
}
@@ -95,12 +105,19 @@ pub fn deinit(device: *InputDevice) void {
util.gpa.free(device.identifier);
- device.link.remove();
- device.seat.updateCapabilities();
+ if (!isKeyboardGroup(device.wlr_device)) {
+ device.link.remove();
+ device.seat.updateCapabilities();
+ }
device.* = undefined;
}
+fn isKeyboardGroup(wlr_device: *wlr.InputDevice) bool {
+ return wlr_device.type == .keyboard and
+ wlr.KeyboardGroup.fromKeyboard(wlr_device.device.keyboard) != null;
+}
+
fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void {
const device = @fieldParentPtr(InputDevice, "destroy", listener);
@@ -108,7 +125,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice)
switch (device.wlr_device.type) {
.keyboard => {
- const keyboard = @fieldParentPtr(Keyboard, "provider", @ptrCast(*Keyboard.Provider, device));
+ const keyboard = @fieldParentPtr(Keyboard, "device", device);
keyboard.deinit();
util.gpa.destroy(keyboard);
},
diff --git a/river/Keyboard.zig b/river/Keyboard.zig
index f4f962c..eeec2ee 100644
--- a/river/Keyboard.zig
+++ b/river/Keyboard.zig
@@ -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);
-}
diff --git a/river/KeyboardGroup.zig b/river/KeyboardGroup.zig
index dc0f883..e759bc0 100644
--- a/river/KeyboardGroup.zig
+++ b/river/KeyboardGroup.zig
@@ -14,12 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
-const Self = @This();
+const KeyboardGroup = @This();
const std = @import("std");
-const heap = std.heap;
+const assert = std.debug.assert;
const mem = std.mem;
-const debug = std.debug;
+
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const xkb = @import("xkbcommon");
@@ -33,81 +33,95 @@ const Seat = @import("Seat.zig");
const Keyboard = @import("Keyboard.zig");
seat: *Seat,
-group: *wlr.KeyboardGroup,
+wlr_group: *wlr.KeyboardGroup,
name: []const u8,
-keyboard_identifiers: std.ArrayListUnmanaged([]const u8) = .{},
+identifiers: std.StringHashMapUnmanaged(void) = .{},
+
+pub fn create(seat: *Seat, name: []const u8) !void {
+ log.debug("new keyboard group: '{s}'", .{name});
-pub fn init(self: *Self, seat: *Seat, _name: []const u8) !void {
- log.debug("new keyboard group: '{s}'", .{_name});
+ const node = try util.gpa.create(std.TailQueue(KeyboardGroup).Node);
+ errdefer util.gpa.destroy(node);
- const group = try wlr.KeyboardGroup.create();
- errdefer group.destroy();
- group.data = @ptrToInt(self);
+ const wlr_group = try wlr.KeyboardGroup.create();
+ errdefer wlr_group.destroy();
- const name = try util.gpa.dupe(u8, _name);
- errdefer util.gpa.free(name);
+ const owned_name = try util.gpa.dupe(u8, name);
+ errdefer util.gpa.free(owned_name);
- self.* = .{
- .group = group,
- .name = name,
+ node.data = .{
+ .wlr_group = wlr_group,
+ .name = owned_name,
.seat = seat,
};
- seat.addDevice(self.group.input_device);
- seat.wlr_seat.setKeyboard(self.group.input_device);
+ seat.addDevice(wlr_group.input_device);
+ seat.keyboard_groups.append(node);
}
-pub fn deinit(self: *Self) void {
- log.debug("removing keyboard group: '{s}'", .{self.name});
+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.*);
+ }
+ group.identifiers.deinit(util.gpa);
- util.gpa.free(self.name);
- for (self.keyboard_identifiers.items) |id| util.gpa.free(id);
- self.keyboard_identifiers.deinit(util.gpa);
+ group.wlr_group.destroy();
- // wlroots automatically removes all keyboards from the group.
- self.group.destroy();
+ const node = @fieldParentPtr(std.TailQueue(KeyboardGroup).Node, "data", group);
+ group.seat.keyboard_groups.remove(node);
+ util.gpa.destroy(node);
}
-pub fn addKeyboardIdentifier(self: *Self, _id: []const u8) !void {
- if (containsIdentifier(self, _id)) return;
- log.debug("keyboard group '{s}' adding identifier: '{s}'", .{ self.name, _id });
+pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void {
+ if (group.identifiers.contains(new_id)) return;
- const id = try util.gpa.dupe(u8, _id);
- errdefer util.gpa.free(id);
- try self.keyboard_identifiers.append(util.gpa, id);
+ log.debug("keyboard group '{s}' adding identifier: '{s}'", .{ group.name, new_id });
- // Add any existing matching keyboard to group.
+ const owned_id = try util.gpa.dupe(u8, new_id);
+ errdefer util.gpa.free(owned_id);
+
+ try group.identifiers.put(util.gpa, owned_id, {});
+
+ // Add any existing matching keyboards to the group.
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
- if (device.seat != self.seat) continue;
+ if (device.seat != group.seat) continue;
if (device.wlr_device.type != .keyboard) continue;
- if (mem.eql(u8, _id, device.identifier)) {
+ if (mem.eql(u8, new_id, device.identifier)) {
log.debug("found existing matching keyboard; adding to group", .{});
const wlr_keyboard = device.wlr_device.device.keyboard;
- if (!self.group.addKeyboard(wlr_keyboard)) continue; // wlroots logs its own errors.
+ if (!group.wlr_group.addKeyboard(wlr_keyboard)) {
+ // wlroots logs an error message to explain why this failed.
+ continue;
+ }
}
// Continue, because we may have more than one device with the exact
- // same identifier. That is in fact the reason for the keyboard group
+ // same identifier. That is in fact one reason for the keyboard group
// feature to exist in the first place.
}
}
-pub fn containsIdentifier(self: *Self, id: []const u8) bool {
- for (self.keyboard_identifiers.items) |ki| {
- if (mem.eql(u8, ki, id)) return true;
+pub fn removeIdentifier(group: *KeyboardGroup, id: []const u8) !void {
+ if (group.identifiers.fetchRemove(id)) |kv| {
+ util.gpa.free(kv.key);
}
- return false;
-}
-pub fn addKeyboard(self: *Self, keyboard: *Keyboard) !void {
- debug.assert(keyboard.provider != .group);
- const wlr_keyboard = keyboard.provider.device.wlr_device.device.keyboard;
- log.debug("keyboard group '{s}' adding keyboard: '{s}'", .{ self.name, keyboard.provider.device.identifier });
- if (!self.group.addKeyboard(wlr_keyboard)) {
- log.err("failed to add keyboard to group", .{});
- return error.OutOfMemory;
+ var it = server.input_manager.devices.iterator(.forward);
+ while (it.next()) |device| {
+ if (device.seat != group.seat) continue;
+ if (device.wlr_device.type != .keyboard) continue;
+
+ if (mem.eql(u8, device.identifier, id)) {
+ const wlr_keyboard = device.wlr_device.device.keyboard;
+ assert(wlr_keyboard.group == group.wlr_group);
+ group.wlr_group.removeKeyboard(wlr_keyboard);
+ }
}
}
diff --git a/river/Seat.zig b/river/Seat.zig
index aef48d2..4881092 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -32,6 +32,7 @@ const DragIcon = @import("DragIcon.zig");
const InputDevice = @import("InputDevice.zig");
const InputManager = @import("InputManager.zig");
const Keyboard = @import("Keyboard.zig");
+const KeyboardGroup = @import("KeyboardGroup.zig");
const KeycodeSet = @import("KeycodeSet.zig");
const LayerSurface = @import("LayerSurface.zig");
const Mapping = @import("Mapping.zig");
@@ -41,7 +42,6 @@ const Switch = @import("Switch.zig");
const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
-const KeyboardGroup = @import("KeyboardGroup.zig");
const log = std.log.scoped(.seat);
const PointerConstraint = @import("PointerConstraint.zig");
@@ -128,6 +128,10 @@ pub fn deinit(self: *Self) void {
self.cursor.deinit();
self.mapping_repeat_timer.remove();
+ while (self.keyboard_groups.first) |node| {
+ node.data.destroy();
+ }
+
while (self.focus_stack.first) |node| {
self.focus_stack.remove(node);
util.gpa.destroy(node);
@@ -478,18 +482,7 @@ fn tryAddDevice(self: *Self, wlr_device: *wlr.InputDevice) !void {
try keyboard.init(self, wlr_device);
- // Add this keyboard to a keyboard group, if the group contains a
- // matching identifier and if the keyboard isn't a group itself.
- if (keyboard.provider == .device) {
- var it = self.keyboard_groups.first;
- while (it) |node| : (it = node.next) {
- if (node.data.containsIdentifier(keyboard.provider.device.identifier)) {
- try node.data.addKeyboard(keyboard);
- break;
- }
- }
- }
-
+ self.wlr_seat.setKeyboard(keyboard.device.wlr_device);
if (self.wlr_seat.keyboard_state.focused_surface) |wlr_surface| {
self.wlr_seat.keyboardNotifyClearFocus();
self.keyboardNotifyEnter(wlr_surface);
@@ -522,7 +515,6 @@ pub fn updateCapabilities(self: *Self) void {
var it = server.input_manager.devices.iterator(.forward);
while (it.next()) |device| {
- log.debug(">>>> '{s}'", .{device.identifier});
if (device.seat == self) {
switch (device.wlr_device.type) {
.keyboard => capabilities.keyboard = true,
diff --git a/river/command.zig b/river/command.zig
index 57fa35a..55dd7ca 100644
--- a/river/command.zig
+++ b/river/command.zig
@@ -89,9 +89,10 @@ const command_impls = std.ComptimeStringMap(
.{ "unmap-switch", @import("command/map.zig").unmapSwitch },
.{ "xcursor-theme", @import("command/xcursor_theme.zig").xcursorTheme },
.{ "zoom", @import("command/zoom.zig").zoom },
- .{ "keyboard-group-create", @import("command/keyboard_group.zig").keyboardGroupCreate},
- .{ "keyboard-group-destroy", @import("command/keyboard_group.zig").keyboardGroupDestroy},
- .{ "keyboard-group-add-keyboard", @import("command/keyboard_group.zig").keyboardGroupAddIdentifier},
+ .{ "keyboard-group-create", @import("command/keyboard_group.zig").keyboardGroupCreate },
+ .{ "keyboard-group-destroy", @import("command/keyboard_group.zig").keyboardGroupDestroy },
+ .{ "keyboard-group-add", @import("command/keyboard_group.zig").keyboardGroupAdd },
+ .{ "keyboard-group-remove", @import("command/keyboard_group.zig").keyboardGroupRemove },
},
);
// zig fmt: on
diff --git a/river/command/keyboard_group.zig b/river/command/keyboard_group.zig
index 85763f0..4453006 100644
--- a/river/command/keyboard_group.zig
+++ b/river/command/keyboard_group.zig
@@ -32,19 +32,13 @@ pub fn keyboardGroupCreate(
if (args.len < 2) return Error.NotEnoughArguments;
if (args.len > 2) return Error.TooManyArguments;
- var it = seat.keyboard_groups.first;
- while (it) |node| : (it = node.next) {
- if (mem.eql(u8, node.data.name, args[1])) {
- const msg = try util.gpa.dupe(u8, "error: failed to create keybaord group: group of same name already exists\n");
- out.* = msg;
- return;
- }
+ if (keyboardGroupFromName(seat, args[1]) != null) {
+ const msg = try util.gpa.dupe(u8, "error: failed to create keybaord group: group of same name already exists\n");
+ out.* = msg;
+ return;
}
- const node = try util.gpa.create(std.TailQueue(KeyboardGroup).Node);
- errdefer util.gpa.destroy(node);
- try node.data.init(seat, args[1]);
- seat.keyboard_groups.append(node);
+ try KeyboardGroup.create(seat, args[1]);
}
pub fn keyboardGroupDestroy(
@@ -54,18 +48,31 @@ pub fn keyboardGroupDestroy(
) Error!void {
if (args.len < 2) return Error.NotEnoughArguments;
if (args.len > 2) return Error.TooManyArguments;
- const kg = keyboardGroupFromName(seat, args[1]) orelse {
+ const group = keyboardGroupFromName(seat, args[1]) orelse {
+ const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
+ out.* = msg;
+ return;
+ };
+ group.destroy();
+}
+
+pub fn keyboardGroupAdd(
+ seat: *Seat,
+ args: []const [:0]const u8,
+ out: *?[]const u8,
+) Error!void {
+ if (args.len < 3) return Error.NotEnoughArguments;
+ if (args.len > 3) return Error.TooManyArguments;
+
+ const group = keyboardGroupFromName(seat, args[1]) orelse {
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
out.* = msg;
return;
};
- kg.deinit();
- const node = @fieldParentPtr(std.TailQueue(KeyboardGroup).Node, "data", kg);
- seat.keyboard_groups.remove(node);
- util.gpa.destroy(node);
+ try group.addIdentifier(args[2]);
}
-pub fn keyboardGroupAddIdentifier(
+pub fn keyboardGroupRemove(
seat: *Seat,
args: []const [:0]const u8,
out: *?[]const u8,
@@ -73,12 +80,12 @@ pub fn keyboardGroupAddIdentifier(
if (args.len < 3) return Error.NotEnoughArguments;
if (args.len > 3) return Error.TooManyArguments;
- const kg = keyboardGroupFromName(seat, args[1]) orelse {
+ const group = keyboardGroupFromName(seat, args[1]) orelse {
const msg = try util.gpa.dupe(u8, "error: no keyboard group with that name exists\n");
out.* = msg;
return;
};
- try kg.addKeyboardIdentifier(args[2]);
+ try group.removeIdentifier(args[2]);
}
fn keyboardGroupFromName(seat: *Seat, name: []const u8) ?*KeyboardGroup {