vaxis: detect pixel mouse mode and translate coordinates to cell offsets
This detects support for pixel mouse mode so it can be enabled only if supported. This also translates pixel coordinates to something more compatible with plaine cell coordinates. This make it much easier to write applications that support both.
This commit is contained in:
parent
a75cce6e78
commit
55809160b9
8 changed files with 62 additions and 21 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
/// A mouse event
|
||||
pub const Mouse = @This();
|
||||
|
||||
pub const ReportingMode = enum {
|
||||
off,
|
||||
cells,
|
||||
pixels,
|
||||
};
|
||||
|
||||
pub const Shape = enum {
|
||||
default,
|
||||
text,
|
||||
|
@ -47,6 +41,8 @@ pub const Type = enum {
|
|||
|
||||
col: usize,
|
||||
row: usize,
|
||||
xoffset: usize = 0,
|
||||
yoffset: usize = 0,
|
||||
button: Button,
|
||||
mods: Modifiers,
|
||||
type: Type,
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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,
|
||||
|
@ -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 => {
|
||||
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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 => {
|
||||
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,
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -16,6 +16,7 @@ pub const Event = union(enum) {
|
|||
cap_kitty_keyboard,
|
||||
cap_kitty_graphics,
|
||||
cap_rgb,
|
||||
cap_sgr_pixels,
|
||||
cap_unicode,
|
||||
cap_da1,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue