分类: LINUX
2011-07-14 18:58:04
1. curses 的历史与版本:
cureses 最早是由柏克莱大学的 Bill Joy 及 Ken Arnold 所发展出来的. 当时发展此一函式库主要原因是为了提高程式对不同终端机的相容性而设计的. 因此, 利用 curses 发展出来的程式将和您所使用的终端机无关. 也就是说, 您不必担心您的程式因为换了一部终端机而无法使用. 这对程式设计师而言, 尤其是网路上程式的撰写, 是件相当重要的一件事. curses之所以能对上百种以上的终端机工作, 是因为它将所有终端机的资料, 存放在一个叫 termcap 的资料库, ( 而在第二版的 System V 系统中, 新版的 curses 以 terminfo 取代原来的 termcap).
有了这些记录, 程式就能够知道遇到哪一种终端机时, 须送什麽字元才能移动游标的位置, 送什麽字元才能清除整个萤幕清除. (* 注一)
另外, 本文的介绍 以 System V 的 curses 版本为主.
2. 如何在您的程式使用 curses:
在您的 C 程式的档头将
另外, 在 System V 版本中,
#include
main()
{
: :
: :
}
3. 如何编译(compile):
当您编辑好您的程式, 在 UNIX 提示符号下键入:
gcc [file.c] -lcurses
或
gcc [file.c] -lcurses -ltermlib(*注二)
4. 如何开始我的第一个 curses 程式:
在开始使用 curses 的一切命令之前, 您必须先利用 initscr()这个函式来开启 curses 模式.
相对的, 在结束 curses 模式前 ( 通常在您结束程式前 ) 也必须以endwin()来关闭 curses 模式.
#include <curses.h>
main()
...{
initscr();
: :
: :
: :
endwin();
} 

这是一般 curses 程式标准的模式.
此外, 您可以就您程式所须, 而做不同的设定. 当然, 您可以不做设定,而只是呼叫 initscr(). 您可以自己写一个函式来存放所有您所须要的设定. 平常使用时, 只要呼叫这个函式即可启动 curses 并完成一切设定. 下面的例子, 即是笔者将平常较常用的一些设定放在一个叫 initial()的函式内.
void initial()
...{
initscr();
cbreak();
nonl();
noecho();
intrflush(stdscr,FALSE);
keypad(stdscr,TRUE);
refresh();
}

各函式分别介绍如下:
5. 游标的控制:
6. 有关清除萤幕的函式:
clear() and erase(): 将整个萤幕清除. (请注意配合refresh() 使用)
7. 如何在萤幕上显示字元:
8. 如何从键盘上读取字元:
例:
int ch;
char string1[80]; /**//* 请注意! 不可宣告为 char *string1; */
char string2[80];
echo(); /**//* 开启 echo 模式, 使输入立刻显示在萤幕上 */
ch=getch();
string1=getstr();
scanw("%s",string2);
mvprintw(10,10,"String1=%s",string1);
mvprintw(11,10,"String2=%s",string2);
9. 如何利用方向键:
curses 将一些如方向键等特殊控制字元, 以 KEY_ 为开头定义在 curses.h这个档案里头.
如 KEY_UP 即代表方向键的 " ↑ ". 但, 如果您想使用curses.h 所为您定义的这些特殊键的话, 您就必须将 keypad 设定为TRUE. 否则, 您就必须自己为所有的特殊键定义了. curses.h 为一些特殊键的定义如下:
以上仅列出笔者较常使用的一些控制键, 至於其他控制键的定义, 请自行参阅 man curses (* 注三).
一并为您列出其他常用的一些特殊字元:
10. 如何改变萤幕显示字元的属性:
为了使输出的萤幕画面更为生动美丽, 我们常须要在萤幕上做一些如反白, 闪烁等变化. curses 定义了一些特殊的属性, 透过这些定义, 我们也可以在 curses 程式控制萤幕的输出变化.
curses.h 里头定义了一些属性, 如:
当使用 attron() 开启某一种特殊属性模式後, 接下来在萤幕的输出都会以该种属性出现. 直到您呼叫 attroff() 将此模式关闭. 请注意, 当您欲 attron() 开启另一种属性时, 请记得利用attroff()先关闭原来的属性, 或直接以attrset(A_NORMAL) 将所有特殊属性关闭.否则, curses 会将两种属性做重叠处理.
例:
attrset(A_NORMAL); /* 先将属性设定为正常模式 */
attron(A_UNDERLINE); /* 加底线 */
mvaddstr(9,10,"加底线"); /* 加底线输出一串字元 */
attroff(A_UNDERLINE); /* 关闭加底线模式, 恢复正常模式 */
attron(A_REVERSE); /* 开启反白模式 */
mvaddstr(10,10,"反白"); /* 输出一串反白字元 */
attroff(A_REVERSE); /* 关闭反白模式, 恢复正常模式 */
attron(A_BLINK); /* 开启闪烁模式 */
mvaddstr(11,10,"闪烁"); /* 输出一串闪烁字元 */
attroff(A_BLINK); /* 关闭闪烁模式, 恢复正常模式 */
attron(A_BOLD); /* 开启高亮度模式 */
mvaddstr(12,10,"高亮度"); /* 输出一串高亮度字元 */
attroff(A_BOLD); /* 关闭高亮度模式, 恢复正常模式 */
11. 其他一些函数:
12. 应用完整例:
下面所举的例子, 即完全利用刚刚所介绍的含式来完成.这个程式可将从键盘上读取的字元显示在萤幕上, 并且可以上下左右方向键来控制游标的位置, 当按下 [ESC] 後, 程式即结束. 您有没有发现, 这不就是一个简单全萤幕编辑器的雏形吗?

