2009-01-07 99 views
128

我永遠不會記得我是如何做到這一點的,因爲它對我來說很少出現。但在C或C++中,從標準輸入中讀取字符而不等待換行(按Enter)的最佳方式是什麼。從標準輸入捕獲字符而不等待輸入被按下

理想情況下,它不會將輸入字符回顯到屏幕。我只想捕獲擊出控制檯屏幕的擊鍵。

+1

你在Windows或不呢? – hasen 2009-01-08 00:55:46

+1

@adam - 你能否澄清一下:你是否想要一個函數,如果沒有可用的字符,它會立即返回,或者一直等待一個按鍵? – Roddy 2009-01-08 09:47:30

+1

@Roddy - 我想要一個總是等待一個按鍵的功能。 – Adam 2009-05-28 04:52:54

回答

80

這在純C++中是不可能移植的,因爲它太依賴於可能與stdin連接的終端(它們通常是線路緩衝)。但是,您可以使用以下庫:

  1. conio可用於Windows編譯器。使用功能_getch()爲您提供一個角色,而無需等待輸入密鑰。我不是一個頻繁的Windows開發人員,但我看到我的同學只包括conio.h並使用它。請參閱維基百科的conio.h。它列出了getch,它在Visual C++中聲明爲不贊成使用。
  2. curses可用於Linux,兼容curses實現也可用於Windows。它也有一個getch函數。 (嘗試man getch查看其聯機幫助頁)。請參閱維基百科的Curses

如果您的目標是跨平臺兼容性,我建議您使用curses。也就是說,我確定有一些函數可以用來關閉行緩衝(我相信這就是所謂的「原始模式」,而不是「熟化模式」(查看man stty))。如果我沒有弄錯,詛咒會以便攜方式爲你處理。

+6

請注意,現在`ncurses`是'curses`的推薦變種。 – 2016-05-07 03:04:01

+0

如果你確實需要一個圖書館,那他們是怎麼做到的?爲了使圖書館你一定要編程它,這意味着任何人都可以編程,所以爲什麼我們不能編程我們自己需要的庫代碼?這也將使**這不可能在純粹的C + +錯誤 – NathanProgrammer 2017-01-03 09:49:00

+0

@ kid8我不明白 – 2017-01-03 16:51:24

5

假設Windows,看看ReadConsoleInput函數。

3

C和C++採用非常抽象的I/O視圖,並且沒有標準的做你想做的方式。有標準的方法可以從標準輸入流中獲取字符,如果有任何可以獲得的字符,其他任何語言都不會定義其他字符。因此,任何答案都必須是平臺特定的,可能不僅取決於操作系統,還取決於軟件框架。

這裏有一些合理的猜測,但沒有辦法在不知道目標環境是什麼的情況下回答你的問題。

15

CONIO.H

您需要的功能是:

int getch(); 
Prototype 
    int _getch(void); 
Description 
    _getch obtains a character from stdin. Input is unbuffered, and this 
    routine will return as soon as a character is available without 
    waiting for a carriage return. The character is not echoed to stdout. 
    _getch bypasses the normal buffering done by getchar and getc. ungetc 
    cannot be used with _getch. 
Synonym 
    Function: getch 


int kbhit(); 
Description 
    Checks if a keyboard key has been pressed but not yet read. 
Return Value 
    Returns a non-zero value if a key was pressed. Otherwise, returns 0. 

libconio http://sourceforge.net/projects/libconio

Linux下C++實現CONIO.H的 http://sourceforge.net/projects/linux-conioh

4

與便攜式設備最接近的是使用ncurses庫將終端設置爲「cbreak模式」。API是巨大的;你最想要的程序是

  • initscrendwin
  • cbreaknocbreak
  • getch

祝你好運!

7

如果您使用的是Windows,你可以使用PeekConsoleInput來檢測是否有任何輸入,

HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); 
DWORD events; 
INPUT_RECORD buffer; 
PeekConsoleInput(handle, &buffer, 1, &events); 

然後使用ReadConsoleInput「消費」輸入字符..

PeekConsoleInput(handle, &buffer, 1, &events); 
if(events > 0) 
{ 
    ReadConsoleInput(handle, &buffer, 1, &events); 
    return buffer.Event.KeyEvent.wVirtualKeyCode; 
} 
else return 0 

說實話這是來自我的一些舊代碼,所以你必須用它來擺弄一下。

雖然很酷的事情是它讀取輸入時沒有提示任何內容,所以字符根本不顯示。

4

以下是從提取的解決方案專家C編程:深度祕密,它應該在SVr4上工作。它使用sttyioctl

#include <sys/filio.h> 
int kbhit() 
{ 
int i; 
ioctl(0, FIONREAD, &i); 
return i; /* return a count of chars available to read */ 
} 
main() 
{ 
int i = 0; 
intc=''; 
system("stty raw -echo"); 
printf("enter 'q' to quit \n"); 
for (;c!='q';i++) { 
    if (kbhit()) { 
     c=getchar(); 
     printf("\n got %c, on iteration %d",c, i); 
    } 
} 
system("stty cooked echo"); 
} 
13

