我从来都不记得我是怎么做到的,因为它很少出现在我身上。但是在C或c++中,从标准输入中读取字符而不等待换行符(按enter)的最佳方法是什么?
理想情况下,它也不会将输入字符回显到屏幕上。我只是想在不影响控制台屏幕的情况下捕捉击键。
我从来都不记得我是怎么做到的,因为它很少出现在我身上。但是在C或c++中,从标准输入中读取字符而不等待换行符(按enter)的最佳方法是什么?
理想情况下,它也不会将输入字符回显到屏幕上。我只是想在不影响控制台屏幕的情况下捕捉击键。
当前回答
下面是一个不向系统提供外壳的版本(在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 );
}
其他回答
C和c++对I/O有一个非常抽象的看法,没有标准的方法来做你想做的事情。有从标准输入流中获取字符的标准方法(如果有的话),这两种语言都没有定义其他任何方法。因此,任何答案都必须是特定于平台的,可能不仅取决于操作系统,还取决于软件框架。
这里有一些合理的猜测,但如果不知道目标环境是什么,就无法回答您的问题。
我在另一个论坛上发现了这个,当时我想解决同样的问题。根据我的发现,我做了一些修改。效果很好。我运行的是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;
}
如果你在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
老实说,这是从一些旧的代码,我有,所以你必须拨弄它一点。
最酷的是它读取输入时没有任何提示,所以字符根本不会显示出来。
在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
下面是一个不向系统提供外壳的版本(在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 );
}