parser: fix handling of function keys with kitty encoding

This commit is contained in:
Tim Culverhouse 2024-06-05 12:52:49 -05:00
parent 3c29f18251
commit 0cb81e30eb

View file

@ -303,17 +303,16 @@ inline fn parseCsi(input: []const u8, text_buf: []u8) Result {
'A', 'B', 'C', 'D', 'E', 'F', 'H', 'P', 'Q', 'R', 'S' => { 'A', 'B', 'C', 'D', 'E', 'F', 'H', 'P', 'Q', 'R', 'S' => {
// Legacy keys // Legacy keys
// CSI {ABCDEFHPQS} // CSI {ABCDEFHPQS}
// CSI 1 ; modifier {ABCDEFHPQS} // CSI 1 ; modifier:event_type {ABCDEFHPQS}
const modifiers: Key.Modifiers = if (sequence.len > 3) mods: { // Split first into fields delimited by ';'
// ESC [ 1 ; <modifier_buf> {ABCDEFHPQS} var field_iter = std.mem.splitScalar(u8, sequence[2 .. sequence.len - 1], ';');
const modifier_buf = sequence[4 .. sequence.len - 1];
const modifiers = parseParam(u8, modifier_buf, 1) orelse return null_event;
break :mods @bitCast(modifiers -| 1);
} else .{};
const key: Key = .{ // skip the first field
.mods = modifiers, _ = field_iter.next(); //
var is_release: bool = false;
var key: Key = .{
.codepoint = switch (final) { .codepoint = switch (final) {
'A' => Key.up, 'A' => Key.up,
'B' => Key.down, 'B' => Key.down,
@ -329,8 +328,35 @@ inline fn parseCsi(input: []const u8, text_buf: []u8) Result {
else => return null_event, else => return null_event,
}, },
}; };
field2: {
// modifier_mask:event_type
const field_buf = field_iter.next() orelse break :field2;
var param_iter = std.mem.splitScalar(u8, field_buf, ':');
const modifier_buf = param_iter.next() orelse unreachable;
const modifier_mask = parseParam(u8, modifier_buf, 1) orelse return null_event;
key.mods = @bitCast(modifier_mask -| 1);
if (param_iter.next()) |event_type_buf| {
is_release = std.mem.eql(u8, event_type_buf, "3");
}
}
field3: {
// text_as_codepoint[:text_as_codepoint]
const field_buf = field_iter.next() orelse break :field3;
var param_iter = std.mem.splitScalar(u8, field_buf, ':');
var total: usize = 0;
while (param_iter.next()) |cp_buf| {
const cp = parseParam(u21, cp_buf, null) orelse return null_event;
total += std.unicode.utf8Encode(cp, text_buf[total..]) catch return null_event;
}
key.text = text_buf[0..total];
}
const event: Event = if (is_release) .{ .key_release = key } else .{ .key_press = key };
return .{ return .{
.event = .{ .key_press = key }, .event = event,
.n = sequence.len, .n = sequence.len,
}; };
}, },
@ -338,47 +364,67 @@ inline fn parseCsi(input: []const u8, text_buf: []u8) Result {
// Legacy keys // Legacy keys
// CSI number ~ // CSI number ~
// CSI number ; modifier ~ // CSI number ; modifier ~
// CSI number ; modifier:event_type ; text_as_codepoint ~
var field_iter = std.mem.splitScalar(u8, sequence[2 .. sequence.len - 1], ';'); var field_iter = std.mem.splitScalar(u8, sequence[2 .. sequence.len - 1], ';');
const number_buf = field_iter.next() orelse unreachable; // always will have one field const number_buf = field_iter.next() orelse unreachable; // always will have one field
const number = parseParam(u16, number_buf, null) orelse return null_event; const number = parseParam(u16, number_buf, null) orelse return null_event;
const key_code = switch (number) { var key: Key = .{
2 => Key.insert, .codepoint = switch (number) {
3 => Key.delete, 2 => Key.insert,
5 => Key.page_up, 3 => Key.delete,
6 => Key.page_down, 5 => Key.page_up,
7 => Key.home, 6 => Key.page_down,
8 => Key.end, 7 => Key.home,
11 => Key.f1, 8 => Key.end,
12 => Key.f2, 11 => Key.f1,
13 => Key.f3, 12 => Key.f2,
14 => Key.f4, 13 => Key.f3,
15 => Key.f5, 14 => Key.f4,
17 => Key.f6, 15 => Key.f5,
18 => Key.f7, 17 => Key.f6,
19 => Key.f8, 18 => Key.f7,
20 => Key.f9, 19 => Key.f8,
21 => Key.f10, 20 => Key.f9,
23 => Key.f11, 21 => Key.f10,
24 => Key.f12, 23 => Key.f11,
200 => return .{ .event = .paste_start, .n = sequence.len }, 24 => Key.f12,
201 => return .{ .event = .paste_end, .n = sequence.len }, 200 => return .{ .event = .paste_start, .n = sequence.len },
57427 => Key.kp_begin, 201 => return .{ .event = .paste_end, .n = sequence.len },
else => return null_event, 57427 => Key.kp_begin,
else => return null_event,
},
}; };
const modifiers: Key.Modifiers = if (field_iter.next()) |modifier_buf| mods: { var is_release: bool = false;
const modifiers = parseParam(u8, modifier_buf, 1) orelse return null_event; field2: {
break :mods @bitCast(modifiers -| 1); // modifier_mask:event_type
} else .{}; const field_buf = field_iter.next() orelse break :field2;
var param_iter = std.mem.splitScalar(u8, field_buf, ':');
const modifier_buf = param_iter.next() orelse unreachable;
const modifier_mask = parseParam(u8, modifier_buf, 1) orelse return null_event;
key.mods = @bitCast(modifier_mask -| 1);
const key: Key = .{ if (param_iter.next()) |event_type_buf| {
.codepoint = key_code, is_release = std.mem.eql(u8, event_type_buf, "3");
.mods = modifiers, }
}; }
field3: {
// text_as_codepoint[:text_as_codepoint]
const field_buf = field_iter.next() orelse break :field3;
var param_iter = std.mem.splitScalar(u8, field_buf, ':');
var total: usize = 0;
while (param_iter.next()) |cp_buf| {
const cp = parseParam(u21, cp_buf, null) orelse return null_event;
total += std.unicode.utf8Encode(cp, text_buf[total..]) catch return null_event;
}
key.text = text_buf[0..total];
}
const event: Event = if (is_release) .{ .key_release = key } else .{ .key_press = key };
return .{ return .{
.event = .{ .key_press = key }, .event = event,
.n = sequence.len, .n = sequence.len,
}; };
}, },