首页 > 解决方案 > 构建文本编辑器。以原始模式从终端读取字符

问题描述

我正在关注如何编写自己的文本编辑器的教程构建您自己的文本编辑器。

我目前处于低级按键读取并将其映射到编辑器操作(部分:重构键盘输入)。但是当我在我的代码中实现相同并运行它时,我的终端只是冻结了,我必须重新启动才能恢复正常。我正在使用 Parrot OS(如果重要的话)。这是我的源代码的相关部分:

char editorReadKey() {
    int nread;
    char c;
    while ((nread = read(STDIN_FILENO, &c, 1) != 1)) {
        if (nread == -1 && errno != EAGAIN)
            die("read");
        /*if (iscntrl(c))
            printf("%d\r\n", c);
        else
            printf("%d('%c')\r\n", c, c);
        */
    }
    return c;

}
void editorProcessKeypress() {
    char c = editorReadKey();
    switch (c) {
        case CTRL_KEY('q') : exit(0);
                             break;
    }
}
int main(void) {
    enableRawMode();
    while (1) {
            editorProcessKeypress();
    }
    return 0;
  

函数enableRawModedisableRawMode没有区别,或多或少是本教程的确切实现。

void disableRawMode() {
    if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios) == -1)
        die("tcsetattr");
}
void enableRawMode() {
    if(tcgetattr(STDIN_FILENO, &orig_termios) == -1)
        die("tcgetattr");
    atexit(disableRawMode);
    struct termios raw = orig_termios;
    tcgetattr(STDIN_FILENO, &raw);
    //turns off echoing the command on the screen
    //turn off cannonical mode
    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    raw.c_oflag &= ~(OPOST);
    raw.c_cflag |= (CS8);
    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
    raw.c_cc[VMIN] = 0;
    raw.c_cc[VTIME] = 1;
    if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1)
        die("tcsetattr");
}

关于为什么会发生这种情况的任何原因?还是我做错了什么?

编辑:editorReadKey()添加了我以某种方式错过将其放在这里的返回值。

标签: clinuxterminal

解决方案


Ctrl-SCtrl-Q用于在熟模式下暂停和恢复到控制台的输出,这可以解释您的观察结果,尽管您通过IXONraw.c_iflag. 和设置VMINVTIME可能不正确:设置VMIN为零似乎是错误的。

在 Quick Emacs 中,我使用以下代码设置原始模式:

    tcgetattr(fileno(s->STDIN), &tty);
    ts->oldtty = tty;

    /* input modes: no break, no CR to NL, no parity check, no strip char,
     * no start/stop output control. */
    tty.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON |
                     IGNBRK | PARMRK | INLCR | IGNCR);
    /* output modes - enable post processing? */
    tty.c_oflag &= ~(OPOST);
    /* control modes - set 8 bit chars, no parity checking */
    tty.c_cflag &= ~(CSIZE | PARENB);
    tty.c_cflag |= CS8;
    /* local modes - echoing off, canonical off, no extended functions,
     * no signal chars (^Z,^C) */
    tty.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG | ECHONL);
    /* control chars - set return condition: min number of bytes and timer.
     * We want read to return every single byte, without timeout. */
    tty.c_cc[VMIN] = 1;   /* 1 byte */
    tty.c_cc[VTIME] = 0;  /* no timer */

    tcsetattr(fileno(s->STDIN), TCSANOW, &tty);

有关这些标志的详细说明,请参见termios 的 Linux 手册页


推荐阅读