在规范模式下处理转义键的任何方法?

Tyl*_*den 5 c unix terminal termios

在unix plain C termios编程中,如果我使用规范模式从用户接收一行输入,我该如何处理转义键?通常,如果用户正在输入一行文本并按下转义,则不会发生任何事情.如果用户按下escape,我想取消当前输入.我知道我可以处理单个字符,但后来我失去了规范模式(退格等)的所有好处.

Iwi*_*ist 4

原来的

感谢Jonathan Leffler 的评论,他的评论暗示了我正确的方向,底部是我带注释的第一个termios程序演示器(谢谢!)。

关键是使用tcgetattr(ttyfd, &attributes)当前终端的文件描述符将其当前属性检索到 a 中struct termios,编辑属性,然后使用 来应用更改tcsetattr(ttyfd, when, &attributes)

属性之一是“kill”字符——该字符导致整个当前缓冲的行被丢弃。它是通过索引到 的c_cc成员数组struct termios并设置attr.c_cc[VKILL]为任何想要的值(此处为 to Esc,等于八进制033)来设置的。

退出时终止字符应恢复为之前的值。

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


int main(){
    char   buf[80];
    int    numBytes;
    struct termios original, tattered;
    int    ttyfd;
    
    /* Open the controlling terminal. */
    ttyfd = open("/dev/tty", O_RDWR);
    if(ttyfd < 0){
        printf("Could not open tty!\n");
        return -1;
    }
    
    /**
     * Get current terminal properties, save them (including current KILL char),
     * set the new KILL char, and make this the new setting.
     */
    
    tcgetattr(ttyfd, &original);
    tattered = original;
    tattered.c_cc[VKILL] = 033;/* New killchar, 033 == ESC. */
    tcsetattr(ttyfd, TCSANOW, &tattered);
    
    /**
     * Simple test to see whether it works.
     */
    
    write(1, "Please enter a line: ", 21);
    numBytes = read(0, buf, sizeof buf);
    write(1, buf, numBytes);
    
    /**
     * Restore original settings.
     */
    
    tcsetattr(ttyfd, TCSANOW, &original);
     
    /* Clean up. */
    close(ttyfd);
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

该演示似乎可以在 Mac OS X 10.6.8 上运行。我还在 Linux 上对此进行了测试,显然Esc终止缓冲区似乎是默认设置,就好像我打印出c_cc[VKILL]我获得的一样27 == 033 == ESC

编辑

以下尝试尽可能模仿您在评论中描述的行为。它设置c_cc[VEOL2]Esc;EOL2 是备用行尾。它还会删除 Esc作为终止字符,因为您想要接收该行。

现在发生的情况是,如果Ret按下法线,一切都会正常。但是,如果Esc按下,缓冲区中的最后一个字符将设置为Esc,这是可以测试的条件(尽管仅在首先读取并缓冲整行之后)。

以下是根据您明确的规格制作的演示器。它等待一行输入并回显它

  • <CANCELLED> Esc如果该行以和终止
  • <NORMAL > 如果该行以 终止Ret

享受!

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


int main(){
    char   buf[80];
    int    numBytes;
    struct termios original, tattered;
    int    ttyfd;

    /* Open the controlling terminal. */
    ttyfd = open("/dev/tty", O_RDWR);
    if(ttyfd < 0){
        printf("Could not open tty!\n");
        return -1;
    }

    /**
     * Get current terminal properties, save them (including current KILL char),
     * set the new KILL char, and make this the new setting.
     */

    tcgetattr(ttyfd, &original);
    tattered = original;
    tattered.c_cc[VKILL] = 0;  /* <Nada> */
    tattered.c_cc[VEOL2] = 033;/* Esc */
    tcsetattr(ttyfd, TCSANOW, &tattered);

    /**
     * Simple test to see whether it works.
     */

    fputs("Please enter a line: ", stdout);
    fflush(stdout);
    numBytes = read(0, buf, sizeof buf);
    if(buf[numBytes-1]==033){/* Last character is Esc? */
        buf[numBytes-1] = '\n';/* Substitute with newline */
        fputs("\n<CANCELLED> ", stdout);   /* Print newline to move to next line */
    }else{
        fputs("<NORMAL   > ", stdout);
    }
    fwrite(buf, 1, numBytes, stdout);

    /**
     * Restore original settings.
     */

    tcsetattr(ttyfd, TCSANOW, &original);

    /* Clean up. */
    close(ttyfd);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • Tyler 在 2014 年 10 月提出了这个问题;他很可能已经克服了这个障碍,但没有一个简单的方法来决定它是否适合他。 (3认同)