From 9950c9eac5286ce0e2835ac21b8aa348f0a94955 Mon Sep 17 00:00:00 2001 From: Tim Culverhouse Date: Wed, 24 Jan 2024 18:36:45 -0600 Subject: [PATCH] vaxis: mode cleanup, initial mouse implementation Signed-off-by: Tim Culverhouse --- examples/text_input.zig | 3 +++ src/ctlseqs.zig | 4 +++ src/vaxis.zig | 58 ++++++++++++++++++++++++++++++----------- 3 files changed, 50 insertions(+), 15 deletions(-) diff --git a/examples/text_input.zig b/examples/text_input.zig index 7ef5597..a7e199e 100644 --- a/examples/text_input.zig +++ b/examples/text_input.zig @@ -13,6 +13,7 @@ const Event = union(enum) { key_press: vaxis.Key, winsize: vaxis.Winsize, focus_in, + focus_out, foo: u8, }; @@ -53,6 +54,8 @@ pub fn main() !void { // _always_ be called, but is left to the application to decide when try vx.queryTerminal(); + try vx.setMouseMode(true); + // The main event loop. Vaxis provides a thread safe, blocking, buffered // queue which can serve as the primary event queue for an application outer: while (true) { diff --git a/src/ctlseqs.zig b/src/ctlseqs.zig index 4b66da1..59a2c9c 100644 --- a/src/ctlseqs.zig +++ b/src/ctlseqs.zig @@ -10,6 +10,10 @@ pub const csi_u_query = "\x1b[?u"; pub const kitty_graphics_query = "\x1b_Gi=1,a=q\x1b\\"; pub const sixel_geometry_query = "\x1b[?2;1;0S"; +// mouse +pub const mouse_set = "\x1b[?1003;1004;1006h"; +pub const mouse_reset = "\x1b[?1003;1004;1006l"; + // sync pub const sync_set = "\x1b[?2026h"; pub const sync_reset = "\x1b[?2026l"; diff --git a/src/vaxis.zig b/src/vaxis.zig index 96f971e..a1c756a 100644 --- a/src/vaxis.zig +++ b/src/vaxis.zig @@ -51,11 +51,14 @@ pub fn Vaxis(comptime T: type) type { /// the next render screen_last: InternalScreen = undefined, - /// alt_screen state. We track so we can exit on deinit - alt_screen: bool, - - /// if we have entered kitty keyboard - kitty_keyboard: bool = false, + state: struct { + /// if we are in the alt screen + alt_screen: bool = false, + /// if we have entered kitty keyboard + kitty_keyboard: bool = false, + bracketed_paste: bool = false, + mouse: bool = false, + } = .{}, caps: Capabilities = .{}, @@ -77,7 +80,6 @@ pub fn Vaxis(comptime T: type) type { .tty = null, .screen = .{}, .screen_last = .{}, - .alt_screen = false, }; } @@ -88,10 +90,16 @@ pub fn Vaxis(comptime T: type) type { pub fn deinit(self: *Self, alloc: ?std.mem.Allocator) void { if (self.tty) |_| { var tty = &self.tty.?; - if (self.kitty_keyboard) { + if (self.state.kitty_keyboard) { _ = tty.write(ctlseqs.csi_u_pop) catch {}; } - if (self.alt_screen) { + if (self.state.mouse) { + _ = tty.write(ctlseqs.mouse_reset) catch {}; + } + if (self.state.bracketed_paste) { + _ = tty.write(ctlseqs.bp_reset) catch {}; + } + if (self.state.alt_screen) { _ = tty.write(ctlseqs.rmcup) catch {}; } tty.flush() catch {}; @@ -165,20 +173,20 @@ pub fn Vaxis(comptime T: type) type { /// enter the alternate screen. The alternate screen will automatically /// be exited if calling deinit while in the alt screen pub fn enterAltScreen(self: *Self) !void { - if (self.alt_screen) return; + if (self.state.alt_screen) return; var tty = self.tty orelse return; _ = try tty.write(ctlseqs.smcup); try tty.flush(); - self.alt_screen = true; + self.state.alt_screen = true; } /// exit the alternate screen pub fn exitAltScreen(self: *Self) !void { - if (!self.alt_screen) return; + if (!self.state.alt_screen) return; var tty = self.tty orelse return; _ = try tty.write(ctlseqs.rmcup); try tty.flush(); - self.alt_screen = false; + self.state.alt_screen = false; } /// write queries to the terminal to determine capabilities. Individual @@ -468,7 +476,7 @@ pub fn Vaxis(comptime T: type) type { } fn enableKittyKeyboard(self: *Self, flags: Key.KittyFlags) !void { - self.kitty_keyboard = true; + self.state.kitty_keyboard = true; const flag_int: u5 = @bitCast(flags); try std.fmt.format( self.tty.?.buffered_writer.writer(), @@ -511,9 +519,16 @@ pub fn Vaxis(comptime T: type) type { // turn bracketed paste on or off. An event will be sent at the // beginning and end of a detected paste. All keystrokes between these // events were pasted - pub fn bracketedPaste(self: *Self, enable: bool) !void { + pub fn setBracketedPaste(self: *Self, enable: bool) !void { if (self.tty == null) return; - const seq = if (enable) ctlseqs.bp_set else ctlseqs.bp_reset; + self.state.bracketed_paste = enable; + const seq = if (enable) { + self.state.bracketed_paste = true; + ctlseqs.bp_set; + } else { + self.state.bracketed_paste = true; + ctlseqs.bp_reset; + }; _ = try self.tty.?.write(seq); try self.tty.?.flush(); } @@ -522,6 +537,19 @@ pub fn Vaxis(comptime T: type) type { pub fn setMouseShape(self: *Self, shape: Shape) void { self.screen.mouse_shape = shape; } + + /// turn mouse reporting on or off + pub fn setMouseMode(self: *Self, enable: bool) !void { + var tty = self.tty orelse return; + self.state.mouse = enable; + if (enable) { + _ = try tty.write(ctlseqs.mouse_set); + try tty.flush(); + } else { + _ = try tty.write(ctlseqs.mouse_reset); + try tty.flush(); + } + } }; }