如何将Ctrl+C作为输入读取

3

(在Linux中)

我找到的方法都使用signal

没有其他方法吗? 我能做些什么让终端把它放入输入缓冲区吗?


4
使用signal是正确的方法。为什么你不能使用它呢?它并不难。 - Bib
4
没有。另外,可以参考“什么是XY问题?”(链接:https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。 - molbdnilo
1
这并不麻烦,非常容易。只需要几行代码就可以了。记住,实践出真知。 - Bib
有替代方案 - sigaction 和在Linux上实际上是 eventfd - 尽管这些都不像 signal 使用简单。无论如何,这三个都可以捕获按下 Ctrl+C 时发送到进程的信号。 - Aconcagua
2
你可以尝试将终端设置为原始模式,具体方法请参考这里:https://dev59.com/L2855IYBdhLWcg3wp2N0#4217250 - Ruud Helderman
显示剩余6条评论
2个回答

5
为了将“CTL+C”作为输入而不是生成“SIGINT”信号,需要使用tcsetattr()函数来清除cc_c[VINTR]或清除该手册页面中描述的ISIG标志。 首先使用tcgetattr读取当前终端设置并相应地进行调整,然后使用tcsetattr设置它们。 确保在程序终止时将终端设置重置为其原始默认值,不能认为shell会为您重置它们。

2
虽然这是正确的,但对OP来说可能没有什么帮助。尽管要求将control-C读取为字符,但这可能对他们没有太大好处。特别是仅凭它本身 - 一旦清除了这些标志,控制-C组合键会发送哪个字符,并且在给定其他默认设置的情况下,它是否会导致缓冲区被发送,还是需要进行其他更改以立即发送字符? (因为,如果不立即发送,用户将按下control-C,然后期望某些立即的程序响应,但程序仍将等待输入。) - Eric Postpischil
1
也许,@EricPostpischil,OP想要重新实现emacs,其中^C是一个有效的键命令或部分命令,并且从标准输入读取并相应地执行没有任何问题。无论如何,是否有用读取^C将根据其自身的优点进行评估,一旦^C变得可读作为普通字符。即使证明它不是,最初提出的问题是一个完全合理,有效的问题,其答案精确地回答了所问的问题。 - Sam Varshavchik
你不需要这样做。这会使你的程序在输入来自tty时以不同的方式处理,而tty有一个用于此目的的转义字符。阅读我的答案,它不需要任何编程解决方案。 - Luis Colorado

0

不,signal() 不是方法。你需要配置 tty 驱动程序以进行 原始输入(驱动程序中没有输入字符处理),因此它会传递所有未经处理的字符。但这需要将 tty 输入设备视为特殊设备,并编写特殊代码来处理该情况(这需要您发出多个 ioctl 系统调用)。但由于下面所述的原因,这并不推荐。

其次,还有另一种更简单的方法,不需要使用原始模式。您可以通过在 tty 前加上转义字符来转义 Ctrl-C 字符。在 Linux 和 BSD 系统中,这通常与 Ctrl-V 字符绑定,因此按下 Ctrl-V + Ctrl-C 可以输入一个单独的 Ctrl-C 字符。我刚刚使用 hd 命令检查过了:

$ hd
^C
00000000 : 03 0a                                           : ..
00000002
$ _

下一个问题是如何输入Ctrl-V?很简单,只需双击!(但我们现在超出了范围,继续阅读即可)
这种方法的优点是不需要在程序中进行编程,并且在从文件、管道、FIFO、套接字等读取时将以相同的方式工作(对于这些设备,Ctrl-C没有特殊含义,因为tty驱动程序已经退出)。唯一会在检测到Ctrl-C时生成中断的设备是tty驱动程序(更确切地说,是控制tty,在其代码通用部分中,因此所有tty都会这样做),它还具有转义字符(由于相同的原因,所有tty都有它)来使下一个字符的特殊含义无效。
您可以使用stty(1)命令检查转义字符是哪个字符,配置为lnext条目。但我几乎可以保证它将是Ctrl-V。
注意
这也适用于任何其他特殊字符(例如终端用于特殊目的的Ctrl-D、Ctrl-H等)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接