[제6장] curses
=================================================================
* Subject : [제6장] curses
* Writer: w0rm9 (research.hackerschool.org)
* Date: 2004/01/29
=================================================================
/* 스터디할때 졸아서 로그를 바탕으로 정리했고, 테스트는 책에 있는 소스를 중심으로 했습니다.
* 그리고 스터디 시간에 하지 않았던 뒷부분은 대부분은 생략했습니다.
*/
0x01. 기본개념
■ 초기화와 종료
사용법)
#include <curses.h>
WINDOW *initscr(void);
int endwin(void);
=> 모든 curses 프로그램은 initscr로 시작하고, endwin으로 끝나야 한다.
테스트)
[w0rm9@work CURSES]$ cat hello.c
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main() {
initscr();
move(5, 15); // 좌표 (5, 15)로 커서를 이동함
printw("%s", "Hello World");
refresh(); ///화면을 갱신
sleep(2);
endwin();
exit(EXIT_SUCCESS);
}
[w0rm9@work CURSES]$ gcc -o hello hello.c -lcurses
[w0rm9@work CURSES]$ ./hello
Hello World
■ 화면에 출력하는 함수들
사용법)
#include <curses.h>
int addch(const chtype char_to_add);
int addchstr(chtype *const string_to_add);
int printw(char *format, ...);
int refresh(void);
int box(WINDOW *win_ptr, chtype vertical_char, chtype horizontal_char);
int insch(chtype char_to_insert);
int insertln(void);
int delch(void);
int deleteln(void);
int beep(void);
int flash(void);
=> add..계열 함수는 지정된 문자나 스트링을 출력함
printw 함수는 printf랑 유사
box 함수는 윈도우 주변에 사각형을 그리게 한다
intsch 함수는 기존의 문자를 오른쪽으로 이동시키며 문자를 삽입함
insertln 함수는 기존의 줄을 아래로 이동시키며 빈줄을 삽입함
■ 화면에서 읽어들이기
사용법)
#include <curses.h>
chtype inch(void);
int instr(char *string);
int innstr(char *string, int number_of_characters);
=> inch 함수는 현재 화면에서 커서 위치로부터 문자와 속성 정보를 반환함
instr, innstr 함수는 화면으로부터 문자를 읽어들인다.
■ 화면지우기
사용법)
#include <curses.h>
int erase(void);
int clear(void);
int clrtobot(void);
int clrtoeol(void);
=> erase 함수는 모든 화면 위치에 빈 칸을 출력한다.
clear 함수는 화면을 지운다.
clrtobot 함수는 커서 위치로부터 앞으로 이동하며 화면을 지운다.
clrtoeol 함수는 커서로부터 뒤로 이동하며 줄의 마지막까지를 지운다.
■ 커서 이동시키기
사용법)
#include <curses.h>
int move(int new_y, int new_x);
int leaveok(WINDOW *window_ptr, bool leave_flag);
=> move 함수는 커서 위치를 지정된 위치로 이동시킨다.
leaveok 함수는 화면 갱신 후에 커서를 남겨둘 곳을 제어하는 플래그를 설정한다.
■ 문자 속성
사용법)
#include <curses.h>
int attron(chtype attribute);
int attroff(chtype attribute);
int attrset(chtype attribute);
int standout(void);
int standend(void);
=> attrset 함수는 curses 속성을 설정하고, attron과 attroff는 지정된 속성을 설정하거나 취소한다.
standout 함수와 standend 함수는 출력 결과를 반전한다.
테스트)
[w0rm9@work CURSES]$ cat moveadd.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main()
{
const char witch_one[] = " wiseguys forver! ";
const char witch_two[] = " I'm babo w0rm9 ";
const char *scan_ptr;
initscr();
move(5, 15);
attron(A_BOLD);
printw("%s", "===== A_BOLD attribute =====");
attroff(A_BOLD);
refresh();
sleep(1);
move(8, 15);
attron(A_DIM);
printw("%s", "====== A_DIM attribute =====");
attroff(A_DIM);
refresh();
sleep(1);
attron(A_DIM);
scan_ptr = witch_one + strlen(witch_one + 1);
while(scan_ptr != witch_one) {
move(10,10);
insch(*scan_ptr--);
}
scan_ptr = witch_two + strlen(witch_two + 1);
while (scan_ptr != witch_two) {
move(13, 10);
insch(*scan_ptr--);
}
attroff(A_DIM);
refresh();
sleep(1);
endwin();
exit(EXIT_SUCCESS);
}
[w0rm9@work CURSES]$ gcc -o moveadd moveadd.c -lcurses
[w0rm9@work CURSES]$ ./moveadd
===== A_BOLD attribute =====
====== A_DIM attribute =====
wiseguys forver!
I'm babo w0rm9
0x02. 키보드
■ 키보드 모드
사용법)
#include <curses.h>
int echo(void);
int noecho(void);
int cbreak(void);
int nocbreak(void);
int raw(void);
int noraw(void);
=> 두 echo 함수는 입력된 문자의 반향을 설정하고 취소한다.
cbreak 함수는 curses에서 initscr()로 초기화를 하면 기본적으로 입력 모드가 cooked mode로 실행되는데
이 모드는 입력 동작이 줄 단위로 수행되기 때문에 사용자가 엔터를 입력하지 않으면 그 입력은 무의미하게 되죠
그런데 cbreak()를 호출해서 입력모드를 cbreak mode로 전환하게 되면 단 한문자만이라도 입력하는
즉시 프로그램이 반응을 할 수 있다. 단점은 특수문자를 입력할 수 없다.
raw 함수는 특수 문자 처리 여부를 결정한다.
noraw 함수는 가공모드와 특수 문자 처리를 모두 복구한다.
■ 키보드 입력
사용법)
#include <curses.h>
int getch(void);
int getstr(char *string);
int getnstr(char *string, int number_of_characters);
int scanw(char *format, ...);
테스트)
[w0rm9@work CURSES]$ cat ipmode.c
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#define PW_LEN 25
#define NAME_LEN 256
int main() {
char name[NAME_LEN];
char password[PW_LEN];
char *real_password = "babo-_-";
int i = 0;
initscr();
move(7, 10);
printw("%s", "User name: ");
getstr(name);
move(9, 10);
printw("%s", "Password: ");
refresh();
cbreak();
noecho();
memset(password, '\0', sizeof(password));
while (i < PW_LEN) {
password[i] = getch();
move(9, 20 + i);
addch('*');
refresh();
if (password[i] == '\n') break;
if (strcmp(password, real_password) == 0) break;
i++;
}
echo();
nocbreak();
move(11, 10);
if (strcmp(password, real_password) == 0) printw("%s", "Correct");
else printw("%s", "Wrong");
refresh();
endwin();
exit(EXIT_SUCCESS);
}
[w0rm9@work CURSES]$ !gcc
gcc -o ipmode ipmode.c -lcurses
[w0rm9@work CURSES]$ ./ipmode
User name: w0rm9
Password: *******
Correct
0x03. 윈도우
■ WINDOW 구조체
사용법)
#include <curses.h>
WINDOW *newwin(int num_of_lines, int num_of_cols, int start_y, int start_x);
int delwin(WINDOW *window_to_delete);
=> newwin 함수는 윈도우를 생성하고, delwin 함수는 파괴한다.
■ 일반형 함수들
사용법)
#include <curses.h>
int addch(const chtype char);
int waddch(WINDOW *window_pointer, const chtype char);
int mvaddch(int y, int x, const chtype char);
int mvwaddch(WINDOW *window_pointer, int y, int x, const chtype char);
int printw(char *format, ...);
int wprintw(WINDOW *window_pointer, char *format, ...);
int mvprintw(int y, int x, char *format, ...);
int mvwprintw(WINDOW *window_pointer, int y, int x, char *format, ...);
■ 윈도우 이동시키고 갱신하기
사용법)
#include <curses.h>
int mvwin(WINDOW *window_to move, int new_y, int new_x);
int wrefresh(WINDOW *window_ptr);
int wclear(WINDOW *window_ptr);
int werase(WINDOW *window_ptr);
int touchwin(WINDOW *window_ptr);
int scrollok(WINDOW *window_ptr, bool scroll_flag);
int scroll(WINDOW *window_ptr);
=> mvwin 함수는 윈도우를 이동시킨다.
touchwin 함수는 화면에서 여러 개의 겹치는 윈도우를 가질 때 출력할 윈도우를 정렬하는 경우 쓰인다.
테스트)
[w0rm9@work CURSES]$ cat mulwin.c
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main()
{
WINDOW *new_window_ptr;
WINDOW *popup_window_ptr;
int x_loop;
int y_loop;
char a_letter = 'a';
initscr();
move(5, 5);
printw("%s", "Testing multiple windows");
refresh();
for (x_loop = 0; x_loop < COLS - 1; x_loop++) {
for (y_loop = 0; y_loop < LINES - 1; y_loop++) {
mvwaddch(stdscr, y_loop, x_loop, a_letter);
a_letter++;
if (a_letter > 'z') a_letter = 'a';
}
}
refresh();
sleep(2);
new_window_ptr = newwin(10, 20, 5, 5);
mvwprintw(new_window_ptr, 2, 2, "%s", "Hello World");
mvwprintw(new_window_ptr, 5, 2, "%s",
"Notice how very long lines wrap inside the window");
wrefresh(new_window_ptr);
sleep(2);
a_letter = '0';
for (x_loop = 0; x_loop < COLS - 1; x_loop++) {
for (y_loop = 0; y_loop < LINES -1; y_loop++) {
mvwaddch(stdscr, y_loop, x_loop, a_letter);
a_letter++;
if (a_letter > '9') a_letter = '0';
}
}
refresh();
sleep(2);
wrefresh(new_window_ptr);
sleep(2);
touchwin(new_window_ptr);
wrefresh(new_window_ptr);
sleep(2);
popup_window_ptr = newwin(10, 20, 8, 8);
box(popup_window_ptr, '|', '-');
mvwprintw(popup_window_ptr, 5, 2, "%s", "Pop Up Window!");
wrefresh(popup_window_ptr);
sleep(2);
touchwin(new_window_ptr);
wrefresh(new_window_ptr);
sleep(2);
wclear(new_window_ptr);
wrefresh(new_window_ptr);
sleep(2);
delwin(new_window_ptr);
touchwin(popup_window_ptr);
wrefresh(popup_window_ptr);
sleep(2);
delwin(popup_window_ptr);
touchwin(stdscr);
refresh();
sleep(2);
endwin();
exit(EXIT_SUCCESS);
}
직접 컴팔해서 실행보세요-_-/
0x04. 서브 윈도우
다중 윈도우와 비슷함-_-;
사용법)
#include <curses.h>
WINDOW *subwin(WINDOW *parent, int num_of_lines, int num_of_cols, int start_y, int start_x);
int delwin(WINDOW *window_to_delete);
0x05. 키패드
기능키에 대한 내용-_-
사용법)
#include <curses.h>
int keypad(WINDOW *window_ptr, bool keypad_on);
테스트)
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#define LOCAL_ESCAPE_KEY 27
int main()
{
int key;
initscr();
crmode();
keypad(stdscr, TRUE); //키보드를 읽어들일 때 처리된 키와 함께 논리키 KEY_ 정의를 반환한다.
noecho();
clear();
mvprintw(5, 5, "Key pad demonstration. Press 'q' to quit");
move(7, 5);
refresh();
key = getch();
while(key != ERR && key != 'q') {
move(7, 5);
clrtoeol();
if ((key >= 'A' && key <= 'Z') ||
(key >= 'a' && key <= 'z')) {
printw("Key was %c", (char)key);
}
else {
switch(key) {
case LOCAL_ESCAPE_KEY: printw("%s", "Escape key"); break;
case KEY_END: printw("%s", "END key"); break;
case KEY_BEG: printw("%s", "BEGINNING key"); break;
case KEY_RIGHT: printw("%s", "RIGHT key"); break;
case KEY_LEFT: printw("%s", "LEFT key"); break;
case KEY_UP: printw("%s", "UP key"); break;
case KEY_DOWN: printw("%s", "DOWN key"); break;
default: printw("Unmatched - %d", key); break;
}
}
refresh();
key = getch();
}
endwin();
exit(EXIT_SUCCESS);
}
컴팔해서 실행해보면 이해됨-_-/
0x06. 색
말그대로 터미널에서 컬러사용하는거...생략...
p.298 참고
0x07. 패드
논리 화면 정보를 관리하는 특별한 테이터 구조체 pad에 대한 설명
p.302 참고
_eof_
