web-dev-qa-db-ja.com

キーボード入力とテキスト出力はどのように機能しますか?

私が押したとしましょう A テキストエディターでキーを押すと、ドキュメントにaが挿入され、画面に表示されます。エディターアプリケーションがハードウェアと直接通信していないことを知っています(その間にカーネルなどがある)ので、コンピューター内で何が起こっているのですか?

いくつかの異なるシナリオがあります。最も一般的なものについて説明します。連続する巨視的イベントは次のとおりです。

  1. 入力:キーを押すイベントがキーボードハードウェアからアプリケーションに送信されます。
  2. 処理:アプリケーションは、キーが A が押された場合、文字aを表示する必要があります。
  3. 出力:アプリケーションは、画面にaを表示するように命令します。

GUIアプリケーション

UNIXシステムの事実上の標準的なグラフィカルユーザーインターフェイスは X Window System で、アプリケーションとディスプレイサーバー間のコアプロトコルの11番目のバージョンで安定したため、X11と呼ばれることがよくあります。 Xサーバーと呼ばれるプログラムは、オペレーティングシステムのカーネルとアプリケーションの間にあります。画面にウィンドウを表示したり、フォーカスのあるウィンドウにキー入力を送信したりするサービスを提供します。

入力

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

まず、キーの押し下げに関する情報がキーボードからコンピュータおよびコンピュータ内部に送信されます。詳細はハードウェアのタイプによって異なります。チェーンのこの部分全体で情報が同じであるので、この部分についてこれ以上詳しく説明しません。特定のキーが押されたか、離されました。

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

ハードウェアイベントが発生すると、CPUは interrupt をトリガーします。これにより、 kernel のコードが実行されます。このコードは、ハードウェアイベントがキーボードからのキープレスまたはキーリリースであることを検出し、 scan code を記録します。キー。

Xサーバーは デバイスファイル を介して入力イベントを読み取ります。たとえば、Linuxの/dev/input/eventNNN(NNNは数値)です。イベントがあると、カーネルはそのデバイスから読み取るデータがあることを通知します。デバイスファイルは、キーアップ/ダウンイベントをスキャンコードとともに送信します。スキャンコードは、ハードウェアによって送信される値と同じであってもなくてもかまいません(カーネルがスキャンコードをキーボード依存の値から一般的な値に変換する場合があり、Linux- わからないスキャンコードは再送信しません )。

Xはkeycodeを読み取るスキャンコードを呼び出します。 Xサーバーは、キーコードを keysyms (「キーシンボル」の略)に変換するテーブルを保持しています。キーコードは数値ですが、keysymはAaacuteF1KP_AddControl_L、…などの名前です。keysymは、修飾キーが押された(Shift、 Ctrl、…)。

