config: implement map-pointer command

This command takes a mode, modifiers, button/event name, and pointer
action as arguments. It stores these in the config data structure.

The currently available pointer actions are move-view and resize-view,
which replace the previously hard-coded functionality.

Closing the hovered view with middle click has temorarily been removed
until it is decided if we wish to make this another special pointer
action or perhaps allow running any arbitrary command (which would of
course include close).
This commit is contained in:
Isaac Freund
2020-08-24 14:52:47 +02:00
parent fd8c5e6410
commit 989e7aaeda
14 changed files with 240 additions and 86 deletions

View File

@ -19,6 +19,7 @@ const std = @import("std");
const util = @import("../util.zig");
const Mode = @import("../Mode.zig");
const Error = @import("../command.zig").Error;
const Mapping = @import("../Mapping.zig");
const Seat = @import("../Seat.zig");
@ -45,9 +46,9 @@ pub fn declareMode(
return Error.Other;
}
try config.modes.ensureCapacity(config.modes.items.len + 1);
const owned_name = try std.mem.dupe(util.gpa, u8, new_mode_name);
errdefer util.gpa.free(owned_name);
try config.mode_to_id.putNoClobber(owned_name, config.modes.items.len);
errdefer _ = config.mode_to_id.remove(owned_name);
try config.modes.append(std.ArrayList(Mapping).init(util.gpa));
config.modes.appendAssumeCapacity(Mode.init());
}

View File

@ -22,6 +22,7 @@ const util = @import("../util.zig");
const Error = @import("../command.zig").Error;
const Mapping = @import("../Mapping.zig");
const PointerMapping = @import("../PointerMapping.zig");
const Seat = @import("../Seat.zig");
const modifier_names = [_]struct {
@ -49,22 +50,114 @@ pub fn map(
args: []const []const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 4) return Error.NotEnoughArguments;
if (args.len < 5) return Error.NotEnoughArguments;
// Parse the mode
const config = seat.input_manager.server.config;
const target_mode = args[1];
const mode_id = config.mode_to_id.getValue(target_mode) orelse {
const mode_id = try modeNameToId(allocator, seat, args[1], out);
const modifiers = try parseModifiers(allocator, args[2], out);
// Parse the keysym
const keysym_name = try std.cstr.addNullByte(allocator, args[3]);
defer allocator.free(keysym_name);
const keysym = c.xkb_keysym_from_name(keysym_name, .XKB_KEYSYM_CASE_INSENSITIVE);
if (keysym == c.XKB_KEY_NoSymbol) {
out.* = try std.fmt.allocPrint(
allocator,
"cannot add mapping to non-existant mode '{}p'",
.{target_mode},
"invalid keysym '{}'",
.{args[3]},
);
return Error.Other;
}
// Check if the mapping already exists
const mode_mappings = &seat.input_manager.server.config.modes.items[mode_id].mappings;
for (mode_mappings.items) |existant_mapping| {
if (existant_mapping.modifiers == modifiers and existant_mapping.keysym == keysym) {
out.* = try std.fmt.allocPrint(
allocator,
"a mapping for modifiers '{}' and keysym '{}' already exists",
.{ args[2], args[3] },
);
return Error.Other;
}
}
try mode_mappings.append(try Mapping.init(util.gpa, keysym, modifiers, args[4..]));
}
/// Create a new pointer mapping for a given mode
///
/// Example:
/// map-pointer normal Mod4 BTN_LEFT move-view
pub fn mapPointer(
allocator: *std.mem.Allocator,
seat: *Seat,
args: []const []const u8,
out: *?[]const u8,
) Error!void {
if (args.len < 5) return Error.NotEnoughArguments;
if (args.len > 5) return Error.TooManyArguments;
const mode_id = try modeNameToId(allocator, seat, args[1], out);
const modifiers = try parseModifiers(allocator, args[2], out);
const event_code = blk: {
const event_code_name = try std.cstr.addNullByte(allocator, args[3]);
defer allocator.free(event_code_name);
const ret = c.libevdev_event_code_from_name(c.EV_KEY, event_code_name);
if (ret < 1) {
out.* = try std.fmt.allocPrint(allocator, "unknown button {}", .{args[3]});
return Error.Other;
}
break :blk @intCast(u32, ret);
};
// Check if the mapping already exists
const mode_pointer_mappings = &seat.input_manager.server.config.modes.items[mode_id].pointer_mappings;
for (mode_pointer_mappings.items) |existing| {
if (existing.event_code == event_code and existing.modifiers == modifiers) {
out.* = try std.fmt.allocPrint(
allocator,
"a pointer mapping for modifiers '{}' and button '{}' already exists",
.{ args[2], args[3] },
);
return Error.Other;
}
}
const action = if (std.mem.eql(u8, args[4], "move-view"))
PointerMapping.Action.move
else if (std.mem.eql(u8, args[4], "resize-view"))
PointerMapping.Action.resize
else {
out.* = try std.fmt.allocPrint(
allocator,
"invalid pointer action {}, must be move-view or resize-view",
.{args[4]},
);
return Error.Other;
};
// Parse the modifiers
var it = std.mem.split(args[2], "+");
try mode_pointer_mappings.append(.{
.event_code = event_code,
.modifiers = modifiers,
.action = action,
});
}
fn modeNameToId(allocator: *std.mem.Allocator, seat: *Seat, mode_name: []const u8, out: *?[]const u8) !usize {
const config = seat.input_manager.server.config;
return config.mode_to_id.getValue(mode_name) orelse {
out.* = try std.fmt.allocPrint(
allocator,
"cannot add mapping to non-existant mode '{}p'",
.{mode_name},
);
return Error.Other;
};
}
fn parseModifiers(allocator: *std.mem.Allocator, modifiers_str: []const u8, out: *?[]const u8) !u32 {
var it = std.mem.split(modifiers_str, "+");
var modifiers: u32 = 0;
while (it.next()) |mod_name| {
for (modifier_names) |def| {
@ -81,32 +174,5 @@ pub fn map(
return Error.Other;
}
}
// Parse the keysym
const keysym_name = try std.cstr.addNullByte(allocator, args[3]);
defer allocator.free(keysym_name);
const keysym = c.xkb_keysym_from_name(keysym_name, .XKB_KEYSYM_CASE_INSENSITIVE);
if (keysym == c.XKB_KEY_NoSymbol) {
out.* = try std.fmt.allocPrint(
allocator,
"invalid keysym '{}'",
.{args[3]},
);
return Error.Other;
}
// Check if the mapping already exists
const mode_mappings = &config.modes.items[mode_id];
for (mode_mappings.items) |existant_mapping| {
if (existant_mapping.modifiers == modifiers and existant_mapping.keysym == keysym) {
out.* = try std.fmt.allocPrint(
allocator,
"a mapping for modifiers '{}' and keysym '{}' already exists",
.{ args[2], args[3] },
);
return Error.Other;
}
}
try mode_mappings.append(try Mapping.init(util.gpa, keysym, modifiers, args[4..]));
return modifiers;
}