2014-10-28 6 views
3

그래서 기본적으로 문자 입력을 읽고 'q'가 입력 될 때까지 인쇄합니다.termios.h를 사용하여 C 프로그램에서 사용자가 입력을 요청할 때 화살표 키와 백 스페이스를 올바르게 작동시키는 방법은 무엇입니까?

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

int main(void) { 
    char c; 
    static struct termios oldtio, newtio; 
    tcgetattr(0, &oldtio); 
    newtio = oldtio; 
    newtio.c_lflag &= ~ICANON; 
    newtio.c_lflag &= ~ECHO; 
    tcsetattr(0, TCSANOW, &newtio); 

    printf("Give text: "); 
    fflush(stdout); 
    while (1) { 
     read(0, &c, 1); 
     printf("%c", c); 
     fflush(stdout); 
     if (c == 'q') { break; } 
    } 
    printf("\n"); 
    tcsetattr(0, TCSANOW, &oldtio); 

    return 0; 
} 

주 기능 시작 부분에서 사용자가 입력 할 때 입력을 볼 수 있도록 표준 모드를 ​​해제합니다. 나는 또한 에코를 꺼서 "^ [[A]는 예를 들어 위쪽 화살표 키를 누를 때 팝업되지 않습니다. 이 작동하지만 터미널 창에서 커서를 위쪽 행으로 이동할 수 있으며 좋지 않습니다. 사용자가 현재 행 내에서만 이동할 수 있도록 수정하는 방법이 있습니까?

또 다른 문제는 백 스페이스입니다. 내가 그것을 누르면 커서의 현재 위치에 남아있는 문자를 지우는 대신 이상한 심볼 (0x7f라고 가정)을 인쇄합니다. 난 propably 어떻게 든 프로그램에서 백 스페이스 키 출력을 처리해야하지만이 이상한 16 진수 이후로 그것을 어떻게 해야할지 모르겠다. 이것에 대한 조언?

이 작업을하기 위해 생각한 한 가지 옵션은 표준 모드를 ​​사용하여 화살표 키와 백스 페이스 기능이 자동으로 사용되도록하는 것입니다. 그러나 정식 모드는 줄 단위로 작동하므로 사용자가 "Enter"를 누르기 전까지는 텍스트가 표시되지 않습니다. 지금까지 입력하는 동안 사용자가 입력 내용을 볼 수있는 방법을 찾지 못했습니다. 이것은 가능한가?

그리고 제발 ncurses 또는 readline 제안. termios.h를 사용하여이 작업을 수행하려고합니다.

+2

에코를 끄고 모든 것을 직접 에코합니다. 그것은 성공적인 전략이 아닙니다. 인쇄 가능한 일반 문자를 반향하고 제어 재봉을 처리하고 해석합니다. 당신은 당신의 통제 순서가 무엇이고 이것이 의미하는 바를 알아야합니다. 이를 위해서는 terminfo 데이터베이스와 동등한 것이 필요합니다. terminfo는 ncurses와 밀접하게 연결되어 있으므로 ncurses는 필요 없으며, 나는 여러분에게 행운을 빌어줍니다. –

+0

너는 ncurses가 없어도 이것이 가능하지 않다는 것을 말하는거야? – JZ555

+0

처음부터 모든 부분을 다시 구현하고 다른 부분에 기능을 포기하지 않으려는 경우 모든 것이 전부없이 모든 것이 가능합니다. 인기있는 터미널 제품군 중 하나 인 VT100 및 자손에 자신을 제한하고 자신의 제어 시퀀스 목록을 컴파일 한 다음이를 사용하여 작업 할 수 있습니다. 그렇지 않으면 적어도 terminfo (기술적으로는 (n)의 일부)를 사용해야합니다. –

답변

4

맨 페이지를 살펴 보았습니까? (man termios 일 또는 어딘가에 online을 찾아야한다)

나는 다음과 같은 효과가 있다고하는 ECHOE 플래그 발견 ICANON도 설정되어있는 경우

, 삭제 문자 앞의 입력 문자가 삭제를하고, WERASE는 앞의 단어를 지 웁니다.

이렇게하면 백 스페이스 문제가 해결됩니까?

또한 설명서 페이지의 예제를 살펴 보시기 바랍니다. 예 : 다음을 수행 할 수 있습니다.

newtio.c_lflag &= ~(ECHO | ECHOE | ICANON); 

... 한 번에 하나 이상의 플래그를 한 번에 설정할 수 있습니다. 맨 페이지는 초보자를위한 읽기가 어렵지만 익숙해 질수록 C/POSIX 기능을 찾는 데 더 효율적이 될 것입니다 (다만, 사용하지 마십시오. 어쨌든).

화살표 키 문제 : 아마도 cfmakeraw() 기능을 시도해 볼 수 있습니다. 그것의 묘사는 유망하게 들린다. 화살표 키에 대해 더 이상 조사 할 시간이 없었습니다. 그러나, 아마도 man 페이지에서 다른 유용한 것을 발견했을 것입니다.

