简体   繁体   English

用stdin识别箭头键

[英]Recognizing arrow keys with stdin

is it possible to have a cross-platform way to handle backspace and arrows keys within a C or OCaml program? 是否有可能采用跨平台方式处理C或OCaml程序中的退格键和箭头键?

Actually an OCaml solution would be appreciated but many standard unix functions are wrapped directly to corresponding API calls so there's should be no problem in porting a C solution. 实际上,OCaml解决方案将受到赞赏,但许多标准的unix函数直接包装到相应的API调用,因此移植C解决方案应该没有问题。

What I'm going to achieve is to catch the arrow keys to override its behaviour inside the shell (by repropting last line or operations like these). 我要实现的是捕获箭头键以覆盖它在shell中的行为(通过重新定位最后一行或类似这样的操作)。 I think that this thing falls before the actual program and it's not handled by code itself so I don't know if it's possible. 我认为这件事落在实际程序之前并且它不是由代码本身处理的,所以我不知道它是否可能。

The program is compiled either on Linux, OS X and Windows (on cygwin) so I would like to do it for all platforms.. 该程序在Linux,OS X和Windows(在cygwin上)编译,所以我想在所有平台上进行编译。

I've done something pretty similar recently (although my code is Linux only). 我最近做了一些非常相似的事情(尽管我的代码只是Linux)。 You have to set stdin to non-canonical mode in order to read arrow key presses. 您必须将stdin设置为非规范模式才能读取箭头键。 This should work on OS X and Linux and will probably work on Cygwin although I can't say for sure. 这应该适用于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;

when canonical mode is off, you don't need to wait for a newline in order to read from stdin. 当规范模式关闭时,您不需要等待换行符才能从标准输入读取。 c_vmin represents the minimum numbers of characters to read before returning (you probably want to be able to read a single character at a time) and c_vtime is the maximum read wait time (in 0.1s units). c_vmin表示返回前要读取的最小字符数(您可能希望一次只能读取一个字符),c_vtime是最大读取等待时间(以0.1s为单位)。

You might also want to set c_echo to false so that the arrow key presses are printed to the terminal (but then you'll have to manually print everything else. 您可能还希望将c_echo设置为false,以便按下箭头键打印到终端(但是您必须手动打印其他所有内容。

Most terminals represent arrow key presses using ANSI escape sequences . 大多数终端使用ANSI转义序列表示箭头按键。 If you run cat with no arguments and start hitting the arrow keys you can see the escape sequences used. 如果你运行没有参数的cat并开始按箭头键,你可以看到使用的转义序列。 They are typically 他们通常是

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

Where '\\033' is the ascii value for esc 其中'\\ 033'是esc的ascii值

Use ncurses to extract the sequences for the arrow key capabilities and then look for them when you read stdin. 使用ncurses提取箭头键功能的序列,然后在读取stdin时查找它们。 It's probably easier to use something like libedit or readline instead, and let that deal with the keyhandling. 使用像libedit或readline这样的东西可能更容易,并让它处理密钥处理。

The standard way of supporting keyboard input beyond lines of printable characters is through the ncurses library, which has an Ocaml binding . 支持键盘输入超出可打印字符行的标准方法是通过ncurses库,它具有Ocaml绑定 Another common possibility is the readline library (most famously used by Bash). 另一种常见的可能性是readline库(Bash最常用的)。

If all you're doing is reading input line by line, but want your users to have a decent line editor, there's no need to include any support in your program. 如果您所做的只是逐行阅读输入,但希望您的用户拥有一个不错的行编辑器,则无需在您的程序中包含任何支持。 Instead, just tell your users to use a wrapper program such as rlwrap (which is based on readline) or ledit . 相反,只需告诉您的用户使用包装器程序,例如rlwrap (基于readline)或ledit These wrappers do provide line edition and history, the two features you list as your requirements. 这些包装器确实提供了行版本和历史记录,这两个功能是您列出的要求。 I would recommend that you build input processing into your program only if you want something fancier, such as program-specific completion when the user presses Tab . 我建议您只在需要更高级的东西时才在程序中构建输入处理,例如当用户按下Tab时程序特定的完成。

Backspace is an ASCII character and will be placed in stdin like any other character. Backspace是一个ASCII字符,将像任何其他字符一样放在stdin中。 The character escape sequence '\\b' is the backspace character. 字符转义序列'\\b'是退格字符。

For cursor keys, these are not associated with any control character, so do not generate data in the stdin stream. 对于光标键,这些键与任何控制字符都没有关联,因此不要在stdin流中生成数据。 Low level access is necessarily platform specific, although there are cross-platform libraries that abstract away the platform differences. 低级访问必然是特定于平台的,尽管有跨平台库可以消除平台差异。 I believe ncurses is available for all the platforms you mentioned. 我相信ncurses适用于您提到的所有平台。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM