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