add(input): mouse support
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 46s

This commit is contained in:
2025-02-17 23:36:27 +01:00
parent c2080ab40f
commit e2f9408850
4 changed files with 81 additions and 2 deletions

View File

@@ -7,6 +7,7 @@ const mergeTaggedUnions = event.mergeTaggedUnions;
const isTaggedUnion = event.isTaggedUnion;
const key = @import("key.zig");
const Mouse = @import("mouse.zig").Mouse;
const Key = key.Key;
const Size = @import("size.zig").Size;
const Queue = @import("queue.zig").Queue;
@@ -95,6 +96,7 @@ pub fn App(comptime E: type) type {
try terminal.saveScreen();
try terminal.enterAltScreen();
try terminal.hideCursor();
try terminal.enableMouseSupport();
// send initial size afterwards
const size = terminal.getTerminalSize();
@@ -104,6 +106,7 @@ pub fn App(comptime E: type) type {
pub fn interrupt(this: *@This()) !void {
this.quit_event.set();
try terminal.disableMouseSupport();
try terminal.exitAltScreen();
try terminal.restoreScreen();
if (this.thread) |thread| {
@@ -115,9 +118,10 @@ pub fn App(comptime E: type) type {
pub fn stop(this: *@This()) !void {
try this.interrupt();
if (this.termios) |*termios| {
try terminal.disableRawMode(termios);
try terminal.disableMouseSupport();
try terminal.showCursor();
try terminal.exitAltScreen();
try terminal.disableRawMode(termios);
try terminal.restoreScreen();
}
this.termios = null;
@@ -171,6 +175,7 @@ pub fn App(comptime E: type) type {
// FIX: I still think that there is a race condition (I'm just waiting 'long' enough)
this.quit_event.timedWait(20 * std.time.ns_per_ms) catch {
const read_bytes = try terminal.read(buf[0..]);
// TODO: `break` should not terminate the reading of the user inputs, but instead only the received faulty input!
// escape key presses
if (buf[0] == 0x1b and read_bytes > 1) {
switch (buf[1]) {
@@ -267,7 +272,47 @@ pub fn App(comptime E: type) type {
},
'I' => this.postEvent(.{ .focus = true }),
'O' => this.postEvent(.{ .focus = false }),
// 'M', 'm' => return parseMouse(sequence), // TODO: parse mouse inputs
'M', 'm' => {
std.debug.assert(sequence.len >= 4);
if (sequence[2] != '<') break;
const delim1 = std.mem.indexOfScalarPos(u8, sequence, 3, ';') orelse break;
const button_mask = std.fmt.parseUnsigned(u16, sequence[3..delim1], 10) catch break;
const delim2 = std.mem.indexOfScalarPos(u8, sequence, delim1 + 1, ';') orelse break;
const px = std.fmt.parseUnsigned(u16, sequence[delim1 + 1 .. delim2], 10) catch break;
const py = std.fmt.parseUnsigned(u16, sequence[delim2 + 1 .. sequence.len - 1], 10) catch break;
const mouse_bits = packed struct {
const motion: u8 = 0b00100000;
const buttons: u8 = 0b11000011;
const shift: u8 = 0b00000100;
const alt: u8 = 0b00001000;
const ctrl: u8 = 0b00010000;
};
const button: Mouse.Button = @enumFromInt(button_mask & mouse_bits.buttons);
const motion = button_mask & mouse_bits.motion > 0;
// const shift = button_mask & mouse_bits.shift > 0;
// const alt = button_mask & mouse_bits.alt > 0;
// const ctrl = button_mask & mouse_bits.ctrl > 0;
const mouse = Mouse{
.button = button,
.col = px -| 1,
.row = py -| 1,
.kind = blk: {
if (motion and button != Mouse.Button.none) {
break :blk .drag;
}
if (motion and button == Mouse.Button.none) {
break :blk .motion;
}
if (sequence[sequence.len - 1] == 'm') break :blk .release;
break :blk .press;
},
};
this.postEvent(.{ .mouse = mouse });
},
'c' => {
// Primary DA (CSI ? Pm c)
},