1

所以我正在考虑如何在 C 中捕获键盘活动。众所周知,我们可以输入一些内容并按 Enter 以将我们想要发送到计算机的任何内容流式传输。但第一个问题是,如何输入一些不可输入的字符,如向上箭头、向下箭头(尤其是这两个家伙,因为我使用的是 Linux,但想将它们用于默认含义以外的其他用途)、shift、ctrl 或其他。其次,如何让程序在我们按下任意键后立即运行,这样我们就不需要一直输入和输入。(就像 Windows 中的“按任意键继续”)。

4

4 回答 4

2

有两种方法。

使用stty命令。

  • 您可以system ("/bin/stty raw");在使用前添加getchar()
  • 更多详情,请man stty

在这里使用termios.h

  • 你应该像这样改变你的 tty 的模式newt.c_lflag &= ~(ICANON | ECHO);
  • 更多详情,请man termios.h
于 2012-06-26T01:24:13.267 回答
1

在 DOS 时代,有一个kbhit()功能。如果您需要该功能,可以查看此线程:kbhit() for linux

我隐约记得尝试了用户 Thantos 的功能,并且效果很好。

我建议您先阅读tcgetattr()tcsetattr()功能。

于 2012-06-26T09:02:51.753 回答
0

如果您使用的是 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);
}

麻省理工学院有一些很棒的教程。

于 2012-06-26T01:13:31.807 回答
0

“通用”方法是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);

}
于 2012-06-26T01:06:01.820 回答