command.zig (2478B)
1 const signals = @import("signals.zig"); 2 const std = @import("std"); 3 const terminal = @import("terminal.zig"); 4 5 pub const Command = enum { 6 Pause, 7 Quit, 8 Reset, 9 }; 10 11 pub const Poller = struct { 12 stdin_fd: std.posix.fd_t, 13 signals_fd: std.posix.fd_t, 14 terminal: ?terminal.Terminal, 15 16 pub fn init(allocator: std.mem.Allocator) !Poller { 17 _ = allocator; 18 const opt_terminal = blk: { 19 break :blk terminal.Terminal.init() catch |err| { 20 std.log.debug("failed to init terminal: {any}", .{err}); 21 break :blk null; 22 }; 23 }; 24 errdefer { 25 if (opt_terminal) |terminal_| { 26 terminal_.deinit(); 27 } 28 } 29 30 const signals_file = try signals.open(); 31 const signals_fd = signals_file.handle; 32 33 return Poller{ 34 .terminal = opt_terminal, 35 .stdin_fd = std.Io.File.stdin().handle, 36 .signals_fd = signals_fd, 37 }; 38 } 39 40 pub fn interactive(self: *Poller) bool { 41 return self.terminal != null; 42 } 43 44 pub fn deinit(self: *Poller) void { 45 if (self.terminal) |terminal_| terminal_.deinit(); 46 } 47 48 pub fn pollTimeout(self: *Poller, nanoseconds: u64) !?Command { 49 var fds = [2]std.posix.pollfd{ 50 .{ .fd = self.stdin_fd, .events = std.posix.POLL.IN, .revents = 0 }, 51 .{ .fd = self.signals_fd, .events = std.posix.POLL.IN, .revents = 0 }, 52 }; 53 54 const timeout_ms = @as(i32, @intCast(@divTrunc(nanoseconds, std.time.ns_per_ms))); 55 const n = try std.posix.poll(&fds, timeout_ms); 56 if (n == 0) return null; 57 58 if (fds[0].revents & std.posix.POLL.IN != 0) { 59 var buf: [1]u8 = undefined; 60 const bytes_read = try std.posix.read(self.stdin_fd, &buf); 61 if (bytes_read > 0) { 62 switch (buf[0]) { 63 'p' => return Command.Pause, 64 'q' => return Command.Quit, 65 'r' => return Command.Reset, 66 else => {}, 67 } 68 } 69 } 70 71 if (fds[1].revents & std.posix.POLL.IN != 0) { 72 const signo = try signals.readSignal(self.signals_fd); 73 switch (signo) { 74 std.posix.SIG.USR1 => return Command.Pause, 75 std.posix.SIG.USR2 => return Command.Reset, 76 else => unreachable, 77 } 78 } 79 80 return null; 81 } 82 };