command: support repeating keyboard mappings

Repeating mappings are created using the -repeat option to the map
command:

    % riverctl map normal $mod+Mod1 K -repeat move up 10

- repeating is only supported for key press (not -release) mappings
- unlike -release, -repeat does not create distinct mappings: mapping a
  key with -repeat will replace an existing bare mapping and vice-versa

Resolves #306
This commit is contained in:
Keith Hubbard
2021-08-15 08:49:11 -04:00
committed by GitHub
parent 6e51a8fcdd
commit 2bdf9e20a5
9 changed files with 92 additions and 22 deletions

View File

@ -44,19 +44,25 @@ pub fn map(
const offset = optionals.i;
if (args.len - offset < 5) return Error.NotEnoughArguments;
if (optionals.release and optionals.repeat) return Error.ConflictingOptions;
const mode_id = try modeNameToId(allocator, seat, args[1 + offset], out);
const modifiers = try parseModifiers(allocator, args[2 + offset], out);
const keysym = try parseKeysym(allocator, args[3 + offset], out);
const mode_mappings = &server.config.modes.items[mode_id].mappings;
const new = try Mapping.init(keysym, modifiers, optionals.release, args[4 + offset ..]);
const new = try Mapping.init(keysym, modifiers, optionals.release, optionals.repeat, args[4 + offset ..]);
errdefer new.deinit();
if (mappingExists(mode_mappings, modifiers, keysym, optionals.release)) |current| {
mode_mappings.items[current].deinit();
mode_mappings.items[current] = new;
} else {
// Repeating mappings borrow the Mapping directly. To prevent a
// possible crash if the Mapping ArrayList is reallocated, stop any
// currently repeating mappings.
seat.clearRepeatingMapping();
try mode_mappings.append(new);
}
}
@ -200,6 +206,7 @@ fn parseModifiers(
const OptionalArgsContainer = struct {
i: usize,
release: bool,
repeat: bool,
};
/// Parses optional args (such as -release) and return the index of the first argument that is
@ -212,6 +219,7 @@ fn parseOptionalArgs(args: []const []const u8) OptionalArgsContainer {
// i is the number of arguments consumed
.i = 0,
.release = false,
.repeat = false,
};
var i: usize = 0;
@ -219,6 +227,9 @@ fn parseOptionalArgs(args: []const []const u8) OptionalArgsContainer {
if (std.mem.eql(u8, arg, "-release")) {
parsed.release = true;
i += 1;
} else if (std.mem.eql(u8, arg, "-repeat")) {
parsed.repeat = true;
i += 1;
} else {
// Break if the arg is not an option
parsed.i = i;
@ -251,6 +262,11 @@ pub fn unmap(
const mode_mappings = &server.config.modes.items[mode_id].mappings;
const mapping_idx = mappingExists(mode_mappings, modifiers, keysym, optionals.release) orelse return;
// Repeating mappings borrow the Mapping directly. To prevent a possible
// crash if the Mapping ArrayList is reallocated, stop any currently
// repeating mappings.
seat.clearRepeatingMapping();
var mapping = mode_mappings.swapRemove(mapping_idx);
mapping.deinit();
}