core: "all" bindings work

This commit is contained in:
Mitchell Hashimoto
2024-09-23 19:20:34 -07:00
parent 7f8c1a37ff
commit 17caeb5fac
2 changed files with 84 additions and 26 deletions

View File

@ -1590,7 +1590,7 @@ fn maybeHandleBinding(
};
// Determine if this entry has an action or if its a leader key.
const action: input.Binding.Action, const consumed: bool = switch (entry) {
const leaf: input.Binding.Set.Leaf = switch (entry) {
.leader => |set| {
// Setup the next set we'll look at.
self.keyboard.bindings = set;
@ -1605,7 +1605,20 @@ fn maybeHandleBinding(
return .consumed;
},
.leaf => |leaf| .{ leaf.action, leaf.flags.consumed },
.leaf => |leaf| leaf,
};
const action = leaf.action;
// consumed determines if the input is consumed or if we continue
// encoding the key (if we have a key to encode).
const consumed = consumed: {
// If the consumed flag is explicitly set, then we are consumed.
if (leaf.flags.consumed) break :consumed true;
// If the global or all flag is set, we always consume.
if (leaf.flags.global or leaf.flags.all) break :consumed true;
break :consumed false;
};
// We have an action, so at this point we're handling SOMETHING so
@ -1617,8 +1630,22 @@ fn maybeHandleBinding(
self.keyboard.bindings = null;
// Attempt to perform the action
log.debug("key event binding consumed={} action={}", .{ consumed, action });
const performed = try self.performBindingAction(action);
log.debug("key event binding flags={} action={}", .{
leaf.flags,
action,
});
const performed = performed: {
// If this is a global or all action, then we perform it on
// the app and it applies to every surface.
if (leaf.flags.global or leaf.flags.all) {
try self.app.performAllAction(self.rt_app, action);
// "All" actions are always performed since they are global.
break :performed true;
}
break :performed try self.performBindingAction(action);
};
// If we performed an action and it was a closing action,
// our "self" pointer is not safe to use anymore so we need to

View File

@ -1160,7 +1160,7 @@ pub const Set = struct {
set.remove(alloc, t);
if (old) |entry| switch (entry) {
.leader => unreachable, // Handled above
.leaf => |leaf| set.put_(
.leaf => |leaf| set.putFlags(
alloc,
t,
leaf.action,
@ -1179,11 +1179,12 @@ pub const Set = struct {
return error.SequenceUnbind;
},
else => if (b.flags.consumed) {
try set.put(alloc, b.trigger, b.action);
} else {
try set.putUnconsumed(alloc, b.trigger, b.action);
},
else => try set.putFlags(
alloc,
b.trigger,
b.action,
b.flags,
),
},
}
}
@ -1196,24 +1197,11 @@ pub const Set = struct {
t: Trigger,
action: Action,
) Allocator.Error!void {
try self.put_(alloc, t, action, .{});
try self.putFlags(alloc, t, action, .{});
}
/// Same as put but marks the trigger as unconsumed. An unconsumed
/// trigger will evaluate the action and continue to encode for the
/// terminal.
///
/// This is a separate function because this case is rare.
pub fn putUnconsumed(
self: *Set,
alloc: Allocator,
t: Trigger,
action: Action,
) Allocator.Error!void {
try self.put_(alloc, t, action, .{ .consumed = false });
}
fn put_(
/// Add a binding to the set with explicit flags.
pub fn putFlags(
self: *Set,
alloc: Allocator,
t: Trigger,
@ -1486,6 +1474,49 @@ test "parse: global triggers" {
}
}
test "parse: all triggers" {
const testing = std.testing;
// all keys
try testing.expectEqual(Binding{
.trigger = .{
.mods = .{ .shift = true },
.key = .{ .translated = .a },
},
.action = .{ .ignore = {} },
.flags = .{ .all = true },
}, try parseSingle("all:shift+a=ignore"));
// all physical keys
try testing.expectEqual(Binding{
.trigger = .{
.mods = .{ .shift = true },
.key = .{ .physical = .a },
},
.action = .{ .ignore = {} },
.flags = .{ .all = true },
}, try parseSingle("all:physical:a+shift=ignore"));
// all unconsumed keys
try testing.expectEqual(Binding{
.trigger = .{
.mods = .{ .shift = true },
.key = .{ .translated = .a },
},
.action = .{ .ignore = {} },
.flags = .{
.all = true,
.consumed = false,
},
}, try parseSingle("unconsumed:all:a+shift=ignore"));
// all sequences not allowed
{
var p = try Parser.init("all:a>b=ignore");
try testing.expectError(Error.InvalidFormat, p.next());
}
}
test "parse: modifier aliases" {
const testing = std.testing;