我發現這在另一個論壇上,同時尋找解決同樣的問題。我從我發現的內容中修改了一下。它效果很好。我正在運行OS X,因此如果您運行的是Microsoft,則需要找到正確的system()命令切換到raw和cooked模式。

#include <iostream> 
#include <stdio.h> 
using namespace std; 

int main() { 
    // Output prompt 
    cout << "Press any key to continue..." << endl; 

    // Set terminal to raw mode 
    system("stty raw"); 

    // Wait for single character 
    char input = getchar(); 

    // Echo input: 
    cout << "--" << input << "--"; 

    // Reset terminal to normal "cooked" mode 
    system("stty cooked"); 

    // And we're out of here 
    return 0; 
} 
71

在Linux(和其他類Unix系統),這可以在下列方式進行:

#include <unistd.h> 
#include <termios.h> 

char getch() { 
     char buf = 0; 
     struct termios old = {0}; 
     if (tcgetattr(0, &old) < 0) 
       perror("tcsetattr()"); 
     old.c_lflag &= ~ICANON; 
     old.c_lflag &= ~ECHO; 
     old.c_cc[VMIN] = 1; 
     old.c_cc[VTIME] = 0; 
     if (tcsetattr(0, TCSANOW, &old) < 0) 
       perror("tcsetattr ICANON"); 
     if (read(0, &buf, 1) < 0) 
       perror ("read()"); 
     old.c_lflag |= ICANON; 
     old.c_lflag |= ECHO; 
     if (tcsetattr(0, TCSADRAIN, &old) < 0) 
       perror ("tcsetattr ~ICANON"); 
     return (buf); 
} 

基本上你必須關閉典型模式(和回聲模式,以抑制呼應)。

8
#include <conio.h> 

if (kbhit() != 0) { 
    cout << getch() << endl; 
} 

這使用kbhit()檢查是否被按下了鍵盤,並使用getch()來獲取被按下的字符。

1

您可以使用SDL(Simple DirectMedia Library)輕鬆轉換,儘管我懷疑您可能不喜歡它的行爲。當我嘗試它時,我不得不讓SDL創建一個新的視頻窗口(儘管我不需要它用於我的程序),並讓此窗口「抓住」幾乎所有的鍵盤和鼠標輸入(這對我的使用來說是可以的,但可以在其他情況下令人討厭或不可行)。我懷疑它是過度的,不值得這樣做,除非完全的可移植性是必須的 - 否則嘗試其他建議的解決方案之一。

順便說一句,如果你喜歡這樣,這將分別爲你提供按鍵和發佈事件。

2

我一直想要一個循環來讀取我的輸入,而不按回車鍵。 這爲我工作。

#include<stdio.h> 
main() 
{ 
    char ch; 
    system("stty raw");//seting the terminal in raw mode 
    while(1) 
    { 
    ch=getchar(); 
     if(ch=='~'){   //terminate or come out of raw mode on "~" pressed 
     system("stty cooked"); 
    //while(1);//you may still run the code 
    exit(0); //or terminate 
    } 
     printf("you pressed %c\n ",ch); //write rest code here 
     } 

    } 
2

爲我工作在Windows上:

#include <conio.h> 
char c = _getch(); 
2

我用的kbhit(),看是否有燒焦存在,然後的getchar()讀取數據。 在窗口上,您可以使用「conio.h」。在Linux上,你將不得不實現你自己的kbhit()。

見下面的代碼:

// kbhit 
#include <stdio.h> 
#include <sys/ioctl.h> // For FIONREAD 
#include <termios.h> 
#include <stdbool.h> 

int kbhit(void) { 
    static bool initflag = false; 
    static const int STDIN = 0; 

    if (!initflag) { 
     // Use termios to turn off line buffering 
     struct termios term; 
     tcgetattr(STDIN, &term); 
     term.c_lflag &= ~ICANON; 
     tcsetattr(STDIN, TCSANOW, &term); 
     setbuf(stdin, NULL); 
     initflag = true; 
    } 

    int nbbytes; 
    ioctl(STDIN, FIONREAD, &nbbytes); // 0 is STDIN 
    return nbbytes; 
} 

// main 
#include <unistd.h> 

int main(int argc, char** argv) { 
    char c; 
    //setbuf(stdout, NULL); // Optional: No buffering. 
    //setbuf(stdin, NULL); // Optional: No buffering. 
    printf("Press key"); 
    while (!kbhit()) { 
     printf("."); 
     fflush(stdout); 
     sleep(1); 
    } 
    c = getchar(); 
    printf("\nChar received:%c\n", c); 
    printf("Done.\n"); 

    return 0; 
}