c-如何在Linux终端中获取当前键盘光标的位置



我正在处理Ubuntu中的一个问题。我想通过Gcc获取终端中当前键盘光标的位置任何协助。。。

"终端";是一个程序,或者更准确地说是一大类程序的描述,它实现了一个模拟外部终端的图形界面(该终端可能通过串行电缆或类似方式连接到您的计算机)。您的程序通过操作系统实现的一种双向管道("伪终端")与终端模拟器通信;对于您的程序来说,它看起来像一对普通流(stdinstdout)。

Linux本身有一个终端模拟器;控制台";,其可以代替窗口管理器来使用。现在很少有程序员使用它,但如果你想进行实验,它仍然存在。控制台是一个";终端";(通常有几个可以使用控制+功能键进行切换)。正如你从单词";终端";以及";"伪终端";,这些在您的应用程序中基本上看起来是一样的。

有很多细节,我跳过了,因为需要一本书来描述整个事情。

你的程序和终端(或伪终端)之间的唯一连接是,你可以向它发送一个字符流,也可以从中接收一个字符。没有其他通信。没有隐藏的操作系统接口,因为终端模拟器不是操作系统的一部分。它甚至不是窗口管理器的一部分。这只是另一个没有特殊权限运行的userland应用程序,就像您的应用程序一样。

除了将字符发送到输出设备之外,您通常希望执行其他操作。也许你想清除屏幕,或者把光标移到另一个位置,或者改变文本或背景的颜色。所有这些都是通过发送特殊编码的序列来完成的,这些序列穿插在您显示的文本中。操作系统不会调解或验证这些序列,终端模拟器应该如何解释它们也没有明确的标准,但在某种程度上,大多数终端模拟器都遵循一个通用的框架,这使得实际编写代码成为可能,而无需确切知道目前使用的是哪个终端模拟器。terminfo库通常用于描述可用的终端;按照惯例,环境变量TERM包含相关终端配置的名称,该配置可用于创建适用于配置终端的具体控制序列字符串[注1]。

现在让我们回到你最初的问题:;如何查找当前光标位置"这是少数可能的查询之一,这些查询也被实现为控制序列。具体来说,您向终端发送一个控制序列,询问光标在哪里(通常是四个字符x1B[6n),终端最终用一个看起来像x1B12,7R的控制序列进行回复,这意味着在发送控制序列的那一刻,光标在第12行第7列[注2]。因此,您可以使用terminfo来帮助发送查询,然后在回复到来时尝试解析它。

请注意,响应与查询不同步,因为发送查询时用户可能正在键入。(但是,响应是作为连续序列发送的。)因此,解析过程的一部分是将用户输入与查询响应分离。

我的猜测是,你实际上并不想做所有的工作。在大多数情况下,如果您想编写一个控制台应用程序,它可以做一些比只将输出顺序写入终端窗口更无聊的事情,那么您应该使用ncurses(也由Thomas Dickey维护)或其他类似的库。Ncurses全权负责维护控制台图像,跳过必要的关卡与终端仿真器进行通信;其特征之一是跟踪当前光标位置[注3]。

如果您只是想提供更好的行编辑和选项卡完成,另一种选择是使用GNU Readline库,或其他操作系统可用的类似接口。


注释

  1. 这可能是也可能不是您实际使用的终端,因为TERM只是一个环境变量。如果你想要的话,你可以自己设置。

  2. 我从man 4 console_codes中获取了这些代码;另一个很好的信息来源是Thomas Dickey的xterm所理解的代码序列的简洁列表。

  3. 据我所知,Ncurses并没有使用光标位置查询来确定光标在屏幕上的位置。它保留自己显示的屏幕副本,其中包括当前光标位置。您可以使用宏getyx()来询问它认为当前光标位置是什么。

大多数终端都支持光标位置报告功能,因为它位于ECMA-48中。

它记录在xterm的控制序列中:

CSI Psn设备状态报告(DSR)

Ps=6⇒报告光标位置(CPR)[]
结果为CSIrcR

其中CSI定义为

ESC [
对照序列导入器(CSI为0x9b)。

例如,调整大小程序使用此功能来查找实际屏幕大小。它通过告诉终端将光标移动到第9999行第9999列,并从ESC6n获得响应来实现这一点(参见代码):

static const char *const getsize[EMULATIONS] =
{
ESCAPE("7") ESCAPE("[r") ESCAPE("[9999;9999H") ESCAPE("[6n"),
ESCAPE("[18t"),
};

该功能没有标准的terminfo功能,但ncurses使用u6/u7来表示:

# INTERPRETATION OF USER CAPABILITIES
#
# The System V Release 4 and XPG4 terminfo format defines ten string
# capabilities for use by applications, <u0>...<u9>.   In this file, we use
# certain of these capabilities to describe functions which are not covered
# by terminfo.  The mapping is as follows:
#
#       u9      terminal enquire string (equiv. to ANSI/ECMA-48 DA)
#       u8      terminal answerback description
#       u7      cursor position request (equiv. to VT100/ANSI/ECMA-48 DSR 6)
#       u6      cursor position report (equiv. to ANSI/ECMA-48 CPR)
#
# The terminal enquire string <u9> should elicit an answerback response
# from the terminal.  Common values for <u9> will be ^E (on older ASCII
# terminals) or E[c (on newer VT100/ANSI/ECMA-48-compatible terminals).
#
# The cursor position request (<u7>) string should elicit a cursor position
# report.  A typical value (for VT100 terminals) is E[6n.

使得使用terminfo数据库的程序可以检查给定终端是否支持该特征。

最新更新