捕获信号时强制终端不打印 Ctrl 热键 [英] Forcing a terminal not to print Ctrl hotkeys when signals are caught

查看:24
本文介绍了捕获信号时强制终端不打印 Ctrl 热键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

美好的一天,

我正在用 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 ^\.

我不喜欢这些变通办法,想知道是否有办法指示终端不要输出这些东西?我可以使用 tgetenttgetflagtgetnumtgetstrtgototputstcsetattrtcgetattr,已经阅读了他们的手册页,但似乎没有任何帮助.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