我已经使用Rust中的termion箱创建了一个简单的命令行工具.它会打印出"Hello World!"按下键时的消息.只有当输入的是q个字符时,它才会退出程序.以下是使用AlternateScreen struct 在终端上编写的代码:

use std::io::{stdin, stdout, Write};
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use termion::screen::IntoAlternateScreen;

fn main() {
    // Initialize stdout and stind
    let stdin = stdin();
    let mut stdout = stdout().into_alternate_screen().unwrap();

    // Print a message indicating what to do
    write!(
        stdout,
        "{}{}Press any key to print 'Hello world!', or press 'q' to quit.{}",
        termion::clear::All,
        termion::cursor::Goto(1, 1),
        termion::cursor::Hide
    )
    .unwrap();
    stdout.flush().unwrap();

    // Create an input reader for key events
    let mut row = 1;
    for c in stdin.keys() {
        write!(
            stdout,
            "{}{}",
            termion::cursor::Goto(1, row),
            termion::clear::CurrentLine
        )
        .unwrap();

        match c.unwrap() {
            Key::Char('q') => break,
            _ => println!("Hello world!"),
        }

        stdout.flush().unwrap();
        row += 1;
    }

    // Enable back the cursor
    write!(stdout, "{}", termion::cursor::Show).unwrap();
}

通过转到下一行和第一列,我将消息写到新行.row变量跟踪下一条消息的写入位置.

问题是我必须按Enter来注册标准输入中的字符.然而,另一首《Hello World!》显示文本是因为额外的键.我想在任何输入键之后立即写入文本,而不需要按Enter按钮.

请注意,如果将标准输出替换为RawTerminal struct ,则一切都将按预期运行.

let mut stdout = stdout().into_raw_mode().unwrap();

在这种情况下,不需要在输入字符上按Enter.

为什么AlternateScreen在读取输入键时需要按Enter键?

推荐答案

您在使用AlternateScreen struct 体时遇到的行为是由于终端缓冲的工作方式.在规范模式下,终端缓冲输入,直到遇到换行符或换行符.RawTerminal struct 体将终端置于raw模式,在这种模式下,输入不被缓冲,而是直接发送到程序.

在您的例子中,当您使用stdout().into_alternate_screen()时,您的终端仍然处于规范模式,因此在将输入发送到您的程序之前需要按Enter键.这就是为什么你会看到额外的"Hello World!"按Enter键时显示消息.

另一方面,当你使用stdout().into_raw_mode()时,你的终端处于原始模式,它直接将输入发送到你的程序,而不需要等待一个新的行或命令行.这就是为什么在这种情况下不需要按Enter键的原因.

要解决这个问题,您需要在使用AlternateScreen时将终端置于原始模式.你可以通过在into_alternate_screen()之后链接into_raw_mode()来实现这一点:

let mut stdout = stdout().into_alternate_screen().unwrap().into_raw_mode().unwrap();

Rust相关问答推荐

为什么单元类型(空元组)实现了`Extend`trait?

当rust中不存在文件或目录时,std::FS::File::Create().unwire()会抛出错误

值为可变对象的不可变HashMap

rust 迹-内存管理-POP所有权-链表

防止cargo test 中的竞争条件

在铁 rust 中传递所有权

如何点击()迭代器?

为昂贵的for循环制作筛子

如何从ruust中的fig.toml中读取?

在Rust中声明和定义一个 struct 体有什么区别

将Vec<;U8&>转换为Vec<;{Float}&>

为什么 tokio 在以奇怪的方式调用时只运行 n 个任务中的 n-1 个?

Rust ECDH 不会产生与 NodeJS/Javascript 和 C 实现相同的共享密钥

根据掩码将 simd 通道设置为 0 的惯用方法?

在Rust中实现Trie数据 struct 的更好方式

返回优化后的标题:返回异步块的闭包的类型擦除

在不安全的 Rust 中存储对 struct 内部数据的静态引用是否合法?

不安全块不返回预期值

类型判断模式匹配panic

在 Traits 函数中设置生命周期的问题