Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sgr-pixel detection and coordinate to offset translation #29

Merged
merged 2 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/pause_tui.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn main() !void {
// _always_ be called, but is left to the application to decide when
try vx.queryTerminal();

try vx.setMouseMode(.cells);
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
Expand Down
2 changes: 1 addition & 1 deletion examples/text_input.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ pub fn main() !void {
// _always_ be called, but is left to the application to decide when
try vx.queryTerminal();

try vx.setMouseMode(.pixels);
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
Expand Down
8 changes: 2 additions & 6 deletions src/Mouse.zig
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
/// A mouse event
pub const Mouse = @This();

pub const ReportingMode = enum {
off,
cells,
pixels,
};

pub const Shape = enum {
default,
text,
Expand Down Expand Up @@ -47,6 +41,8 @@ pub const Type = enum {

col: usize,
row: usize,
xoffset: usize = 0,
yoffset: usize = 0,
button: Button,
mods: Modifiers,
type: Type,
7 changes: 5 additions & 2 deletions src/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ pub fn parse(self: *Parser, input: []const u8, paste_allocator: ?std.mem.Allocat
const shift = seq.params[0] & mouse_bits.shift > 0;
const alt = seq.params[0] & mouse_bits.alt > 0;
const ctrl = seq.params[0] & mouse_bits.ctrl > 0;
const col: usize = seq.params[1] - 1;
const row: usize = seq.params[2] - 1;
const col: usize = if(seq.params[1] > 0) seq.params[1] - 1 else 0;
const row: usize = if(seq.params[2] > 0) seq.params[2] - 1 else 0;

const mouse = Mouse{
.button = button,
Expand Down Expand Up @@ -404,6 +404,9 @@ pub fn parse(self: *Parser, input: []const u8, paste_allocator: ?std.mem.Allocat
// 3: permanently set
// 4: permanently reset
switch (seq.params[0]) {
1016 => {
return .{ .event = .cap_sgr_pixels, .n = i + 1 };
},
2027 => {
switch (seq.params[1]) {
0, 4 => return .{ .event = null, .n = i + 1 },
Expand Down
7 changes: 6 additions & 1 deletion src/Tty.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ state: struct {
kitty_keyboard: bool = false,
bracketed_paste: bool = false,
mouse: bool = false,
pixel_mouse: bool = false,
cursor: struct {
row: usize = 0,
col: usize = 0,
Expand Down Expand Up @@ -179,7 +180,7 @@ pub fn run(
},
.mouse => |mouse| {
if (@hasField(Event, "mouse")) {
loop.postEvent(.{ .mouse = mouse });
loop.postEvent(.{ .mouse = loop.vaxis.translateMouse(mouse) });
}
},
.focus_in => {
Expand Down Expand Up @@ -229,6 +230,10 @@ pub fn run(
loop.vaxis.caps.unicode = .unicode;
loop.vaxis.screen.width_method = .unicode;
},
.cap_sgr_pixels => {
log.info("pixel mouse capability detected", .{});
loop.vaxis.caps.sgr_pixels = true;
},
.cap_da1 => {
std.Thread.Futex.wake(&loop.vaxis.query_futex, 10);
},
Expand Down
59 changes: 47 additions & 12 deletions src/Vaxis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub const Capabilities = struct {
kitty_graphics: bool = false,
rgb: bool = false,
unicode: gwidth.Method = .wcwidth,
sgr_pixels: bool = false,
};

pub const Options = struct {
Expand Down Expand Up @@ -199,6 +200,7 @@ pub fn queryTerminalSend(self: *Vaxis) !void {
// doesn't hurt to blindly use them
// _ = try tty.write(ctlseqs.decrqm_focus);
// _ = try tty.write(ctlseqs.decrqm_sync);
_ = try tty.write(ctlseqs.decrqm_sgr_pixels);
_ = try tty.write(ctlseqs.decrqm_unicode);
_ = try tty.write(ctlseqs.decrqm_color_theme);
// TODO: XTVERSION has a DCS response. uncomment when we can parse
Expand Down Expand Up @@ -703,25 +705,58 @@ pub fn setMouseShape(self: *Vaxis, shape: Shape) void {
}

/// Change the mouse reporting mode
pub fn setMouseMode(self: *Vaxis, mode: Mouse.ReportingMode) !void {
pub fn setMouseMode(self: *Vaxis, enable: bool) !void {
if (self.tty) |*tty| {
switch (mode) {
.off => {
_ = try tty.write(ctlseqs.mouse_reset);
},
.cells => {
tty.state.mouse = true;
_ = try tty.write(ctlseqs.mouse_set);
},
.pixels => {
tty.state.mouse = true;
if (enable) {
tty.state.mouse = true;
if (self.caps.sgr_pixels) {
log.debug("enabling mouse mode: pixel coordinates", .{});
tty.state.pixel_mouse = true;
_ = try tty.write(ctlseqs.mouse_set_pixels);
},
} else {
log.debug("enabling mouse mode: cell coordinates", .{});
_ = try tty.write(ctlseqs.mouse_set);
}
} else {
_ = try tty.write(ctlseqs.mouse_reset);
}
try tty.flush();
}
}

/// Translate pixel mouse coordinates to cell + offset
pub fn translateMouse(self: Vaxis, mouse: Mouse) Mouse {
var result = mouse;
const tty = self.tty orelse return result;
if (tty.state.pixel_mouse) {
std.debug.assert(mouse.xoffset == 0);
std.debug.assert(mouse.yoffset == 0);
const xpos = mouse.col;
const ypos = mouse.row;
const xextra = self.screen.width_pix % self.screen.width;
const yextra = self.screen.height_pix % self.screen.height;
const xcell = (self.screen.width_pix - xextra) / self.screen.width;
const ycell = (self.screen.height_pix - yextra) / self.screen.height;
result.col = xpos / xcell;
result.row = ypos / ycell;
result.xoffset = xpos % xcell;
result.yoffset = ypos % ycell;
log.debug("translateMouse x/ypos:{d}/{d} cell:{d}/{d} xtra:{d}/{d} col/rol:{d}/{d} x/y:{d}/{d}", .{
xpos, ypos,
xcell, ycell,
xextra, yextra,
result.col, result.row,
result.xoffset, result.yoffset,
});
} else {
log.debug("translateMouse col/rol:{d}/{d} x/y:{d}/{d}", .{
result.col, result.row,
result.xoffset, result.yoffset,
});
}
return result;
}

pub fn loadImage(
self: *Vaxis,
alloc: std.mem.Allocator,
Expand Down
1 change: 1 addition & 0 deletions src/ctlseqs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub const tertiary_device_attrs = "\x1b[=c";
pub const device_status_report = "\x1b[5n";
pub const xtversion = "\x1b[>0q";
pub const decrqm_focus = "\x1b[?1004$p";
pub const decrqm_sgr_pixels = "\x1b[?1016$p";
pub const decrqm_sync = "\x1b[?2026$p";
pub const decrqm_unicode = "\x1b[?2027$p";
pub const decrqm_color_theme = "\x1b[?2031$p";
Expand Down
1 change: 1 addition & 0 deletions src/event.zig
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub const Event = union(enum) {
cap_kitty_keyboard,
cap_kitty_graphics,
cap_rgb,
cap_sgr_pixels,
cap_unicode,
cap_da1,
};