如何让"cin"读取原始模式终端



为什么标准流可以在规范模式下从终端接收输入,但您将其置于原始模式,突然此方法不再有效?我很清楚POSIX串行编程,通常您使用read。我正在尝试更好地理解标准流。

#include <termios.h>
#include <unistd.h>
#include <iostream>
termios original;
void enableRawMode() {
tcgetattr(STDIN_FILENO, &original);
termios raw = original;
cfmakeraw(&raw);
raw.c_cc[VMIN] = 0;
raw.c_cc[VTIME] = 1;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
int main() {
enableRawMode();
char c;
// This works as expected.
//int nread;
//while ((nread = read(STDIN_FILENO, &c, 1)) != 1) {
//  if (nread == -1 && errno != EAGAIN) {
//    break;
//  }
//}
// This loops forever, the failbit is always true, gcount is always 0.
while (!(std::cin.get(c))) {
if (std::cin.bad() || std::cin.eof()) {
break;
}
std::cin.clear();
}
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original);
}

经过大量讨论和一些调查,我发现这是对给定标准流实现的限制。基本上,我已经推断出当您的终端处于烘焙模式时,标准流可以正常工作,但如果处于原始模式,则不可靠。

代码可以简化为使用std::cin.rdbuf()->sbumpc(),在这种情况下,它将调用uflow,这可能会调用underflow,这将从底层设备获取数据。与标准流关联的流缓冲区是实现定义的。

sbumpc的第一次调用,更具体地说,最终underflow将在从标准输入读取时启动与VTIME关联的计时器。如果在超时内收到输入,cin将按预期工作。但如果发生超时,流缓冲区将进入未定义状态,sbumpc将永远返回EOF

状态与流相关联,而不是与流缓冲区相关联,因此调用std::cin.clear()会清除状态标志,但不会更正流缓冲区中的基础问题,该问题仍然已损坏。

重置搜索位置可能有解决方案,但同样,给定的标准流是实现定义的,并且不知道它们可能拥有什么内部状态,或者如果在一个平台上成功,如果在另一个平台上成功。据我所知,该文档不存在涵盖这种情况。

两种可能的解决方案是直接使用 POSIX API 并喜欢它,或者编写自己的使用 POSIX API 的流实现。

最新更新