6.7 keypad模式
你已看到curses提供的一些用于处理键盘的功能。一般键盘至少都会包含方向键和功能键,许多键盘还带有数字小键盘以及诸如Insert、Home等其他按键。
对于大多数终端来说,解码这些按键是一件很困难的事,因为它们往往会发送以escape字符开头的字符串序列。应用程序不仅要区分“单独按下Escape键”和“按下某个功能键而生成的以Escape字符开头的字符串序列”,还必须处理不同的终端对于同一逻辑按键使用不同字符串序列的情况。
幸运的是,curses函数库提供了一个精巧的用于管理功能键的功能。对每个终端来说,它的每个功能键所对应的转义序列都被保存,通常是保存在一个terminfo结构中,而头文件curses.h通过一组以KEY_为前缀的定义来管理逻辑键。
curses在启动时会关闭转义序列与逻辑键之间的转换功能,该功能需要通过调用keypad函数来启用。该函数调用成功时,返回OK,否则就返回ERR。
将keypadon参数设置为true,然后调用keypad函数来启用keypad模式。在该模式中,curses将接管按键转义序列的处理工作,读键盘操作不仅能够返回用户按下的键,还将返回与逻辑按键对应的KEY定义。
使用keypad模式有下面3个小小的限制。
❑ 识别escape转义序列的过程是与时间相关的。许多网络协议会将字符组合成数据包(这将导致escape转义序列的识别不准确),或者是将字符串分割开(这将导致功能键的转义序列有可能被识别为一个单独的Escape按键和其他独立的字符串)。这种情况在广域网和其他慢速链路上将更为严重。这一问题的唯一解决方法是设法对终端进行编程,让它针对用户希望使用的每个功能键只发送一个单独的、唯一的字符,虽然这将限制可使用的控制字符的数目。
❑ 为了让curses能够区分“单独按下Escape键”和“一个以Escape字符开头的键盘转义序列”,它必须等待一小段时间。有时候,在启用了keypad模式后,处理Escape按键所造成的非常细微的延时都可能会被注意到。
❑ curses不能处理二义性的escape转义序列。如果终端上两个不同的按键会产生完全相同的转义序列,curses将不会处理这个转义序列,因为它不知道该返回哪个逻辑按键。
实 验 使用keypad模式
下面这个小程序keypad.c演示了keypad模式的使用方法。当运行这个程序时,按下Esc按键并注意观察细微的延时。程序将在这段延时里判断这个Esc是一个escape转义序列的开头还是一个单独的按键:
(1)首先对程序和curses函数库进行初始化,然后启用keypad模式:
(2)接下来,关闭回显功能以防止光标在你按下方向键时发生移动。然后清屏并显示一些文本。程序将等待用户的击键动作,除非用户的按键是字母Q或发生了错误,否则按键所对应的字符将显示在屏幕上。如果按键匹配终端上的某个转义序列,就把这个转义序列显示在屏幕上:
实验解析
在启用keypad模式之后,你看到了该模式是如何识别键盘上的各种其他按键的,这些按键都将生成escape转义序列。你还将注意到Escape键的检测要略慢于其他按键。