respect application cursor keys for arrow (DECCKM)

This fixes the arrow keys in htop.
This commit is contained in:
Mitchell Hashimoto
2022-11-27 20:57:58 -08:00
parent 0e55f4054e
commit b8832833cb
6 changed files with 77 additions and 6 deletions

View File

@ -980,6 +980,29 @@ fn keyCallback(
win.io_thread.wakeup.send() catch {};
},
.cursor_key => |ck| {
// We send a different sequence depending on if we're
// in cursor keys mode. We're in "normal" mode if cursor
// keys mdoe is NOT set.
const normal = normal: {
win.renderer_state.mutex.lock();
defer win.renderer_state.mutex.unlock();
break :normal !win.io.terminal.modes.cursor_keys;
};
if (normal) {
_ = win.io_thread.mailbox.push(.{
.write_stable = ck.normal,
}, .{ .forever = {} });
} else {
_ = win.io_thread.mailbox.push(.{
.write_stable = ck.application,
}, .{ .forever = {} });
}
win.io_thread.wakeup.send() catch {};
},
.copy_to_clipboard => {
// We can read from the renderer state without holding
// the lock because only we will write to this field.

View File

@ -190,12 +190,31 @@ pub const Config = struct {
.{ .paste_from_clipboard = {} },
);
try result.keybind.set.put(alloc, .{ .key = .up }, .{ .csi = "A" });
try result.keybind.set.put(alloc, .{ .key = .down }, .{ .csi = "B" });
try result.keybind.set.put(alloc, .{ .key = .right }, .{ .csi = "C" });
try result.keybind.set.put(alloc, .{ .key = .left }, .{ .csi = "D" });
try result.keybind.set.put(alloc, .{ .key = .home }, .{ .csi = "H" });
try result.keybind.set.put(alloc, .{ .key = .end }, .{ .csi = "F" });
try result.keybind.set.put(alloc, .{ .key = .up }, .{ .cursor_key = .{
.normal = "\x1b[A",
.application = "\x1bOA",
} });
try result.keybind.set.put(alloc, .{ .key = .down }, .{ .cursor_key = .{
.normal = "\x1b[B",
.application = "\x1bOB",
} });
try result.keybind.set.put(alloc, .{ .key = .right }, .{ .cursor_key = .{
.normal = "\x1b[C",
.application = "\x1bOC",
} });
try result.keybind.set.put(alloc, .{ .key = .left }, .{ .cursor_key = .{
.normal = "\x1b[D",
.application = "\x1bOD",
} });
try result.keybind.set.put(alloc, .{ .key = .home }, .{ .cursor_key = .{
.normal = "\x1b[H",
.application = "\x1bOH",
} });
try result.keybind.set.put(alloc, .{ .key = .end }, .{ .cursor_key = .{
.normal = "\x1b[F",
.application = "\x1bOF",
} });
try result.keybind.set.put(alloc, .{ .key = .page_up }, .{ .csi = "5~" });
try result.keybind.set.put(alloc, .{ .key = .page_down }, .{ .csi = "6~" });

View File

@ -15,6 +15,7 @@ action: Action,
pub const Error = error{
InvalidFormat,
InvalidAction,
};
/// Parse the format "ctrl+a=csi:A" into a binding. The format is
@ -101,6 +102,9 @@ pub fn parse(input: []const u8) !Binding {
break :action @unionInit(Action, field.name, param);
},
// Cursor keys can't be set currently
Action.CursorKey => return Error.InvalidAction,
else => unreachable,
}
}
@ -127,6 +131,10 @@ pub const Action = union(enum) {
/// without the CSI header ("ESC ]" or "\x1b]").
csi: []const u8,
/// Send data to the pty depending on whether cursor key mode is
/// enabled ("application") or disabled ("normal").
cursor_key: CursorKey,
/// Copy and paste.
copy_to_clipboard: void,
paste_from_clipboard: void,
@ -152,6 +160,11 @@ pub const Action = union(enum) {
/// Quit ghostty
quit: void,
pub const CursorKey = struct {
normal: []const u8,
application: []const u8,
};
};
/// Trigger is the associated key state that can trigger an action.

View File

@ -72,6 +72,7 @@ previous_char: ?u21 = null,
modes: packed struct {
const Self = @This();
cursor_keys: bool = false, // 1
reverse_colors: bool = false, // 5,
origin: bool = false, // 6
autowrap: bool = true, // 7

View File

@ -42,6 +42,17 @@ pub const RenditionAspect = enum(u16) {
/// values correspond to the `?`-prefixed modes, since those are the ones
/// of primary interest. The enum value is the mode value.
pub const Mode = enum(u16) {
/// This control function selects the sequences the arrow keys send.
/// You can use the four arrow keys to move the cursor through the current
/// page or to send special application commands.
///
/// If the DECCKM function is set, then the arrow keys send application
/// sequences to the host.
///
/// If the DECCKM function is reset, then the arrow keys send ANSI cursor
/// sequences to the host.
cursor_keys = 1,
/// Change terminal wide between 80 and 132 column mode. When set
/// (with ?40 set), resizes terminal to 132 columns and keeps it that
/// wide. When unset, resizes to 80 columns.

View File

@ -627,6 +627,10 @@ const StreamHandler = struct {
pub fn setMode(self: *StreamHandler, mode: terminal.Mode, enabled: bool) !void {
switch (mode) {
.cursor_keys => {
self.terminal.modes.cursor_keys = enabled;
},
.reverse_colors => {
self.terminal.modes.reverse_colors = enabled;