vaxis: enable da1 parsing, use futex timeout to return from query

Now that DA1 parsing is done, block the queryTerminal function until the
DA1 response is received, or a 1 second timeout elapses. With this
functionality, move certain events into Vaxis's realm of handling: IE
enabling kitty keyboard, unicode mode, etc

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
Tim Culverhouse 2024-01-23 21:30:09 -06:00
parent a2dc97c039
commit 04f6117cfe
7 changed files with 47 additions and 17 deletions

View file

@ -61,8 +61,6 @@ pub fn main() !void {
.winsize => |ws| { .winsize => |ws| {
try vx.resize(alloc, ws); try vx.resize(alloc, ws);
}, },
.cap_rgb => continue,
.cap_kitty_keyboard => try vx.enableKittyKeyboard(.{}),
else => {}, else => {},
} }
@ -98,7 +96,5 @@ const Event = union(enum) {
key_press: vaxis.Key, key_press: vaxis.Key,
winsize: vaxis.Winsize, winsize: vaxis.Winsize,
focus_in, focus_in,
cap_rgb,
cap_kitty_keyboard,
foo: u8, foo: u8,
}; };

View file

@ -357,6 +357,17 @@ pub fn parse(self: *Parser, input: []const u8) !Result {
log.warn("unhandled csi: CSI {s}", .{input[start + 1 .. i + 1]}); log.warn("unhandled csi: CSI {s}", .{input[start + 1 .. i + 1]});
return .{ .event = null, .n = i + 1 }; return .{ .event = null, .n = i + 1 };
}, },
'c' => { // DA1 response
const priv = seq.private_indicator orelse {
log.warn("unhandled csi: CSI {s}", .{input[start + 1 .. i + 1]});
return .{ .event = null, .n = i + 1 };
};
if (priv != '?') {
log.warn("unhandled csi: CSI {s}", .{input[start + 1 .. i + 1]});
return .{ .event = null, .n = i + 1 };
}
return .{ .event = .cap_da1, .n = i + 1 };
},
else => { else => {
log.warn("unhandled csi: CSI {s}", .{input[start + 1 .. i + 1]}); log.warn("unhandled csi: CSI {s}", .{input[start + 1 .. i + 1]});
return .{ return .{

View file

@ -178,19 +178,16 @@ pub fn run(
} }
}, },
.cap_kitty_keyboard => { .cap_kitty_keyboard => {
if (@hasField(EventType, "cap_kitty_keyboard")) { vx.caps.kitty_keyboard = true;
vx.postEvent(.cap_kitty_keyboard);
}
}, },
.cap_rgb => { .cap_rgb => {
if (@hasField(EventType, "cap_rgb")) { vx.caps.rgb = true;
vx.postEvent(.cap_rgb);
}
}, },
.cap_unicode => { .cap_unicode => {
if (@hasField(EventType, "cap_unicode")) { vx.caps.unicode = true;
vx.postEvent(.cap_unicode); },
} .cap_da1 => {
std.Thread.Futex.wake(&vx.query_futex, 10);
}, },
} }
} }

View file

@ -14,6 +14,9 @@ pub const sixel_geometry_query = "\x1b[?2;1;0S";
pub const sync_set = "\x1b[?2026h"; pub const sync_set = "\x1b[?2026h";
pub const sync_reset = "\x1b[?2026l"; pub const sync_reset = "\x1b[?2026l";
pub const unicode_set = "\x1b[?2027h";
pub const unicode_reset = "\x1b[?2027l";
// Key encoding // Key encoding
pub const csi_u_push = "\x1b[>{d}u"; pub const csi_u_push = "\x1b[>{d}u";
pub const csi_u_pop = "\x1b[<u"; pub const csi_u_pop = "\x1b[<u";

View file

@ -1,7 +1,6 @@
pub const Key = @import("Key.zig"); pub const Key = @import("Key.zig");
/// The events that Vaxis emits. This can be used as the generic EventType if /// The events that Vaxis emits internally
/// there are no internal events
pub const Event = union(enum) { pub const Event = union(enum) {
key_press: Key, key_press: Key,
focus_in, focus_in,
@ -13,4 +12,5 @@ pub const Event = union(enum) {
cap_kitty_keyboard, cap_kitty_keyboard,
cap_rgb, cap_rgb,
cap_unicode, cap_unicode,
cap_da1,
}; };

View file

@ -7,7 +7,6 @@ pub const Style = cell.Style;
pub const Key = @import("Key.zig"); pub const Key = @import("Key.zig");
pub const Winsize = @import("Tty.zig").Winsize; pub const Winsize = @import("Tty.zig").Winsize;
pub const Event = @import("event.zig").Event;
pub const widgets = @import("widgets/main.zig"); pub const widgets = @import("widgets/main.zig");

View file

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const atomic = std.atomic;
const Queue = @import("queue.zig").Queue; const Queue = @import("queue.zig").Queue;
const ctlseqs = @import("ctlseqs.zig"); const ctlseqs = @import("ctlseqs.zig");
@ -30,6 +31,12 @@ pub fn Vaxis(comptime T: type) type {
pub const EventType = T; pub const EventType = T;
pub const Capabilities = struct {
kitty_keyboard: bool = false,
rgb: bool = false,
unicode: bool = false,
};
/// the event queue for Vaxis /// the event queue for Vaxis
// //
// TODO: is 512 ok? // TODO: is 512 ok?
@ -49,9 +56,15 @@ pub fn Vaxis(comptime T: type) type {
/// if we have entered kitty keyboard /// if we have entered kitty keyboard
kitty_keyboard: bool = false, kitty_keyboard: bool = false,
caps: Capabilities = .{},
/// if we should redraw the entire screen on the next render /// if we should redraw the entire screen on the next render
refresh: bool = false, refresh: bool = false,
/// blocks the main thread until a DA1 query has been received, or the
/// futex times out
query_futex: atomic.Value(u32) = atomic.Value(u32).init(0),
// statistics // statistics
renders: usize = 0, renders: usize = 0,
render_dur: i128 = 0, render_dur: i128 = 0,
@ -201,6 +214,17 @@ pub fn Vaxis(comptime T: type) type {
_ = try tty.write(ctlseqs.primary_device_attrs); _ = try tty.write(ctlseqs.primary_device_attrs);
try tty.flush(); try tty.flush();
// 1 second timeout
std.Thread.Futex.timedWait(&self.query_futex, 0, 1 * std.time.ns_per_s) catch {};
// enable detected features
if (self.caps.kitty_keyboard) {
try self.enableKittyKeyboard(.{});
}
if (self.caps.unicode) {
_ = try tty.write(ctlseqs.unicode_set);
}
} }
// the next render call will refresh the entire screen // the next render call will refresh the entire screen
@ -429,7 +453,7 @@ pub fn Vaxis(comptime T: type) type {
} }
} }
pub fn enableKittyKeyboard(self: *Self, flags: Key.KittyFlags) !void { fn enableKittyKeyboard(self: *Self, flags: Key.KittyFlags) !void {
self.kitty_keyboard = true; self.kitty_keyboard = true;
const flag_int: u5 = @bitCast(flags); const flag_int: u5 = @bitCast(flags);
try std.fmt.format( try std.fmt.format(