terminal: kitty keyboard actions

pull/9342/head
Mitchell Hashimoto 2025-10-23 20:49:50 -07:00
parent b7ea979f38
commit 2520e27aef
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
2 changed files with 63 additions and 45 deletions

View File

@ -86,6 +86,11 @@ pub const Action = union(Key) {
protected_mode_dec, protected_mode_dec,
xtversion, xtversion,
kitty_keyboard_query, kitty_keyboard_query,
kitty_keyboard_push: KittyKeyboardFlags,
kitty_keyboard_pop: u16,
kitty_keyboard_set: KittyKeyboardFlags,
kitty_keyboard_set_or: KittyKeyboardFlags,
kitty_keyboard_set_not: KittyKeyboardFlags,
prompt_end, prompt_end,
end_of_input, end_of_input,
end_hyperlink, end_hyperlink,
@ -150,6 +155,11 @@ pub const Action = union(Key) {
"protected_mode_dec", "protected_mode_dec",
"xtversion", "xtversion",
"kitty_keyboard_query", "kitty_keyboard_query",
"kitty_keyboard_push",
"kitty_keyboard_pop",
"kitty_keyboard_set",
"kitty_keyboard_set_or",
"kitty_keyboard_set_not",
"prompt_end", "prompt_end",
"end_of_input", "end_of_input",
"end_hyperlink", "end_hyperlink",
@ -222,6 +232,16 @@ pub const Action = union(Key) {
top_left: u16, top_left: u16,
bottom_right: u16, bottom_right: u16,
}; };
pub const KittyKeyboardFlags = struct {
flags: kitty.KeyFlags,
pub const C = u8;
pub fn cval(self: KittyKeyboardFlags) KittyKeyboardFlags.C {
return @intCast(self.flags.int());
}
};
}; };
/// Returns a type that can process a stream of tty control characters. /// Returns a type that can process a stream of tty control characters.
@ -1564,7 +1584,7 @@ pub fn Stream(comptime Handler: type) type {
1 => switch (input.intermediates[0]) { 1 => switch (input.intermediates[0]) {
'?' => try self.handler.vt(.kitty_keyboard_query, {}), '?' => try self.handler.vt(.kitty_keyboard_query, {}),
'>' => if (@hasDecl(T, "pushKittyKeyboard")) push: { '>' => push: {
const flags: u5 = if (input.params.len == 1) const flags: u5 = if (input.params.len == 1)
std.math.cast(u5, input.params[0]) orelse { std.math.cast(u5, input.params[0]) orelse {
log.warn("invalid pushKittyKeyboard command: {f}", .{input}); log.warn("invalid pushKittyKeyboard command: {f}", .{input});
@ -1573,19 +1593,19 @@ pub fn Stream(comptime Handler: type) type {
else else
0; 0;
try self.handler.pushKittyKeyboard(@bitCast(flags)); try self.handler.vt(.kitty_keyboard_push, .{ .flags = @as(kitty.KeyFlags, @bitCast(flags)) });
}, },
'<' => if (@hasDecl(T, "popKittyKeyboard")) { '<' => {
const number: u16 = if (input.params.len == 1) const number: u16 = if (input.params.len == 1)
input.params[0] input.params[0]
else else
1; 1;
try self.handler.popKittyKeyboard(number); try self.handler.vt(.kitty_keyboard_pop, number);
}, },
'=' => if (@hasDecl(T, "setKittyKeyboard")) set: { '=' => set: {
const flags: u5 = if (input.params.len >= 1) const flags: u5 = if (input.params.len >= 1)
std.math.cast(u5, input.params[0]) orelse { std.math.cast(u5, input.params[0]) orelse {
log.warn("invalid setKittyKeyboard command: {f}", .{input}); log.warn("invalid setKittyKeyboard command: {f}", .{input});
@ -1599,20 +1619,23 @@ pub fn Stream(comptime Handler: type) type {
else else
1; 1;
const mode: kitty.KeySetMode = switch (number) { const action_tag: streampkg.Action.Tag = switch (number) {
1 => .set, 1 => .kitty_keyboard_set,
2 => .@"or", 2 => .kitty_keyboard_set_or,
3 => .not, 3 => .kitty_keyboard_set_not,
else => { else => {
log.warn("invalid setKittyKeyboard command: {f}", .{input}); log.warn("invalid setKittyKeyboard command: {f}", .{input});
break :set; break :set;
}, },
}; };
try self.handler.setKittyKeyboard( const kitty_flags: streampkg.Action.KittyKeyboardFlags = .{ .flags = @as(kitty.KeyFlags, @bitCast(flags)) };
mode, switch (action_tag) {
@bitCast(flags), .kitty_keyboard_set => try self.handler.vt(.kitty_keyboard_set, kitty_flags),
); .kitty_keyboard_set_or => try self.handler.vt(.kitty_keyboard_set_or, kitty_flags),
.kitty_keyboard_set_not => try self.handler.vt(.kitty_keyboard_set_not, kitty_flags),
else => unreachable,
}
}, },
else => log.warn( else => log.warn(
@ -2254,18 +2277,15 @@ test "stream: pop kitty keyboard with no params defaults to 1" {
const Self = @This(); const Self = @This();
n: u16 = 0, n: u16 = 0,
pub fn popKittyKeyboard(self: *Self, n: u16) !void {
self.n = n;
}
pub fn vt( pub fn vt(
self: *@This(), self: *Self,
comptime action: anytype, comptime action: streampkg.Action.Tag,
value: anytype, value: streampkg.Action.Value(action),
) !void { ) !void {
_ = self; switch (action) {
_ = action; .kitty_keyboard_pop => self.n = value,
_ = value; else => {},
}
} }
}; };

View File

@ -272,6 +272,26 @@ pub const StreamHandler = struct {
.protected_mode_dec => self.terminal.setProtectedMode(.dec), .protected_mode_dec => self.terminal.setProtectedMode(.dec),
.xtversion => try self.reportXtversion(), .xtversion => try self.reportXtversion(),
.kitty_keyboard_query => try self.queryKittyKeyboard(), .kitty_keyboard_query => try self.queryKittyKeyboard(),
.kitty_keyboard_push => {
log.debug("pushing kitty keyboard mode: {}", .{value.flags});
self.terminal.screen.kitty_keyboard.push(value.flags);
},
.kitty_keyboard_pop => {
log.debug("popping kitty keyboard mode n={}", .{value});
self.terminal.screen.kitty_keyboard.pop(@intCast(value));
},
.kitty_keyboard_set => {
log.debug("setting kitty keyboard mode: set {}", .{value.flags});
self.terminal.screen.kitty_keyboard.set(.set, value.flags);
},
.kitty_keyboard_set_or => {
log.debug("setting kitty keyboard mode: or {}", .{value.flags});
self.terminal.screen.kitty_keyboard.set(.@"or", value.flags);
},
.kitty_keyboard_set_not => {
log.debug("setting kitty keyboard mode: not {}", .{value.flags});
self.terminal.screen.kitty_keyboard.set(.not, value.flags);
},
.prompt_end => try self.promptEnd(), .prompt_end => try self.promptEnd(),
.end_of_input => try self.endOfInput(), .end_of_input => try self.endOfInput(),
.end_hyperlink => try self.endHyperlink(), .end_hyperlink => try self.endHyperlink(),
@ -865,28 +885,6 @@ pub const StreamHandler = struct {
}); });
} }
pub fn pushKittyKeyboard(
self: *StreamHandler,
flags: terminal.kitty.KeyFlags,
) !void {
log.debug("pushing kitty keyboard mode: {}", .{flags});
self.terminal.screen.kitty_keyboard.push(flags);
}
pub fn popKittyKeyboard(self: *StreamHandler, n: u16) !void {
log.debug("popping kitty keyboard mode n={}", .{n});
self.terminal.screen.kitty_keyboard.pop(@intCast(n));
}
pub fn setKittyKeyboard(
self: *StreamHandler,
mode: terminal.kitty.KeySetMode,
flags: terminal.kitty.KeyFlags,
) !void {
log.debug("setting kitty keyboard mode: {} {}", .{ mode, flags });
self.terminal.screen.kitty_keyboard.set(mode, flags);
}
pub fn reportXtversion( pub fn reportXtversion(
self: *StreamHandler, self: *StreamHandler,
) !void { ) !void {