捕获信号时强制终端不打印 Ctrl 热键 [英] Forcing a terminal not to print Ctrl hotkeys when signals are caught
问题描述
美好的一天,
我正在用 C 为我的学校编写自己的 shell,它必须尽可能地类似于 bash
.
I'm writing my own shell in C for my school which has to resemble bash
as closely as possible.
我必须像 bash
那样处理诸如 Ctrl-\ 和 Ctrl-C 之类的信号;出于这个原因,我被允许使用 signal
功能.它工作正常,但问题是每当捕获到 Ctrl-C 信号时(从第二个捕获开始),就会打印 ^C
.
I have to handle signals such as Ctrl-\ and Ctrl-C as bash
does; for this reason I'm allowed to use signal
function. It works fine, but the thing is whenever a Ctrl-C signal is caught (starting from the second catch), a ^C
is printed.
在网上,我找到了一种解决方法,建议在捕获 Ctrl-C 时打印 "\b \b\b \b\nminishell$ "
,这将吞噬两个符号.问题是,因为在第一次 ^C
没有被打印出来,所以打印消耗了我提示的两个符号,使它只是 minishell
而不是 minishell$
,光标显示不正确.
On the net, I've found a workaround suggesting printing "\b \b\b \b\nminishell$ "
whenever a Ctrl-C is caught, which will devour the two symbols. The thing is, since at the very first time ^C
is not printed, the print devours two symbols of my prompting, making it just minishell
instead of minishell$
, with the cursor incorrectly displayed.
现在我想出了另一种解决方法,即声明一个静态布尔值,以便在第一次调用时不打印 baskspaces.但是,这在 Ctrl-\ 的情况下无济于事;当我尝试编写必须替换 ^\
的两个空格时,Ctrl-\ 继续将光标向右移动.
Now I've come up with another workaround for this workaround which is to declare a static boolean to not print the baskspaces at the very first call. This doesn't help in case of Ctrl-\ though; Ctrl-\ proceeds to move my cursor to right when I attempt to write the two whitespaces that must replace the ^\
.
我不喜欢这些变通办法,想知道是否有办法指示终端不要输出这些东西?我可以使用 tgetent
、tgetflag
、tgetnum
、tgetstr
、tgoto
、tputs
、tcsetattr
、tcgetattr
,已经阅读了他们的手册页,但似乎没有任何帮助.
I don't like these workarounds and would like to know whether there is a way to instruct the terminal not to output this stuff? I'm allowed to use tgetent
, tgetflag
, tgetnum
, tgetstr
, tgoto
, tputs
, tcsetattr
, tcgetattr
, have read their man pages but nothing seems to be helpful.
推荐答案
当您在终端上键入一个键时,会发生两件事
When you type a key on a terminal, two things happen
- 字符在这个终端上回显(显示)
- 字符被发送(通过线路)到附加的程序
这两个动作都可以通过 termios/tcsetattr() 控制:可以发送或回显不同的字符,可以抑制一些字符,等等(这些动作中的一些/大部分发生在终端中-driver ,但这与此处无关)
Both these actions can be controlled via termios/tcsetattr(): a different character(s) can be sent or echoed, some can be suppressed, etc. (some/most of these actions take place in the terminal-driver , but this is not relevant here)
演示:使用tcsetattr()
控制终端的回显:
Demonstration: using tcsetattr()
to control the echoing of the terminal:
#include <stdio.h>
#include <stdlib.h>
#define _SVID_SOURCE 1
#include <termios.h>
#include <unistd.h>
#include <signal.h>
struct termios termios_save;
void reset_the_terminal(void)
{
tcsetattr(0, 0, &termios_save );
}
sig_atomic_t the_flag = 0;
void handle_the_stuff(int num)
{
char buff[4];
buff[0] = '[';
buff[2] = '0' + num%10;
num /= 10;
buff[1] = '0' + num%10;
buff[3] = ']';
write(0, buff, sizeof buff);
the_flag = 1;
}
int main (void)
{
int rc;
int ch;
struct termios termios_new;
rc = tcgetattr(0, &termios_save );
if (rc) {perror("tcgetattr"); exit(1); }
rc = atexit(reset_the_terminal);
if (rc) {perror("atexit"); exit(1); }
termios_new = termios_save;
termios_new.c_lflag &= ~ECHOCTL;
rc = tcsetattr(0, 0, &termios_new );
if (rc) {perror("tcsetattr"); exit(1); }
signal(SIGINT, handle_the_stuff);
printf("(pseudoshell)Start typing:\n" );
while(1) {
ch = getc(stdin);
if (the_flag) {
printf("Saw the signal, last character was %02x\n", (unsigned) ch);
break;
}
}
exit (0);
}
这篇关于捕获信号时强制终端不打印 Ctrl 热键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!