键盘输入和文本输出如何工作?

Gil*_*il' 105 keyboard x11 architecture display

假设我A在文本编辑器中按下键,这会a在文档中插入字符并将其显示在屏幕上。我知道编辑器应用程序没有直接与硬件通信(中间有内核和其他东西),那么我的计算机内部发生了什么?

Gil*_*il' 126

有几种不同的场景;我将描述最常见的。连续的宏观事件是:

  1. 输入:按键事件从键盘硬件传输到应用程序。
  2. 处理:应用程序决定因为按键A被按下,所以它必须显示字符a
  3. 输出:应用程序给出在屏幕a上显示的顺序。

图形用户界面应用程序

unix 系统事实上的标准图形用户界面是X Window System,通常称为 X11,因为它在应用程序和显示服务器之间的核心协议的第 11 版中稳定下来。一个称为 X 服务器的程序位于操作系统内核和应用程序之间;它提供的服务包括在屏幕上显示窗口并将按键传输到具有焦点的窗口。

输入

+----------+              +-------------+         +-----+
| keyboard |------------->| motherboard |-------->| CPU |
+----------+              +-------------+         +-----+
             USB, PS/2, …                 PCI, …
             key down/up
Run Code Online (Sandbox Code Playgroud)

首先,关于按键按下和按键释放的信息从键盘传输到计算机和计算机内部。详细信息取决于硬件类型。我不会更多地讨论这一部分,因为信息在整个链的这一部分保持不变:按下或释放某个键。

         +--------+        +----------+          +-------------+
-------->| kernel |------->| X server |--------->| application |
         +--------+        +----------+          +-------------+
interrupt          scancode             keysym
                   =keycode            +modifiers
Run Code Online (Sandbox Code Playgroud)

当硬件事件发生时,CPU 会触发中断,从而导致内核中的某些代码执行。此代码检测硬件事件是来自键盘的按键按下或按键释放,并记录识别按键的扫描代码

