3

我正在使用我在上一个问题中建议的 termios ,但现在询问是否有办法让退格键在非规范模式下使用 termios 时工作。我正在使用 termios 没有echo如果我使用&=ECHO并且&=ICANON这是我想要的结果,则键盘输入会在按下并显示键后立即发送到 putchar() 但如果我执行相反的操作,则'\b'键显示为hex在按下输入之前我看不到文本,但'\b'可以。我查了说明书和其他一些论坛,他们说“不可能只是不要犯任何错误”,这是有道理的,因为当我在 Ubuntu 的终端中没有正确输入密码时,我无法退格并更改它. 但我确保我没有错过手册中的任何内容。

代码是从标准输入获取输入而不显示空行。

#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <stdio.h>
#define ECHOFLAGS (ECHO)

int setecho(int fd, int onflag);
int first_line(int *ptrc);

int main(void){

struct termios old;
tcgetattr(STDIN_FILENO,&old);


setecho(STDIN_FILENO,0);
    int c;
    while((c = getchar())!= 4) //no end of file in non-canionical match to control D
        first_line(&c);
tcsetattr(STDIN_FILENO,&old);    
return 0;

    }


int setecho(int fd, int onflag){
    int error;
    struct termios term;

    if(tcgetattr(fd, &term) == -1)
        return -1;
    if(onflag){ printf("onflag\n");
        term.c_lflag &= ECHOFLAGS ; // I know the onflag is always set to 0 just 
        term.c_lflag &=ICANON;      // testing at this point
    }
    else{ printf("else\n");
        term.c_lflag &= ECHO;
        term.c_lflag &=ICANON;

    }

    while (((error = tcsetattr(fd, TCSAFLUSH, &term)) ==-1 && (errno == EINTR)))
            return error;
}

int first_line(int *ptrc){
    if (*ptrc != '\n' && *ptrc != '\r'){
            putchar(*ptrc);
        while (*ptrc != '\n'){
            *ptrc = getchar();
            putchar(*ptrc);
            }


    }
    else return 0;

    return 0;
}

谢谢拉克兰

PS 在我的研究中,我注意到有人说 Termios 不是“标准 C”,这是因为它依赖于系统吗?(仅用于评论)

4

3 回答 3

3

你希望这如何工作?如果输入字符立即发送到您的程序,那么当接收到退格字符时,终端处理退格就为时已晚 - 您的程序已经看到前一个字符,因此无法收回。

例如,假设用户按下A。您的程序将接收'A'getchar()处理它。现在用户按下backspace- 现在终端应该做什么?

因此,这意味着您可以在非规范模式下处理退格的唯一地方是您的程序本身。当您从 接收'\b'字符时getchar(),您可以对其进行特殊处理(就像您对 进行特殊处理一样'\n') - 例如,从缓冲区中删除最近输入的字符。

于 2012-04-23T07:26:59.843 回答
3

It's implementation-dependent. On my machine, pressing backspace led to the byte 127 being read by read(). This code worked on my machine.

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

#define MAXBUFSIZE (10000U)
#define DEL (127)

int main(void) {
    char buf[MAXBUFSIZE];
    char c;
    size_t top;
    struct termios curterm;

    tcgetattr(STDIN_FILENO, &curterm);
    curterm.c_lflag &= ~(ICANON| ECHO);
    curterm.c_cc[VTIME] = 0;
    curterm.c_cc[VMIN] = 1;
    tcsetattr(STDIN_FILENO, TCSANOW, &curterm);

    top = 0;
    while (read(STDIN_FILENO, &c, sizeof c) == 1) {
        switch (c) {
            case DEL:
                if (top) {
                    --top;
                    const char delbuf[] = "\b \b";
                    write(STDOUT_FILENO, delbuf, strlen(delbuf));
                }
                break;
            case '\n':
                write(STDOUT_FILENO, &c, sizeof c);
                write(STDOUT_FILENO, buf, top);
                top = 0;
                break;
            default:
                buf[top++] = c;
                write(STDOUT_FILENO, &c, sizeof c);
                break;
         }
    }

    return 0;
}
于 2015-12-02T19:52:52.073 回答
1

当用户按下退格键时,应用程序会收到一些控制代码。应用程序必须解释控制代码并从其缓冲区(应用程序缓冲区,因为您没有使用内核缓冲区)中取出一个字符。如果应用程序正在执行任何类型的回显(例如:回显星号代替密码字符),则它必须发送一些其他控制代码来将光标向左移动并清除最后一个星号。

收到的删除或退格代码以及您发送的移动光标的代码都取决于用户所拥有的终端类型,因此在您执行任何此类游戏之前,您还必须检测终端类型。大多数程序员不想花时间阅读数百种不同类型终端的手册,所以他们通常使用一个库来隐藏所有这些。一个这样的库是curses。

于 2015-03-08T18:59:02.890 回答