본문 바로가기

About 배우고 익히는법/펌글

[Linux] NCURSES 프로그래밍



1절. ncurses 는 무엇인가

dos 사용을 해본 사람이라면 아마도 MDIRII 라는 유명한 프로그램을 알고 있을것이다. 이 프로그램을 사용하면, 메뉴와 키보드를 이용해서 파일삭제, 복사, 편집, 내용보기 등의 작업을 굳이 명령어를 익히거나, 복잡하고 긴문장을 키보드를 이용해 일일이 타이핑하지 않아도 편리하고 빠른 작업이 가능했다. 그런 이유로 정말 많은 사랑을 받았는데, Unix 에도 이러한 편리한 환경의 구현을 도와주는 라이브러리가 있다. 그것이 바로 ncurses 라이브러 리이다.

ncurses 는 UNIX System V 에서 사용하던 curses 라이브러리를 재작성한 라이브러리로 curses 의 GNU 버젼이쯤된다. 이 라이브러리가 하는일은 일반 터미널 의 콘솔 화면에서 사용자 친화적인 Consol 윈도우 환경을 만들는 일을한다. 즉 콘솔 화면에서 메뉴바를 제어하게 한다든지, 키보드제어를 돕거나, 윈도우를 띄우는등의 작업을 한다.

대표적인 ncurses 를 사용하는 응용프로그램은 mc(Midnight Commander)이 있다. Dos 의 MDirII와 배우 비슷한 프로그램인데, 다음은 mc를 실행시킨 화면이다.

그림 1. 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, "헬로 월드");
				
는 같은일을 한다(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);
			
첫번째 아규먼트인 pair 은 나중에 이 색을 참조할 index 번호이다. 2번째 아규먼트는 전경색 3번째 아규먼트는 배경색이다. 전경색과 배경으로 사용할수 있는 색은 다음의 8가지로, ncurses.h 에 define 되어 있다.

표 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);
			
이후로 위의 전/배경 색이 필요할경우 참조번호 1 을 사용하면 된다.

 

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);
			
touchwin 은 wrefresh 앞에 쓰이며 윈도우를 다시 그리기 위해서 사용한다. wrefresh, touchwin 은 윈도우의 내용을 다시그리고, touchwin 은 윈도우 자체를 다시 그린다는 점이 다르다. 혼동하지 않기 바란다.

 


2.5절. 윈도우(Window)

2.5.1절. 윈도우 생성,이동,삭제

ncurses 는 다중의 윈도우 환경을 제공한다. 즉 하나의 윈도우는 또다른 윈도우를 만들수 있도록 되어있다. 윈도우가 생성되면, 그 윈도우가 생성된 원래의 윈도우가 있을것이다. 이중 초기 initscr()을 이용해서 만들어진 화면이 모든 윈도우의 부모 윈도우가 되며 모든 창은 명시적으로 이 부모윈도우 위에 만들어지게 되거나, 혹은 이미 만들어진 윈도우를 참조하는 subwindow 형태로 만들어지게 된다. 이때 참조하는 윈도우 객체는 WINDOW 타입을 가지게 되며, 특별히 기본화면을 stdscr 이라고 명시해서 사용한다. stdscr 은 기본화면을 가리킨다. 다음은 이러한 화면구성을 그림으로 나타낸 것이다.

그림 2. ncurses 의 화면구성

 

윈도우 생성함수를 호출해서 새로운 윈도를 만들게 되면 새로만들어진 윈도우를 가리키는 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);
				
nlines와 ncols 는 윈도우의 크기를 결정하고, begin_y, begin_x 는 화면내에서 위도우의 위치를 결정하기 위해 사용하는 인자값이다. nlines 는 라인크기 nclols 는 컬럼크기, begin_y, begin_x 는 화면 좌표 에서의 위치이다. 화면 좌표는 모니터의 왼쪽 꼭대기가 (0,0)이며, 세로가 y축을 가로가 y 축을 나타낸다.

 

newwin 은 기본 화면 즉 stdscr 위에 윈도우가 생성되며, subwin 은 이미 만들어진 다른윈도우 위에 윈도우가 생성된다.

