curses标准作为一个重要的过渡,位于简单的文本行程序和完全图形化界面的X视窗系统程序之间。curses还可以管理键盘提供一种简单易用的非阻塞字符输入字符输入模式。
curses的操作目标是一个curses窗口,通常是一个终端屏幕。有两个数据结构来映射终端屏幕,stdscr和curscr。stdscr理解为逻辑屏幕,curscr理解为物理屏幕。通过调用refresh函数来刷新curscr
逻辑屏幕左上角的坐标为(0,0)
在使用curses函数库前需要对其进行初始化,并在结束使用后允许curses恢复原先设置。这两项工作是由initscr和endwim函数分别完成的。
WINDOW *initscr(void);//在一个程序中只能调用一次。成功返回一个指向stdscr结构的指针;失败,输出一条错误信息并使程序退出
int endwin(void);//成功 OK 失败 ERR
例如一个hello world程序
#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
int main()
{
initscr();
move(5, 15);
printw("%s", "Hello World");
refresh();
sleep(2);
endwin();
exit(EXIT_SUCCESS);
}
输出到屏幕
curses提供了一些用于刷新屏幕的基本函数,且它有自己的字符类型chtype,它可能比标准char类型包含更多的二进制位
#include <curses.h>
int addch(const chtype char_to_add);//在当前位置添加字符
int addchstr(chtype *const string_to_add);//在当前为值添加字符串
int printw(char *format, ...);//在当前位置格式化输出字符串,。类似与printf
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);//屏幕闪烁
读取屏幕
#include <curses.h>
chtype inch(void); //读取一个字符
int instr(char *string);//读取字符串
int innstr(char *string, int number_of_characters);//读取设定数量的字符
清除屏幕
int earse(void);//在每个屏幕位置上写空白字符
int clear(void);//通常是用一个终端命令来清除整个屏幕,clear是一种彻底清除屏幕的可靠方法,通过clear函数和refresh函数可以重新绘制屏幕原文
int clrtobot(void);//清除当前光标位置到屏幕结尾的所有内容
int clrtoeol(void);//清除当前光标位置到所处行行尾的所有内容
移动光标
int move(int new_y, int new_x);//如名(行,列)
int leaveok(WINDOW *window_ptr, bool leave_flag);//用于控制屏幕刷新后curses将物理屏幕光标的放置位置
//默认情况下为 false 意味着硬件管标将停留在逻辑管标所在的位置,若为true 则硬件光标将随机放置在任意位置
字符属性
int attron(chtype attribute);//使能一个属性,比如 A_BOLD
int attroff(chtype attribute);//取消一个属性
int attrset(chtype attribute);
int standout(void);//突出显示,通常映射为反白
int standend(void);//关闭突出显示
键盘模式
cooked模式在回车按下后输入才会被传递给程序,键盘特殊字符是被启用的
cbreak模式在字符被输入后就被传递给程序,键盘特殊字符也是被启用的,但是一些简单的图示字符会被直接传递给程序,交给程序处理。如退格键若想继续保持功能需要自己在程序中实现它
int echo(void);//开启回显功能
int noecho(void);//关闭回显功能
int cbreak(void);//将输入模式切换为cbreak模式
int nocbreak(void);//将输入模式重新设置为cooked模式,但特殊字符的处理方式不变
int raw(void);//关闭特殊字符处理
int noraw(void);恢复cooked模式和特殊字符处理功能。
键盘输入
int getch(void);//类似于getchar
int getstr(char *string);//gets
int getnstr(char *string, int number_of_characters);//尽可能使用这个替代getstr
int scanw(char *format, ...);//scanf
创建窗口
WINDOW *newwin(int num_of_lines, int num_of_cols, int start_y, int start_x);
//创建一个窗口,若想让窗口的右下角恰好落在屏幕的右下角,可设lines和cols为0
int delwin(WINDOW *window_to_delete);
//删除一个窗口,不要删除stdscr和curscr
通用函数
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, ...);
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);//通知curses函数库其指针参数指向的窗口内容已发生改变,以为着下次调用wrefresh时,curses必须重新绘制该窗口,当有多个窗口时,可以通过该函数来安排要显示的窗口。
int scrollok(WINDOW *window_ptr, bool scroll_flag);//若传入 true则允许卷屏
int scroll(WINDOW *window_ptr);//把窗口内容向上卷一行
int wnoutrefresh(WINDOW *window_ptr);
int doupdate(void);
wnoutrefresh不会立刻发送字符到屏幕上,它会保存每个窗口绘制后的结果
再调用doupdate将最后的结果输出到屏幕
子窗口
WINDOW *subwin(WINDOW *parent, int num_of_lines, int num_of_cols, int start_y, int strat_x);
int delwin(WINDOW *window_to_delete);
子窗口与窗口在操作上没有太大的区别,它们只有一个重要的区别就是:
子窗口没有自己独立的屏幕字符存储空间,它们与父窗口共享同一字符存储空间。这意味着,对子窗口中内容的任何修改都会反映到其父窗口中,所以删除子窗口时,屏幕显示不会发生改变。
keypad模式
对于多数终端,当功能键被按下时,通常都是发送以escape字符开头的字符串序列。由此产生两个问题
1.应用程序需要区分“单独按下Escape键“和”按下某个功能键而产生的以Escape字符开头的字符串序列“
2.还要处理不同终端对同一逻辑按键使用不同字符串序列的情况
对于每一个终端来说,它的每个功能键所对应的转义序列都被保存,通常是在一个terminfo结构中,而curses.h通过一组以KEY_为前缀的定义来管理逻辑键。
curses在启动时会关闭转义序列与逻辑键之间的转换功能,该功能需要通过调用keypad函数来启用。OK/ERR
int keypad(WINDOW *window_ptr, bool keypad_on);
keypad模式的三个限制
1.识别escape转义序列的过程是与时间相关的,这样希望每个功能键都只发送一个单独的、唯一的字符
2.解决问题1,curses在识别字符串时需要等待一小段时间
3.curses不能处理二义性的escape转义序列,若两个按键产生相同的转义序列,curses将不会处理这个转义序列
彩色显示
curses只能够以一种非常受限的方式来显示彩色
屏幕上每个字符位置都可以从多种颜色中选择一种作为它的前景色或背景色,但是我们必须同时定义一个字符的前景色和背景色。
在使用彩色显示之前,需要检查终端是否支持彩色显示功能
bool has_colors(void); // true/false
int start_colors(void)://OK/? 此函数调用成功后变量COLOR_PAIRS将被设置为终端所能支持的颜色组合数目的最大值,一般64,COLORS定义可用颜色数目的最大值,一般8种,在内部实现中,每种可用的颜色以一个从0到63的数字作为唯一ID号。
使用颜色前,需要用init_pair()函数对准备使用的颜色组合进行初始化。对颜色属性的访问是通过COLOR_PAIR来完成的
int init_pair(short pair_number, short foreground, short background);
int COLOR_PAIR(int pair_number);
int pair_content(short pair_number, short *foreground, short *background);//查看pair_number颜色组合的颜色信息
int init_color(short color_number, short red, short green, short blue); //自定义颜色
例:
init_pair(1, COLOR_RED, COLOR_GREEN);//初始化字符颜色为红色,背景色为绿色的颜色组合 COLEOR_RED这些常用颜色被定义在头文件中
wattron(window_ptr, COLOR_PAIR(1));//启用颜色属性1
wattron(window_ptr, COLOR_PAIR(1) | A_BOLD);//实现高浓度属性
PAD
WINDOW *newpad(int number_of_lines, int number_of_columns);
int pregresh(WINDOW *pad_ptr, int pad_row, int pad_column, int screen_row_min, int screen_col_min, int screen_row_max, int screen_col_max);//将从pad_row,pad_column位置开始的内容 显示在后四个参数标记的矩形中