getch() 确实显示最近输入的字符并跳过输入的所有其他字符

getch() does display most recently typed character and skips every other character entered

正在为 class 完成作业并且已经与 ncurses 斗争了一段时间(这对我来说是新的)。创建一个能够通过网络与同一程序的另一个实例进行通信的程序。该程序的一部分是交互式地从键盘获取字符并将它们发送到接收端。 (我们被建议使用单线程方法并在 ncurses 中使用 getch,并使用来自 getch 的非阻塞输入)。

我 运行 遇到的问题是我的 getch 有我无法弄清楚的行为。在不同的变体中,它会显示我输入的所有其他字符,并且不会显示最近输入的字符,直到在它之后输入另一个字符。我已经使用 nodelay() 来获取实时输入,但是 .

这是我的 ncurses 显示设置。 (注意:我使用 noecho() 因为后来我不想显示输入的每个字符)。

/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();

这是我编写的代码,可用于 getch 和 sending/receiving 套接字上的数据。

while(1) {
    rfdset = master;

    if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(EXIT_FAILURE);
    }

    ch = getch();

    if (ch != ERR) {
        printw("%c",ch);
        write(direct, &ch, 1); // direction to send data
    }

    for(i = 0; i <= maxfd; i++) {
        if (FD_ISSET(i, &rfdset)) {
            bzero(msgbuf, MSGSIZE);
            idx = read(i, msgbuf, MSGSIZE);
            if (i != STDIN)
                printw("%s",msgbuf); // display received msg
        }
    }
}

当我 运行 在应用程序的任何一端输入数据时,我得到的结果如下:

Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2

Computer 2 message recv'd: tsig2

因此,我确信 getch 是造成我的大部分问题的原因,我一定是在实施过程中遗漏了某些事情或做错了什么。任何建议表示赞赏。

编辑 1:

我设法通过删除 for 循环并直接检查套接字的输入来解决 所有其他字符问题。我很困惑为什么要修复它。现在我唯一剩下的问题是 为什么在输入字符后才显示字符。这是我在 while 循环中修改后的代码:

while(1) {
    rfdset = master;

    if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(EXIT_FAILURE);
    }

    ch = getch();

    if (ch != ERR) {
        printw("%c",ch);
        write(direct, &ch, 1);
    }

    /* check for incoming data from left socket */
    if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
        bzero(leftmsg, MSGSIZE);
        idx = read(lcsad, leftmsg, MSGSIZE);
        leftmsg[idx] = 0;
        printw("%s", leftmsg);
        lm = 1;
    }

    /* check for incoming data from right socket */
    if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
        bzero(rghtmsg, MSGSIZE);
        idx = read(rsd, rghtmsg, MSGSIZE);
        rghtmsg[idx] = 0;
        printw("%s", rghtmsg);
        rm = 1;
    }

    /* check and send left message onward */
    if (lm && !NORIGHT) {
        write(direct, leftmsg, MSGSIZE);
    }

    /* check and send right message onward */
    if (rm && !NOLEFT) {
        write(direct, rghtmsg, MSGSIZE);
    }
    lm, rm = 0;
}

如果使用 wgetch() 而不是 getch() 可以解决您的问题,您可以试试。

问题在于,因为您的 select 调用没有指定超时(最后一个参数是 NULL),它会阻塞直到有一些未决的 I/O(例如您键入的下一个字符)。那时,程序继续进入 getch 调用,它执行 refresh(回显来自 printw 调用的字符)。

指定一个较短的超时时间,例如 10 毫秒,会有所改善,例如,

struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;

并在对 select...

的调用中传递 myTimeout 的地址