我正在开发多个 C 程序,例如 shell 和文本编辑器,这些程序需要在没有 ECHO 和 ICANON 标志的情况下运行。我使用 termios.h 禁用了这些功能,并设法编写了自己的 gets 函数,该函数可以将返回的字符串中继到我的程序,并对转义字符执行特殊操作。我唯一不能做的就是打印退格键。例如,如果我使用以下代码:
void mgets(char *str)
{
int c, i = 0;
while((c = getchar()) != '\n')
if(c == 27)
// the user hit ESC, ignore it for now
else if(c == '\b')
puts("\b \b") // this is where it SHOULD backspace
// else if it's a regular character:
else {
str+i = c; i++; // write that to the string...
putchar(c); // ...and echo it to the screen
}
}
一切都很好,但当我退格时程序没有响应。如果我稍微改变一下 if 语句...
if(c == '\b')
printf("You hit a backspace!");
但它仍然没有反应。我知道 put("\b \b") 有效,所以唯一的结论是我的退格键没有被检测为 '\b'。我能做些什么?请帮忙?提前致谢!
答案1
前您更改 termios 设置,节省他们。该信息与您所看到的“相同”stty -a
。
例如
$ stty -a
speed 38400 baud; rows 40; columns 80; line = 0;
intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke
之后显示的值erase
是您所说的“退格键”字符。根据系统约定,可能是^H
(8 或 ASCII 退格键)或^?
(127 或 ASCII DEL)。
在 termios 设置中,例如,
#include <termios.h>
...
struct termios data;
tcgetattr(0, &data);
然后
data.c_cc[VERASE]
是一样的擦除字符(当数据从未设置时有一些警告:stty
将显示“undef”)。
与其他一些设置不同,擦除字符在 raw/cbreak 模式中仍然相关,因为它是一个告诉终端驱动程序您的终端预计发送什么内容的设置。如果您的stty
设置不正确,测试这两种可能性并没有什么坏处......
进一步阅读:
答案2
我的退格键没有被检测为“\b”。我能做些什么?
⌫(退格)和(删除)键生成的控制或转义序列⌦各不相同。
在尝试类似于 DEC VT 的终端上:
- 该⌦按键发出 DECFNK 控制序列。
- 的行为⌫可在 ASCII BS 和 DEL 字符之间切换,并向终端发送名为 DECBKM 的控制序列。
但并不是每个终端(模拟器)都尝试像 DEC VT 一样,更不用说实现 DECBKM 机制了。您不能只是硬连线键盘输入序列并期望它们在所有情况下都能工作。
你的程序需要工作的方式是这样的:它需要从环境变量中获取终端类型,从(或)数据库TERM
中获取相应的记录,并在那里查找两个功能:terminfo
termcap
kbs
( ) —密钥kb
发送的序列⌫kdch1
( ) —密钥kD
发送的序列⌦
它必须将这些字符串与其读取的输入相匹配。为了区分实际的控制序列和简单的按下,Esc您的程序需要比fgetc()
循环更复杂。您必须设置非规范模式并设置(短)读取超时。仅当read()
在超时期限内返回整个字符串时,才应将其视为输入控制序列。
请注意,这里设置的特殊字符stty
几乎是转移注意力。它们不适用于非规范模式,并且仅影响线路纪律反正。这终端的行为完全取决于它如何将硬件按键事件映射到控制序列,然后将其“沿着线路”发送到线路规程。如前所述,终端可以通过多种方式自由地执行此操作,从使用键码和控制序列(FreeBSD 内置内核终端仿真器)之间的可加载映射到 X 资源。
进一步阅读
- VT510视频终端编程器信息。 EK-VT510-RM。 1993 年 11 月。
- VT520/VT525视频终端编程器信息。 EK-VT520-RM。 1994 年 7 月。
- 为什么“shift-tab”会在终端中导致“Escape”?
- https://unix.stackexchange.com/a/299423/5132