parser: fix handling of function keys with kitty encoding
This commit is contained in:
parent
3c29f18251
commit
0cb81e30eb
1 changed files with 88 additions and 42 deletions
130
src/Parser.zig
130
src/Parser.zig
|
@ -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,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue