用stdin识别箭头键

是否可以采用跨平台方式处理C或OCaml程序中的退格键和箭头键?

实际上,OCaml解决方案将受到赞赏,但许多标准的unix函数直接包装到相应的API调用中,因此移植C解决方案应该没有问题。

我要实现的是捕获箭头键以覆盖它在shell中的行为(通过重新定位最后一行或类似这样的操作)。 我认为这件事落在实际程序之前并且它不是由代码本身处理的,所以我不知道它是否可能。

该程序在Linux,OS X和Windows(在cygwin上)编译,所以我想在所有平台上进行编译。

我最近做了一些非常相似的事情(尽管我的代码只是Linux)。 您必须将stdin设置为非规范模式才能读取箭头键。 这应该适用于OS X和Linux,并且可能适用于Cygwin,尽管我不能肯定。

open Unix let terminfo = tcgetattr stdin in let newterminfo = {terminfo with c_icanon = false; c_vmin = 0; c_vtime = 0} in at_exit (fun _ -> tcsetattr tsdin TCSAFLUSH terminfo); (* reset stdin when you quit*) tcsetattr stdin TCSAFLUSH newterminfo; 

当规范模式关闭时,您不需要等待换行符才能从标准输入读取。 c_vmin表示返回前要读取的最小字符数(您可能希望一次只能读取一个字符),c_vtime是最大读取等待时间(以0.1s为单位)。

您可能还想将c_echo设置为false,以便按下箭头键打印到终端(但是您必须手动打印其他所有内容。

大多数终端使用ANSI转义序列表示箭头按键。 如果你运行没有参数的cat并开始点击箭头键,你可以看到使用的转义序列。 他们通常是

 up - "\027[A" down - "\027[B" left - "\027[D" right - "\027[C" 

其中’\ 027’是esc的ascii值

使用ncurses提取箭头键function的序列,然后在读取stdin时查找它们。 使用像libedit或readline这样的东西可能更容易,并且让它处理密钥处理。

支持超出可打印字符行的键盘输入的标准方法是通过ncurses库,它具有Ocaml绑定 。 另一种常见的可能性是readline库(Bash最常用)。

如果您所做的只是逐行阅读输入,但希望您的用户拥有一个不错的行编辑器,则无需在您的程序中包含任何支持。 相反,只需告诉用户使用包装程序,如rlwrap (基于readline)或ledit 。 这些包装器确实提供了行版本和历史记录,这两个function是您列出的要求。 我建议你只在你想要更高级的东西时才在你的程序中构建输入处理,例如当用户按下Tab时程序特定的完成。

Backspace是一个ASCII字符,将像任何其他字符一样放在stdin中。 字符转义序列'\b'是退格符。

对于光标键,这些键与任何控制字符都没有关联,因此不要在stdin流中生成数据。 低级访问必然是特定于平台的,尽管有跨平台库可以消除平台差异。 我相信ncurses适用于您提到的所有平台。