3

我正在开发一个程序,该程序将从控制台接收用户输入并在单独的线程中打印出来。我想避免用户在输入内容到一半时出现 printf 并在光标处打印自身的情况。

有没有办法从控制台窗口在 c 中执行非阻塞 io?理想情况下,捕获按键或类似的东西,这样用户键入的内容就不会出现在屏幕上。我在 Ubuntu 中开发,最好不要使用 ncurses 之类的东西。

4

3 回答 3

4

使用termios您可以禁用终端回显:

#include <termios.h>

struct termios oflags, nflags;
tcgetattr(fileno(stdin), &oflags);
nflags = oflags;
nflags.c_lflag &= ~ECHO;
nflags.c_lflag |= ECHONL;

if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) {
    /* handle error */
}

然后在退出(使用atexit)之前,您必须恢复终端:

if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) {
    /* handle error */
}
于 2009-08-14T04:37:38.913 回答
2

这是一个如何从 C 中关闭回声的示例,直接取自HP 论坛(我还没有亲自测试过):

好的,这应该是一个关闭回声的简单示例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>

#define STDIN_FDES 0

struct termios save;

int main(int argc, char *argv[])
{
int cc = 0;
char s_tmp[80],*p = NULL;
struct termios work;

cc = tcgetattr(STDIN_FDES,&save);
work = save;
work.c_lflag &= ~(ECHO);
cc = tcsetattr(STDIN_FDES,TCSANOW,&work);
(void) printf("\nEnter value: ");
(void) fflush(stdout);
p = fgets(s_tmp,sizeof(s_tmp),stdin);
if (p != NULL) (void) printf("Out -> %s\n",p);
cc = tcsetattr(STDIN_FDES,TCSANOW,&save);
return(cc);
}

注意:拥有信号处理程序来捕获 SIGINT、SIGTERM ......并使用原始 termios 重置终端非常重要,因为最后一个 tcsetattr() 获胜,这适用于终端设备而不仅仅是进程。如果您在关闭 echo 的情况下离开该进程,它也会在 shell 中关闭。

否则,如果 Bash 是一种合适的方法,显然你可以这样做stty -echo

于 2009-08-14T04:31:51.840 回答
0

如果我正确理解您的问题,关闭回声或使用非阻塞 I/O 不是答案。相反,您想防止后台线程中断用户输入线程,对吗?

为此,您需要访问原始按键而不是行缓冲输入。我不知道你为什么对 ncurses 或类似的库过敏;这就是他们的目的!我想你可以用 termios 或 ioctl 调用来做到这一点,如果你是这样滚动的......

但要解决您的多线程 TTY 输出问题,您可以这样做:

1)创建互斥锁来控制谁可以访问控制台

在后台线程中,输出消息:

抓住互斥锁;写信息;释放互斥锁;回去睡觉!

在用户输入线程中:

检测到新输入时获取互斥锁。保持独占访问,直到用户点击进入,然后释放互斥锁并给后台线程一个说话的机会。

这有帮助吗?

于 2009-08-14T05:35:20.967 回答