是否可以采用跨平台方式处理C或OCaml程序中的退格键和箭头键?
实际上可以理解OCaml解决方案,但许多标准的unix函数直接包装到相应的API调用中,因此移植C解决方案应该没有问题。
我要实现的是捕获箭头键以覆盖它在shell中的行为(通过重新排列最后一行或类似这样的操作)。我认为这件事落在实际程序之前并且它不是由代码本身处理的,所以我不知道它是否可能。
该程序是在Linux,OS X和Windows(在cygwin上)编译的,所以我想在所有平台上进行编译..
答案 0 :(得分:8)
我最近做了一些非常相似的事情(虽然我的代码只是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 stdin TCSAFLUSH terminfo); (* reset stdin when you quit*)
tcsetattr stdin TCSAFLUSH newterminfo;
当规范模式关闭时,您无需等待换行符以便从标准输入读取。 c_vmin表示返回之前要读取的最小字符数(您可能希望一次能够读取一个字符),c_vtime是最大读取等待时间(以0.1s为单位)。
您可能还想将c_echo
设置为false,以便按下箭头键打印到终端(但之后您必须手动打印其他所有内容。
大多数终端使用ANSI escape sequences表示按箭头键。如果您运行没有参数的cat
并开始按箭头键,您可以看到使用的转义序列。它们通常是
up - "\033[A"
down - "\033[B"
left - "\033[D"
right - "\033[C"
其中'\ 033'是esc
答案 1 :(得分:5)
使用ncurses提取箭头键功能的序列,然后在读取stdin时查找它们。使用像libedit或readline这样的东西可能更容易,并且让它处理密钥处理。
答案 2 :(得分:2)
支持键盘输入超出可打印字符行的标准方法是通过ncurses库,其中Ocaml binding。另一种常见的可能性是readline库(最常用于Bash)。
如果您所做的只是逐行读取输入,但希望您的用户拥有一个不错的行编辑器,则无需在您的程序中包含任何支持。相反,只需告诉您的用户使用包装程序,例如rlwrap(基于readline)或ledit。这些包装器确实提供了行版本和历史记录,这两个功能是您列出的要求。我建议您只在需要更高级的东西时才在程序中构建输入处理,例如当用户按下 Tab 时程序特定的完成。
答案 3 :(得分:1)
Backspace是一个ASCII字符,将像任何其他字符一样放在stdin中。字符转义序列'\b'
是退格符。
对于光标键,这些键与任何控制字符都没有关联,因此不要在stdin流中生成数据。低级访问必然是特定于平台的,尽管有跨平台库可以消除平台差异。我相信ncurses适用于您提到的所有平台。