Linux 为什么 getch() 在按下任意键之前返回?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7410447/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why getch() returns before press any key?
提问by new_perl
int main(int argc, char *argv[], char *env[])
{
printf("Press any key to exit.\n");
getch();
return 0;
}
According to the man page,
根据手册页,
getch
should wait until any key is pressed
getch
应该等到任何键被按下
...but in fact it returns directly before press any key. (The value returned is -1
).
...但实际上它在按任意键之前直接返回。(返回的值为-1
)。
Why?
为什么?
Update
更新
I'm on Linux. How can I implement Press any key to exit.
, if not using getch()
?
我在 Linux 上。Press any key to exit.
如果不使用,我该如何实现getch()
?
getchar()
will only return after press Enter, it's not what I want.
getchar()
只会在按 Enter 后返回,这不是我想要的。
回答by Keith Thompson
On Linux, getch()
is probably the curses
function, which is quite different from the Windows-specific function of the same name. curses
(ncurses
) is probably overkill for what you want to do.
在Linux上,getch()
大概是curses
函数,和Windows特有的同名函数有很大的不同。 curses
( ncurses
) 对于您想要做的事情来说可能有点矫枉过正。
The simplest approach would be to wait until the user presses Enter, which you can do like this:
最简单的方法是等到用户按下Enter,您可以这样做:
int c;
printf("Press <enter> to quit: ");
fflush(stdout);
while ((c = getchar()) != '\n' && c != EOF) {
/* nothing */
}
If you really want the user to be able to press anykey, not just Enter, you can do something like this:
如果您真的希望用户能够按任意键,而不仅仅是Enter,您可以执行以下操作:
system("stty cbreak -echo");
getchar();
system("stty cooked echo");
The second stty
is intended to restore the tty to reasonable settings (it should really restore them to whatever they were, but saving and restoring the state is a little more complicated). There are probably cleaner ways to do that (using whatever library functions the stty
program itself uses).
第二个stty
目的是将 tty 恢复到合理的设置(它应该真正将它们恢复到它们原来的样子,但是保存和恢复状态有点复杂)。可能有更简洁的方法来做到这一点(使用stty
程序本身使用的任何库函数)。
EDIT:Reading a single character without waiting for Enteris a frequently asked question. In fact, it's question 19.1 in the comp.lang.c FAQ.
编辑:无需等待即可读取单个字符Enter是一个常见问题。实际上,这是comp.lang.c FAQ 中的问题 19.1 。
EDIT2:I haven't done much work with curses recently, but I just did some playing around with it. It appears that getch()
won't work unless you first call initscr()
-- and initscr()
clears the screen. curses is intended for use with applications like text editors that need full control of the display. There may be a way to use getch()
without taking control of the screen, but I haven't found it.
EDIT2:我最近没有做过多少关于诅咒的工作,但我只是玩了一些。getch()
除非您先致电initscr()
并initscr()
清除屏幕,否则这似乎不起作用。curses 旨在与需要完全控制显示的应用程序一起使用,例如文本编辑器。可能有一种getch()
无需控制屏幕即可使用的方法,但我还没有找到。
The system("stty ...")
kludge might actually be the best approach.
将system("stty ...")
杂牌组装电脑实际上可能是最好的办法。
EDIT3:The termios
solution in the other answer is probably the best (system("stty ...")
is simpler, but invoking an external program feels like overkill.
EDIT3:termios
另一个答案中的解决方案可能是最好的(system("stty ...")
更简单,但调用外部程序感觉有点矫枉过正。
As for the OP's comment "I can't believe Press any key to exit.
is so troublesome to do in c", yes, that does seem odd -- but on further thought there are valid reasons for it.
至于 OP 的评论“我不敢相信Press any key to exit.
在 c 中做这么麻烦”,是的,这确实看起来很奇怪——但进一步思考有充分的理由。
Take a look at the programs installed on a typical Unix or Linux system. I think you'll find that very few of them require this kind of input (waiting for a single keypress).
查看安装在典型 Unix 或 Linux 系统上的程序。我想你会发现他们中很少有人需要这种输入(等待一个按键)。
A lot of programs work with command line arguments and data read from files or from stdin
. Anything the user types is input data, not commands or responses to prompts.
许多程序使用命令行参数和从文件或stdin
. 用户键入的任何内容都是输入数据,而不是命令或对提示的响应。
Some programs do ask for confirmation for some actions (installers like apt-get
and cpan
often do this) -- but they usually read a lineof input and check the first character. Or, for some drastic actions, they might require you to type the whole word "yes" followed by Enter(you don't want to reformat your hard drive because you accidentally hit a key).
有些程序确实要求对某些操作进行确认(安装程序喜欢apt-get
并cpan
经常这样做)——但它们通常会读取一行输入并检查第一个字符。或者,对于某些激烈的操作,它们可能会要求您键入整个单词“是”,然后键入Enter(您不想因为不小心敲击键而重新格式化硬盘驱动器)。
Of course a lot of programs (text editors, file viewers) read single-character non-echoing input, but such programs tend to be curses-based; they take control of the entire terminal window.
当然,很多程序(文本编辑器、文件查看器)读取单字符非回显输入,但此类程序往往是基于curses 的;他们控制整个终端窗口。
Finally, a number of programs have GUI interfaces (web browsers, etc.); they probably don't even read from stdin.
最后,许多程序具有 GUI 界面(网络浏览器等);他们可能甚至不从标准输入读取。
Most production Unix programs don't use or need Press any key to exit
prompts. They just do their jobs, often silently, and then terminate so you can do the next thing. The need exists largely for relatively elementary programs, such as homework assignments. Not that there's anything wrong with homework assignments, but the system as a whole isn't primarily designed to support such usage.
大多数生产 Unix 程序不使用或不需要Press any key to exit
提示。他们只是默默地做他们的工作,然后终止,这样你就可以做下一件事情。这种需求主要存在于相对初级的程序中,例如家庭作业。并不是说家庭作业有什么问题,而是整个系统的主要设计目的并不是支持这种用法。
回答by luser droog
Here's a minimal example
这是一个最小的例子
#include <curses.h>
int main(){
initscr();
cbreak();
noecho();
printw("Press any key to continue.");
refresh();
getch();
endwin();
return 0;
}
But there doesn't seem to be any way to use ncurses without clearing the screen. The Stain of Overkill, perhaps?!
但是似乎没有任何方法可以在不清除屏幕的情况下使用 ncurses。也许是矫枉过正的污点?!
Edit
编辑
Here's another way I got working. This does not use curses, nor does it clear the screen.
这是我开始工作的另一种方式。这不会使用诅咒,也不会清除屏幕。
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
int main() {
struct termios old,new;
tcgetattr(fileno(stdin),&old);
tcgetattr(fileno(stdin),&new);
cfmakeraw(&new);
tcsetattr(fileno(stdin),TCSANOW,&new);
fputs("Press any key to continue.",stdout);
fflush(NULL);
fgetc(stdin);
tcsetattr(fileno(stdin),TCSANOW,&old);
return 0;
}
The manpage says cfmakeraw() might not be fully portable. But it's just a shorthand for setting a whole mess of flags:
联机帮助页说 cfmakeraw() 可能不是完全可移植的。但这只是设置一堆标志的简写:
Raw mode
cfmakeraw() sets the terminal to something like the "raw" mode of the old Version 7 terminal
driver: input is available character by character, echoing is disabled, and all special pro-
cessing of terminal input and output characters is disabled. The terminal attributes are set
as follows:
termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
termios_p->c_cflag &= ~(CSIZE | PARENB);
termios_p->c_cflag |= CS8;