使用curses函数库管理基于文本的屏幕
curses函数库用两个数据结构来映射终端屏幕,它们是 stdscr 和 curscr。
屏幕
#include <curses.h>
WINDOW *initscr(void);
int endwin(void);
initscr函数在一个程序中 只能调用一次。如果成功它返回一个指向stdscr结构的指针,失败就输出一条诊断钷信息并使程序退出。
endwin成功时返回OK,失败时返回ERR。
输出到屏幕
#include <curses.h>
int addch(const chtype char_to_add);
int addchstr(chtype *const string_to_add);
int printw(char *format, ...);
int refresh();
int box(WINDOW *win_ptr, chtype vertical_char, chtype horizontal_char);
int insch(chtype char_to_insert);
int insertln();
int delch();
int deleteln();
int beep();
int flash();
curses有自己的字符类型 chtype。在ncurses的标准Linux版本中,chtype实际上是 unsigned long 类型的一个typedef类型定义。
beep可以让程序发出声音,flash可以使屏幕闪烁。
box用来围绕一个窗口绘制方框。
从屏幕读取
#include <curses.h>
chtype inch();
int instr(char *string);
int innstr(char *string, int number_of_characters);
instr和innstr并不总被支持。
清除屏幕
#include <curses.h>
int erase();
int clear();
int clrtobot();
int clrtoeol();
erase是在每个位置写上空白字符。而clear通过在内部调用一个底层函数clearok来强制重现屏幕原文。clearok函数会强制执行清屏操作,并在下次调用refresh时重现屏幕原文。
clrtobot清除当前光标位置直到屏幕结尾的所有内容。clrtoeol清除当前光标位置直到光标所处行行尾的所有内容。
移动光标
#include <curses.h>
int move(int new_y, int new_x);
int leaveok(WINDOW *window_ptr, bool leave_flag);
leaveok设置了一个标志,该标志用于控制在屏幕刷新后curses将物理光标放置的位置,默认情况下为false,光标将停留在屏幕上逻辑光标所处的位置,如果设置为true,则硬件光标会被随机地旋转在屏幕上的任意位置。
字符属性
#include <curses.h>
int attron(chtype attribute);
int attroff(chtype attribute);
int attrset(chtype attribute);
int standout();
int standend();
预定义的属性有A_BLINK、A_BOLD、A_DIM、A_REVERSE、A_STANDOUT和A_UNDERLINE。
standout和standend提供了一种更加通用的强调或突出模式,在大多数终端上,它通常被映射为反白显示。
键盘
键盘模式
#include <curses.h>
int echo();
int noecho();
int cbreak(); //字符一经键入立刻传递给程序
int nocbreak();
int raw(); //特殊字符不处理直接传递给程序
int noraw();
键盘输入
#include <curses.h>
int getch();
int getstr(char *string);
int getnstr(char *string, int number_of_characters);
int scanw(char *format, ...);
窗口
WINDOW结构
标准屏幕stdscr是WINDOW结构的一个特例,WINDOW结构通常被定义在头文 curses.h 中,程序应该永远都不要直接访问它。
#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);
通用函数
之前的函数上加上一些前缀即可变为通用函数,之前的函数很多都只是调用这些通用函数的简单的宏定义。w用于窗口,mv用于光标移动,mvw用于在窗口中移动光标。
#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);
//其余函数类似
移动和更新窗口
#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); //scroll_flag为true时允许卷屏
int scroll(WINDOW *window_ptr); //内容上卷一行
优化窗口刷新
#include <curses.h>
int wnoutrefresh(WINDOW *window_ptr);
int doupdate();
wnoutrefresh用于决定把哪些字符发送到屏幕上,但并不真正地发送这些字符,真正将更新发送到终端的工作由doupdate来完成。
可以为多个窗口调用wnoutrefresh,最后再调用doupdate,从而减少curses需要发送的字符数目。
子窗口
#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);
使用子窗口有个强加的限制:在应用程序刷新屏幕之前必须先对其父窗口调用touchwin函数。
keypad模式
#include <curses.h>
int keypad(WINDOW *window_ptr, bool keypad_on);
对每个终端来说,它的每个功能键所对应的转义离殇都被保存,通常是保存在一个terminfo结构中,而头文件curses.h通过一组以 KEY_ 为前缀的定义来管理逻辑键。
在keypad模式中,curses将接管按键转义序列的处理工作,读键盘操作不仅能够返回用户按下的键,还将返回与逻辑按键对应的KEY_定义。
彩色显示
#include <curses.h>
bool has_colors();
int start_color();
如果终端支持彩色显示,has_colors返回true。然后调用start_color函数,如果该函数成功初始化了颜色显示功能,它将返回OK。
一旦start_color函数被成功调用,变量COLOR_PAIRS定义可用颜色数目的最大值,一般只有8种。在内部实现中,每种可用的颜色以一个从0到63的数字作为其唯一的ID号。(6位,3位表示前景,3位表示背景)
#include <curses.h>
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);
头文件curses.h通常会定义一些基本颜色,它们的名字以 COLOR_ 为前缀。
pair_content的作用是获取已定义的颜色组合的信息。
以红色前景绿色背景为例:
init_pair(1, COLOR_RED, COLOR_GREEN);
wattron(window_ptr, COLOR_PAIR(1));
#include <curses.h>
int init_color(short color_number, short red, short green, short blue);
将已有的颜色的亮度值重新定义,亮度值范围(0~1000)。
pad
#include <curses.h>
WINDOW *newpad(int number_of_lines, int number_of_columns);
建立逻辑屏幕,可以比物理屏幕大,只显示一部分。
#include <curses.h>
int prefresh(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);