add(input): mouse support
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 46s
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 46s
This commit is contained in:
49
src/app.zig
49
src/app.zig
@@ -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)
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const std = @import("std");
|
||||
const terminal = @import("terminal.zig");
|
||||
|
||||
const Mouse = @import("mouse.zig").Mouse;
|
||||
const Size = @import("size.zig").Size;
|
||||
const Key = @import("key.zig").Key;
|
||||
|
||||
@@ -23,6 +24,8 @@ pub const SystemEvent = union(enum) {
|
||||
resize: Size,
|
||||
/// Input key event received from the user
|
||||
key: Key,
|
||||
/// Mouse input event
|
||||
mouse: Mouse,
|
||||
/// Focus event for mouse interaction
|
||||
/// TODO: this should instead be a union with a `Size` to derive which container / element the focus meant for
|
||||
focus: bool,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//! Keybindings and Modifiers for user input detection and selection.
|
||||
|
||||
// TODO: rename this module to 'input' and include the mouse.zig contents as well!
|
||||
const std = @import("std");
|
||||
|
||||
pub const Key = packed struct {
|
||||
|
||||
29
src/mouse.zig
Normal file
29
src/mouse.zig
Normal file
@@ -0,0 +1,29 @@
|
||||
/// Mouse input detection.
|
||||
pub const Mouse = packed struct {
|
||||
col: u16,
|
||||
row: u16,
|
||||
button: Button,
|
||||
kind: Kind,
|
||||
|
||||
pub const Button = enum(u8) {
|
||||
left,
|
||||
middle,
|
||||
right,
|
||||
none,
|
||||
wheel_up = 64,
|
||||
wheel_down = 65,
|
||||
wheel_right = 66,
|
||||
wheel_left = 67,
|
||||
button_8 = 128,
|
||||
button_9 = 129,
|
||||
button_10 = 130,
|
||||
button_11 = 131,
|
||||
};
|
||||
|
||||
pub const Kind = enum(u2) {
|
||||
press,
|
||||
release,
|
||||
motion,
|
||||
drag,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user