使用 curses 来操作字符
可使用键盘或 curses 应用程序向 curses 窗口添加字符。 此部分描述如何添加、除去或更改出现在 curses 窗口中的字符。
字符大小
一些字符集定义显示在屏幕上时占用多列位置的多列字符。
写入一个其宽度大于目标窗口宽度的字符将导致错误。
将字符添加到屏幕图像
curses 库提供了许多子例程,这些子例程将文本更改写入窗口,并在下次调用 wrefresh 子例程时标记要更新的区域。
waddch 子例程
waddch 子例程使用指定的字符覆盖当前逻辑光标位置处的字符。 覆盖后,将逻辑光标向右移动一个空格。 如果在右边空白处调用 waddch 子例程,那么这些子例程也将添加自动换行符。 此外,如果在滚动区域的底部调用这些子例程之一,并且启用了 scrollok 子例程,那么此区域向上滚动一行。 例如,如果在窗口底行添加新行,那么窗口将向上滚动一行。
| 子例程 | 描述 |
|---|---|
| addch 宏 | 向 stdscr 添加字符 |
| mvaddch 宏 | 在向 stdscr 添加字符前将此字符移动到指定位置 |
| mvwaddch 宏 | 在向用户定义的窗口添加字符前将此字符移动到指定位置 |
| waddch 子例程 | 向用户定义的窗口添加字符 |
通过一起使用 winch 和 waddch 子例程系列,可将文本和视频属性从一个位置复制到另一位置。 使用 winch 子例程系列,可检索字符及其视频属性。 然后可使用 waddch 子例程之一将该字符及其属性添加到另一位置。
还可使用 waddch 子例程向窗口添加控制字符。 控制字符以 ^X 表示法表示。
输出单个非控制字符
输出单个、非控制字符时,使用 wechochar 子例程可显著改进性能。 这些子例程在功能上等价于调用对应的 waddchr 子例程,该子例程后跟相应的 wrefresh 子例程。 wechochar 子例程包括 wechochar 子例程、echochar 宏,以及 pechochar 子例程。
某些字符集可能包含非空字符。 (非空字符为除“\ 0”字符之外的字符,而对于“\ 0”,wcwidth 子例程返回的宽度为 0。) 应用程序可将非空字符写到窗口。 窗口中的每个非空字符均与留空字符相关,并修改该留空字符。 无法单独寻址窗口中的非空字符。 只要 curses 操作影响了与非空字符相关的留空字符,就会隐式寻址非空字符。
非空字符不支持属性。 对于使用宽字符和属性的接口,如果该宽字符为非空字符,那么忽略这些属性。 对于所有列,多列字符具有单一属性集。 应用程序可使用宽字符接口控制非空字符与留空字符的关联。 宽字符串功能提供与代码集相关的关联。
与称为 c 的留空字符相关的非空字符的典型影响如下:
- 非空字符可修改 c 的显示。 (例如,可能有向字符添加区分标记的非空字符。 然而,还可能有带有内置区分标记的留空字符。)
- 非空字符可能将 c 传递给 c 后的字符。 有关此用法的示例为连字的形成以及从字符到复合显示格式、字或意符的转换。
实现能限制可与留空字符关联的非空字符的数目,前提是任何限制至少为 5。
复杂字符
复杂字符即一组相关字符,这些字符可包括留空字符,还可包括与之相关的非空字符。 留空复杂字符为复杂字符,它包括一个留空字符及与其相关的任何非空字符。 具有复杂字符的代码集的示例为 ISO/IEC 10646-1:1993。
可将复杂字符写到屏幕。 如果该复杂字符不包括留空字符,那么任何非空字符均与存 在于指定屏幕位置的留空复杂字符相关联。 当应用程序从屏幕读回信息时,它得到留空复杂字符。
cchar_t 数据类型代表复杂字符及其解释。 当 cchar_t 代表非空复杂字符(也就是当复杂字符内没有留空字符)时,不使用其解释。 将它写到屏幕时,它使用由已经显示的留空字符指定的解释。
可使用 setchar 子例程初始化类型为 cchar_t 的对象,且其内容可使用 getchar 子例程抽取。 获取 cchar_t 值(该值未以此方法初始化)的函数的行为是从具有 cchar_t 输出参数的 curses 函数获取的。
特殊字符
某些函数处理特殊字符。 在不移动光标(基于放置在窗口中的信息)的函数中,仅在字符串中使用这些特殊字符以影响后续字符的布局。 下面指定的光标移动在操作结束后不维持可视光标。 在不移动光标的函数中,可使用这些特殊字符影响后续字符的布局并移动物理光标。
| 字符 | 描述 |
|---|---|
| 退格 | 除非光标已位于列 0 中,否则退格将光标向当前行的起始位置移动一列,而退格后的任何字符被添加或插入该处。 |
| 回车 | 除非光标已位于列 0 中,否则回车符将光标移动到当前行的起始位置。 回车符后的任何字符被添加或插入到该处。 |
| 新行 | 在添加操作中,curses 将背景符添加到后续列,直至到达行尾。 进行滚动,从新行的开头处添加换行符后的任何字符。 在插入操作中,换行符使用背景符(有效 wclrtoeol 子例程)擦除当前行的剩余部分,并将光标移动到新行的开始。 启用滚动时,将光标推进到新行将导致滚动。 换行符后的任何字符将被插入到新行的开头。 filter 函数可能禁止此处理。 |
| 制表符 | 文本中的跳进字符将后续字符移动到下一个水平制表符停止位。 在缺省情况下,制表符停止位位于列 0、8、16 等中。 在插入和添加操作中,curses 分别将背景符插入或添加到后续列,直至到达下一个制表符停止位。 如果当前行中没有更多的制表符停止位,那么发生回绕和滚动。 |
控制字符
执行特殊字符处理的 curses 函数在概念上将控制字符转换为后跟第二个字符(如果为字母,那么为大写字母)的 (' ^ ') 字符,并将此字符串写到窗口以替代控制字符。 从窗口检索文本的函数将不检索原始控制字符。
线图:
可通过 waddch 子例程使用以下变量将折线绘制字符添加到屏幕。 针对终端定义时,变量的 A_ALTCHARSET 位将被打开。 否则,在下表中列示的缺省字符将存储在变量中。
| 变量名称 | 缺省字符 | 图像字符描述 |
|---|---|---|
| ACS_ULCORNER | + | 左上角 |
| ACS_LLCORNER | + | 左下角 |
| ACS_URCORNER | + | 右上角 |
| ACS_LRCORNER | + | 右下角 |
| ACS_RTEE | + | 右侧 T 型 |
| ACS_LTEE | + | 左侧 T 型 |
| ACS_BTEE | + | 底部 T 型 |
| ACS_TTEE | + | 顶部 T 型 |
| ACS_HLINE | — | 水平线 |
| ACS_VLINE | | | 垂直线 |
| ACS_PLUS | + | 加号 |
| ACS_S1 | - | 扫描线 1 |
| ACS_S9 | _ | 扫描线 9 |
| ACS_DIAMOND | + | 菱形 |
| ACS_CKBOARD | : | 棋盘(点刻) |
| ACS_DEGREE | , | 等级符 |
| ACS_PLMINUS | # | 加号/减号 |
| ACS_BULLET | o | 项目符号 |
| ACS_LARROW | < | 向左箭头 |
| ACS_RARROW | > | 向右箭头 |
| ACS_DARROW | v | 向下箭头 |
| ACS_UARROW | ^ | 向上箭头 |
| ACS_BOARD | # | 正方形 |
| ACS_LANTERN | # | 灯形符号 |
| ACS_BLOCK | # | 实心正方形 |
waddstr 子例程
| 子例程 | 描述 |
|---|---|
| addstr 宏 | 向 stdscr 添加字符串 |
| mvaddstr 宏 | 向 stdscr 添加字符串前,将逻辑光标移动到指定位置 |
| waddstr 子例程 | 向用户定义的窗口添加字符串 |
| wmvaddstr 宏 | 向用户定义的窗口添加字符串前,将逻辑光标移动到指定位置 |
winsch 子例程
winsch 子例程在窗口中的当前字符之前插入指定字符。 插入字符右侧的所有字符均向右移动一个空格。 因此,行上最右侧的字符可能丢失。 逻辑光标和物理光标的位置在移动后不会更改。 winsch 子例程包括以下内容:
| 子例程 | 描述 |
|---|---|
| insch 宏 | 在 stdscr 中插入字符 |
| mvinsch 宏 | 插入字符前,将逻辑光标移动到 stdscr 中的指定位置 |
| mvwinsch 宏 | 插入字符前,将逻辑光标移动到用户定义的窗口中的指定位置 |
| winsch 子例程 | 在用户定义的窗口中插入字符 |
winsertln 子例程
winsertln 子例程在窗口中的当前行上面插入一个空行。 insertln 子例程在 stdscr 中插入一行。 窗口的底行丢失。 winsertln 子例程在用户定义的窗口中执行相同的操作。
wprintw 子例程
wprintw 子例程将一系列字符 (从当前字符开始) 替换为格式化输出。 格式与 printf 命令的格式相同。 printw 系列由以下内容组成:
| 子例程 | 描述 |
|---|---|
| mvprintw 宏 | 替换字符前,将逻辑光标移动到 stdscr 中的指定位置 |
| mvwprintw 宏 | 替换字符前,将逻辑光标移动到用户定义的窗口中的指定位置 |
| printw 宏 | 在 stdscr 中替换一系列字符 |
| wprintw 子例程 | 在用户定义的窗口中替换一系列字符 |
wprintw 子例程对 waddch 子例程进行调用以替换字符。
unctrl 宏
unctrl 宏返回指定控制字符(以 ^X 表示法显示)的可显示说明。 unctrl 宏并照原样返回传示字符。
启用文本滚动
| 子例程 | 描述 |
|---|---|
| idlok | 允许 curses 使用硬件插入/删除行功能 |
| 卷轴 | 当从窗口最后一行的右边移走光标时,使窗口滚动 |
| setscrreg 或 wsetscrreg | 在窗口中设置软件滚动区域 |
当程序或用户从窗口底部移走光标时,发生滚动。 为了使滚动发生,必须首先使用 scrollok 子例程对窗口启用滚动。 如果启用了滚动并且如果以下情况之一发生,窗口将滚动:
- 从窗口边缘移走光标。
- 在最后一行遇到了换行符。
- 在最后一行的最后位置插入一个字符。
窗口滚动时,curses 将更新窗口和。 但是,为了使物理滚动在终端上发挥作用,必须调用 idlok 子例程,并将 Flag 参数设为 TRUE。
如果禁用滚动,那么光标将驻留在字符输入位置的底行。
对窗口启用滚动时,可使用 setscrreg 子例程在窗口内部创建软件滚动区域。 传递区域顶行和底行的 setscrreg 子例程值。 如果对区域启用了 setscrreg 并对窗口启用了滚动,那么移走指定底行的任何尝试将导致区域中的所有行向上滚动一行。 您可以使用 setscrreg 宏在 stdscr 中定义滚动区域。 否则,使用 wsetscrreg 子例程在用户定义的窗口中定义滚动区域。
删除字符
可通过使用空格替换文本或通过从字符数组除去字符并将行上剩余字符向左滑动一个空格的方法来删除文本。
werase 子例程
擦除 宏将空白复制到 stdscr 中的每个位置。 werase 子例程在用户定义的窗口中的每个位置都放置一个空格。 要删除窗口中的单个字符,请使用 wdelch 子例程。
wclear 子例程
| 子例程 | 描述 |
|---|---|
| clear或 wclear | 清除屏幕并设置清除标记以备下一次刷新。 |
| 清除 | 确定 curses 是否在下一次调用 refresh 或 wrefresh 子例程时清除窗口。 |
wclear 子例程类似于 werase 子例程。 但是,除了在窗口的每个位置放置空格之外, wclear 子例程还调用 wclearok 子例程。 因此,下次调用 wrefresh 子例程时将清除屏幕。
wclear 子例程系列包含 wclear 子例程、clear 宏以及 clearok 子例程。 clear 宏将一个空格置于 stdscr 中每一个位置。
wclrtoeol 子例程
clrtoeol 宏在 stdscr 中运行,而 wclrtoeol 子例程在用户定义的窗口中执行相同的操作。
wclrtobot 子例程
clrtobot 宏在 stdscr 中运行,而 wclrtobot 在用户定义的窗口中执行相同的操作。
wdelch 子例程
| 子例程 | 描述 |
|---|---|
| delch 宏 | 从 stdscr 删除当前字符 |
| mvdelch 宏 | 从 stdscr 删除字符前,移动逻辑光标 |
| mvwdelch 宏 | 从用户定义的窗口删除字符前,移动逻辑光标 |
| wdelch 子例程 | 在用户定义的窗口中删除当前字符 |
wdelch 子例程删除当前字符,并将当前行上当前字符右侧的所有字符移动到左侧的一个位置。 行上的最后一个字符用空格填充。 delch 子例程系列由以下子例程和宏组成:
wdeleteln 子例程
deleteln 子例程删除当前行,并将当前行下的所有行上移一行。 此操作将清除窗口的底行。
获取字符
程序可从键盘或显示器检索字符。 wgetch 子例程从键盘检索字符。 winch 子例程从显示器检索字符。
wgetch 子例程
wgetch 子例程从连接到窗口相关终端的键盘读取字符。 获取字符前,如果窗口中的任何内容发生更改(比如,如果移动了光标或更改了文本),那么这些子例程将调用 wrefresh 子例程。
wgetch 子例程系列由以下内容组成:
| 子例程 | 描述 |
|---|---|
| getch 宏 | 从 stdscr 获取字符 |
| mvgetch 宏 | 从 stdscr 获取字符前移动光标 |
| mvwgetch 宏 | 从用户定义的窗口获取字符前移动光标 |
| wgetch 子例程 | 从用户定义的窗口获取字符 |
要将先前通过调用 wgetch 子例程而获得的字符放回输入队列中,请使用 ungetch 子例程。 通过下次调用 wgetch 子例程检索字符。
终端方式
wgetch 子例程的输出部分取决于终端的方式。 以下列表描述了每种终端方式的 wgetch 子例程的操作:
| 子例程 | 描述 |
|---|---|
| DELAY 方式 | 停止读取,直至系统通过程序传递文本。 如果还设置了 CBREAK 方式,那么该程序将在某个字符后停止。 如果未设置 CBREAK 方式(NOCBREAK 方式),那么 wgetch 子例程在第一个换行符后停止读取。 如果设置了 ECHO,那么字符还将回传到窗口。 |
| HALF-DELAY 方式 | 停止读取,直至输入字符或到达指定的超时时间。 如果设置了 ECHO 方式,那么字符还将回传到窗口。 |
| NODELAY 方式 | 如果没有输入正在等待,那么返回 ERR 值。 |
功能键
在 curses.h 文件中定义了功能键。 如果启用了小键盘,那么功能键可由 wgetch 子例程返回。 终端可能不支持所有功能键。 要查看终端是否支持特殊键,请检查其 terminfo 数据库定义。
获取功能键
如果程序使用 keypad 子例程启用键盘,并且用户按下功能键,那么返回该功能键的标记而不是原始字符。 /usr/include/curses.h 文件定义可能的功能键。 每个定义语句均以 KEY_ 前缀开头,并将键定义为以值 03510 开头的整数。
如果接收到的字符可能是功能键的开始字符(比如转义字符),那么 curses 将设置计时器(在 /usr/include/sys/time.h 中定义的时间值类型的结构)。 如果在计时器到期之前未接收到序列的剩余部分,那么传递字符。 否则,返回功能键的值。 出于此原因,用户按下 ESC 键后,在将转义返回到程序之前将会有一段延迟。 在调用如 wgetch 子例程之类的单个字符子例程时,只要有可能就避免使用 ESC 键。 使用 ESCDELAY 环境变量可覆盖或扩展此计时器。
ESCDELAY 环境变量设置在超时并将 ESC 按键作为转义字符对待而不是将它与缓冲区中的其他字符合并之前等待的时间,以创建键序列。 ESCDELAY 值以五分之一毫秒为单位进行度量。 如果 ESCDELAY 变量为 0,那么系统会立即组成转义响应,而不等待来自缓冲区的更多信息。 可在 0 至 99,999 之间选择任何值。 ESCDELAY 变量的缺省设为 500(一秒的 1/10)。
要防止 wgetch 子例程设置计时器,请调用 notimeout 子例程。 如果将 notimeout 设为 TRUE,那么检索数据时,curses 不区分功能键和字符。
keyname 子例程
keyname 子例程将指针返回到包含 Key 参数符号名称的字符串。 Key 参数可以是从 wgetch、getch、mvgetch 或 mvwgetch 子例程返回的任何键。
winch 子例程
绞盘 子例程在当前位置检索字符。 如果对该位置设置了任何属性,那么将会对属性值执行 OR 操作,并将结果放到返回的值中。 可使用 winch 子例程仅抽取字符或其属性。 To do this, use the predefined constants 文本 (_CHARTEXT) and A_ATTRIBUTES with the logical & (ampersand) operator. 这些常量在 curses.h 文件中定义。 以下是 winch 子例程:
| 子例程 | 描述 |
|---|---|
| inch 宏 | 从 stdscr 获取当前字符 |
| mvinch 宏 | 在 stdscr 上调用 inch 子例程前,移动逻辑光标 |
| mvwinch 宏 | 在用户定义的窗口中调用 winch 子例程前,移动逻辑光标 |
| winch 子例程 | 从用户定义的窗口获取当前字符 |
wscanw 子例程
wscanw 子例程读取字符数据,根据转换规范对其进行解释,并将转换后的结果存储到内存中。 wscanw 子例程使用 wgetstr 子例程读取字符数据。 以下是 wscanw 子例程:
| 子例程 | 描述 |
|---|---|
| mvscanw 宏 | 扫描 stdscr 前移动逻辑光标 |
| mvwscanw 宏 | 扫描前,在用户定义的窗口中移动逻辑光标 |
| scanw 宏 | 扫描 stdscr |
| wscanw 子例程 | 扫描用户定义的窗口 |