如何让 `cin` 读取原始模式终端
How to get `cin` to read a raw mode terminal
为什么标准流可以在规范模式下从终端接收输入,但是你把它放在原始模式下,突然这种方法就不再有效了?我很了解 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
将按预期工作。但是如果发生超时,stream buffer会进入undefined状态,sbumpc
永远return EOF
.
状态与流相关联,而不是流缓冲区,因此调用 std::cin.clear()
会清除状态标志,但不会更正流缓冲区中的潜在问题,流缓冲区仍处于损坏状态。
可能有一个重置搜索位置的解决方案,但同样,给定的标准流是实现定义的,不知道它们可能拥有什么内部状态,或者如果在一个平台上成功,如果它在另一个平台。据我所知,没有涵盖这种情况的文档。
两种可能的解决方案是直接使用 POSIX API 并喜欢它,或者编写您自己的使用 POSIX API 的流实现。
为什么标准流可以在规范模式下从终端接收输入,但是你把它放在原始模式下,突然这种方法就不再有效了?我很了解 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
将按预期工作。但是如果发生超时,stream buffer会进入undefined状态,sbumpc
永远return EOF
.
状态与流相关联,而不是流缓冲区,因此调用 std::cin.clear()
会清除状态标志,但不会更正流缓冲区中的潜在问题,流缓冲区仍处于损坏状态。
可能有一个重置搜索位置的解决方案,但同样,给定的标准流是实现定义的,不知道它们可能拥有什么内部状态,或者如果在一个平台上成功,如果它在另一个平台。据我所知,没有涵盖这种情况的文档。
两种可能的解决方案是直接使用 POSIX API 并喜欢它,或者编写您自己的使用 POSIX API 的流实现。