我从来都不记得我是怎么做到的,因为它很少出现在我身上。但是在C或c++中,从标准输入中读取字符而不等待换行符(按enter)的最佳方法是什么?

理想情况下,它也不会将输入字符回显到屏幕上。我只是想在不影响控制台屏幕的情况下捕捉击键。


当前回答

我在另一个论坛上发现了这个,当时我想解决同样的问题。根据我的发现,我做了一些修改。效果很好。我运行的是OS X,所以如果你运行的是微软,你需要找到正确的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; 
}

其他回答

我使用kbhit()来查看是否存在一个字符,然后使用getchar()来读取数据。 在windows上,您可以使用“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;
}

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

or

conio.h的Linux c++实现 http://sourceforge.net/projects/linux-conioh

C和c++对I/O有一个非常抽象的看法,没有标准的方法来做你想做的事情。有从标准输入流中获取字符的标准方法(如果有的话),这两种语言都没有定义其他任何方法。因此,任何答案都必须是特定于平台的,可能不仅取决于操作系统,还取决于软件框架。

这里有一些合理的猜测,但如果不知道目标环境是什么,就无法回答您的问题。

ssinfod对Linux的回答的变体,对我的口味来说稍微干净一些,为wcout和wchar_t实现,并在没有错误的情况下擦除无效字符。

#include <functional>

//For Linux kbhit(). For Windows, use conio.h.
#ifdef __unix__
  #include <sys/ioctl.h> //For FIONREAD.
  #include <termios.h>

  //Call this at program start to setup for kbhit.
  void initTerminalInput()
  {
    //Disable internal buffering.
    std::wcout << std::unitbuf;

    //Turn off line buffering.
    struct termios term;
    tcgetattr(0, &term);
    term.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &term);
    setbuf(stdin, NULL);
  }

  //Returns 0 if there's no input character to read.
  int kbhit()
  {
    static int nbbytes;
    ioctl(0, FIONREAD, &nbbytes);
    return nbbytes;
  }
#endif

//Waits for and retrieves a single validated character, calling a validation function on each character entered and
//erasing any that are invalid (when the validation function returns false).
static wchar_t getWChar(std::function<bool(wchar_t)> validationFunction)
{
  static wchar_t inputWChar;
  do
  {
    //Wait until there's an input character.
    while (!kbhit())
    {
    }
    inputWChar = getwchar();
    //Validate the input character.
    if (validationFunction(inputWChar))
    {
      //Valid.
      break;
    }
    else
    {
      //Erase the invalid character.
      std::wcout << L"\b \b";
    }
  } while (true);
  return inputWChar;
}

在下面的例子中,我想让用户输入1、2或3。输入的任何其他字符都不会显示,它将等待,直到按下其中一个有效字符:

int main()
{
  #ifdef __unix__
    initTerminalInput();
  #endif

  getWChar([] (wchar_t inputWChar)
  {
    return (inputWChar >= L'1' && inputWChar <= L'3');
  });

  return 0;
}

You can do it portably using SDL (the Simple DirectMedia Library), though I suspect you may not like its behavior. When I tried it, I had to have SDL create a new video window (even though I didn't need it for my program) and have this window "grab" almost all keyboard and mouse input (which was okay for my usage but could be annoying or unworkable in other situations). I suspect it's overkill and not worth it unless complete portability is a must--otherwise try one of the other suggested solutions.

顺便说一下,这将分别提供按键和释放事件,如果你喜欢的话。