BTW : termios 흥미롭게 보아, 나는 항상 어떤 명령 행 프로그램이 어떤 기능을 사용하고 있는지 궁금해했다. 귀하의 질문에 의해 뭔가 배웠습니다, 감사합니다!

수정

이번 주말에 더 많은 조사를했습니다. 백 스페이스 키를 누를 때 인쇄되는 "이상한"기호는 숨기기 쉽습니다. ASCII 값 0x7f입니다.그래서 간단한 것을 추가하십시오.

if (c == 0x7f) { continue; } 

... 단지 백 스페이스 키를 무시하십시오. 또는 마지막 문자를 제거하는 방법으로 처리하십시오 (아래 코드 예제 참조).

화살표 키에는 ASCII 문자가 없기 때문에이 간단한 해결 방법이 작동하지 않습니다.// 그러나이 두 항목은 topic 1topic 2과 같은 문제를 처리하는 데 도움이되었습니다. 기본적으로 화살표 키를 누르면 두 개의 문자 시퀀스가 ​​stdin으로 전송됩니다 (자세한 내용은 두 번째 링크 참조).

int main(void) { 
    char c; 
    while (1) { 
     c = getchar(); 
     printf("%d", c); 
    } 
    return 0; 
} 

가 내가 생각 :

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

int main(void) { 
    char c; 
    static struct termios oldtio, newtio; 
    tcgetattr(0, &oldtio); 
    newtio = oldtio; 
    newtio.c_lflag &= ~ICANON; 
    newtio.c_lflag &= ~ECHO; 
    tcsetattr(0, TCSANOW, &newtio); 

    printf("Give text:\n"); 
    fflush(stdout); 
    while (1) { 
     c = getchar(); 

     // is this an escape sequence? 
     if (c == 27) { 
      // "throw away" next two characters which specify escape sequence 
      c = getchar(); 
      c = getchar(); 
      continue; 
     } 

     // if backspace 
     if (c == 0x7f) { 
      // go one char left 
      printf("\b"); 
      // overwrite the char with whitespace 
      printf(" "); 
      // go back to "now removed char position" 
      printf("\b"); 
      continue; 
     } 

     if (c == 'q') { 
      break; 
     } 
     printf("%c", c); 
    } 
    printf("\n"); 
    tcsetattr(0, TCSANOW, &oldtio); 

    return 0; 
} 

가 BTW 다음 코드에 의해 전체 이스케이프 시퀀스를 얻을 수 있습니다 : 여기

이 방법은 당신이하고자하는 (내가 생각하는) 작동 내 전체 코드입니다 이 완전한 것은 상당히 더러운 해킹이고 일부 특수 키 처리를 잊는 것은 쉽다는 것을 말할 필요가 없습니다. 예 : 내 코드에서는 page-up/down 또는 home 키를 처리하지 않습니다. 위의 코드는 아직 완료되지 않았지만 시작할 지점을 제공합니다. 필요한 정보를 많이 제공 할 수있는 terminfo도 살펴 봐야합니다. 또한 더 이식 가능한 솔루션을 제공해야합니다. 아시다시피,이 "단순한"것은 상당히 복잡해 질 수 있습니다. 그래서 당신은 ncurses에 대한 당신의 결정을 다시 생각할 수 있습니다 :)

+0

아니요, ICANON을 설정해야하기 때문에 문자를 지우지 않고도 여전히 "0x7f"기호를 표시합니다. 즉 켜야한다는 의미입니다. 그리고 내가 그것을 켜면, 사용자는 그가 "Enter"를 칠 때까지 그가 타이핑하고있는 것을 볼 수 없다. 그러나 노력에 감사드립니다. – JZ555

+0

@ JZ555 : 네, 맞습니다. 오늘 밤 집에서 테스트 해 보겠습니다. (Linux (-> POSIX) 시스템을 사용할 수 있습니다.) 어쩌면 다른 것을 알아낼 수 있습니다. 죄송합니다. 지금 당장 도와주세요. – mozzbozz

+0

@ JZ555 생각했던 것보다 약간 힘들었지 만 지금은 해결책이 있다고 생각합니다. 내 대답의 * 편집 * 섹션을 참조하십시오. – mozzbozz

0

실제로, 화살표 키를 처리하기 위해서는 상당한 크기의 ncurses 덩어리를 구현해야합니다. 장점/단점이 있습니다 : 명령 줄 응용 프로그램에서 ncurses를 사용하는 데있어서의 주요 단점은 대개 화면을 지우는 것일 수 있습니다. 그러나 (n) curses는 함수 filter을 제공합니다. ncurses 소스에는 왼쪽 화살표 키를 지우기 문자로 사용하여이를 보여주는 샘플 프로그램 "test/filter.c"가 있으며 결과 행을 system()에 전달하여 간단한 명령을 실행합니다. 샘플은 100 줄 미만의 코드입니다. 위 예제보다 간단하고 완벽합니다.