#include <curses.h> /**//* 引进 curses.h , 并自动引进stdio.h */
#define StartX 1 /* 决定游标初始位置 */
#define StartY 1
void initial();

main()
...{
int x=StartX; /**//* 宣告 x,y 并设定其初值*/
int y=StartY;
int ch; /**//* 宣告 ch 为整数,配合 getch()使用 */
initial(); /**//* 呼叫 initial(), 启动 curses 模式, */

/**//* 并完成其它设定*/
box(stdscr,'|','-'); /**//* 画方框 */
attron(A_REVERSE); /**//* 开启反白模式 */
mvaddstr(0,20,"Curses Program"); /**//* 在 (20,0) 处输出反白字元 */
attroff(A_REVERSE); /**//* 关闭反白模式 */
move(x,y); /**//* 将游标移至初始位置 */

do ...{ /**//* 以无限回圈不断等待输入 */
ch=getch(); /**//* 等待自键盘输入字元 */
switch(ch) ...{ /**//* 判断输入字元为何 */
case KEY_UP: 
--y; /**//* 判断是否"↑"键被按下 */
break;
case KEY_DOWN: 
++y; /**//* 判断是否"↓"键被按下 */
break;
case KEY_RIGHT: 
++x; /**//* 判断是否"→"键被按下 */
break;
case KEY_LEFT: 
--x; /**//* 判断是否"←"键被按下 */
break;
case ' ': /**//* 判断是否 ENTER 键被按下 */
++y;
x=0;
break;
case ' ': /**//* 判断是否 TAB 键被按下 */
x+=7;
break;
case 127: /**//* 判断是否 BACKSPACE 键被按下 */
mvaddch(y,--x,' ');/**//* delete 一个字元 */
break;
case 27: /**//* 判断是否[ESC]键被按下 */
endwin(); /**//* 结束 curses 模式 */
exit(1); /**//* 结束此程式 */
default: 
addch(ch); /**//* 如果不是特殊字元, 将此字元印出 */
x++;
break;
}
move(y,x); /**//* 移动游标至现在位置*/
} while (1);
}


void initial() /**//* 自定开启 curses 函式 */ 
...{
initscr();
cbreak();
nonl();
noecho();
intrflush(stdscr,FALSE);
keypad(stdscr,TRUE);
refresh();
}
13. 後记:
学完了上述的一些命令, 相不相信您已经可以写出一个漂亮的全萤幕编辑器了. 事实上, curses 提供的函式不下 200 个, 可是笔者认为, 一切再复杂的函式都可以用本文提到的一些组合变化而成, 学了太多的函式, 只是徒增自己困扰罢了. 当然, 如果您对其它函式有兴趣, 可以自行参阅curses 说明档. ( 方法: % man curses ) 本文不过行抛砖引玉之效, 也希望未来能陆续出现更多同学自行创作的程式.
引进 curses.h 这个 library 当然, 您的系统内必须放有 curses.h 这个函式库.