所以我正在考虑如何在 C 中捕获键盘活动。众所周知,我们可以输入一些内容并按 Enter 以将我们想要发送到计算机的任何内容流式传输。但第一个问题是,如何输入一些不可输入的字符,如向上箭头、向下箭头(尤其是这两个家伙,因为我使用的是 Linux,但想将它们用于默认含义以外的其他用途)、shift、ctrl 或其他。其次,如何让程序在我们按下任意键后立即运行,这样我们就不需要一直输入和输入。(就像 Windows 中的“按任意键继续”)。
4 回答
有两种方法。
使用stty
命令。
- 您可以
system ("/bin/stty raw");
在使用前添加getchar()
- 更多详情,请
man stty
。
在这里使用termios.h
- 你应该像这样改变你的 tty 的模式
newt.c_lflag &= ~(ICANON | ECHO);
- 更多详情,请
man termios.h
在 DOS 时代,有一个kbhit()
功能。如果您需要该功能,可以查看此线程:kbhit() for linux。
我隐约记得尝试了用户 Thantos 的功能,并且效果很好。
我建议您先阅读tcgetattr()
和tcsetattr()
功能。
如果您使用的是 Linux,则键盘输入的最佳选择是 GNU readline库。
这提供了所有开箱即用的功能,包括 emacs 和 vi 编辑模式(如果需要)。
/* A static variable for holding the line. */
static char *line_read = (char *)NULL;
/* Read a string, and return a pointer to it. Returns NULL on EOF. */
char *
rl_gets ()
{
/* If the buffer has already been allocated, return the memory to the free pool. */
if (line_read)
{
free (line_read);
line_read = (char *)NULL;
}
/* Get a line from the user. */
line_read = readline ("");
/* If the line has any text in it, save it on the history. */
if (line_read && *line_read)
add_history (line_read);
return (line_read);
}
麻省理工学院有一些很棒的教程。
“通用”方法是getchar()。Getchar()" 使用“缓冲输入”:在用户按下“Enter”之前,您实际上不会获得任何输出。除非您使用命令提示符(或等效项),否则它实际上并不适用。
旧的 DOS 方式是来自“conio.h”的 getch() 和 getche()。该方法在针对现代操作系统的现代 C/C++ 库中不存在。
建议:
如果您想创建文本模式 UI(尤其是在 Linux 上),请查看 ncurses:
如果您想编写游戏(在 Windows 或 Linux 上),请查看 SDL:
=== 附录 ===
我仍然推荐一个库......但这里有一个函数说明了 Linux 下的“原始键盘输入”(又名“未煮过的”或“非规范”输入):
http://cboard.cprogramming.com/c-programming/63166-kbhit-linux.html
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
void changemode(int);
int kbhit(void);
int
main(int argc, char *argv[])
{
int ch;
changemode(1);
while ( !kbhit() )
{
putchar('.');
}
ch = getchar();
printf("\nGot %c\n", ch);
changemode(0);
return 0;
}
void
changemode(int dir)
{
static struct termios oldt, newt;
if ( dir == 1 )
{
tcgetattr( STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt);
}
else
tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
}
int
kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}