summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-29 14:27:29 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:16 -0300
commitf9502fa884ac3baff04de40c82b68034e02df61e (patch)
tree5af0f4233826b0e5297207ffec73b90e83c404bd
parente373dea7e32ab83e37c9db97ef5709786b9b2188 (diff)
downloadpardes-f9502fa884ac3baff04de40c82b68034e02df61e.tar.gz
pardes-f9502fa884ac3baff04de40c82b68034e02df61e.zip
Function keys, Insert and the keypad reach a terminal pane as their terminal sequences
-rw-r--r--src/Terminal.zig11
-rw-r--r--src/pardes.zig8
-rw-r--r--src/tty/tty.zig28
3 files changed, 43 insertions, 4 deletions
diff --git a/src/Terminal.zig b/src/Terminal.zig
index a32819c3..c99a92a6 100644
--- a/src/Terminal.zig
+++ b/src/Terminal.zig
@@ -1113,6 +1113,11 @@ pub fn forwardKey(p: *Pardes, id: usize, key: Key) void {
const pane = p.panes[id] orelse return;
const state = pane.terminal orelse return;
const input = ghostty_vt.input;
+ const function_keys = comptime keys: {
+ var keys: [Key.f25 - Key.f1 + 1]input.Key = undefined;
+ for (&keys, 1..) |*k, n| k.* = @field(input.Key, std.fmt.comptimePrint("f{d}", .{n}));
+ break :keys keys;
+ };
const physical: input.Key = switch (key.cp) {
Key.enter => .enter,
Key.backspace => .backspace,
@@ -1127,6 +1132,12 @@ pub fn forwardKey(p: *Pardes, id: usize, key: Key) void {
Key.page_up => .page_up,
Key.page_down => .page_down,
Key.delete => .delete,
+ Key.insert => .insert,
+ Key.print_screen => .print_screen,
+ Key.scroll_lock => .scroll_lock,
+ Key.pause => .pause,
+ Key.menu => .context_menu,
+ Key.f1...Key.f25 => function_keys[key.cp - Key.f1],
else => if (key.cp < 128) input.Key.fromASCII(@intCast(key.cp)) orelse .unidentified else .unidentified,
};
var utf8: [4]u8 = undefined;
diff --git a/src/pardes.zig b/src/pardes.zig
index ae04b4e7..4fb11362 100644
--- a/src/pardes.zig
+++ b/src/pardes.zig
@@ -3590,6 +3590,14 @@ pub const Key = struct {
pub const page_up: u21 = 0xF0007;
pub const page_down: u21 = 0xF0008;
pub const delete: u21 = 0xF0009;
+ pub const insert: u21 = 0xF000A;
+ pub const print_screen: u21 = 0xF000B;
+ pub const scroll_lock: u21 = 0xF000C;
+ pub const pause: u21 = 0xF000D;
+ pub const menu: u21 = 0xF000E;
+ /// F1 to F25, in order: Fn is `f1 + n - 1`.
+ pub const f1: u21 = 0xF0011;
+ pub const f25: u21 = f1 + 24;
};
pub fn hit(key: Key, binding: []const config.Chord) bool {
diff --git a/src/tty/tty.zig b/src/tty/tty.zig
index 206d5c58..01d2f08e 100644
--- a/src/tty/tty.zig
+++ b/src/tty/tty.zig
@@ -1941,6 +1941,24 @@ fn mapKey(cp: u21) u21 {
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,
};
}
@@ -1966,7 +1984,7 @@ fn keyEvent(key: vaxis.Key) pardes.Event {
} };
}
-test "keys with no text of their own type nothing into a terminal pane" {
+test "a terminal pane gets function keys as their sequences and lone modifiers not at all" {
if (comptime builtin.os.tag == .windows) return error.SkipZigTest;
const gpa = std.testing.allocator;
const io = std.testing.io;
@@ -2005,8 +2023,10 @@ test "keys with no text of their own type nothing into a terminal pane" {
// Kitty reports Ctrl and Shift pressed on their own: the Ctrl of a
// Ctrl-V typed `\x1b[57442;5u` into the shell.
"\x1b[57442;5u\x1b[57441;2u\x1b[57358u",
- // F3, F5 and Insert, kitty's way and the legacy way.
- "\x1b[13~\x1b[15~\x1b[2~\x1bOR",
+ // F3, F5 and Insert the kitty way, F3 the legacy way and the
+ // keypad's Up: once typed as private-use junk, now what htop,
+ // mc and vim read them as.
+ "\x1b[13~\x1b[15~\x1b[2~\x1bOR\x1b[57419u",
"\x1b[104;;104u",
},
};
@@ -2024,7 +2044,7 @@ test "keys with no text of their own type nothing into a terminal pane" {
while (core.nextEffect()) |effect| {
if (effect == .write) try written.writer.writeAll(effect.write.bytes.slice());
}
- try std.testing.expectEqualStrings("h", written.written());
+ try std.testing.expectEqualStrings("\x1bOR\x1b[15~\x1b[2~\x1bOR\x1b[Ah", written.written());
}
test "keypad Enter matches Return for editor input terminal writes and paste" {