不,我不想使用 ncurses ,因为我想学习如何 终端工作,并自己编程乐趣。 :)它没有 必须是可移植的,它必须仅适用于基于linux xterm的终端模拟器。
我想要做的是编写像htop和vim这样的交互式终端应用程序。我的意思不是字符的输出看起来像盒子或设置颜色,这是微不足道的;还要使内容适合窗口大小。我需要的是
如何获得鼠标交互,例如点击字符并滚动鼠标滚轮(当鼠标位于特定字符时)以实现滚动[编辑:在终端中当然是模拟器]和
如何完全保存并恢复父进程的输出并从输出中分离我的打印,所以在离开我的应用程序后,我在shell中输入的命令应该在那里,就像在运行htop并再次退出时一样:此应用程序不再显示任何内容。
我真的不想使用ncurses。但是,当然,如果您知道ncurses的哪一部分负责这些任务,欢迎您告诉我在源代码中我可以找到它,所以我将研究它。
答案 0 :(得分:18)
为了操作终端,您必须使用控制序列。不幸的是,这些代码取决于您使用的特定终端。这就是为什么terminfo
(以前termcap
)首先存在的原因。
您没有说是否要使用terminfo。所以:
如果您想将其用于学习目的,我将在第二部分详细说明。
您可以从环境变量$TERM
中发现您正在使用的终端类型。在Linux中,最常见的是xterm
用于终端仿真器(XTerm,gnome-terminal,konsole),以及linux
用于虚拟终端(X未运行时)。
您可以使用命令tput
轻松发现控制序列。但是当tput
在控制台上打印它们时,它们会立即应用,所以如果你想真正看到它们,请使用:
$ TERM=xterm tput clear | hd
00000000 1b 5b 48 1b 5b 32 4a |.[H.[2J|
$ TERM=linux tput clear | hd
00000000 1b 5b 48 1b 5b 4a |.[H.[J|
也就是说,要清除xterm
中的屏幕,您必须在xterm中输出ESC [ H ESC [ 2J
,但在Linux终端中输出ESC [ H ESC [ J
。
关于您询问的特定命令,您应该仔细阅读man 5 terminfo
。那里有很多信息。
答案 1 :(得分:7)
虽然这个问题有点陈旧,但我想我应该分享一个如何在不使用ncurses的情况下做到这一点的简短例子,这并不难,但我确信它不会像便携式的。
此代码在原始模式下设置stdin,切换到备用缓冲区屏幕(在启动之前保存终端的状态),启用鼠标跟踪并在用户单击某处时打印按钮和坐标。退出 Ctrl + C 后,程序将恢复终端配置。
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
int main (void)
{
unsigned char buff [6];
unsigned int x, y, btn;
struct termios original, raw;
// Save original serial communication configuration for stdin
tcgetattr( STDIN_FILENO, &original);
// Put stdin in raw mode so keys get through directly without
// requiring pressing enter.
cfmakeraw (&raw);
tcsetattr (STDIN_FILENO, TCSANOW, &raw);
// Switch to the alternate buffer screen
write (STDOUT_FILENO, "\e[?47h", 6);
// Enable mouse tracking
write (STDOUT_FILENO, "\e[?9h", 5);
while (1) {
read (STDIN_FILENO, &buff, 1);
if (buff[0] == 3) {
// User pressd Ctr+C
break;
} else if (buff[0] == '\x1B') {
// We assume all escape sequences received
// are mouse coordinates
read (STDIN_FILENO, &buff, 5);
btn = buff[2] - 32;
x = buff[3] - 32;
y = buff[4] - 32;
printf ("button:%u\n\rx:%u\n\ry:%u\n\n\r", btn, x, y);
}
}
// Revert the terminal back to its original state
write (STDOUT_FILENO, "\e[?9l", 5);
write (STDOUT_FILENO, "\e[?47l", 6);
tcsetattr (STDIN_FILENO, TCSANOW, &original);
return 0;
}
注意:对于列数超过255的终端,这将无法正常工作。
答案 2 :(得分:3)
我有点困惑。你说的是“终端应用”, 像vim;终端应用程序不会获得鼠标事件,也不会 回应鼠标。
如果您正在谈论真正的终端应用程序,它们运行在
xterm
,需要注意的重要思路是许多可移植性
问题涉及终端,而不是操作系统。终端受到控制
通过发送不同的转义序列。哪些取决于终端; ANSI转义码现在相当普遍,但请参阅http://en.wikipedia.org/wiki/ANSI_escape_code。例如,xterm
通常可以理解这些。
您可能必须在开始和结束时输出一个额外的序列才能进入和退出“全屏”模式;这对xterm
来说是必要的。
最后,您必须在输入/输出级别执行一些特殊操作,以确保输出驱动程序不添加任何字符(例如,将简单的LF转换为CRLF),并确保输入不回显,是透明的,并立即返回。在Linux下,这是使用ioctl
完成的。 (再次,不要忘记在完成后恢复它。)