버퍼링되지 않은/비표준 모드에서 백스페이스를 허용하는 방법은 무엇입니까?

버퍼링되지 않은/비표준 모드에서 백스페이스를 허용하는 방법은 무엇입니까?

저는 ECHO 및 ICANON 플래그 없이 실행해야 하는 쉘 및 텍스트 편집기와 같은 여러 C 프로그램을 개발 중입니다. 나는 termios.h를 사용하여 이러한 기능을 비활성화하고 반환된 문자열을 내 프로그램에 전달하고 이스케이프된 문자에 대해 특수 작업을 수행하는 가져오기 함수를 직접 작성했습니다. 내가 할 수 없는 유일한 일은 백스페이스 키를 인쇄하는 것입니다. 예를 들어, 다음 코드를 사용하면:

void mgets(char *str)
{
    int c, i = 0;

    while((c = getchar()) != '\n')
        if(c == 27)
            // the user hit ESC, ignore it for now
        else if(c == '\b')
            puts("\b \b") // this is where it SHOULD backspace
        // else if it's a regular character:
        else {
            str+i = c; i++; // write that to the string...
            putchar(c); // ...and echo it to the screen
        }
}

모든 것이 괜찮지만 백스페이스를 실행하면 프로그램이 응답하지 않게 됩니다. if 문을 조금 바꾸면...

if(c == '\b')
    printf("You hit a backspace!");

하지만 여전히 반응이 없습니다. 나는 put("\b \b")이 작동한다는 것을 알고 있으므로 유일한 결론은 내 백스페이스 키가 '\b'로 감지되지 않는다는 것입니다. 어떡해? 도와주세요? 미리 감사드립니다!

답변1

앞으로termios 설정을 변경하면구하다그들을. 정보는 귀하가 보는 것과 "동일"합니다.stty -a.

예를 들어

$ stty -a
speed 38400 baud; rows 40; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke

이후에 표시되는 값erase"백스페이스" 문자라고 부르는 것입니다. 시스템 규칙에 따라 이는 ^H(8 또는 ASCII 백스페이스) 또는 ^?(127 또는 ASCII DEL)일 수 있습니다.

예를 들어 termios 설정에서

#include <termios.h>
...
struct termios data;
tcgetattr(0, &data);

그 다음에

data.c_cc[VERASE]

그것은 동일합니다삭제문자(데이터가 설정되지 않은 경우 경고가 표시됩니다. stty"undef"가 표시됩니다).

다른 설정과는 다르게,삭제문자는 터미널이 보낼 것으로 예상되는 내용을 터미널 드라이버에 알려주는 설정이기 때문에 raw/cbreak 모드와 여전히 관련이 있습니다. 설정이 올바르지 않은 경우 stty두 가지 가능성을 모두 테스트해도 문제가 되지 않습니다.

추가 자료:

답변2

내 백스페이스 키가 "\b"로 감지되지 않습니다. 어떡해?

(백스페이스) 및 (삭제) 키는 서로 다른 제어 또는 이스케이프 시퀀스를 생성합니다.

DEC VT와 같은 것을 시도하는 터미널에서:

  • 키는 DECFNK 제어 시퀀스를 발행합니다.
  • 동작은 ASCII BS와 DEL 문자 사이를 전환하고 DECBKM이라는 제어 시퀀스를 터미널로 보냅니다.

그러나 모든 터미널(에뮬레이터)이 DECBKM 메커니즘 구현은 고사하고 DEC VT처럼 작동하려고 시도하는 것은 아닙니다. 키보드 입력 시퀀스를 고정 배선하여 모든 상황에서 작동할 것으로 기대할 수는 없습니다.

프로그램이 작동해야 하는 방식은 다음과 같습니다. 환경 변수에서 터미널 유형을 가져와야 하고, TERM데이터베이스에서 해당 레코드를 가져와서(또는) 거기에서 두 가지 기능을 찾아야 합니다.terminfotermcap

  • kbs( ) - kb키가 전송되는 순서
  • kdch1( ) - kD키가 전송되는 순서

이 문자열은 읽는 입력과 일치해야 합니다. 실제 제어 순서와 단순한 누르기를 구별하려면 프로그램이 루프보다 더 복잡 Esc해야 합니다 . fgetc()비표준 모드를 ​​설정하고 (짧은) 읽기 시간 제한을 설정해야 합니다. read()제한 시간 내에 전체 문자열이 반환되는 경우에만 입력 제어 시퀀스로 간주되어야 합니다.

여기에 설정된 특수 문자는 stty거의 붉은 청어에 가깝습니다. 비정규 모드에는 적용되지 않으며 영향만 미칩니다.라인 규율그래도. 이것단말기컨트롤의 동작은 하드웨어 키 이벤트를 컨트롤 시퀀스에 매핑한 다음 이를 라인 분야로 "라인 아래" 보내는 방법에 전적으로 달려 있습니다. 앞서 언급했듯이 터미널은 키코드와 제어 시퀀스(FreeBSD의 내장 커널 터미널 에뮬레이터) 사이의 로드 가능한 매핑을 사용하는 것부터 X 리소스에 이르기까지 다양한 방법으로 이 작업을 자유롭게 수행할 수 있습니다.

추가 읽기

관련 정보