2014-10-12 27 views
15

我想運行一個可執行文件阻止stdin,並且當按下一個鍵時立即打印相同的字符而不需要輸入必須被按下。如何從標準輸入讀取一個字符而無需點擊回車?

如何從標準輸入讀取一個字符而不必擊中輸入?我開始與這個例子:

fn main() { 
    println!("Type something!"); 

    let mut line = String::new(); 
    let input = std::io::stdin().read_line(&mut line).expect("Failed to read line"); 

    println!("{}", input); 
} 

我看着通過API,並試圖bytes()更換read_line(),但一切我儘量要求我打發生讀取前,輸入

這個問題被問了C/C++,但似乎這樣做的標準方式:Capture characters from standard input without waiting for enter to be pressed

它可能不是拉斯特可行考慮它不是在C/C++簡單。

+3

這是一個平臺問題,而不是語言問題。在Windows上有字符輸入功能,但在Unix/Linux上,你必須使終端不在線緩衝模式。 – 2014-10-12 03:42:44

+0

您可以使用所提到的SO鏈接中的'getch'功能。你只需要將它編譯成一個共享對象,並從Rust中使用它:https://gist.github.com/ihrwein/a4558d63d9250ee0bbf6你需要一個C編譯器,它只能在Linux上工作(至少我在那裏測試過) 。 – 2016-01-05 19:50:16

回答

10

使用現在可用的'ncurses'庫之一,例如this之一。

添加依賴於貨物

[dependencies] 
ncurses = "5.86.0" 

,包括在main.rs:

extern crate ncurses; 
use ncurses::*; // watch for globs 

按照實例庫中的初始化ncurses的,等待這樣的單字符輸入:

initscr(); 
/* Print to the back buffer. */ 
printw("Hello, world!"); 

/* Update the screen. */ 
refresh(); 

/* Wait for a key press. */ 
getch(); 

/* Terminate ncurses. */ 
endwin(); 
+0

這個工作,但它似乎不可能避免清除由'initscr()'強制執行的屏幕[討論] [這裏](http://stackoverflow.com/questions/4772061/curses-library-c-getch-沒有清除屏幕)和[那裏](http://stackoverflow.com/questions/654471/ncurses-initialization-without-clearing-the-screen)。 – dojuba 2016-05-24 10:03:27

9

雖然@ Jon使用ncurses的解決方案有效,但ncurses按設計清除了屏幕。我想出了這個解決方案,它使用termios crate作爲我的小項目來學習Rust。這個想法是通過termios綁定訪問tcsetattr修改ECHOICANON標誌。的讀取單個字節

extern crate termios; 
use std::io; 
use std::io::Read; 
use std::io::Write; 
use termios::{Termios, TCSANOW, ECHO, ICANON, tcsetattr}; 

fn main() { 
    let stdin = 0; // couldn't get std::os::unix::io::FromRawFd to work 
        // on /dev/stdin or /dev/tty 
    let termios = Termios::from_fd(stdin).unwrap(); 
    let mut new_termios = termios.clone(); // make a mutable copy of termios 
              // that we will modify 
    new_termios.c_lflag &= !(ICANON | ECHO); // no echo and canonical mode 
    tcsetattr(stdin, TCSANOW, &mut new_termios).unwrap(); 
    let stdout = io::stdout(); 
    let mut reader = io::stdin(); 
    let mut buffer = [0;1]; // read exactly one byte 
    print!("Hit a key! "); 
    stdout.lock().flush().unwrap(); 
    reader.read_exact(&mut buffer).unwrap(); 
    println!("You have hit: {:?}", buffer); 
    tcsetattr(stdin, TCSANOW, & termios).unwrap(); // reset the stdin to 
                // original termios data 
} 

一個優點是捕獲箭頭鍵,CTRL等擴展F鍵不捕獲(雖然可以ncurses的捕捉這些)。

此解決方案適用於類UNIX平臺。我沒有使用Windows的經驗,但根據此forum,在Windows中使用SetConsoleMode也許可以實現類似的功能。

相關問題