3

我有一个getch()我的导师给我的功能,它可以在不点击“ENTER”的情况下从键盘获取输入。但是,当我在 Eclipse 的 Ubuntu 12 中运行它时,出现以下错误:

tcsetattr(): Inappropriate ioctl for device
tcsetattr ICANON: Inappropriate ioctl for device

这是我的代码:

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

char getch();

int main(int argc, const char* argv[])
{
    char c;
    do
    {
        c=getch();
        printf("%c",c);
    } while(c!='q');

    return 0;
}

char getch()
{
    char buf = 0;
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;

    if (tcsetattr(0, TCSANOW, &old) < 0)
        perror("tcsetattr ICANON");
    if (read(0, &buf, 1) < 0)
        perror ("read()");
    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    if (tcsetattr(0, TCSADRAIN, &old) < 0)
        perror ("tcsetattr ~ICANON");
    return (buf);
}

注意:该代码在 SSH 安全外壳中工作。但是我必须在我的 Ubuntu 中完成这项工作,因为我在那里编写了我的代码。谢谢

4

1 回答 1

4

这可能是因为 Eclipse 没有为在 IDE 下运行的程序提供伪终端。试试这个依赖非阻塞 I/O 而不是终端控制的替代方案。

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define perror_exit(msg) do { perror(msg); exit(1); } while(0)

#if defined EAGAIN && defined EWOULDBLOCK
#define retry_p(err) ((err) == EAGAIN || (err) == EWOULDBLOCK)
#elif defined EAGAIN
#define retry_p(err) ((err) == EAGAIN)
#elif defined EWOULDBLOCK
#define retry_p(err) ((err) == EWOULDBLOCK)
#else
#error "Don't know how to detect read-would-block condition."
#endif

int
main(void)
{
    int flags = fcntl(0, F_GETFL);
    if (flags == -1)
        perror_exit("fcntl(F_GETFL)");
    flags |= O_NONBLOCK;
    if (fcntl(0, F_SETFL, flags))
        perror_exit("fcntl(F_SETFL, O_NONBLOCK)");

    for (;;)
    {
       char ch;
       ssize_t n = read(0, &ch, 1);
       if (n == 1)
       {
           putchar(ch);
           if (ch == 'q')
               break;
       }
       else if (n < 0 && !retry_p(errno))
          perror_exit("read");
    }
    return 0;
}

如果这仍然不起作用,请尝试修改它以同时执行此操作和您的getch()操作,忽略失败tcsetattrtcgetattr何时errno == ENOTTY

请注意,此代码和您的原始代码都在忙于等待 I/O,这是不好的做法。您真正应该做的是使用ncurses库,它具有更复杂的方法来同时处理和等待更适合多任务环境的输入,并且还可以处理您的缺乏-a-tty 问题和任意数量的其他你不想浪费精力的低级头痛。

于 2013-04-19T16:49:19.200 回答