command/map: layout-pinned mappings

e.g. `riverctl map -layout 0 normal Super Y spawn foot`

When this mapping is checked against a pressed key, layout 0 will be used to translate the pressed key instead of the currently active layout.

The number denotes to an index of the layouts set with
`XKB_DEFAULT_LAYOUT`.
This commit is contained in:
Peter Kaplan
2022-04-20 15:38:18 +02:00
committed by Isaac Freund
parent 8f59075bc5
commit 44aaee3a51
9 changed files with 131 additions and 56 deletions
+64
View File
@@ -26,6 +26,10 @@ keysym: xkb.Keysym,
modifiers: wlr.Keyboard.ModifierMask,
command_args: []const [:0]const u8,
// This is set for mappings with layout-pinning
// If set, the layout with this index is always used to translate the given keycode
layout_index: ?u32,
/// When set to true the mapping will be executed on key release rather than on press
release: bool,
@@ -37,6 +41,7 @@ pub fn init(
modifiers: wlr.Keyboard.ModifierMask,
release: bool,
repeat: bool,
layout_index: ?u32,
command_args: []const []const u8,
) !Self {
const owned_args = try util.gpa.alloc([:0]u8, command_args.len);
@@ -50,6 +55,7 @@ pub fn init(
.modifiers = modifiers,
.release = release,
.repeat = repeat,
.layout_index = layout_index,
.command_args = owned_args,
};
}
@@ -58,3 +64,61 @@ pub fn deinit(self: Self) void {
for (self.command_args) |arg| util.gpa.free(arg);
util.gpa.free(self.command_args);
}
/// Compare mapping with given keycode, modifiers and keyboard state
pub fn match(
self: Self,
keycode: xkb.Keycode,
modifiers_raw: wlr.Keyboard.ModifierMask,
released: bool,
xkb_state: *xkb.State,
) bool {
if (released != self.release) return false;
const keymap = xkb_state.getKeymap();
// If the mapping has no pinned layout, use the active layout.
// It doesn't matter if the index is out of range, since xkbcommon
// will fall back to the active layout if so.
const layout_index = self.layout_index orelse xkb_state.keyGetLayout(keycode);
// Raw keysyms and modifiers as if modifiers didn't change keysyms.
// E.g. pressing `Super+Shift 1` does not translate to `Super Exclam`.
const keysyms_raw = keymap.keyGetSymsByLevel(
keycode,
layout_index,
0,
);
if (std.meta.eql(modifiers_raw, self.modifiers)) {
for (keysyms_raw) |sym| {
if (sym == self.keysym) {
return true;
}
}
}
// Keysyms and modifiers as translated by xkb.
// Modifiers used to translate the key are consumed.
// E.g. pressing `Super+Shift 1` translates to `Super Exclam`.
const keysyms_translated = keymap.keyGetSymsByLevel(
keycode,
layout_index,
xkb_state.keyGetLevel(keycode, layout_index),
);
const consumed = xkb_state.keyGetConsumedMods2(keycode, xkb.ConsumedMode.xkb);
const modifiers_translated = @bitCast(
wlr.Keyboard.ModifierMask,
@bitCast(u32, modifiers_raw) & ~consumed,
);
if (std.meta.eql(modifiers_translated, self.modifiers)) {
for (keysyms_translated) |sym| {
if (sym == self.keysym) {
return true;
}
}
}
return false;
}