일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- termcap
- 서버 프로그래밍
- pipe buffer
- 클래스 상속
- 명령어
- kevent
- 레지스터
- 멀티플렉싱
- canonical
- lseek
- 가상상속
- 터미널제어
- opcode
- getch
- 어셈블리어
- 터미널 제어
- multiplexing
- MAN
- 커서 제어
- Assembly
- 가상 상속
- IPC
- 프롬프트
- 터미널 커서
- kqueue
- virtual 상속
- cursor
- UNIX
- nonblock
- termios
- Today
- Total
오늘도 밤이야
[UNIX] 개행 없이 한 글자씩 입력받는 getch() 만들기 (터미널 제어) 본문
프롬프트 또는 콘솔 환경을 만들기 위해서 키보드 입력을 한 자씩 받아야할 때가 있다. unistd.h의 read함수를 STDIN에서 1바이트만큼 받으면 되지 않을까? 해서 다음과 같은 코드를 실행해보았다.
#include <unistd.h>
#include <stdio.h>
int main(void)
{
char c;
while (read(0, &c, sizeof(c)) > 0)
{
printf("input: %c\n", c);
}
}
read는 분명 1byte씩 잘 읽고 있다. 그렇다면 왜 return이 입력되기 전에는 계속 입력만 받고 있을까?
이는 터미널의 canonical input 설정 때문이다. 한 line(line의 기준은 '\n'이다) 단위로 읽기 때문에 read()가 몇 byte로 읽든 newline이 입력되기 전까지 실시간으로 읽어주지 않는다.
터미널 제어 함수를 통해 설정을 바꿔보자!
<termios.h>와 함께라면 터미널 설정을 바꿀 수 있다.
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
char c;
struct termios term;
tcgetattr(STDIN_FILENO, &term);
term.c_lflag &= ~ICANON; // non-canonical input 설정
term.c_lflag &= ~ECHO; // 입력 시 터미널에 보이지 않게
term.c_cc[VMIN] = 1; // 최소 입력 버퍼 크기
term.c_cc[VTIME] = 0; //버퍼 비우는 시간 (timeout)
tcsetattr(STDIN_FILENO, TCSANOW, &term);
while (read(0, &c, sizeof(c)) > 0)
{
printf("input: %c\n", c);
}
}
먼저 터미널 설정을 받아오고 수정할 termios 구조체를 선언한다. tcgetattr()를 통해 STDIN의 설정을 받아오고, lflag와 c_cc를 수정해준다. 수정된 값은 tcsetattr()를 통해 반영시킬 수 있다.
~ICANON, ~ECHO와 현재 lflag를 연산해주어 canonical input 설정과 ECHO (키보드 입력을 터미널에 보여주는) 설정을 비활성화 해준다.
non-canonical input에서는 VMIN과 VTIME을 가지고 입력 프로세스 기준을 설정하는데, VMIN은 최소 입력 버퍼의 크기이다. 만약 3의 값으로 설정할 경우 3자를 입력받고 나서 가장 먼저 입력된 것을 처리한다. VTIME은 버퍼를 비워주는 timeout 시간이다. 설정된 시간만큼 입력이 없으면 입력 버퍼에 있던 값들을 처리해준다. 지금은 한 자씩 즉시 처리해야하므로 VMIN과 VTIME을 각각 1과 0으로 설정해준다.
실행 결과
'긴 글 읽어주셔서 감사합니다. 잘못된 정보나 수정 사항, 질문 등은 댓글로 남겨주셔주시면 감사하겠습니다!'
참고 자료
'UNIX' 카테고리의 다른 글
[UNIX] kqueue man page (macOS - BSD) 번역 (0) | 2021.07.11 |
---|---|
[UNIX] I/O Multiplexing을 위한 kqueue 사용법 (2) | 2021.07.11 |
[UNIX] pipe(2) 더 잘 알고 활용하기 (0) | 2021.07.10 |
[UNIX] termcap 라이브러리를 이용한 커서 제어 (4) | 2021.03.28 |