キーコードからキーシムへのマッピングを設定するには、2つのメカニズムがあります。

  • xmodmap は従来のメカニズムです。これは、キーコードをキーシムのリスト(変更されていない、シフトされている、…)にマッピングする単純なテーブルです。
  • [〜#〜] xkb [〜#〜] はより強力ですが、より複雑なメカニズムであり、とりわけ、より多くの修飾子、特に2言語構成のサポートが向上しています。

アプリケーションはXサーバーに接続し、そのアプリケーションのウィンドウにフォーカスがあるときにキーが押されると通知を受け取ります。通知は、特定のキーシムが押されたか解放されたこと、および現在押されている修飾子を示します。端末からプログラム xev を実行すると、キーシムを確認できます。アプリケーションが情報をどのように処理するかは、アプリケーション次第です。一部のアプリケーションには、構成可能なキーバインディングがあります。

典型的な構成では、ラベルの付いたキーを押すと A 修飾子なしで、これはkeysym aをアプリケーションに送信します。アプリケーションがテキストを入力しているモードの場合、これはaを挿入します。

キーボードレイアウトとxmodmapの関係 は、キーボード入力についてさらに詳しく説明します。 Linuxでのマウスイベントの仕組み は、下位レベルでのマウス入力の概要を示します。

出力

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

キャラクターを表示するには2つの方法があります。

X11でのクライアント側とサーバー側のテキストレンダリングについては、 XWindowsフォントのさまざまな種類の目的は何ですか? を参照してください。

Xサーバーと グラフィックスプロセッシングユニット (ビデオカードのプロセッサ)の間で何が起こるかは、ハードウェアに大きく依存します。単純なシステムでは、Xサーバーは framebuffer と呼ばれるメモリ領域に描画し、GPUはこれを表示用に取得します。 21世紀のPCやスマートフォンに見られるような高度なシステムにより、GPUは一部の操作を直接実行してパフォーマンスを向上させることができます。最終的に、GPUはスクリーンコンテンツをピクセル単位で1秒ごとにモニターに送信します。

端末で実行されているテキストモードアプリケーション

テキストエディターがターミナルで実行されているテキストモードアプリケーションである場合、それは上記のセクションの目的のためのアプリケーションであるターミナルです。このセクションでは、テキストモードアプリケーションと端末間のインターフェイスについて説明します。まず、X11で実行されている ターミナルエミュレータ の場合について説明します。 「ターミナル」、「シェル」、「tty」、および「コンソール」の正確な違いは何ですか? ここで役立つ背景になるかもしれません。これを読んだ後、もっと詳細に読みたいと思うかもしれません 各擬似端末(PTY)コンポーネント(ソフトウェア、マスター側、スレーブ側)の責任は何ですか?

入力

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

端末エミュレータは、「LeftがダウンしているときにShiftが押された」などのイベントを受け取ります。ターミナルエミュレータとテキストモードアプリケーションの間のインターフェースは pseudo-terminal(pty) 、a キャラクターデバイス バイトを送信します。端末エミュレーターは、キープレスイベントを受信すると、これを1つ以上のバイトに変換し、アプリケーションがこれをptyデバイスから読み取ります。

ASCIIの範囲外の印刷可能な文字は、文字と encoding に応じて1バイト以上として送信されます。たとえば、 TF-8 = nicode 文字セットのエンコード、 [〜#〜] ascii [〜#〜] 範囲内の文字は1バイトとしてエンコードされ、その範囲外の文字は複数バイトとしてエンコードされます。

ファンクションキーまたは次のような修飾子を持つ印刷可能な文字に対応するキーを押す Ctrl または Alt エスケープシーケンス として送信されます。エスケープシーケンスは通常、文字 escape (バイト値27 = 0x1B = \033、時々^[または\eとして表される)と、それに続く1つ以上の印刷可能な文字で構成されます。 。いくつかのキーまたはキーの組み合わせには、ASCIIベースのエンコーディングでそれらに対応する 制御文字 があります(これは、現在Unicodeを含むほとんどすべてが使用されています)。 Ctrl+letter 1から26の範囲の文字値を生成します。 Esc 上記のエスケープ文字であり、以下と同じです Ctrl+[、 Tab と同じです Ctrl+I、 Return と同じです Ctrl+M、など.

異なる端末は、特定のキーまたはキーの組み合わせに対して異なるエスケープシーケンスを送信します。幸いなことに、その逆は当てはまりません。シーケンスが与えられた場合、実際には最大で1つのキーの組み合わせでエンコードされます。 1つの例外は、文字127 = 0x7f = \0177です。 Backspace でも時々 Delete

端末で、あなたがタイプした場合 Ctrl+V その後にキーの組み合わせが続きます。これにより、文字のキーの組み合わせからエスケープシーケンスの最初のバイトが挿入されます。エスケープシーケンスは通常、最初の文字の後の印刷可能な文字のみで構成されるため、これにより、エスケープシーケンス全体が文字どおりに挿入されます。このコンテキストでのzshの説明については、 key bindings table? を参照してください。

端末は、一部の修飾子の組み合わせに対して同じエスケープシーケンスを送信する場合があります(たとえば、多くの端末は両方のスペース文字を送信します Space そして Shift+Space; xtermには修飾子の組み合わせを区別するモードがあります ですが 人気のあるvteライブラリに基づく端末にはありません )。一部のキーはまったく送信されません。たとえば、修飾キーやターミナルエミュレーターのバインドをトリガーするキー(コピーまたは貼り付けコマンドなど)です。

必要に応じて、エスケープシーケンスをシンボリックキー名に変換するのはアプリケーション次第です。

出力

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

出力は入力よりもかなり単純です。アプリケーションが文字をptyデバイスファイルに出力する場合、端末エミュレータは現在のカーソル位置に文字を表示します。 (端末エミュレータはカーソル位置を維持し、カーソルが画面の下部にある場合はスクロールします。)アプリケーションはエスケープシーケンス(主に^[または^]で始まる)を出力して、カーソルの移動、テキスト属性の変更(色、太字など)、または画面の一部の消去などのアクションを実行するターミナル。

端末エミュレーターでサポートされるエスケープシーケンスは、 termcap または terminfo データベースで説明されています。最近のほとんどの端末エミュレータは xterm とかなり密接に連携しています。端末機能情報データベースの詳細な説明については LESS_TERMCAP_ *変数に関するドキュメント? を参照してください カーソルの点滅を停止する方法 および ローカルマシンの端末を設定できますか? sshを使用するマシンの色を使用するための色) いくつかの使用例。

テキストコンソールで実行されているアプリケーション

アプリケーションがテキストコンソール、つまりターミナルエミュレーターアプリケーションではなくカーネルによって提供されるターミナルで直接実行されている場合も、同じ原則が適用されます。端末とアプリケーション間のインターフェースは、文字を送信するバイトストリームであり、特別なキーとコマンドがエスケープシーケンスとしてエンコードされています。

ネットワーク経由でアクセスされるリモートアプリケーション

リモートテキストアプリケーション

リモートマシンでプログラムを実行する場合。 over [〜#〜] 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レンダリングなどの一部のアクセラレーション機能は使用できません。

理解できるほど小さいUnixシステムでこれを見たい場合は、 Xv6 を調べてください。ジョンライオンの有名な 解説 のベースになったのは、多かれ少なかれ神話的なUnix 6th Editionで、長い間samizdatとして流通していました。そのコードはANSI Cでコンパイルするように作り直され、マルチプロセッサのような最新の開発を考慮に入れました。

4
vonbrand