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

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


当前回答

在WINDOWS上我这样做:

#include <Windows.h>
int main()
{
    system("PAUSE>NUL");
    if (GetKeyState(0x41/*(the 'A' key, choosen e.g.)*/) & (0xff80/*That stands for "Default state / Key Down"*/)) {
        //whatever I want to do after 'A' is pressed
    }
}

这里可以找到一个键的列表,每个键都有自己的十六进制值: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes

其他回答

以下是一个从Expert C Programming: Deep Secrets中提取的解决方案,它应该可以在SVr4上工作。它使用stty和ioctl。

#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");
}

假设是Windows,看一下ReadConsoleInput函数。

如果你在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

老实说,这是从一些旧的代码,我有,所以你必须拨弄它一点。

最酷的是它读取输入时没有任何提示,所以字符根本不会显示出来。

这在纯c++中以可移植的方式是不可能的,因为它太依赖于可能与stdin连接的终端(它们通常是行缓冲的)。不过,你可以使用一个库来实现:

conio available with Windows compilers. Use the _getch() function to give you a character without waiting for the Enter key. I'm not a frequent Windows developer, but I've seen my classmates just include <conio.h> and use it. See conio.h at Wikipedia. It lists getch(), which is declared deprecated in Visual C++. curses available for Linux. Compatible curses implementations are available for Windows too. It has also a getch() function. (try man getch to view its manpage). See Curses at Wikipedia.

如果你的目标是跨平台兼容性,我建议你使用curses。也就是说,我相信有一些函数可以用来关闭行缓冲(我相信这被称为“原始模式”,而不是“熟模式”-看看man stty)。如果我没记错的话,诅咒可以方便地帮你解决这个问题。

下面是一个不向系统提供外壳的版本(在macOS 10.14上编写和测试)

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

char* getStr( char* buffer , int maxRead ) {
  int  numRead  = 0;
  char ch;

  struct termios old = {0};
  struct termios new = {0};
  if( tcgetattr( 0 , &old ) < 0 )        perror( "tcgetattr() old settings" );
  if( tcgetattr( 0 , &new ) < 0 )        perror( "tcgetaart() new settings" );
  cfmakeraw( &new );
  if( tcsetattr( 0 , TCSADRAIN , &new ) < 0 ) perror( "tcssetattr makeraw new" );

  for( int i = 0 ; i < maxRead ; i++)  {
    ch = getchar();
    switch( ch )  {
      case EOF: 
      case '\n':
      case '\r':
        goto exit_getStr;
        break;

      default:
        printf( "%1c" , ch );
        buffer[ numRead++ ] = ch;
        if( numRead >= maxRead )  {
          goto exit_getStr;
        }
        break;
    }
  }

exit_getStr:
  if( tcsetattr( 0 , TCSADRAIN , &old) < 0)   perror ("tcsetattr reset to old" );
  printf( "\n" );   
  return buffer;
}


int main( void ) 
{
  const int maxChars = 20;
  char      stringBuffer[ maxChars+1 ];
  memset(   stringBuffer , 0 , maxChars+1 ); // initialize to 0

  printf( "enter a string: ");
  getStr( stringBuffer , maxChars );
  printf( "you entered: [%s]\n" , stringBuffer );
}