Unix/Linux 화면조작 (curses.h) http://blog.naver.com/neutrino37/110009868351 http://blog.naver.com/iku88/120019415939 출처 : http://blog.naver.com/kamvo.do?redirect=log&logno=60003596240 제 10 장화면조작 10.1. 서론 CRT/VDU 단말기의화면을다루는도구들을소개한다. 화면을다루는도구에는밀접하게관련된두개의 C 라이브러리가있다. 1. curses 이것은하드웨어에의존하지않고화면을조작하는방법이다. 이라이브러리는단말기의하드웨어에무관한자료구조인윈도우 (window) 를제공한다. curses 라는이름역시최적화커서이동 ( cursor motion optimization ) 에서따온것이다. 이것은 AT&T 시스템 V 인터페이스정의 (SVID) 의 Issue 2 에정의되어있다. 2. terminfo 이라이브러리는 curses 와는달리하드웨어와밀접한연관성을가진루틴을제공한다. terminfo 역시 SVID 의 Issue 2 에정의되어있다. curses 와 terminfo 둘다, 현재의버전은 terminfo 라는각각의단말기의특성을기록해두는데이타베이스 (database) 를사용한다. /usr/lib/terminfo/<c>/<name> <name> 은실제단말기의이름이고 <c> 는 <name> 의첫글자이다. /usr/lib/terminfo/v/vt100 은단말기 vt100 의특성들을기록해두는화일이다. curses 와 terminfo 의루틴들은먼저환경변수 (environment variable) TERM 을보고단말기의이름을알아낸다음, terminfo 데이타베이스에서그단말기에대응하는화일을찾는다. termcap 라이브러리 terminfo 는 AT&T 에서새로이만들어낸것이다. 어떤 UNIX 시스템에서는 terminfo 대신 termcap 이나 termlib 가있을수도있다. termcap 은단말기명세가 /etc/termcap 이라는화일에기록되어있다. 새로운단말기에대한명세를만들려면그화일을사용자가편집 (edit) 하면된다. 소프트웨어개발을쉽게하기위해 terminfo 라이브러리는 termcap 라이브러리보다상위의호환성을가진다. 10.2. curses 라이브러리 : 개요 프로그래머는윈도우라는자료구조를통해서모든작업을하게된다. 윈도우의자료형은 WINDOW 인데, 이것은표준인크루드화일 (standard include file) 인 curses.h 에정의가되어있다. 프로그래머는 newwin 이라는루틴을사용해서새로운윈도우를만들수있다. 그리고전역에서사용할수있는표준윈도우 stdscr 도있다. curses 에대해자세하게설명하기전에두가지점을먼저지적하고넘어가려고한다. 1. curses 의루틴들이자동적으로프로그램과링크되는것은아니다. 따라서컴파일할때, 사용자가링크시켜야한다.
$cc -o scrnprog scrnprog.c -lcurses terminfo 에대해서도같은방법으로링크한다. 2. curses 는 C 언어의매크로 (macro) 를이용해서정의되는것이많다. 따라서프로그래머는그것들을사용할때주의해야한다. 그리고컴파일시예상치못한오류메시지에대비해야한다. 10.3. curses 의일반적인구조 모든 curses 프로그램은기본적인구조로구성된다. main() { initscr(); /* main body */ endwin(); exit(0); } curses.h 는 curses 루틴을사용하는모든프로그램에항상포함 (include) 되어야한다. 시스템 V 에서는 curses.h 에헤드화일 terminfo.h 가자동적으로포함된다. curses.h 에는 curses 의자료구조와중요한매크로들이들어있다. initscr 루틴은모든 curses 함수에앞서서수행시켜야한다. 이루틴은 curses 의자료구조를초기화하고 UNIX 환경의 TERM 변수를통하여단말기의종류를결정한다. 그렇게함으로서원래의단말기상태로돌아갈수있고커서는맨아래왼쪽에위치하게된다. main() { initscr(); refresh(); endwin(); } refresh 또는더일반적인버전인 wrefresh 를수행시켜야만윈도우의내용이실제화면 (physical screen) 에나타나게된다. refresh 는표준윈도우 stdscr 의내용을실제화면에표시하고, wrefresh 는특정윈도우의내용을실제화면에표시한다. 10.4. 모드지정 curses 루틴을사용하는프로그램에서는 initscr 을수행시킨다음단말기의입출력모드를지정한다. echo(); /* enable echoing */ noecho(); /* disable echoing */ 단말기의반향 (echo) 기능을작동시키거나정지시킬수있다. 디폴트 (default) 로는반향기능을작동시킨다. nl(); /* enable CR-NL mappings */
monl(); /* disable mappings */ nl 은출력시개행문자 (newline) 가 newline/ carriage-return 으로바뀌어서출력되거나, 입력시 newline/carriage-return 이개행문자로바뀌어서입력된다. default 는 nl 이다. cbreak(); /* enable CBREAK mode */ nocbreak(); /* disable CBREAK mode */ cbreak 는입력시, 인터럽트 (interrupt) 와흐름제어키 (flow control key) 를제외하고는입력자료에어떠한작용도가하지않는다. raw(); /* enable RAW mode */ noraw(); /* disable RAW mode */ raw 는단말기를 RAW 모드로만든다. 이모드는 CBREAK 모드와비슷하다. savetty(); /* save tty state */ resetty(); /* reset tty state */ 단말기의상태를저장하거나복구시킬수있다. savetty 는현재단말기상태를 curses 의내부버퍼에저장해준다. restty 는바로전에 savetty 로저장해둔상태를복구시킨다. 10.5. 문자와문자열쓰기 curses 는윈도우 stdscr 에문자와문자열을쓰는 4 개의루틴을제공한다. addch, mvaddch, addstr, mvaddstr 이다. int c, y, x; char *string; addch(c); mvaddch(y, x, c); addstr(string); mvaddstr(y, x, string); addch 루틴은 stdscr 상의현재커서위치에문자 c 를쓴다. refresh 를해주어야만실제화면에나타난다. CTRL-C 는 ^C 처럼쓰인다. mvaddch 루틴은커서를세로로 y 번째줄, 가로로 x 번째열로움직인후에글자를쓴다. 맨윗줄왼쪽이좌표 (0,0) 이다. addstr 과 mvaddstr 은 0 으로끝나는문자열 string 을윈도우 stdscr 에쓴다. 10.6. 형식화된출력 curses 에는 C 언어의 printf 와비슷한기능을제공하는루틴들이있다. 표준윈도우 stdscr 에쓰이는루틴들로는 printw 와 mvprintw 가있다. char *fmt; int y, x; /* NB arg0, arg1... argn have arbitrary type */ printw(fmt, arg0, arg1,... argn);
mvprintw(y, x, fmt, arg0, arg1,... argn); 10.7. 커서이동 move 명령을사용하여표준윈도우 stdscr 위에서커서를움직일수있다. int y, x; move(y, x); 매개변수 y 와 x 를사용하여새로운좌표에커서를위치시킬수있다. refresh 가수행되어야만실제커서위치가바뀐다. getyx 루틴을사용하여커서의현재위치를알수있다. int y, x; WINDOW *w; getyx 는 WINDO 에대한포인터가첫번째변수로주어져야한다. 첫번째변수로표준화면인 stdscr 을사용하면표준화면상의현재커서위치를얻을수있다. 수행결과는 y 와 x 변수에주어진다. getyx 가실제 C 함수가아니라매크로 (macro) 이기때문에가능한것이다. 10.8. 키보드입력 : getch curses 에서키보드로부터하나의문자를받아들일경우에 getch 를사용한다. getch 는 C 언어의 getc 루틴처럼정수값을돌려준다. int in_ch; in_ch = getch(); 기능키입력처음해야하는작업은 curses keypad 루틴을수행시켜서단말기의키패드 (keypad) 를초기화시키는것이다. keypad(stdscr, TRUE); 특수키는 curses.h 에정의된값을통해돌려준다. ASCII 값과의충돌을막기위해이값들은 8 진수 401 부터시작된다. int in_ch; in_ch = getch(); switch(in_ch) { case KEY_DOWN; /* down arrow key processing */
case KEY_UP; /* up arrow key processing */ } 10.9. 화면입력 : inch stdscr 의특정위치에어떤문자가있는지알아야될경우가있다. inch 는화면의현재커서위치에있는문자를돌려준다. 그리고 mvinch 는주어진위치의문자를돌려준다. int in_ch; in_ch = inch(); in_ch = mvinch(y, x); 화면상의글자에는하이라이트타입 (highlight type) 같은속성 (attribute) 을지닌경우가있다. 이때실제문자만을얻고싶으면 curses.h 에서정의된상수 A_CHARTEXT 와비트단위 AND 를해야한다. cvalue = ivalue & A_CHARTEXT; 10.10. 화면편집 이미그려진화면을변화시켜야하는경우가종종있다. curses 에는이러한경우에유용한여러가지루틴들이있다. 이러한루틴들을 3 가지로구분할수있다. 화면을백지화 (clear) 시키는것, 문자들을지우고화면을재구성하는것, 화면을전혀지우는것없이문자를끼워넣는것등이있다. stdscr 상에서화면의일부분을지우는루틴 erase(); clear(); clrtobot(); clrtoeol(); erase 와 clear 은둘다표준윈도우 stdscr 의모든위치에공백 (space) 을쓴다. 다른점은 clear 는또한다음번 refresh 가호출될때화면을자동적으로백지화시킨다는점이다. clrtobot 는현재줄의커서오른쪽에있는모든문자와커서아래에있는모든줄을지운다. clrtoeol 은현재줄에서커서의오른쪽에있는모든문자를지운다. 화면상의문자들을지울뿐만아니라문자를지우면서생긴공백을메꾸기위해서화면을이동시키는루틴 int y, x; delch();
mvdelch(y, x); deleteln(); delch 의경우현재커서위치에있는문자가지워진다. 그리고그공백을메꾸기위해커서의오른쪽에있는문자들을한칸씩왼쪽으로이동시킨다. mvdelch 도기능이거의같다. 다만먼저커서를주어진위치에이동시킨다음 delch 와같은기능을수행한다. deleteln 은커서가있는줄을지운다. 그리고나서그줄밑에있던모든줄을한칸씩위로이동시킨다. 문자를끼우는데관련된루틴 int c, y, x; insch(c); mvinsch(y, x, c); insertln(); insch 는현재위치에문자 c 를끼운다. 현재커서위치의오른쪽에있는글자들은모두한칸씩오른쪽으로이동한다. 그줄의마지막에있는문자는잃어버리게된다. mvinsch 는커서의위치를바꾼다음 insch 와같은작용을한다. insertln 은커서가있는줄의위에빈줄 (blank line) 을하나집어넣는다. 그줄밑에있는줄들은모두한줄씩밑으로이동한다. 따라서화면의맨밑에있던줄은화면상에서사라지게된다. 10.11. 영상속성 curses 에서는특정모드로글자를화면에나타내고싶으면그모드에해당하는상수와비트단위 OR 하면된다. addch(ch A_BOLD); 는 ch 를볼드체 (bold; 주위의글들보다더밝은모드 ) 로나타낸다. 이외에도여러가지모드가있다. A_STANDOUT 이모드는글자를집중모드로나타낼때쓰인다. A_REVERSE 역전모드 A_BOLD 글자들이보울드로나타난다. A_DIM 글자들이기본모드보다약간어둡게나타난다. A_UNDERLINE 글자밑에밑줄이그어진형태로나타난다. A_BLINK 글자들이반짝인다. int atts; attrset(atts); attron(atts); attroff(atts); standout(); standend(); attrset 은표준화면상에서모드를작동시킬때사용하는루틴이다. attron 루틴은 atts 에주어진모드들을작동시킨다. 이루틴은앞에서지정된모드를바꾸지는않는다. 마찬가지로 attroff 는선택된모드를해제한다.
그리고두루틴 standout 와 standend 는각각 attron(a_standout) 와 attroff(a_standout) 와동일한기능을한다. 10.12. 새윈도우화면의생성과조작 새로운윈도우를다루는방범을소개한다. 윈도우를위한가장기본적인루틴은 newwin 이다. WINDOW *win; int lines, cols, startline, startcol; win = newwin(lines, cols, startline, startcol); 이루틴을수행시키면세로크기가 lines, 가로크기가 cols 인윈도우가생긴다. wmove(win, y, x); 이루틴을수행하면윈도우 win 상의현재커서위치가좌표 (x,y) 로바뀌게된다. 이좌표는표준윈도우 stdscr 표가아니라윈도우 win 의맨윗줄맨왼쪽을기준으로한좌표이다. wrefresh(win); 은윈도우 win 에있는내용들이실제화면에나타난다. 10.13. curses 예 : domenu -- 생략 10.14. 하드웨어의존단말기조정 : terminfo terminfo 라이브러리는프로그래머가직접단말기의하드웨어를직접제어하는기능을제공한다. terminfo 데이타베이스에는각단말기의특성을얻을수있다. 가장크게문제가발생하는경우가패딩 (padding, 속도늦춤 ) 을할때다. 이단어는단말기가프로그램의속도를적당히유지하도록출력속도를늦추는것을의미한다. #include <term.h> main() { setupterm(0, 1, 0); putp(clear_screen); reset_shell_mode(); exit(0); } 화면을백지시키는프로그램이다. term.h 에는 clear_screen 을포함하여여러가지기능을나타내는매크로들이정의되어있다. setr- pterm 은 termino 의초기화루틴이다. putp 을호출하면화면을백지화시키기는문자열을화면에내보낸다. putp 는좀더일반적인기능을갖는루틴 tputs 의제한된버전이다.
reset_shell_mode 는단말기를원래의상태로되돌린다.