如何在Linux终端中获取当前键盘光标位置
我正在处理Ubuntu的一个问题。我想通过GCC在终端中获得当前的键盘光标位置 任何协助...
I am dealing with an issue in Ubuntu. I want to get current keyboard cursor position in terminal via Gcc
any assist...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
“终端”是一个程序,或更准确地描述了一大类程序,该程序实现了模拟外部终端的图形接口(该界面将通过串行电缆或某些类似的方式连接到您的计算机)。您的程序通过操作系统实施的一种双向管道(一种“伪射管”)与终端模拟器进行通信;对于您的程序,它看起来像一对普通流(
stdin
和stdout
)。Linux本身具有终端模拟器,称为“控制台”,可以使用该模拟器代替窗口管理器。如今,很少有程序员使用它,但是如果您想尝试一下,它仍然存在。控制台是“终端”(通常有几个可以在使用Control+函数键之间切换)。正如您可能从“终端”和“伪类似”一词中所期望的那样,这些基本上对您的应用程序看起来相同。
有很多细节,我会跳过来,因为这需要一本书来描述整个事情。
您的程序与终端(或伪情报)之间的唯一连接是您可以发送一组字符,并且可以从中收到一系列字符。没有其他交流。没有隐藏的操作系统接口,因为终端模拟器不是操作系统的一部分。它甚至不是窗口管理器的一部分。就像您的应用程序一样,这只是另一个没有特殊特权的Userland应用程序。
您经常想做其他事情,而只是将字符发送到输出设备。也许您想清除屏幕,或将光标移至另一个位置,或更改文本或背景的颜色。所有这些事情都是通过发送特殊编码的序列来完成的,这些序列散布在您显示的文本中。操作系统没有调解或验证这些序列,并且对于终端仿真器的解释没有确定的标准,但是有一些共同的框架在某种程度上符合大多数终端模拟器,这使得实际上可以写代码。目前不需要确切知道正在使用哪个终端模拟器。 terminfo库通常用于描述可用的终端;按照惯例,环境变量
术语
包含相关终端配置的名称,并且该配置可用于创建适用于配置的终端[Note 1]的混凝土控制序列字符串。现在让我们回到您的最初问题:“我如何找出当前的光标位置?”这是少数可能的查询之一,也将其作为控制序列实现。具体来说,您向终端发送了一个控制sequnce,该控制sequnce询问光标在哪里(通常是四个字符
\ x1b [6n
),终端最终使用控制序列回复,看起来像>
> \ x1b12,7r
表示光标在发送控制序列时在第7列的第12行上[Note 2]。因此,您可以使用terminfo
来帮助您发送查询,然后尝试在回复时解析。请注意,响应与查询不同步,因为在发送查询时可以输入用户。 (但是,响应是作为连续序列发送的。)因此,解析过程的一部分是将用户输入从查询响应中解散。
我的猜测是,您实际上并不想做所有工作。在大多数情况下,如果要编写一个控制台应用程序,该应用程序应用程序的操作比仅在终端窗口上依次写入输出不那么无聊,则应使用 ncurses (也由托马斯·迪基(Thomas Dickey)维护)或其他一些类似的库。
ncurses
对维护控制台映像承担全部责任,跳过必要的箍与终端模拟器进行通信;它的功能之一是跟踪当前光标位置[注3]。另一个选项是,如果您仅尝试提供更好的行编辑和选项卡的完成,则是使用 gnu readline < /a>库或其他操作系统的类似接口。
Notes
这可能是您实际使用的终端,因为
TERM
只是环境变量。如果您想要的话,可以自己设置。我从
man 4 Console_codes
中获取了这些代码;另一个良好的信息来源是 thomas dickey' xterm 。"Terminal" is a program, or more accurately a description of a large class of programs, which implements a graphical interface emulating an external terminal (which would have been connected to your computer via a serial cable, or in some similar fashion). Your program communicates with the terminal emulator through a kind of bidirectional pipe (a "pseudoterminal") implemented by the operating system; to your program it looks like a pair of ordinary streams (
stdin
andstdout
).Linux itself has a terminal emulator, called "the console", which can be used instead of a window manager. Few programmers use it these days, but it's still there if you want to experiment. The console is a "terminal" (and there are usually several of them which you can switch between using a control+function key). As you might expect from the words "terminal" and "pseudoterminal", these basically look the same to your application.
There are a ton of details, which I'm skipping over because it would take a book to describe the whole thing.
The only connection between your program and the terminal (or pseudoterminal) is that you can send it a stream of characters, and you can receive a stream of characters from it. There is no other communication. There's no hidden operating system interface, because the terminal emulator is not part of the operating system. It's not even part of the window manager. It's just another userland application running without special privileges, just like your application.
You often want to do things other than just send characters to the output device. Maybe you want to clear the screen, or move the cursor to another location, or change the colour of the text or the background. All of these things are done by sending specially coded sequences interspersed with the text you're displaying. The operating system doesn't mediate or verify these sequences, and there's no definitive standard for how the terminal emulator should interpret them, but there is common framework which most terminal emulators conform to, to some extent, which makes it possible to actually write code which doesn't need to know exactly which terminal emulator is being used at the moment. The terminfo library is commonly used to describe the available terminals; by convention, the environment variable
TERM
contains the name of the relevant terminfo configuration, and that configuration can be used to create concrete control sequence strings suitable for the configured terminal [Note 1].Now let's get back to your initial question: "how do I find out the current cursor location?" That's one of a small number of possible queries, which are also implemented as control sequences. Specifically, you send the terminal a control sequnce which asks it where the cursor is (usually the four characters
\x1B[6n
) and the terminal eventually replies with a control sequence which might look something like\x1B12,7R
meaning that the cursor was on row 12 at column 7 at the moment that the control sequence was sent [Note 2]. So you could useterminfo
to help you send the query and then attempt to parse the reply when it comes.Note that the response is not synchronous with the query, since the user could be typing while the query is sent. (However, the response is sent as a contiguous sequence.) So part of the parsing process is disentangling the user input from the query response.
My guess is that you don't actually want to do all that work. In most cases, if you want to write a console application which does something less boring than just write output sequentially to a terminal window, you should use ncurses (also maintained by Thomas Dickey) or some other similar library.
Ncurses
takes full responsibility for maintaining the console image, jumping through the necessary hoops to communicate with the terminal emulator; one of its features is to keep track of the current cursor position [Note 3].Another option, if you are only trying to provide better line editing and tab completion, is to use the GNU Readline library, or similar interfaces available for other operating systems.
Notes
This might or might not be the terminal you're actually using, since
TERM
is just an environment variable. You could set it yourself if you wanted it.I took those codes from
man 4 console_codes
; another good source of information is Thomas Dickey's terse list of code sequences understood byxterm
.As far as I know, Ncurses does not use the cursor-position query to figure out where the cursor is on the screen. It maintains its own copy of the screen being displayed, which includes the current cursor position. You can use the macro
getyx()
to ask for what it considers the current cursor position.大多数终端都支持A 光标位置报告功能,因为它在ECMA-48中。
It is documented in xterm's
其中 csi 已定义
调节程序使用此功能,例如查找实际的屏幕尺寸。它是通过告诉终端将光标移至第9999列,第9999列并从 esc [ 6 n (请参阅
https://github.com/thomasdickey/xterm-snapshots/blob/c2b36af8d216926b8931c6b8931c6c6f9cebefd692228e437c/resize.c/resize.c.c#l143 is no standard terminfo capability for the feature, but ncurses uses u6/u7< /a>表示它:
因此,使用终端数据库的程序可以检查给定终端是否支持该功能。
Most terminals support a cursor-position report feature, because it is in ECMA-48.
It is documented in xterm's control-sequences:
where CSI is defined
The resize program uses this feature for instance, to find the actual screen size. It does that by telling the terminal to move the cursor to row 9999, column 9999 and getting the response from ESC[6n (see code):
There is no standard terminfo capability for the feature, but ncurses uses u6/u7 to represent it:
so that programs which use the terminfo database can check if the feature is supported for a given terminal.