我正在编写VT100终端引擎,但是输入处理有些棘手。 首先,我不回显地初始化tty。
static void init_tty() {
if (tcgetattr(STDIN_FILENO, &ctty) != 0)
throw std::runtime_error("can not get tty attribute");
ctty.c_lflag &= ~(FLAG(ICANON) | FLAG(ECHO) | FLAG(ISIG));
if (tcsetattr(STDIN_FILENO, TCSANOW, &ctty) != 0)
throw std::runtime_error("can not set tty attribute");
}
接下来,我初始化一个非阻塞键盘文件描述符。
static void init_keyboard(const char *device) {
if ((kfd = open(device, FLAG(O_RDONLY) | FLAG(O_SYNC))) == -1)
throw std::runtime_error("can not open keyboard fd");
unsigned flags = fcntl(kfd, F_GETFL, 0);
flags |= FLAG(O_NONBLOCK);
if (fcntl(kfd, F_SETFL, flags) == -1)
throw std::runtime_error("can not set keyboard fd flags");
}
到目前为止,一切都很好。主循环只是轮询事件,如果按ESC就会中断。
int main() {
while (true) {
read(kfd, evt, sizeof(input_event));
if (evt->type == EV_KEY && evt->value == 1 && evt->code == KEY_ESC)
break;
}
}
所以我输入一些字符。同时,我的终端正在缓冲我输入的所有字符。程序退出后,所有字符都会显示。
这是我的问题:在程序运行时如何禁用终端输出流缓冲?
下面是一个GIF来说明问题。
步骤:
答案 0 :(得分:0)
程序不应该显示键入的键,这就是为什么我转为回显,但是在后台键得到缓冲的原因。当程序退出时,这些字符被打印出来。就像我必须在退出前冲洗一些缓冲区。
这可以通过致电
来完成 tcflush(STDIN_FILENO, TCIFLUSH);
就在退出之前;参见tcflush(3) - Linux man page。
答案 1 :(得分:0)
我已经解决了我的问题。 (https://unix.stackexchange.com/questions/126974/where-do-i-find-ioctl-eviocgrab-documented)
因此,我在程序开始后立即抓取所有事件,包括ENTER
示例:sudo ./clac ENTER
解决方案是在开始时添加1000毫秒的延迟,然后使用来抓取fd事件
std::this_thread::sleep_for(std::chrono::seconds(1));
if (ioctl(kfd, EVIOCGRAB, FD_GRAB) == -1)
throw std::runtime_error("can not set keyboard fd grab");
当程序退出UNGRAB时,
if (ioctl(kfd, EVIOCGRAB, FD_UNGRAB) == -1)
throw std::runtime_error("can not set keyboard fd ungrab");