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


85

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

Answers:


100

有几种不同的方案。我将介绍最常见的那些。连续的宏观事件是:

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

GUI应用

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

输入值

+----------+              +-------------+         +-----+
| keyboard |------------->| motherboard |-------->| CPU |
+----------+              +-------------+         +-----+
             USB, PS/2, …                 PCI, …
             key down/up

首先,有关按键和释放键的信息从键盘传输到计算机以及计算机内部。详细信息取决于硬件类型。在这一部分中,我不会再赘述,因为在整个链的这一部分中,信息都是相同的:按下或释放某个键。

         +--------+        +----------+          +-------------+
-------->| kernel |------->| X server |--------->| application |
         +--------+        +----------+          +-------------+
interrupt          scancode             keysym
                   =keycode            +modifiers

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

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

X调用它读取密钥代码的扫描代码。X服务器维护转换键码到表键符(以下简称“重点符号”)。键码是数字的,而键符的名字,如AaacuteF1KP_AddControl_L,...的键符可以根据在其上按下修改键(不同ShiftCtrl...)。

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

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

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

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

键盘布局和xmodmap的关系在键盘输入上有更详细的说明。鼠标事件在Linux中如何工作?概述了较低级别的鼠标输入。

输出量

+-------------+        +----------+          +-----+         +---------+
| application |------->| X server |---····-->| GPU |-------->| monitor |
+-------------+        +----------+          +-----+         +---------+
               text or              varies          VGA, DVI,
               image                                HDMI, …

有两种显示字符的方法。

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

X服务器与图形处理单元(视频卡上的处理器)之间发生的情况与硬件有关。简单的系统将X服务器绘制在称为framebuffer的内存区域中,GPU会拾取该内存以进行显示。诸如21世纪PC或智能手机上的高级系统都可以使GPU直接执行某些操作,以提高性能。最终,GPU每隔几分之一秒将屏幕内容逐像素传输到监视器。

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

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

输入值

      +-------------------+               +-------------+
----->| terminal emulator |-------------->| application |
      +-------------------+               +-------------+
keysym                     character or
                           escape sequence

终端仿真器接收到诸如“ 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

输出比输入要简单得多。如果应用程序将字符输出到pty设备文件,则终端仿真器将其显示在当前光标位置。(终端仿真器保持光标位置,并滚动如果光标将落在屏幕底部下方。)应用程序还可以输出转义序列(主要以^[或开头^]),以告知终端执行诸如移动光标,更改文本属性(颜色,粗体等)或删除屏幕的一部分。

termcapterminfo数据库中描述了终端仿真器支持的转义序列。如今,大多数终端仿真器都与xterm紧密结合。请参阅有关LESS_TERMCAP_ *变量的文档?有关终端功能信息数据库的详细讨论,以及如何停止光标闪烁,是否可以将本地计算机的终端颜色设置为使用ssh进入的计算机的终端颜色?对于一些用法示例。

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

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

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

远程文本应用

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

+-------------+           +------+           +-----+           +----------+
| application |<--------->| sshd |<--------->| ssh |<--------->| terminal |
+-------------+           +------+           +-----+           +----------+
               byte stream        byte stream       byte stream
               (char/seq)         over TCP/…        (char/seq)

这几乎是透明的,只是有时远程终端数据库可能不知道本地终端的所有功能。

远程X11应用

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

+-------------+            +------+        +-----+            +----------+
| application |<---------->| sshd |<------>| ssh |<---------->| X server |
+-------------+            +------+        +-----+            +----------+
               X11 protocol        X11 over       X11 protocol
                                   TCP/…

这几乎是透明的,除了某些加速功能(如电影解码和3D渲染)无法在应用程序和显示器之间进行直接通信之外,这是不可用的。


不能完全确定,但是由于答案通常比较详细,所以我想知道“在文本控制台中运行的应用程序”这一部分是否可能不包含将诸如此类man 5 keymaps的内容翻译keycodes为的内容scancodes。如前所述,它基本上是一组完全不同的工具/程序,这可能值得更多的见解。其次,答案是+1,因为嵌入的相关问题非常好。
humanityANDpeace

我在tty1(TERM = linux)中发现了PgUp并且Ctrl+PgUp无法区分。可以配置keysym->控制序列映射吗?
stewbasic

@stewbasic是的,键映射由加载loadkeys。搜索标记为linux console keyboard-layout的问题
吉尔斯

@吉尔斯谢谢!值得注意的是,loadkeys会同时更改键码-> keysym和keysym->转义序列的映射(这在我看来并不明显)。
stewbasic

1
哇,这一定是我在Stackexchange上见过的最好的答案之一-井井有条,回答问题,提供相关上下文,交叉引用其他有用的答案,甚至具有很好的ASCII艺术!
Johntron '18年

4

如果要在足够小以至于可以理解的Unix系统中看到它,请深入Xv6。神话般的Unix第6版或多或少地成为John Lion著名评论的基础,长期以来以samizdat的形式发行。它的代码经过重新设计,可以在ANSI C下进行编译,并考虑到了诸如多处理器之类的现代开发。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.