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 isTaggedUnion = event.isTaggedUnion;
|
||||||
|
|
||||||
const key = @import("key.zig");
|
const key = @import("key.zig");
|
||||||
|
const Mouse = @import("mouse.zig").Mouse;
|
||||||
const Key = key.Key;
|
const Key = key.Key;
|
||||||
const Size = @import("size.zig").Size;
|
const Size = @import("size.zig").Size;
|
||||||
const Queue = @import("queue.zig").Queue;
|
const Queue = @import("queue.zig").Queue;
|
||||||
@@ -95,6 +96,7 @@ pub fn App(comptime E: type) type {
|
|||||||
try terminal.saveScreen();
|
try terminal.saveScreen();
|
||||||
try terminal.enterAltScreen();
|
try terminal.enterAltScreen();
|
||||||
try terminal.hideCursor();
|
try terminal.hideCursor();
|
||||||
|
try terminal.enableMouseSupport();
|
||||||
|
|
||||||
// send initial size afterwards
|
// send initial size afterwards
|
||||||
const size = terminal.getTerminalSize();
|
const size = terminal.getTerminalSize();
|
||||||
@@ -104,6 +106,7 @@ pub fn App(comptime E: type) type {
|
|||||||
|
|
||||||
pub fn interrupt(this: *@This()) !void {
|
pub fn interrupt(this: *@This()) !void {
|
||||||
this.quit_event.set();
|
this.quit_event.set();
|
||||||
|
try terminal.disableMouseSupport();
|
||||||
try terminal.exitAltScreen();
|
try terminal.exitAltScreen();
|
||||||
try terminal.restoreScreen();
|
try terminal.restoreScreen();
|
||||||
if (this.thread) |thread| {
|
if (this.thread) |thread| {
|
||||||
@@ -115,9 +118,10 @@ pub fn App(comptime E: type) type {
|
|||||||
pub fn stop(this: *@This()) !void {
|
pub fn stop(this: *@This()) !void {
|
||||||
try this.interrupt();
|
try this.interrupt();
|
||||||
if (this.termios) |*termios| {
|
if (this.termios) |*termios| {
|
||||||
try terminal.disableRawMode(termios);
|
try terminal.disableMouseSupport();
|
||||||
try terminal.showCursor();
|
try terminal.showCursor();
|
||||||
try terminal.exitAltScreen();
|
try terminal.exitAltScreen();
|
||||||
|
try terminal.disableRawMode(termios);
|
||||||
try terminal.restoreScreen();
|
try terminal.restoreScreen();
|
||||||
}
|
}
|
||||||
this.termios = null;
|
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)
|
// 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 {
|
this.quit_event.timedWait(20 * std.time.ns_per_ms) catch {
|
||||||
const read_bytes = try terminal.read(buf[0..]);
|
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
|
// escape key presses
|
||||||
if (buf[0] == 0x1b and read_bytes > 1) {
|
if (buf[0] == 0x1b and read_bytes > 1) {
|
||||||
switch (buf[1]) {
|
switch (buf[1]) {
|
||||||
@@ -267,7 +272,47 @@ pub fn App(comptime E: type) type {
|
|||||||
},
|
},
|
||||||
'I' => this.postEvent(.{ .focus = true }),
|
'I' => this.postEvent(.{ .focus = true }),
|
||||||
'O' => this.postEvent(.{ .focus = false }),
|
'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' => {
|
'c' => {
|
||||||
// Primary DA (CSI ? Pm c)
|
// Primary DA (CSI ? Pm c)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const terminal = @import("terminal.zig");
|
const terminal = @import("terminal.zig");
|
||||||
|
|
||||||
|
const Mouse = @import("mouse.zig").Mouse;
|
||||||
const Size = @import("size.zig").Size;
|
const Size = @import("size.zig").Size;
|
||||||
const Key = @import("key.zig").Key;
|
const Key = @import("key.zig").Key;
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ pub const SystemEvent = union(enum) {
|
|||||||
resize: Size,
|
resize: Size,
|
||||||
/// Input key event received from the user
|
/// Input key event received from the user
|
||||||
key: Key,
|
key: Key,
|
||||||
|
/// Mouse input event
|
||||||
|
mouse: Mouse,
|
||||||
/// Focus event for mouse interaction
|
/// Focus event for mouse interaction
|
||||||
/// TODO: this should instead be a union with a `Size` to derive which container / element the focus meant for
|
/// TODO: this should instead be a union with a `Size` to derive which container / element the focus meant for
|
||||||
focus: bool,
|
focus: bool,
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
//! Keybindings and Modifiers for user input detection and selection.
|
//! 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");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const Key = packed struct {
|
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