X 服务器通过设备文件读取输入事件,例如/dev/input/eventNNN在 Linux 上(其中 NNN 是一个数字)。每当发生事件时,内核都会发出信号,表示有数据要从该设备读取。设备文件使用扫描码传输按键上/下事件,该扫描码可能与硬件传输的值相同也可能不同(内核可能会将扫描码从依赖于键盘的值转换为通用值,而 Linux不会'不重新传输它不知道的扫描码)。

X 调用它读取键码的扫描。X服务器维护转换键码到表键符(以下简称“重点符号”)。键码是数字,而键符是名称,例如A, aacute, F1, KP_Add, Control_L, ... 键符可能因按下的修饰键(Shift, Ctrl, ...)而异。

有两种机制可以配置从键码到键符的映射:

  • xmodmap是传统的机制。它是一个简单的表,将键码映射到键符列表(未修改、移位等)。
  • XKB是一种更强大但更复杂的机制,可以更好地支持更多修饰符,尤其是双语言配置等。

应用程序连接到 X 服务器并在该应用程序的窗口具有焦点时按下某个键时收到通知。该通知指示按下或释放了某个键符以及当前按下了哪些修饰符。您可以通过xev从终端运行程序来查看键符。应用程序如何处理信息取决于它;一些应用程序具有可配置的键绑定。

在典型配置中,当您按下A没有修饰符标记的键时,这会将键符发送a到应用程序;如果应用程序处于您输入文本的模式,则会插入字符a

键盘布局和 xmodmap 的关系更详细地介绍了键盘输入。鼠标事件在 linux 中如何工作?概述了较低级别的鼠标输入。

输出

+-------------+        +----------+          +-----+         +---------+
| application |------->| X server |---····-->| GPU |-------->| monitor |
+-------------+        +----------+          +-----+         +---------+
               text or              varies          VGA, DVI,
               image                                HDMI, …
Run Code Online (Sandbox Code Playgroud)

有两种显示字符的方法。

请参阅不同类型的 XWindows 字体的用途是什么?用于讨论 X11 下的客户端和服务器端文本渲染。

X 服务器和图形处理单元(视频卡上的处理器)之间发生的事情非常依赖于硬件。简单的系统让 X 服务器在称为framebuffer的内存区域中进行绘制,GPU 会选取该区域进行显示。任何 21 世纪 PC 或智能手机上的高级系统都允许 GPU 直接执行某些操作以获得更好的性能。最终,GPU 每隔几分之一秒将屏幕内容逐个像素地传输到显示器。

文本模式应用程序,在终端中运行

如果您的文本编辑器是在终端中运行的文本模式应用程序,那么终端就是用于上述部分目的的应用程序。在本节中,我将解释文本模式应用程序和终端之间的接口。首先描述一个终端模拟器在X11下运行的情况。“终端”、“外壳”、“tty”和“控制台”之间的确切区别是什么?可能是有用的背景。阅读本文后,您可能想阅读更详细的每个伪终端 (PTY) 组件(软件、主端、从端)的职责是什么?

输入

      +-------------------+               +-------------+
----->| terminal emulator |-------------->| application |
      +-------------------+               +-------------+
keysym                     character or
                           escape sequence
Run Code Online (Sandbox Code Playgroud)

终端模拟器接收诸如“Left被按下时Shift被按下”之类的事件。终端模拟器和文本模式应用程序之间的接口是一个伪终端 (pty),一种传输字节的字符设备。当终端仿真器接收到一个按键事件时,它会将其转换为应用程序从 pty 设备读取的一个或多个字节。

ASCII 范围之外的可打印字符根据字符和编码作为一个或多个字节传输。例如,在Unicode字符集的UTF-8编码中,ASCII范围内的字符编码为单个字节,而该范围之外的字符编码为多个字节。

对应于功能键或带有修饰符的可打印字符的按键,例如CtrlAlt作为转义序列发送。转义序列通常由字符转义(字节值 27 = 0x1B = \033,有时表示为^[\e)后跟一个或多个可打印字符组成。一些键或键组合在基于 ASCII 的编码中具有与它们对应的控制字符(今天几乎所有这些键或组合键都在使用,包括 Unicode):Ctrl+letter产生一个 1-26 范围内的字符值,Esc是转义字符看出上述和也一样Ctrl+ [Tab是一样的Ctrl+ IReturnCtrl+M等相同。

不同的终端为给定的键或键组合发送不同的转义序列。幸运的是,反过来不是这样:给定一个序列,实际上它最多编码一个组合键。一个例外是字符 127 = 0x7f =\0177这通常Backspace但有时是Delete.

在终端中,如果您键入Ctrl+V后跟一个组合键,这将按字面意思插入组合键中转义序列的第一个字节。由于转义序列通常仅由第一个之后的可打印字符组成,因此这会按字面意思插入整个转义序列。看到键绑定表了吗?在这种情况下讨论 zsh。

终端可能会为某些修饰符组合传输相同的转义序列(例如,许多终端为SpaceShift+传输空格字符Spacexterm 具有区分修饰符组合的模式,基于流行的 vte 库的终端则没有)。一些键根本不传输,例如修饰键或触发终端仿真器绑定的键(例如复制或粘贴命令)。

如果需要,由应用程序将转义序列转换为符号键名。

输出

+-------------+               +-------------------+
| application |-------------->| terminal emulator |--->
+-------------+               +-------------------+
               character or
               escape sequence
Run Code Online (Sandbox Code Playgroud)

输出比输入简单。如果应用程序向 pty 设备文件输出一个字符,终端仿真器会在当前光标位置显示它。(终端模拟器保持一个光标位置,并在光标落在屏幕底部时滚动。)应用程序还可以输出转义序列(主要以^[或开头^])来告诉终端执行诸如移动光标、更改文本属性(颜色、粗体等),或擦除部分屏幕。

终端仿真器支持的转义序列在termcapterminfo数据库中进行了描述。现在大多数终端模拟器都与xterm非常接近。请参阅有关 LESS_TERMCAP_* 变量的文档?有关终端功能信息数据库的更长时间讨论,以及如何阻止光标闪烁以及我可以设置本地机器的终端颜色以使用我通过 ssh 连接的机器的颜色吗?对于一些使用示例。

在文本控制台中运行的应用程序

如果应用程序直接在文本控制台中运行,即内核提供的终端而不是终端仿真器应用程序,则适用相同的原则。终端和应用程序之间的接口仍然是一个字节流,它传输字符,特殊的键和命令被编码为转义序列。

远程应用程序,通过网络访问

远程文本应用

如果您在远程机器上运行程序,例如通过SSH,则网络通信协议在 pty 级别中继数据。

+-------------+           +------+           +-----+           +----------+
| application |<--------->| sshd |<--------->| ssh |<--------->| terminal |
+-------------+           +------+           +-----+           +----------+
               byte stream        byte stream       byte stream
               (char/seq)         over TCP/…        (char/seq)
Run Code Online (Sandbox Code Playgroud)

这主要是透明的,除了有时远程终端数据库可能不知道本地终端的所有功能。

远程 X11 应用程序

应用程序和服务器之间的通信协议本身就是一个字节流,可以通过网络协议(如 SSH)发送。

+-------------+            +------+        +-----+            +----------+
| application |<---------->| sshd |<------>| ssh |<---------->| X server |
+-------------+            +------+        +-----+            +----------+
               X11 protocol        X11 over       X11 protocol
                                   TCP/…
Run Code Online (Sandbox Code Playgroud)

这大部分是透明的,除了一些需要应用程序和显示器之间直接通信的加速功能(如电影解码和 3D 渲染)不可用。

  • 哇,这一定是我在 Stackexchange 上见过的最好的答案之一——组织良好、回答问题、提供相关上下文、交叉引用其他有用的答案,甚至还有漂亮的 ASCII 艺术! (2认同)

von*_*and 5

如果您想在小到可以理解的 Unix 系统中看到这一点,请深入研究Xv6。或多或少是神话般的 Unix 第 6 版成为了 John Lion 著名评论的基础,长期作为 samizdat 流传。它的代码经过重新设计以在 ANSI C 下编译,并考虑到现代开发,如多处理器。


归档时间:

查看次数:

27185 次

最近记录:

5 年 前