- 차례
- 1절. ncurses 는 무엇인가
- 2절. ncurses 프로그래밍
-
- 2.1절. ncurses 기본 이해
- 2.2절. 초기화 및 종료
- 2.3절. 색상(Color)
- 2.4절. 화면 업데이트
- 2.5절. 윈도우(Window)
- 2.3절. 색상(Color)
-
- 2.5.1절. 윈도우 생성,이동,삭제
- 2.5.2절. 윈도우주위에 테두리 만들기
- 2.5.1절. 윈도우 생성,이동,삭제
- 2.6절. 키보드 제어
-
- 2.6.1절. Function Keys
- 2.6.2절. 방향키및 특수키들
- 2.6.1절. Function Keys
- 2.7절. 문자출력
-
- 2.7.1절. 형식화된 문자열 출력
- 2.7.2절. 문자/개행 출력
- 2.7.3절. 문자/개행 삭제
- 2.7.4절. Boxes 와 Line출력
- 2.7.2절. 문자/개행 출력
- 2.7.1절. 형식화된 문자열 출력
- 2.8절. 입력
-
- 2.8.1절. 문자 / 문자열 입력
- 2.8.2절. 형식화된 입력
- 2.8.1절. 문자 / 문자열 입력
- 3절. 간단한 예제
1절. ncurses 는 무엇인가
dos 사용을 해본 사람이라면 아마도 MDIRII 라는 유명한 프로그램을 알고 있을것이다. 이 프로그램을 사용하면, 메뉴와 키보드를 이용해서 파일삭제, 복사, 편집, 내용보기 등의 작업을 굳이 명령어를 익히거나, 복잡하고 긴문장을 키보드를 이용해 일일이 타이핑하지 않아도 편리하고 빠른 작업이 가능했다. 그런 이유로 정말 많은 사랑을 받았는데, Unix 에도 이러한 편리한 환경의 구현을 도와주는 라이브러리가 있다. 그것이 바로 ncurses 라이브러 리이다.
ncurses 는 UNIX System V 에서 사용하던 curses 라이브러리를 재작성한 라이브러리로 curses 의 GNU 버젼이쯤된다. 이 라이브러리가 하는일은 일반 터미널 의 콘솔 화면에서 사용자 친화적인 Consol 윈도우 환경을 만들는 일을한다. 즉 콘솔 화면에서 메뉴바를 제어하게 한다든지, 키보드제어를 돕거나, 윈도우를 띄우는등의 작업을 한다.
대표적인 ncurses 를 사용하는 응용프로그램은 mc(Midnight Commander)이 있다. Dos 의 MDirII와 배우 비슷한 프로그램인데, 다음은 mc를 실행시킨 화면이다.
mc 는 콘솔상에서 사용자가 편하게 사용할수 있도록 풀다운 메뉴, F1-F9 와 같은 특수기, 메뉴 선택을 위한 방향키 제어, 빠른 작업을 위한 단축키, 메시지 창과 같은 윈도우 화면, 색깔 등을 제공함으로써 사용자 친화적인 환경을 구축해 준다는걸 알수 있다. 또한 vi에서와 같은 전화면 제어 기능을 제공해주며, 마우스 까지 지원해줌을 알수 있다. 그러므로써 파일관련된 여러가지 작업들을 좀더 직관적으로 처리할수 있도록 도와준다. 이러한 기능의 구현을 위해 ncurses 라이브러리를 사용하며, ncurses 는 이러한 기능의 손쉬운 구현을 위한 다양한 함수들을 제공한다.
2절. ncurses 프로그래밍
2.1절. ncurses 기본 이해
2.1.1절. 기본 구성요소
ncurses는 기본적으로 화면제어, 창(윈도우)제어, 키보드 제어로 이루어지며, 실지로 창다루는 법과 키보드 제어하는 방법, 화면제어 방법을 알면 기본적인 대부분의 응용프로그램을 만들수 있다. 마우스제어도 있겠지만, 이문서에서는 다루지 않도록 할것이다.
2.1.2절. 함수 이름 규칙
대부분의 함수는 refresh/wrefresh, printw/wprintw, bkgd/wbkgd 와 같이 'w'가 붙은것과 붙지 않은것으로 나뉜다. w가 붙은것은 윈도우를 특별히 명시하고자 할때 사용되며, 붙지 않은경우는 윈도우를 명시하지 않고, 기본윈도우(stdscr)를 사용하고자 할때 사용한다. 함수의 사용방법도 동일하며 단지 'w'가 붙은 함수일경우 윈도우를 명시하기 위해서 첫번째 아규먼트로 WINDOW 타입 포인터가 추가된다는 점이 다르다. 즉
printw("헬로 월드"); wprintw(stdscr, "헬로 월드"); |
그리고 함수명 앞에 "mv" 가 붙는 경우가 있다. mvprintw 같은 함수가 대표적인 경우인데, mv 는 move 의 약자로써, 현재 커서의 위치가 아닌 특정 위치(y,x)에 커서를 위치하고, 위치된 커서에서 작업을 하기 위해서 사용한다.
2.2절. 초기화 및 종료
X윈도우 환경에서 GUI 어플리케이션을 제작할때 가장 먼저 하는일이 바로 타이틀바, 메뉴바, 스크롤바 등이 놓이게 될 기본 윈도우를 만드는 것이다. ncurses 프로그래밍 역시 마찬가지로 가장 먼저 해야되는 일은 화면을 초기화(만드는) 하는 일이다.
보통 화면 초기화를 위해서 하는 일은 기본바탕화면을 만들고, 바탕화면의 배경색을 만들어주는 일을 한다. 가장 먼저할일은 initscr() 함수를 호출해서 화면을 초기화하는 일로, ncurses 플밍을 할때 가장 먼저 호출되는 함수이다.
종료는 단지 endwin() 함수만 호출하면 된다.
2.3절. 색상(Color)
ncurses 에서 색은 전경색과 배경색의 2가지 색상으로 이루어진다. 이는 우리가 한텀에서 글을 입력할때, 검정배경색에 하얀색의 전경색을 가지는 글자가 입력되는 것과 같은 이치이다. ncurses 에서의 모든 색은 이처럼 배경색과 전경색의 한 쌍으로 이루어지게 된다. 보통 이러한 색상은 프로그램의 일관성을 확보하기 위해서 전역으로 선언되게 된다. ncurses 는 이러한 전역적인 색상을 선언하기 위해서 init_pair() 이라는 함수를 제공한다.
int init_pair(short pair, short f, short b); |
표 1. 사용가능한 색
COLOR_BLACK | 0 |
COLOR_RED | 1 |
COLOR_GREEN | 2 |
COLOR_YELLOW | 3 |
COLOR_BLUE | 4 |
COLOR_MAGENTA | 5 |
COLOR_CYAN | 6 |
COLOR_WHITE | 7 |
init_pair(1, COLOR_WHITE, COLOR_BLUE); |
bkgd() 함수를 사용해서 배경색을 지정할수 있다. 예로 위의 init_pair 로 지정한 색중 1번을 사용하길 원한다면 bkgd(1) 로 사용하면 된다.
init_pair 로 지정한 색의 사용은 COLOR_PAIR() 라는 매크로를 이용해서 필요할때 사용하면 된다.
2.4절. 화면 업데이트
위에서 우리는 화면을 만들고, 문자를 출력했다. 그러나 화면을 만들고 문자를 출력한다고 해서 이게 바로 화면에 뿌려지는건 아니다. 화면에 대한 여러가지 변경내용을 가지고 있다가 이제 변경내용을 토대로 화면을 만들어라 라고 명령을 해야지만 화면이 업데이트 된다.
ncurses 는 가장 마지막 화면의 내용의 정보를 가지고 있다가, 화면 업데이트 명령이 떨이지면 전체 화면을 갱신하는게 아닌 변경된 창의 정보만을 갱신한다. 이로써 자원소모를 절약하고 좀더 빠른 반응속도를 보장하게 된다.
화면 업데이트를 위해서 사용하는 함수는 refresh() 와 wrefresh() 이다.
int touchwin(WINDOW *win); int refresh(void); int wrefresh(WINDOW *win); |
2.5절. 윈도우(Window)
2.5.1절. 윈도우 생성,이동,삭제
ncurses 는 다중의 윈도우 환경을 제공한다. 즉 하나의 윈도우는 또다른 윈도우를 만들수 있도록 되어있다. 윈도우가 생성되면, 그 윈도우가 생성된 원래의 윈도우가 있을것이다. 이중 초기 initscr()을 이용해서 만들어진 화면이 모든 윈도우의 부모 윈도우가 되며 모든 창은 명시적으로 이 부모윈도우 위에 만들어지게 되거나, 혹은 이미 만들어진 윈도우를 참조하는 subwindow 형태로 만들어지게 된다. 이때 참조하는 윈도우 객체는 WINDOW 타입을 가지게 되며, 특별히 기본화면을 stdscr 이라고 명시해서 사용한다. stdscr 은 기본화면을 가리킨다. 다음은 이러한 화면구성을 그림으로 나타낸 것이다.
윈도우 생성함수를 호출해서 새로운 윈도를 만들게 되면 새로만들어진 윈도우를 가리키는 WINDOW 타입에 대한 포인터를 되돌려주게 된다. 다음은 윈도우 생성을 위해 사용되는 함수들이다.
WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x); WINDOW *subwin(WINDOW *roigint nlines, int ncols, int begin_y, int begin_x); |
newwin 은 기본 화면 즉 stdscr 위에 윈도우가 생성되며, subwin 은 이미 만들어진 다른윈도우 위에 윈도우가 생성된다.
윈도우 이동을 위해서는 mvwin 을 사용한다.
int mvwin(WINDOW *win, int y, int x); |
윈도우 삭제를 위해서는 wclear 와 werase, delwin 함수가 있다.
int erase(void); int werase(WINDOW *win); int clear(void); int wclear(WINDOW *win); int delwin(WINDOW *win); |
2.5.2절. 윈도우주위에 테두리 만들기
기본적으로 새로운 윈도우가 만들어지면, 만들어진 윈도우는 테두리를 가지지 않게 된다. 이런 이유로 부모윈도우와 경계가 애매모해 해지는 결과를 가져오게 되는데, 이의 해결을 위해서 box() 라는 함수를 제공해서 만들어지는 윈도우에 박스를 그릴수 있다.
int box(WINDOW *win, chtype verch, chtype horch); |
2.6절. 키보드 제어
키보드 제어는 크게 Function Key 를 감지하는것과, 방향키, 특수키, 일반키 를 감지하는 것으로 나뉠수 있다.
2.6.1절. Function Keys
Function Keys 란 F1-F9 까지의 키를 말하며, ncurses 에서는 이러한 키를 사용자 가 눌렀는지 알수 있는 간단한 방법을 제공한다. ncurses 에서 제공하는 getch() 등의 함수를 이용해서 키입력을 받아들이면 이것이 F1-F9까지의 어떤 키값과 동일한지 확인하는 방법을 취한다.
int key=getch(); if(key==KEY_F(1)) // F1 키를 눌렀을때 { 원하는 함수를 실행 } if (key==KEY_F(2)) // F2 키를 눌렀을때 { 원하는 함수를 실행 } |
#define KEY_F0 0410 /* Function keys. Space for 64 */ #define KEY_F(n) (KEY_F0+(n)) /* Value of function key n */ |
2.6.2절. 방향키및 특수키들
방향키는 주로 메뉴의 이동을 위해서 사용되는데, 사용방법은 Function 과 비슷하다. 즉 getch()를 이용해서 입력을 받아들이고, 이입력이 키보드 이동키와 일치하는지 검사 위/아래 키일 경우 메뉴의 위아래 이동, 좌/우 키 일경우 메뉴와 메뉴사이를 이동하도록 처리를 해주는 방식이다. Function Key 와 마찬가지로 ncurses.h 에 방향키에 관련된 키값이 등록되어 있다. 이 값은 KEY_DOWN, KEY_UP, KEY_LEFT, KEY_RIGHT 등이 있다.
이외에도 ncurses 는 home, page up, page down, insert 등 의 키입력도 간단하게 확인할수 있도록 키값이 등록되어 있다.
2.7절. 문자출력
문자열입출력은 그 사용방법이 쉽고, 평이하므로 특별히 많은 설명을 하지는 않을것이다. 이러한 입출력함수들이 있다는 정도를 설명하는데에 만족하도록 할것이다.
2.7.1절. 형식화된 문자열 출력
int printw(char *fmt [, arg] ...); int wprintw(WINDOW *win, char *fmt [, arg] ...); int mvprintw(int y, int x, char *fmt [, arg] ...); int mvwprintw(WINDOW *win, int y, int x, char *fmt [, arg] ...); |
2.7.2절. 문자/개행 출력
단일 문자나 문자열의 입력과 관련된 함수들이다. 그외에도 개행과 관련된 함수도 있다.
int insch(chtype ch); int winsch(WINDOW *win, chtype ch); int mvinsch(int y, int x, chtype ch); int mvwinsch(WINDOW *win, int y, int x, chtype ch); int insertln(); int winsertln(WINDOW *win); int insstr(const char *str); int insnstr(const char *str, int n); int winsstr(WINDOW *win, const char *str); int winsnstr(WINDOW *win, const char *str, int n); int mvinsstr(int y, int x, const char *str); int mvinsnstr(int y, int x, const char *str, int n); int mvwinsstr(WINDOW *win, int y, int x, const char *str); int mvwinsnstr(WINDOW *win, int y, int x, const char *str, int n); |
2.7.3절. 문자/개행 삭제
단일문자나 줄삭제를 위해서 사용한다. 문자 삭제일 경우 커서는 왼쪽으로 한칸 이동하며, 라인 삭제일경우 커서는 위로 이동한다.
int delch(void); int wdelch(WINDOW *win); int mvdelch(int y, int x); int mvwdelch(WINDOW *win, int y, int x); |
2.7.4절. Boxes 와 Line출력
int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, chtype tr, chtype bl, chtype br); int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, chtype tr, chtype bl, chtype br); int box(WINDOW *win, chtype verch, chtype horch); |
******* +-------+ * * | | * * | | * * | | ******* +-------+ |
아래의 함수들은 수평 혹은 수직의 선을 화면에 그리기 위해서 사용한다.
int hline(chtype ch, int n); int vline(chtype ch, int n); int whline(WINDOW *win, chtype ch, int n); int wvline(WINDOW *win, chtype ch, int n); |
2.8절. 입력
키보드로 부터 문자나 문자열을 입력받기 위해서 ncurses 에서 제공하는 함수들이다. 역시 이러한 것들이 있다라는 정도만 설명하도록 하겠다.
2.8.1절. 문자 / 문자열 입력
아래의 함수들은 하나의 키보드 입력을 받아들이기 위해서 사용된다. 넘어온 값은 "KEY_" 디파인된 값들과 비교함으로써, Function key, 방향키, 특수키 입력등을 판단하기 위해서 유용하게 사용할수 있다.
int getch(void); int wgetch(WINDOW *win); int mvgetch(int y, int x); int mvwgetch(WINDOW *win, int y, int x); |
아래의 함수들은 문자열을 입력받기 위해서 사용된다. getch() 함수를 개행문자를 만날때까지 loop 돌리는 것이라고 생각할수 있다.
int getstr(char *str); int getnstr(char *str, int n); int wgetstr(WINDOW *win, char *str); int wgetnstr(WINDOW *win, char *str, int n); int mvgetstr(int y, int x, char *str); int mvwgetstr(WINDOW *win, int y, int x, char *str); int mvgetnstr(int y, int x, char *str, int n); int mvwgetnstr(WINDOW *, int y, int x, char *str, int n); |
2.8.2절. 형식화된 입력
stdio.h 의 scanf와 같은일을 한다.
int scanw(char *fmt [, arg] ...); int wscanw(WINDOW *win, char *fmt [, arg] ...); int mvscanw(int y, int x, char *fmt [, arg] ...); int mvwscanw(WINDOW *win, int y, int x, char *fmt [, arg] ...); int vw_scanw(WINDOW *win, char *fmt, va_list varglist); int vwscanw(WINDOW *win, char *fmt, va_list varglist); |
3절. 간단한 예제
그럼 지금까지의 내용을 토대로 간단한 예제프로그램을 하나 만들어 보도록 하겠다.
예제: test_ncurses.c
#include <ncurses.h> #include <stdlib.h> #include <unistd.h> #define ESCAPE 27 #define ENTER 10 char *file_item[] = {"","new", "open", "save", "save as"}; char *help_item[] = {"", "help", "about"}; WINDOW **file_menu_list(int start_col) { int i; WINDOW **items; items=(WINDOW **)malloc(5 * sizeof(WINDOW *)); items[0]=newwin(6,19,1,start_col); wbkgd(items[0], COLOR_PAIR(2)); box(items[0],ACS_VLINE, ACS_HLINE); items[1]=subwin(items[0], 1, 17, 2, start_col+1); items[2]=subwin(items[0], 1, 17, 3, start_col+1); items[3]=subwin(items[0], 1, 17, 4, start_col+1); items[4]=subwin(items[0], 1, 17, 5, start_col+1); for (i =1; i < 5; i++) wprintw(items[i], "%s",file_item[i]); wbkgd(items[1], COLOR_PAIR(1)); wrefresh(items[0]); return items; } void about_window() { WINDOW *about; about = newwin(6, 40, 5, 10); box(about, ACS_VLINE, ACS_HLINE); wmove(about, 1, 2); wprintw(about, "Ncurses Test Verson 0.1"); wmove(about, 2, 2); wprintw(about, "Made : yundream"); wmove(about, 3, 2); wprintw(about, "Date : 2001.5.2"); wmove(about, 4, 2); wprintw(about, "Press any key.. "); wbkgd(about, COLOR_PAIR(3)); refresh(); wgetch(about); delwin(about); } int check_quit() { WINDOW *check; int key; check = newwin(3, 40, 5, 10); wmove(check, 1, 2); wprintw(check, "Exit program (y/n) ? "); wbkgd(check, COLOR_PAIR(2)); box(check, ACS_VLINE, ACS_HLINE); refresh(); key = wgetch(check); delwin(check); if (key == 'y') return 1; else return 0; } WINDOW **help_menu_list(int start_col) { int i; WINDOW **items; items=(WINDOW **)malloc(3 * sizeof(WINDOW *)); items[0]=newwin(4,19,1,start_col); wbkgd(items[0], COLOR_PAIR(2)); box(items[0],ACS_VLINE, ACS_HLINE); items[1]=subwin(items[0], 1, 17, 2, start_col+1); items[2]=subwin(items[0], 1, 17, 3, start_col+1); for (i = 1; i < 3; i++) wprintw(items[i], "%s", help_item[i]); wbkgd(items[1], COLOR_PAIR(1)); wrefresh(items[0]); return items; } void delete_menu(WINDOW **items, int count) { int i; for (i = 0; i < count; i++) delwin(items[i]); free(items); } int scroll_menu(WINDOW **items,int count,int menu_start_col, int index_num) { int key; int selected=0; while (1) { key=getch(); if (key==KEY_DOWN || key==KEY_UP) { wbkgd(items[selected+1],COLOR_PAIR(2)); wnoutrefresh(items[selected+1]); if (key==KEY_DOWN) { selected=(selected+1) % count; } else { selected=(selected+count-1) % count; } wbkgd(items[selected+1],COLOR_PAIR(1)); wnoutrefresh(items[selected+1]); doupdate(); } else if (key==ESCAPE) { return -1; } else if (key==ENTER) { return selected; } } } void init_scr() { initscr(); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_WHITE); init_pair(3, COLOR_RED, COLOR_WHITE); curs_set(2); noecho(); keypad(stdscr, TRUE); } void make_menubar(WINDOW *menubar) { wbkgd(menubar, COLOR_PAIR(2)); wattron(menubar, COLOR_PAIR(3)); waddstr(menubar, "File"); wattron(menubar, COLOR_PAIR(3)); waddstr(menubar, "(a)"); wmove(menubar, 0, 20); wattron(menubar, COLOR_PAIR(3)); waddstr(menubar, "Help"); wattron(menubar, COLOR_PAIR(3)); waddstr(menubar, "(h)"); wattron(menubar, COLOR_PAIR(3)); } int main() { WINDOW *menubar, *statusbar, *about; int key; init_scr(); bkgd(COLOR_PAIR(1)); menubar = subwin(stdscr, 1, 80, 0, 0); statusbar = subwin(stdscr, 1, 79, 23, 1); make_menubar(menubar); move(2, 1); printw("Press 'a' or 'h' to open the menus. "); printw("ESC or 'q' quits."); refresh(); while(1) { WINDOW **menu_items; int selected_item; key = getch(); werase(statusbar); wrefresh(statusbar); if (key == 'a') { menu_items=file_menu_list(0); selected_item = scroll_menu(menu_items, 4, 20, 0); delete_menu(menu_items, 5); if (selected_item < 0) wprintw(statusbar, "You haven't selected any item"); else wprintw(statusbar, "You have selected menu item %d.", selected_item); touchwin(stdscr); refresh(); } if (key == 'h') { menu_items=help_menu_list(20); selected_item = scroll_menu(menu_items, 2, 0, 1); delete_menu(menu_items, 3); if (selected_item == 1) { about_window(); } if (selected_item < 0) wprintw(statusbar, "You haven't selected any item"); } if (key == ESCAPE || key == 'q') { if (check_quit() == 1) break; } touchwin(stdscr); refresh(); } endwin(); } |
[root@localhost test]# gcc -o test_ncurses test_nucrses.c -lncurses |
위의 프로그램을 컴파일해서 실행 시키면 대충 아래와 같은 모양을 가지는 프로그램이 만들어질 것이다.
'About 배우고 익히는법 > 펌글' 카테고리의 다른 글
[Linux] Serial-Programming (0) | 2013.12.31 |
---|---|
Linux] NCURSES란 ? (0) | 2013.12.31 |
[Linux] shmat - 공유메모리 관리 연산 (0) | 2013.12.31 |
[Linux] shmget - 공유메모리 영역을 할당 (0) | 2013.12.31 |
[Linux] Charater Cell Graphics (0) | 2013.12.31 |