termios 구조체, tcsetatrr()

박선하·2023년 11월 2일
0

struct termios

터미널 관련 설정을 저장하는 데 사용되는 구조체

{
tcflag_t c_iflag; /*input mode flags*/
tcflag_t c_oflag; /*output mode flags*/
tcflag_t c_cflag; /*control mode flags*/
tcflag_t c_lflag; /*local mode flags*/
cc_t c_cc[NCCS]; /*control charters*/
speed_t c_ispeed; /*input speed*/
speed_t c_ospeed; /*output speed*/
};

각 멤버는 터미널 동작을 세밀하게 제어하기 위해 사용됩니다.

  1. c_iflag (Input Flags):

    • 입력 모드 플래그를 설정합니다. 이 멤버는 입력에 대한 특정 플래그를 비트 필드로 설정합니다. 예를 들어, 입력 데이터의 흐름 제어, 인터럽트 문자 및 입력 비트의 비트 수 등을 설정할 수 있습니다.
  2. c_oflag (Output Flags):

    • 출력 모드 플래그를 설정합니다. 이 멤버는 출력에 대한 특정 플래그를 비트 필드로 설정합니다. 예를 들어, 출력 데이터의 흐름 제어, 출력 비트의 비트 수, 출력 전송 속도 등을 설정할 수 있습니다.
  3. c_cflag (Control Flags):

    • 제어 모드 플래그를 설정합니다. 이 멤버는 터미널의 제어 모드와 관련된 플래그를 비트 필드로 설정합니다. 터미널의 데이터 비트 수, 정지 비트 수, 흐름 제어 설정 등을 여기에서 제어합니다.
  4. c_lflag (Local Flags):

    • 로컬 모드 플래그를 설정합니다. 이 멤버는 로컬 터미널 설정과 관련된 플래그를 비트 필드로 설정합니다. 예를 들어, ICANON(크리 모드)과 ECHO(에코)와 같은 로컬 터미널 동작을 여기에서 설정합니다.
  5. c_line:

    • 이 멤버는 터미널 라인 디스시플린(선호되지 않음)을 지원하며 일반적으로 사용되지 않습니다.
  6. c_cc (Control Characters):

    • 이 배열은 터미널에서 사용하는 제어 문자를 설정합니다. 배열의 각 요소는 특정한 제어 문자를 나타내며, 예를 들어 INTR(인터럽트), EOF(파일의 끝), ERASE(문자 지우기)와 같은 제어 문자들을 설정할 수 있습니다.
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>

#define ASK "Do you want another transaction"
#define TRIES 3                // 최대 시도 횟수
#define SLEEPTIME 2            // 각 시도 간 대기 시간
#define BEEP putchar('\a')     // 사용자에게 알림

int get_response(char *question, int maxtries) {
    int input;

    printf("mode setting starts !\n"); // 모드 변경 메시지 출력
    fflush(stdout);

    // 터미널 모드 변경
    tty_mode(0);              // 현재 모드 저장
    set_cr_noecho_mode();     // 모드 변경: -icanon, echo
    set_nodelay_mode();       // 모드 변경: noinput = EOF

    printf("%s (y/n)?\n", question);
    fflush(stdout);
    while(1) {
        sleep(SLEEPTIME);               // wait a bit
        input = tolower(get_ok_char()); // get next char
        if(input == 'y') {
            printf("yes\n");
            break; // 변경 완료 메시지를 출력하고 종료
        }
        if(input == 'n') {
            printf("no\n");
            break; // 변경 완료 메시지를 출력하고 종료
        }
        if(maxtries-- == 0) {
            printf("time out\n");
            break; // 변경 완료 메시지를 출력하고 종료
        }
        BEEP;
    }

    // 입력 모드 변경 복원
    tty_mode(1);              // 원래 모드로 복원

    return (input == 'y') ? 0 : 1;
}

int get_ok_char() {
    int c;
    while((c = getchar()) != EOF && strchr("yYnN",c) == NULL);
    return c;
}

