diff options
Diffstat (limited to 'src/vaxis_input.zig')
| -rw-r--r-- | src/vaxis_input.zig | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/vaxis_input.zig b/src/vaxis_input.zig new file mode 100644 index 00000000..0e25dea1 --- /dev/null +++ b/src/vaxis_input.zig @@ -0,0 +1,77 @@ +//! A key as vaxis parses it from a terminal's bytes, as the core's Event: +//! the one map for every shell that reads a terminal (tty, gui's stdin, +//! esp32p4). Three copies had drifted; the gui's had lost the F-keys, +//! Insert and the keypad. +const std = @import("std"); +const vaxis = @import("vaxis"); +const pardes = @import("pardes.zig"); + +/// The effective codepoint the way vaxis's own `Key.matches` sees it: a +/// single-character `text` wins, the terminal having resolved shift; +/// otherwise the shifted codepoint. +pub fn effCp(key: vaxis.Key) u21 { + if (key.text) |t| { + const view = std.unicode.Utf8View.init(t) catch return key.codepoint; + var it = view.iterator(); + if (it.nextCodepoint()) |c| { + if (it.nextCodepoint() == null) return c; + } + } + return key.shifted_codepoint orelse key.codepoint; +} + +/// vaxis's functional-key codepoints as the core's; the ASCII ones +/// (enter, tab, escape, backspace) already coincide. +pub fn mapKey(cp: u21) u21 { + return switch (cp) { + vaxis.Key.kp_enter => pardes.Key.enter, + vaxis.Key.up => pardes.Key.up, + vaxis.Key.down => pardes.Key.down, + vaxis.Key.left => pardes.Key.left, + vaxis.Key.right => pardes.Key.right, + vaxis.Key.home => pardes.Key.home, + vaxis.Key.end => pardes.Key.end, + vaxis.Key.page_up => pardes.Key.page_up, + vaxis.Key.page_down => pardes.Key.page_down, + vaxis.Key.delete => pardes.Key.delete, + vaxis.Key.insert => pardes.Key.insert, + vaxis.Key.print_screen => pardes.Key.print_screen, + vaxis.Key.scroll_lock => pardes.Key.scroll_lock, + vaxis.Key.pause => pardes.Key.pause, + vaxis.Key.menu => pardes.Key.menu, + vaxis.Key.f1...vaxis.Key.f25 => pardes.Key.f1 + (cp - vaxis.Key.f1), + // The keypad's own keys, which the kitty keyboard protocol tells + // apart, do what the keys they are named for do. + vaxis.Key.kp_left => pardes.Key.left, + vaxis.Key.kp_right => pardes.Key.right, + vaxis.Key.kp_up => pardes.Key.up, + vaxis.Key.kp_down => pardes.Key.down, + vaxis.Key.kp_page_up => pardes.Key.page_up, + vaxis.Key.kp_page_down => pardes.Key.page_down, + vaxis.Key.kp_home => pardes.Key.home, + vaxis.Key.kp_end => pardes.Key.end, + vaxis.Key.kp_insert => pardes.Key.insert, + vaxis.Key.kp_delete => pardes.Key.delete, + else => cp, + }; +} + +/// The key as the core's event, its text the key's own. +pub fn keyEvent(key: vaxis.Key) pardes.Event { + return .{ .key = .{ + .cp = mapKey(effCp(key)), + .text = key.text orelse "", + .ctrl = key.mods.ctrl, + .alt = key.mods.alt, + .shift = key.mods.shift, + } }; +} + +test "F-keys, Insert and the keypad map to the core's keys" { + try std.testing.expectEqual(pardes.Key.f1 + 4, mapKey(vaxis.Key.f5)); + try std.testing.expectEqual(pardes.Key.f1 + 24, mapKey(vaxis.Key.f25)); + try std.testing.expectEqual(pardes.Key.insert, mapKey(vaxis.Key.insert)); + try std.testing.expectEqual(pardes.Key.up, mapKey(vaxis.Key.kp_up)); + try std.testing.expectEqual(pardes.Key.enter, keyEvent(.{ .codepoint = vaxis.Key.kp_enter }).key.cp); + try std.testing.expectEqual(@as(u21, 'a'), mapKey('a')); +} |
