如何在Rust中读取ANSI DSR查询响应(纯标准库无libc依赖方案)
解决方案
核心问题
当前实现无法读取响应的根因如下:
print!宏默认使用行缓冲,未手动刷新的情况下DSR请求序列不会真正发送到终端- 终端默认处于规范模式,会缓存输入直到遇到换行符才返回给程序,且默认开启输入回显,DSR响应属于无换行的控制序列,自然无法被读取
- 读线程中冗余的
if buf != [0u8]判断可能拦截合法响应字节
修复实现
以下为符合要求的纯Rust实现,仅依赖标准库,可选择使用纯Rust系统调用库rustix替代libc实现完全无C依赖:
use std::sync::mpsc::{channel, Receiver, TryRecvError}; use std::{ io::{self, Read, Write}, panic, thread, time, }; use libc::{tcgetattr, tcsetattr, termios, ECHO, ICANON, TCSANOW, STDIN_FILENO}; fn main() { // 保存原有终端属性 let mut original_termios = std::mem::MaybeUninit::<termios>::uninit(); unsafe { tcgetattr(STDIN_FILENO, original_termios.as_mut_ptr()); } let original_termios = unsafe { original_termios.assume_init() }; // 切换终端为原始模式:关闭规范输入、关闭回显,让终端直接返回响应 let mut raw_termios = original_termios; unsafe { raw_termios.c_lflag &= !(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &raw_termios); } // 捕获panic确保终端属性被恢复 let run_result = panic::catch_unwind(|| { let timeout = time::Duration::from_millis(1); let rx = spawn_read(); // 发送请求并立刻刷新缓冲,确保请求到达终端 print!("\x1b[19t"); io::stdout().flush().unwrap(); let mut data = Vec::new(); // 最多等待100ms,足够接收终端响应 for _ in 0..100 { thread::sleep(timeout); match rx.try_recv() { Ok(value) => { data.push(value); // 收到响应终止符t直接提前退出 if value == b't' { break; } }, Err(TryRecvError::Empty) => {}, Err(TryRecvError::Disconnected) => break, } } data }); // 强制恢复原有终端属性,避免终端行为异常 unsafe { tcsetattr(STDIN_FILENO, TCSANOW, &original_termios); } let data = run_result.unwrap(); let string = match std::str::from_utf8(&data) { Ok(value) => value, Err(_) => "", }; println!("Captured: {:?}", string); } fn spawn_read() -> Receiver<u8> { let (tx, rx) = channel::<u8>(); thread::spawn(move || loop { let mut buf = [0u8]; if io::stdin().read_exact(&mut buf).is_ok() { tx.send(buf[0]).ok(); } else { break; } }); rx }
注意事项
- 该方案仅在真实tty终端环境下生效,管道、重定向、部分IDE内置终端、不支持DSR的远程终端场景下无法拿到响应
- Windows平台可通过调用Win32 API的
GetConsoleMode和SetConsoleMode关闭行输入、回显开关,逻辑和Unix平台完全一致 - 若需要完全无libc依赖,可使用纯Rust实现的系统调用库
rustix替换上述代码中的libc调用,无需修改核心逻辑
内容的提问来源于stack exchange,提问作者Brian Bruggeman
相关产品推荐
相关产品推荐