void tty_mode(int how) {
    static struct termios original_mode;
    static int original_flags;
    if (how == 0) {
        tcgetattr(0, &original_mode);
        original_flags = fcntl(0, F_GETFL);
    } else {
        tcsetattr(0, TCSANOW, &original_mode);
        fcntl(0, F_SETFL, original_flags);
    }
}

void set_nodelay_mode() {
    int termflags;
    termflags = fcntl(0, F_GETFL);  // 현재 설정 읽기
    termflags |= O_NDELAY;          // nodelay 비트 설정
    fcntl(0, F_SETFL, termflags);   // 설정 적용
    printf("Nodelay mode is set\n"); // 모드 변경 완료 메시지 출력
    fflush(stdout);
}

void set_cr_noecho_mode() {
    struct termios ttystate;
    tcgetattr(0, &ttystate);     // 현재 설정 읽기
    ttystate.c_lflag &= ~ICANON; // 버퍼링 비활성화
    ttystate.c_lflag &= ~ECHO;   // 에코 비활성화
    ttystate.c_cc[VMIN] = 1;     // 한 번에 1 문자씩 읽기
    tcsetattr(0, TCSANOW, &ttystate);  // 설정 적용
    printf("CR-NoEcho mode is set\n"); // 모드 변경 완료 메시지 출력
    fflush(stdout);
}

int main() {
    int response;
    response = get_response(ASK, TRIES);
    printf("mode setting is finish !\n"); // 모드 변경 완료 메시지 출력
    return response;
}

터미널에서 사용자에게 여러 번의 'y/n' 질문을 하고 사용자의 응답을 처리하는 프로그램

  1. int get_response(char *question, int maxtries): 이 함수는 사용자에게 질문을 묻고, 사용자의 입력을 받아서 처리합니다. 입력을 받기 전에 터미널 모드를 변경하여 라인 버퍼링을 해제하고 입력을 에코하지 않도록 설정합니다. 사용자의 입력에 따라 "yes", "no", 또는 "time out" 메시지를 출력하고 해당 결과를 반환합니다.

  2. int get_ok_char(): 이 함수는 사용자로부터 입력을 받아서 대기 상태에 있는 입력을 처리합니다. 사용자가 "y" 또는 "n"을 입력할 때까지 대기하며, 대소문자를 구분하지 않도록 변환하여 반환합니다.

  3. void tty_mode(int how): 이 함수는 현재 터미널 모드를 저장하고, 필요한 경우 모드를 복원합니다. "how" 인수가 0이면 현재 모드를 저장하고, 1이면 저장한 모드를 복원합니다.

  4. void set_nodelay_mode(): 이 함수는 터미널 모드를 변경하여 입력 대기 시간 없이 바로 반환하도록 설정합니다. 모드가 변경되면 "Nodelay mode is set" 메시지를 출력합니다.

  5. void set_cr_noecho_mode(): 이 함수는 터미널 모드를 변경하여 라인 버퍼링을 비활성화하고 입력 에코를 비활성화합니다. 한 번에 한 문자씩 입력을 받도록 설정합니다. 모드가 변경되면 "CR-NoEcho mode is set" 메시지를 출력합니다.

  6. int main(): 먼저 get_response 함수를 호출하여 사용자와의 상호작용을 수행하고, 모드 변경이 완료된 후 "mode setting is finish !" 메시지를 출력합니다. 마지막으로 get_response 함수의 반환값을 반환합니다.

실행결과

echo 모드를 해제하여 사용자가 입력할 때는 보이진 않지만,
입력 후에는 yes/no/time out을 print하게 했다.

tcsetattr()

int result = tcsetattr(int fd, int when, struct termios *info);

when: 세팅을 적용할 시점을 설정한다

TCSANOW: 즉시 적용
TCSADRAIN: 출력 종료 후 적용
TCSAFLUSH: 출력 종료 후 적용. 변화 발생시 생긴 데이터를 버림

0개의 댓글