diff --git a/river/Keyboard.zig b/river/Keyboard.zig index ba82180..c2426cf 100644 --- a/river/Keyboard.zig +++ b/river/Keyboard.zig @@ -94,6 +94,7 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa // First check translated keysyms as xkb reports them for (wlr_keyboard.xkb_state.?.keyGetSyms(keycode)) |sym| { + std.log.debug("sym: {}, mods: {}, released: {}", .{ sym, modifiers, released }); // Handle builtin mapping only when keys are pressed if (!released and self.handleBuiltinMapping(sym)) { handled = true; @@ -109,6 +110,7 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa if (!handled) { const layout_index = wlr_keyboard.xkb_state.?.keyGetLayout(keycode); for (wlr_keyboard.keymap.?.keyGetSymsByLevel(keycode, layout_index, 0)) |sym| { + std.log.debug("Ignoring modifiers: sym: {}", .{sym}); // Handle builtin mapping only when keys are pressed if (!released and self.handleBuiltinMapping(sym)) { handled = true; diff --git a/river/Seat.zig b/river/Seat.zig index 966263d..0c0357b 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -323,6 +323,22 @@ pub fn handleViewUnmap(self: *Self, view: *View) void { if (self.focused == .view and self.focused.view == view) self.focus(null); } +fn getMatches( + mod1: wlr.Keyboard.ModifierMask, + mod2: wlr.Keyboard.ModifierMask, +) u5 { + var this: u5 = 0; + if (mod1.shift and mod2.shift) this += 1; + if (mod1.caps and mod2.caps) this += 1; + if (mod1.ctrl and mod2.ctrl) this += 1; + if (mod1.alt and mod2.alt) this += 1; + if (mod1.mod2 and mod2.mod2) this += 1; + if (mod1.mod3 and mod2.mod3) this += 1; + if (mod1.logo and mod2.logo) this += 1; + if (mod1.mod5 and mod2.mod5) this += 1; + return this; +} + /// Handle any user-defined mapping for the passed keysym and modifiers /// Returns true if the key was handled pub fn handleMapping( @@ -332,8 +348,18 @@ pub fn handleMapping( released: bool, ) bool { const modes = &server.config.modes; + var highest_match: u5 = 0; for (modes.items[self.mode_id].mappings.items) |*mapping| { - if (std.meta.eql(modifiers, mapping.modifiers) and keysym == mapping.keysym and released == mapping.release) { + if (keysym != mapping.keysym or released != mapping.release) continue; + const matches = getMatches(mapping.modifiers, modifiers); + if (matches > highest_match) { + highest_match = matches; + } + } + for (modes.items[self.mode_id].mappings.items) |*mapping| { + const matches = getMatches(mapping.modifiers, modifiers); + if (matches == highest_match and keysym == mapping.keysym and released == mapping.release) { + std.log.debug("Using first highest match ({}) mapping: {}", .{ highest_match, mapping }); if (mapping.repeat) { self.repeating_mapping = mapping; self.mapping_repeat_timer.timerUpdate(server.config.repeat_delay) catch {