如何在 unix 控制台应用程序中捕获单次击键而不会阻塞?

How can I capture single keystrokes in a unix console app without blocking?

提问人:Graeme Perrow 提问时间:10/9/2008 更新时间:10/18/2008 访问量:1668

问:

我有一个非常简单的 TCP 服务器,用 C 编写。它无限期地运行,等待连接。在 Windows 上,我用于检查套接字上的活动,如果没有,我有以下代码允许我通过点击键盘上的“q”退出:select

if( kbhit() ) {
   char c = getch();
   if( c == 'q' ) break;
}

这在 unix 上不起作用,因为不存在并且工作方式不同。我找到了一些示例代码,用于更改终端设置并允许逐个字符输入。调用 init 函数后,我打开 /dev/stdin (with ) 并读取一个字符,但直到命中一个字符为止。kbhitgetchtcsetattrO_NONBLOCKread( f, &c, 1 )

我想我可以生成一个单独的线程并让它无限期地等待,然后在用户点击“q”时向第一个线程发出信号,但这似乎有点严厉。肯定有更简单的方法吗?

C UNIX 输入 终端

评论


答:

5赞 Lou Franco 10/9/2008 #1

将 stdin 添加到选择句柄列表中,如果它有数据,请调用 read 从中读取一个字符。

评论

0赞 Graeme Perrow 10/9/2008
即使我的应用尚未使用 select,这也将起作用。事实上,我正在使用 select 已经使它变得非常容易,而且它就像一个魅力。谢谢
1赞 user3458 10/9/2008 #2

相反,从你的

read( f, &c, 1 )

选择呼叫。当 f 准备好读取时,一个字符已被按下,read() 不会阻塞。

1赞 mpez0 10/18/2008 #3

在 Unix 中,无论是在系统控制台上还是在 X 终端窗口中,键盘 I/O 都通过虚拟终端。如今,设备 /dev/tty 是访问进程控制终端的常用方式。除了打开/关闭/读/写之外,设备操作都是由该特定设备的 ioctl(2) 系统调用处理的。你想做什么的一般想法是

打开控制终端(可能是也可能不是标准)

将该终端上的操作模式更改为返回,而无需等待整行输入(这是正常的默认值)

继续执行程序的其余部分,知道从该终端(可能是 stdin)读取可能会返回部分行甚至零个字符,而不会出现错误或终止条件。


有关如何执行第二步的详细答案,请参见 C 编程常见问题解答。他们还指出,这是一个操作系统问题,而不是语言问题。它们提供了九种可能性,但与这个问题相关的三种主要可能性是

  1. 使用 curses(3) 库
  2. 旧的 BSD 风格系统,使用 sgttyb 设置 CBREAK 或 RAW
  3. Posix 或旧的 System V 样式系统,使用 TCGETAW/TCSETAW 将 c_cc[VMIN] 设置为 1,将 c_cc[VTIME] 设置为 0。

遵循 C FAQ 中的几个引用可能会导致此 kbhit 代码片段页面