如何在等待终端输入时处理窗口事件?

lus*_*oog 3 c windows stdio nonblocking xcb

我有一个跨平台(windows 和 unix+xcb)terminal+graphics_window 应用程序,它大部分工作正常,直到您在输入提示处等待太长时间,在重负载下图像可能会消失。:(

我有一个用于解释器(postscript 解释器)的主循环(REPL),它每次围绕其循环调用一个事件处理函数。事件处理程序执行通常是窗口的消息/事件循环的一次迭代。但是输入是用普通的 C i/o 处理的,因此当阻塞时事件处理程序永远不会被调用fgetc()

图形窗口仅用于输出。它没有按钮,只需要响应 Raise、Map、Expose 等事件。

如何安排在调用堆栈更深处的输入读取循环期间调用事件处理程序?这需要能够使用 POSIX 和 win32 API 来实现。

选项似乎是

  • 非阻塞 i/o
    在 unix 中相对简单。在窗户上看起来很痛苦
  • 轮询
  • 输入线程
    pthreads?
  • 窗口线程
    pthreads?

其中任何一个可能比其他的疼痛减轻吗?

如果我可以继续使用 unix,那么这似乎可以解决整个问题:

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

void idleproc () {  /* simulates calling the event handler 
                        (ie. one slice of the window loop) */
    //printf("idle\n");
    putchar('.');
}

int idlefgetc (FILE *stream) {
    int ret;

    do {
        ret = fgetc(stream);
        idleproc();
    } while(ret == EOF && 
            (errno == EAGAIN || errno == EINTR));

    return ret;
}

int setraw (FILE *stream) {
    struct termios tbuf;
    if (tcgetattr(fileno(stream), &tbuf) == -1)
        return -1;
    tbuf.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
            | INLCR | IGNCR | ICRNL | IXON);
    tbuf.c_oflag &= ~OPOST;
    tbuf.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
    tbuf.c_cflag &= ~(CSIZE | PARENB);
    tbuf.c_cflag |= CS8;
    if (tcsetattr(fileno(stream), TCSANOW, &tbuf) == -1)
        return -1;
    return 0;
}

int setnonblocking (FILE *stream) {
    int flags;

    if (setraw(stream) != 0)
        return -1;
    if (!((flags = fcntl(fileno(stream), F_GETFL)) & O_NONBLOCK)) {
        flags |= O_NONBLOCK;
        fcntl(fileno(stream), F_SETFL, flags);
    }
    return 0;
}

int main (int argc, char **argv) {
    if (setnonblocking(stdin)) {
        perror(argv[0]);
        return 0;
    }
    printf("'%d'\n", idlefgetc(stdin));
    system("stty sane");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

jpm*_*muc 5

在 Windows 下,您需要使用控制台 API。您可以使用ReadFileEx执行异步、非阻塞字符读取。另一种可能性是ReadConsoleInput,并连续轮询输入,而不会阻塞。使用SetConsole,您可以决定要捕获哪些事件。

有关 Windows 下异步 I/O 的更多详细信息,请参阅此处