mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
respect application cursor keys for arrow (DECCKM)
This fixes the arrow keys in htop.
This commit is contained in:
@ -980,6 +980,29 @@ fn keyCallback(
|
|||||||
win.io_thread.wakeup.send() catch {};
|
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 => {
|
.copy_to_clipboard => {
|
||||||
// We can read from the renderer state without holding
|
// We can read from the renderer state without holding
|
||||||
// the lock because only we will write to this field.
|
// the lock because only we will write to this field.
|
||||||
|
@ -190,12 +190,31 @@ pub const Config = struct {
|
|||||||
.{ .paste_from_clipboard = {} },
|
.{ .paste_from_clipboard = {} },
|
||||||
);
|
);
|
||||||
|
|
||||||
try result.keybind.set.put(alloc, .{ .key = .up }, .{ .csi = "A" });
|
try result.keybind.set.put(alloc, .{ .key = .up }, .{ .cursor_key = .{
|
||||||
try result.keybind.set.put(alloc, .{ .key = .down }, .{ .csi = "B" });
|
.normal = "\x1b[A",
|
||||||
try result.keybind.set.put(alloc, .{ .key = .right }, .{ .csi = "C" });
|
.application = "\x1bOA",
|
||||||
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 = .down }, .{ .cursor_key = .{
|
||||||
try result.keybind.set.put(alloc, .{ .key = .end }, .{ .csi = "F" });
|
.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_up }, .{ .csi = "5~" });
|
||||||
try result.keybind.set.put(alloc, .{ .key = .page_down }, .{ .csi = "6~" });
|
try result.keybind.set.put(alloc, .{ .key = .page_down }, .{ .csi = "6~" });
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ action: Action,
|
|||||||
|
|
||||||
pub const Error = error{
|
pub const Error = error{
|
||||||
InvalidFormat,
|
InvalidFormat,
|
||||||
|
InvalidAction,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parse the format "ctrl+a=csi:A" into a binding. The format is
|
/// 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);
|
break :action @unionInit(Action, field.name, param);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Cursor keys can't be set currently
|
||||||
|
Action.CursorKey => return Error.InvalidAction,
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,6 +131,10 @@ pub const Action = union(enum) {
|
|||||||
/// without the CSI header ("ESC ]" or "\x1b]").
|
/// without the CSI header ("ESC ]" or "\x1b]").
|
||||||
csi: []const u8,
|
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 and paste.
|
||||||
copy_to_clipboard: void,
|
copy_to_clipboard: void,
|
||||||
paste_from_clipboard: void,
|
paste_from_clipboard: void,
|
||||||
@ -152,6 +160,11 @@ pub const Action = union(enum) {
|
|||||||
|
|
||||||
/// Quit ghostty
|
/// Quit ghostty
|
||||||
quit: void,
|
quit: void,
|
||||||
|
|
||||||
|
pub const CursorKey = struct {
|
||||||
|
normal: []const u8,
|
||||||
|
application: []const u8,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Trigger is the associated key state that can trigger an action.
|
/// Trigger is the associated key state that can trigger an action.
|
||||||
|
@ -72,6 +72,7 @@ previous_char: ?u21 = null,
|
|||||||
modes: packed struct {
|
modes: packed struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
cursor_keys: bool = false, // 1
|
||||||
reverse_colors: bool = false, // 5,
|
reverse_colors: bool = false, // 5,
|
||||||
origin: bool = false, // 6
|
origin: bool = false, // 6
|
||||||
autowrap: bool = true, // 7
|
autowrap: bool = true, // 7
|
||||||
|
@ -42,6 +42,17 @@ pub const RenditionAspect = enum(u16) {
|
|||||||
/// values correspond to the `?`-prefixed modes, since those are the ones
|
/// values correspond to the `?`-prefixed modes, since those are the ones
|
||||||
/// of primary interest. The enum value is the mode value.
|
/// of primary interest. The enum value is the mode value.
|
||||||
pub const Mode = enum(u16) {
|
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
|
/// Change terminal wide between 80 and 132 column mode. When set
|
||||||
/// (with ?40 set), resizes terminal to 132 columns and keeps it that
|
/// (with ?40 set), resizes terminal to 132 columns and keeps it that
|
||||||
/// wide. When unset, resizes to 80 columns.
|
/// wide. When unset, resizes to 80 columns.
|
||||||
|
@ -627,6 +627,10 @@ const StreamHandler = struct {
|
|||||||
|
|
||||||
pub fn setMode(self: *StreamHandler, mode: terminal.Mode, enabled: bool) !void {
|
pub fn setMode(self: *StreamHandler, mode: terminal.Mode, enabled: bool) !void {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
.cursor_keys => {
|
||||||
|
self.terminal.modes.cursor_keys = enabled;
|
||||||
|
},
|
||||||
|
|
||||||
.reverse_colors => {
|
.reverse_colors => {
|
||||||
self.terminal.modes.reverse_colors = enabled;
|
self.terminal.modes.reverse_colors = enabled;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user