윈도우 이동을 위해서는 mvwin 을 사용한다.

int mvwin(WINDOW *win, int y, int x);
				
win 이 가르키는 윈도우를 y,x 화면 좌표로 이동시킨다. 윈도우가 이동할경우 기존에 있던 윈도우가 화면에 그대로 표시되게 되어서 결과적으로 눈에 는 2개의 윈도우가 보이게 된다. 그러므로 touchwin()을 사용해서 부모 윈도우 화면정보를 갱신시켜줘야 한다.

 

윈도우 삭제를 위해서는 wclear 와 werase, delwin 함수가 있다.

int erase(void);
int werase(WINDOW *win);
int clear(void);
int wclear(WINDOW *win);
int delwin(WINDOW *win);
				
함수를 보면 w가 붙은것과 그렇지 않은것이 있는데, w가 안붙는 것은 제어할 윈도우가 기본화면 즉 stdscr 이다. werase 는 wclear 은 윈도우를 하얀색 공백으로 채워버린다. 화면을 지워 버린다고 생각하면 될것이다. delwin 윈도우 객체를 소멸시키고자 할때 사용한다.

 


2.5.2절. 윈도우주위에 테두리 만들기

기본적으로 새로운 윈도우가 만들어지면, 만들어진 윈도우는 테두리를 가지지 않게 된다. 이런 이유로 부모윈도우와 경계가 애매모해 해지는 결과를 가져오게 되는데, 이의 해결을 위해서 box() 라는 함수를 제공해서 만들어지는 윈도우에 박스를 그릴수 있다.

int box(WINDOW *win, chtype verch, chtype horch);
				
첫번째 아규먼트로 윈도우객체를 가르키는 WINDOW 포인터가 오고, 그다음에 가로와 세로의 경계선 스타일이 온다. verch 는 세로 경계선 스타일, 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 키를 눌렀을때 
{
    원하는 함수를 실행
} 
				
KEY_F는 ncurses.h 에 등럭되어 있는 메크로 함수로 다음과 같은 모양을 가진다.
#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] ...);
				
여기에 있는 함수들은 stdio.h 에서 제공하는 printf(3) 와 같은 일을한다. 형식화된 출력을 담당한다. printw와 wprintw 는 현재 커서에, mvprintw, mvwprintw 는 y, x 좌표로 커서를 옮겨서 출력한다.

 


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);
				
ch 가 붙은 함수는 단일 문자 입력, str 은 문자열입력과 관련된 함수들이다. ln 이 붙은 함수는 개행문자 입력관련 함수이다.

 


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);
				
boder, wboder, box 는 윈도우 경계를 구분하기 위한 테두리를 만들때 사용한다. box 를 사용할경우 기본적으로 사용되는 테두리 라인을 이용하며, border,wborder 을 사용할경우 사용자 정의 테두리 문자를 지정할수 있다. 즉 border 을 사용하면 다음과 같은 테두리를 구성할수 있다.
 *******   +-------+
 *     *   |       |
 *     *   |       |
 *     *   |       |
 *******   +-------+
 				

 

아래의 함수들은 수평 혹은 수직의 선을 화면에 그리기 위해서 사용한다.

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);
				
이 함수들을 사용하면 현재 커서가 위치하는 곳에서 수직/수평 선을 그린다. ch 는 선을 그리기 위해서 사용할 문자이며, 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);
				
'w' 가 붙은것들은 win 이 가르키는 창에서 입력을 받는다. getstr, getnstr 과 같이 'n' 이 붙은것들과 그렇지 않은 것들이 있는데, 'n'이 들어간 함수는 int n 크기만큼만 입력을 받는다. 버퍼 오버플로 를 막기 위해서는 'n' 이 들어간 함수를 사용하도록 하자. "mv"가 앞에 붙은 함수는 입력 위치가 현재커서가 아닌 현재커서에서 y, x 만큼 움직인 위치에서 입력을 받는다.

 


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
		

 

위의 프로그램을 컴파일해서 실행 시키면 대충 아래와 같은 모양을 가지는 프로그램이 만들어질 것이다.

그림 3. test_ncurses 실행화면