widgets(terminal): implement legacy key encoding
This commit is contained in:
parent
7954e8c9ba
commit
6d4c180e31
4 changed files with 178 additions and 19 deletions
|
@ -82,8 +82,8 @@ pub fn main() !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const win = vx.window();
|
const win = vx.window();
|
||||||
win.clear();
|
|
||||||
win.hideCursor();
|
win.hideCursor();
|
||||||
|
win.clear();
|
||||||
const child = win.child(.{
|
const child = win.child(.{
|
||||||
.x_off = 4,
|
.x_off = 4,
|
||||||
.y_off = 2,
|
.y_off = 2,
|
||||||
|
|
|
@ -90,6 +90,8 @@ buf: []Cell = undefined,
|
||||||
|
|
||||||
cursor: Cursor = .{},
|
cursor: Cursor = .{},
|
||||||
|
|
||||||
|
csi_u_flags: vaxis.Key.KittyFlags = @bitCast(@as(u5, 0)),
|
||||||
|
|
||||||
/// sets each cell to the default cell
|
/// sets each cell to the default cell
|
||||||
pub fn init(alloc: std.mem.Allocator, w: usize, h: usize) !Screen {
|
pub fn init(alloc: std.mem.Allocator, w: usize, h: usize) !Screen {
|
||||||
var screen = Screen{
|
var screen = Screen{
|
||||||
|
|
|
@ -14,6 +14,7 @@ const DisplayWidth = @import("DisplayWidth");
|
||||||
const Key = vaxis.Key;
|
const Key = vaxis.Key;
|
||||||
const Queue = vaxis.Queue(Event, 16);
|
const Queue = vaxis.Queue(Event, 16);
|
||||||
const code_point = @import("code_point");
|
const code_point = @import("code_point");
|
||||||
|
const key = @import("key.zig");
|
||||||
|
|
||||||
pub const Event = union(enum) {
|
pub const Event = union(enum) {
|
||||||
exited,
|
exited,
|
||||||
|
@ -207,7 +208,7 @@ pub fn draw(self: *Terminal, win: vaxis.Window) !void {
|
||||||
if (self.mode.cursor) {
|
if (self.mode.cursor) {
|
||||||
win.setCursorShape(self.front_screen.cursor.shape);
|
win.setCursorShape(self.front_screen.cursor.shape);
|
||||||
win.showCursor(self.front_screen.cursor.col, self.front_screen.cursor.row);
|
win.showCursor(self.front_screen.cursor.col, self.front_screen.cursor.row);
|
||||||
} else win.hideCursor();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tryEvent(self: *Terminal) ?Event {
|
pub fn tryEvent(self: *Terminal) ?Event {
|
||||||
|
@ -216,7 +217,7 @@ pub fn tryEvent(self: *Terminal) ?Event {
|
||||||
|
|
||||||
pub fn update(self: *Terminal, event: InputEvent) !void {
|
pub fn update(self: *Terminal, event: InputEvent) !void {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.key_press => |key| try self.encodeKey(key, true),
|
.key_press => |k| try key.encode(self.anyWriter(), k, true, self.back_screen.csi_u_flags),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,22 +699,6 @@ pub fn setMode(self: *Terminal, mode: u16, val: bool) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encodeKey(self: *Terminal, key: vaxis.Key, press: bool) !void {
|
|
||||||
switch (press) {
|
|
||||||
true => {
|
|
||||||
if (key.text) |text| {
|
|
||||||
try self.anyWriter().writeAll(text);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (key.codepoint) {
|
|
||||||
0x00...0x7F => try self.anyWriter().writeByte(@intCast(key.codepoint)),
|
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn carriageReturn(self: *Terminal) void {
|
pub fn carriageReturn(self: *Terminal) void {
|
||||||
self.back_screen.cursor.pending_wrap = false;
|
self.back_screen.cursor.pending_wrap = false;
|
||||||
self.back_screen.cursor.col = if (self.mode.origin)
|
self.back_screen.cursor.col = if (self.mode.origin)
|
||||||
|
|
172
src/widgets/terminal/key.zig
Normal file
172
src/widgets/terminal/key.zig
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const vaxis = @import("../../main.zig");
|
||||||
|
|
||||||
|
pub fn encode(
|
||||||
|
writer: std.io.AnyWriter,
|
||||||
|
key: vaxis.Key,
|
||||||
|
press: bool,
|
||||||
|
kitty_flags: vaxis.Key.KittyFlags,
|
||||||
|
) !void {
|
||||||
|
const flags: u5 = @bitCast(kitty_flags);
|
||||||
|
switch (press) {
|
||||||
|
true => {
|
||||||
|
switch (flags) {
|
||||||
|
0 => try legacy(writer, key),
|
||||||
|
else => unreachable, // TODO: kitty encodings
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn legacy(writer: std.io.AnyWriter, key: vaxis.Key) !void {
|
||||||
|
// If we have text, we always write it directly
|
||||||
|
if (key.text) |text| {
|
||||||
|
try writer.writeAll(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shift = 0b00000001;
|
||||||
|
const alt = 0b00000010;
|
||||||
|
const ctrl = 0b00000100;
|
||||||
|
|
||||||
|
const effective_mods: u8 = blk: {
|
||||||
|
const mods: u8 = @bitCast(key.mods);
|
||||||
|
break :blk mods & (shift | alt | ctrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we have no mods and an ascii byte, write it directly
|
||||||
|
if (effective_mods == 0 and key.codepoint <= 0x7F) {
|
||||||
|
const b: u8 = @truncate(key.codepoint);
|
||||||
|
try writer.writeByte(b);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are lowercase ascii and ctrl, we map to a control byte
|
||||||
|
if (effective_mods == ctrl and key.codepoint >= 'a' and key.codepoint <= 'z') {
|
||||||
|
const b: u8 = @truncate(key.codepoint);
|
||||||
|
try writer.writeByte(b -| 0x60);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are printable ascii + alt
|
||||||
|
if (effective_mods == alt and key.codepoint >= ' ' and key.codepoint < 0x7F) {
|
||||||
|
const b: u8 = @truncate(key.codepoint);
|
||||||
|
try writer.print("\x1b{c}", .{b});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are ctrl + alt + lowercase ascii
|
||||||
|
if (effective_mods == (ctrl | alt) and key.codepoint >= 'a' and key.codepoint <= 'z') {
|
||||||
|
// convert to control sequence
|
||||||
|
try writer.print("\x1b{d}", .{key.codepoint - 0x60});
|
||||||
|
}
|
||||||
|
|
||||||
|
const def = switch (key.codepoint) {
|
||||||
|
vaxis.Key.escape => escape,
|
||||||
|
vaxis.Key.enter,
|
||||||
|
vaxis.Key.kp_enter,
|
||||||
|
=> enter,
|
||||||
|
vaxis.Key.tab => tab,
|
||||||
|
vaxis.Key.backspace => backspace,
|
||||||
|
vaxis.Key.insert,
|
||||||
|
vaxis.Key.kp_insert,
|
||||||
|
=> insert,
|
||||||
|
vaxis.Key.delete,
|
||||||
|
vaxis.Key.kp_delete,
|
||||||
|
=> delete,
|
||||||
|
vaxis.Key.left,
|
||||||
|
vaxis.Key.kp_left,
|
||||||
|
=> left,
|
||||||
|
vaxis.Key.right,
|
||||||
|
vaxis.Key.kp_right,
|
||||||
|
=> right,
|
||||||
|
vaxis.Key.up,
|
||||||
|
vaxis.Key.kp_up,
|
||||||
|
=> up,
|
||||||
|
vaxis.Key.down,
|
||||||
|
vaxis.Key.kp_down,
|
||||||
|
=> down,
|
||||||
|
vaxis.Key.page_up,
|
||||||
|
vaxis.Key.kp_page_up,
|
||||||
|
=> page_up,
|
||||||
|
vaxis.Key.page_down,
|
||||||
|
vaxis.Key.kp_page_down,
|
||||||
|
=> page_down,
|
||||||
|
vaxis.Key.home,
|
||||||
|
vaxis.Key.kp_home,
|
||||||
|
=> home,
|
||||||
|
vaxis.Key.end,
|
||||||
|
vaxis.Key.kp_end,
|
||||||
|
=> end,
|
||||||
|
vaxis.Key.f1 => f1,
|
||||||
|
vaxis.Key.f2 => f2,
|
||||||
|
vaxis.Key.f3 => f3_legacy,
|
||||||
|
vaxis.Key.f4 => f4,
|
||||||
|
vaxis.Key.f5 => f5,
|
||||||
|
vaxis.Key.f6 => f6,
|
||||||
|
vaxis.Key.f7 => f7,
|
||||||
|
vaxis.Key.f8 => f8,
|
||||||
|
vaxis.Key.f9 => f9,
|
||||||
|
vaxis.Key.f10 => f10,
|
||||||
|
vaxis.Key.f11 => f11,
|
||||||
|
vaxis.Key.f12 => f12,
|
||||||
|
else => return, // TODO: more keys
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (effective_mods) {
|
||||||
|
0 => {
|
||||||
|
if (def.number == 1)
|
||||||
|
switch (key.codepoint) {
|
||||||
|
vaxis.Key.f1,
|
||||||
|
vaxis.Key.f2,
|
||||||
|
vaxis.Key.f3,
|
||||||
|
vaxis.Key.f4,
|
||||||
|
=> try writer.print("\x1bO{c}", .{def.suffix}),
|
||||||
|
else => try writer.print("\x1b[{c}", .{def.suffix}),
|
||||||
|
}
|
||||||
|
else
|
||||||
|
try writer.print("\x1b[{d}{c}", .{ def.number, def.suffix });
|
||||||
|
},
|
||||||
|
else => try writer.print("\x1b[{d};{d}{c}", .{ def.number, effective_mods + 1, def.suffix }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Definition = struct {
|
||||||
|
number: u21,
|
||||||
|
suffix: u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const escape: Definition = .{ .number = 27, .suffix = 'u' };
|
||||||
|
const enter: Definition = .{ .number = 13, .suffix = 'u' };
|
||||||
|
const tab: Definition = .{ .number = 9, .suffix = 'u' };
|
||||||
|
const backspace: Definition = .{ .number = 127, .suffix = 'u' };
|
||||||
|
const insert: Definition = .{ .number = 2, .suffix = '~' };
|
||||||
|
const delete: Definition = .{ .number = 3, .suffix = '~' };
|
||||||
|
const left: Definition = .{ .number = 1, .suffix = 'D' };
|
||||||
|
const right: Definition = .{ .number = 1, .suffix = 'C' };
|
||||||
|
const up: Definition = .{ .number = 1, .suffix = 'A' };
|
||||||
|
const down: Definition = .{ .number = 1, .suffix = 'B' };
|
||||||
|
const page_up: Definition = .{ .number = 5, .suffix = '~' };
|
||||||
|
const page_down: Definition = .{ .number = 6, .suffix = '~' };
|
||||||
|
const home: Definition = .{ .number = 1, .suffix = 'H' };
|
||||||
|
const end: Definition = .{ .number = 1, .suffix = 'F' };
|
||||||
|
const caps_lock: Definition = .{ .number = 57358, .suffix = 'u' };
|
||||||
|
const scroll_lock: Definition = .{ .number = 57359, .suffix = 'u' };
|
||||||
|
const num_lock: Definition = .{ .number = 57360, .suffix = 'u' };
|
||||||
|
const print_screen: Definition = .{ .number = 57361, .suffix = 'u' };
|
||||||
|
const pause: Definition = .{ .number = 57362, .suffix = 'u' };
|
||||||
|
const menu: Definition = .{ .number = 57363, .suffix = 'u' };
|
||||||
|
const f1: Definition = .{ .number = 1, .suffix = 'P' };
|
||||||
|
const f2: Definition = .{ .number = 1, .suffix = 'Q' };
|
||||||
|
const f3: Definition = .{ .number = 13, .suffix = '~' };
|
||||||
|
const f3_legacy: Definition = .{ .number = 1, .suffix = 'R' };
|
||||||
|
const f4: Definition = .{ .number = 1, .suffix = 'S' };
|
||||||
|
const f5: Definition = .{ .number = 15, .suffix = '~' };
|
||||||
|
const f6: Definition = .{ .number = 17, .suffix = '~' };
|
||||||
|
const f7: Definition = .{ .number = 18, .suffix = '~' };
|
||||||
|
const f8: Definition = .{ .number = 19, .suffix = '~' };
|
||||||
|
const f9: Definition = .{ .number = 20, .suffix = '~' };
|
||||||
|
const f10: Definition = .{ .number = 21, .suffix = '~' };
|
||||||
|
const f11: Definition = .{ .number = 23, .suffix = '~' };
|
||||||
|
const f12: Definition = .{ .number = 24, .suffix = '~' };
|
Loading…
Reference in a new issue