如何使用 Zig 在不按 Enter 的情况下捕获终端中的单个击键?
这是我正在尝试的:
const std = @import("std");
const c = @cImport({
@cInclude("termios.h");
@cInclude("unistd.h");
@cInclude("stdlib.h");
});
var orig_termios: c.termios = undefined;
pub fn enableRawMode() void {
_ = c.tcgetattr(c.STDIN_FILENO, &orig_termios);
_ = c.atexit(disableRawMode);
var raw: c.termios = undefined;
const flags = c.ICANON;
raw.c_lflag &= ~flags;
_ = c.tcsetattr(c.STDIN_FILENO, c.TCSANOW, &orig_termios);
}
pub fn disableRawMode() callconv(.C) void {
_ = c.tcsetattr(c.STDIN_FILENO, c.TCSANOW, &orig_termios);
}
pub fn main() !void {
enableRawMode();
var char: u8 = undefined;
const stdin = std.io.getStdIn().reader();
char = try stdin.readByte();
std.debug.print("char: {c}\n", .{char});
}
这无法编译,因为我无法分配我的标志。 我收到错误:
main.zig:16:20: error: type 'c_ulong' cannot represent integer value '-257'
raw.c_lflag &= ~flags;
^~~~~~
我已经在 C 语言中运行了类似的代码,所以我试图将其适应 Zig:
#include <termios.h>
void buffer_off(struct termios *term) {
tcgetattr(STDIN_FILENO, term);
term->c_lflag &= ~ICANON;
tcsetattr(STDIN_FILENO, TCSANOW, term);
}
我学习了 Zig 方式来禁用/启用终端缓冲:
const stdin = std.io.getStdIn();
pub fn buffer_on(stdin: *const std.fs.File) !void {
const term = try std.posix.tcgetattr(stdin.handle);
try std.posix.tcsetattr(stdin.handle, .NOW, term);
}
pub fn buffer_off(stdin: *const std.fs.File) !void {
var term = try std.posix.tcgetattr(stdin.handle);
term.lflag.ICANON = false;
try std.posix.tcsetattr(stdin.handle, .NOW, term);
}
调用
buffer_off()
使得 stdin.reader().readByte()
不再需要按 Enter 键。 然后在 main()
结束时,我致电 buffer_on()
将我的终端恢复正常。