diff --git a/src/Surface.zig b/src/Surface.zig index 3462df8f0..e1b226da1 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1094,12 +1094,7 @@ pub fn keyCallback( if (action != .press and action != .repeat) return false; // Mods for bindings never include caps/num lock. - const binding_mods = mods: { - var binding_mods = mods; - binding_mods.caps_lock = false; - binding_mods.num_lock = false; - break :mods binding_mods; - }; + const binding_mods = mods.binding(); // Check if we're processing a binding first. If so, that negates // any further key processing. diff --git a/src/input/Binding.zig b/src/input/Binding.zig index fd6fa940c..6431853bd 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -293,10 +293,10 @@ pub const Trigger = struct { physical: bool = false, /// Returns a hash code that can be used to uniquely identify this trigger. - pub fn hash(self: Binding) u64 { + pub fn hash(self: Trigger) u64 { var hasher = std.hash.Wyhash.init(0); std.hash.autoHash(&hasher, self.key); - std.hash.autoHash(&hasher, self.mods); + std.hash.autoHash(&hasher, self.mods.binding()); std.hash.autoHash(&hasher, self.physical); return hasher.final(); } @@ -306,7 +306,12 @@ pub const Trigger = struct { /// The use case is that this will be called on EVERY key input to look /// for an associated action so it must be fast. pub const Set = struct { - const HashMap = std.AutoHashMapUnmanaged(Trigger, Action); + const HashMap = std.HashMapUnmanaged( + Trigger, + Action, + Context, + std.hash_map.default_max_load_percentage, + ); /// The set of bindings. bindings: HashMap = .{}, @@ -318,10 +323,14 @@ pub const Set = struct { /// Add a binding to the set. If the binding already exists then /// this will overwrite it. - pub fn put(self: *Set, alloc: Allocator, t: Trigger, action: Action) !void { + pub fn put( + self: *Set, + alloc: Allocator, + t: Trigger, + action: Action, + ) !void { // unbind should never go into the set, it should be handled prior assert(action != .unbind); - try self.bindings.put(alloc, t, action); } @@ -334,6 +343,19 @@ pub const Set = struct { pub fn remove(self: *Set, t: Trigger) void { _ = self.bindings.remove(t); } + + /// The hash map context for the set. This defines how the hash map + /// gets the hash key and checks for equality. + const Context = struct { + pub fn hash(ctx: Context, k: Trigger) u64 { + _ = ctx; + return k.hash(); + } + + pub fn eql(ctx: Context, a: Trigger, b: Trigger) bool { + return ctx.hash(a) == ctx.hash(b); + } + }; }; test "parse: triggers" { diff --git a/src/input/key.zig b/src/input/key.zig index 2d951b996..99ebeb192 100644 --- a/src/input/key.zig +++ b/src/input/key.zig @@ -24,6 +24,16 @@ pub const Mods = packed struct(u8) { return @as(u8, @bitCast(self)) == @as(u8, @bitCast(other)); } + /// Return mods that are only relevant for bindings. + pub fn binding(self: Mods) Mods { + return .{ + .shift = self.shift, + .ctrl = self.ctrl, + .alt = self.alt, + .super = self.super, + }; + } + /// Returns the mods without locks set. pub fn withoutLocks(self: Mods) Mods { var copy = self;