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

#1 楼

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


输入:按键事件从键盘硬件传输到应用程序。
处理:应用程序确定是因为按下了键A ,它必须显示字符a
输出:应用程序命令在屏幕上显示a

GUI应用程序

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

输入

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


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

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


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

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

X调用它读取密钥代码的扫描代码。 X服务器维护一个表,该表将键控代码转换为键符(“键符”的缩写)。按键代码是数字,而按键符号是诸如AaacuteF1KP_AddControl_L之类的名称,…按键符号可能会有所不同,具体取决于所按下的修饰键(Shift,Ctrl等)。有两种机制可以配置从键码到键符的映射:xmodmap是传统机制。它是一个简单的表,将键代码映射到一个keyyms列表(未修改,已移位...)。语言配置等。

应用程序连接到X服务器并在该应用程序的窗口具有焦点的情况下按下键时收到通知。该通知表明已按下或释放了某个键,以及当前按下了哪些修饰符。您可以通过从终端运行程序xev来查看按键符号。应用程序如何处理信息就可以了;在某些典型的配置中,当您按没有修饰符的标有A的键时,这会将键盘符号a发送给该应用程序。如果应用程序处于您键入文本的模式下,则会插入字符a

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

输出

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


有两种显示字符的方法。



服务器端渲染:应用程序告诉X服务器“在此位置以这种字体绘制此字符串”。字体驻留在X服务器上。

客户端渲染:应用程序生成一个图像,该图像以其选择的字体表示该字符,然后告诉X服务器显示该图像。 >
请参阅不同类型的XWindows字体的用途是什么?有关在X11下进行客户端和服务器端文本渲染的讨论。简单的系统将X服务器绘制在称为帧缓冲区的内存区域中,GPU会选择该缓冲区进行显示。诸如21世纪任何PC或智能手机上的高级系统都可以使GPU直接执行某些操作,以提高性能。最终,GPU会每隔一秒将像素的屏幕内容逐像素传输到监视器。文本模式应用程序在终端中运行,那么就以上部分而言,终端就是该应用程序。在本节中,我将解释文本模式应用程序和终端之间的接口。首先,我描述了在X11下运行终端仿真器的情况。 “终端”,“外壳”,“ tty”和“控制台”之间的确切区别是什么?在这里可能是有用的背景。阅读本文之后,您可能想要阅读更详细的内容,每个伪终端(PTY)组件(软件,主控端,从属端)的职责是什么? br />
      +-------------------+               +-------------+
----->| terminal emulator |-------------->| application |
      +-------------------+               +-------------+
keysym                     character or
                           escape sequence


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

ASCII范围之外的可打印字符将作为一个或多个字节进行传输取决于字符和编码。例如,在Unicode字符集的UTF-8编码中,ASCII范围内的字符被编码为单个字节,而超出范围的字符被编码为多个字节。

对应的按键功能键或带有修饰符(例如Ctrl或Alt)的可打印字符发送到转义序列。转义序列通常由字符转义(字节值27 = 0x1B = 3,有时表示为^[\e)组成,后跟一个或多个可打印字符。在基于ASCII的编码中,一些键或组合键具有与之相对应的控制字符(今天几乎所有这些键都在使用中,包括Unicode):Ctrl +字母产生的字符值范围为1至26,Esc上面显示的转义字符,也与Ctrl + [相同,Tab与Ctrl + I相同,Return与Ctrl + M相同,依此类推。

不同的终端为给定键或组合键。幸运的是,事实并非如此:给定一个序列,实际上最多只能编码一个组合键。一个例外是字符127 = 0x7f = 77,该字符通常为Backspace键,但有时为Delete键。

在终端中,如果键入Ctrl + V后跟一个组合键,则会从字面上直接插入转义序列的第一个字节。由于转义序列通常仅在第一个字符之后包含可打印字符,因此这会按字面意义插入整个转义序列。看到键绑定表?在此上下文中讨论zsh。

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

由应用程序来翻译转义序列如果需要,可以将其转换为符号键名称。

输出

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


输出比输入要简单得多。如果应用程序将字符输出到pty设备文件,则终端仿真器将其显示在当前光标位置。 (终端仿真器保持光标位置,并滚动,如果光标将落在屏幕底部下方。)应用程序还可以输出转义序列(主要以^[^]开头),以告知终端执行诸如移动键盘,光标,更改文本属性(颜色,粗体,...)或擦除屏幕的一部分。termcap或terminfo数据库中描述了终端仿真器支持的转义序列。如今,大多数终端仿真器都与xterm紧密结合。请参阅有关LESS_TERMCAP_ *变量的文档?有关终端功能信息数据库的详细讨论,以及如何使光标停止闪烁,并且可以设置本地计算机的终端颜色以使用ssh进入的计算机的终端颜色吗?有关一些用法示例。

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

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

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

远程文本应用程序

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



远程X11应用程序

服务器本身的应用程序之间的通信协议本身就是字节流,可以通过诸如SSH之类的网络协议发送。 br />
+-------------+           +------+           +-----+           +----------+
| application |<--------->| sshd |<--------->| ssh |<--------->| terminal |
+-------------+           +------+           +-----+           +----------+
               byte stream        byte stream       byte stream
               (char/seq)         over TCP/…        (char/seq)


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

评论


不能完全确定,但是由于答案通常比较详细,所以我想知道“应用程序在文本控制台中运行”这一部分是否可能没有以man 5键映射为例将键码转换为扫描码的功能。如前所述,它基本上是一组完全不同的工具/程序,这可能值得更多的见解。其次,答案是+1,因为嵌入的相关问题非常好。

–人类与和平
16年1月1日在8:38

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

–stewbasic
17年8月9日,0:06

@stewbasic是的,具有由loadkeys加载的键映射。搜索标记为linux console键盘布局的问题。

–吉尔斯'所以-不再是邪恶的'
17年8月9日,0:09

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

–stewbasic
17年8月9日在22:02

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

–Johntron
18年1月27日在4:28

#2 楼

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