4

我有一个聊天客户端,它以原始终端模式接收输入,但我不知道在这种模式下处理输入。我需要知道两件事:

  • 如何逐个字符地读取输入并显示它?我是否必须有某种读取循环,一次读取一个字符并将其存储在缓冲区中?
  • 如果我希望我的服务器处理新行条目的输入,我是否必须在每个字符进入我的缓冲区时扫描它并查找\n

此外,一个示例的逐字符读取循环刷新\n将非常棒。谢谢!

4

2 回答 2

6

在 Windows 中有一个非常有用的函数 kbhit() 但不幸的是在 linux 中没有。为此可以有多种方法。我们将为 linux 创建自己的 kbhit() 方法。当在输入缓冲区中检测到某些东西时,kbhit() 将返回非零值,否则它将返回 0 并继续。简而言之,它是非阻塞的。只要结果为真,则调用 getch() 方法来获取该按下的键。

#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(void)
{
  int ch;
  changemode(1);
  while ( !kbhit() );      // Waiting for some keyboard input.

  // something has been detected. now get that.
  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-10-29T21:07:18.777 回答
5

我为此推荐GNU readline 库。它负责获取输入行的繁琐工作,并允许用户使用退格键、左右箭头等编辑行,并使用向上箭头调用旧命令,甚至使用 ^R 搜索旧命令,等。Readline 安装了典型的类 unix 发行版,如 linux,但如果你没有它,你可以在这里找到它

编辑:这是一个最小的 readline 示例:

#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>

int main(int argc, char ** argv)
{
    while(1)
    {
        char * line = readline("> ");
        if(!line) break;
        if(*line) add_history(line);
        /* Do something with the line here */
    }
}

使用 gcc -o test test.c -lreadline -lncurses 编译。

如果您不能使用 readline,getline 是一种替代方法:

#include <stdio.h>
int main()
{
    char * line = NULL;
    size_t len;
    while(getline(&line, &len, stdin) >= 0)
       printf("I got: %s", line);
}

如果连 getline 都不可接受,您可以使用 fgets。它不会动态分配合适大小的缓冲区,所以太长的行会被截断。但至少它是标准C:

#include <stdio.h>
int main()
{
    char buf[1000];
    while(fgets(buf, sizeof(buf), stdin)
        printf("I got: %s, line);      
}
于 2012-10-29T00:05:55.247 回答