Linuxカーネルで中国語の文字を出力する方法

Linuxカーネルで中国語の文字を出力する方法

次のように、Windows/MacOS からログインした Linux の SSH ターミナルで簡単に中国語を入力し、中国語の出力を得ることができます。

ここに画像の説明を挿入

しかし、Linux 独自の仮想端末で中国語を表示することはほぼ不可能です。

[root@localhost font]# echo 革靴>/dev/tty2 

ここに画像の説明を挿入

疑問符が 2 つ表示され、Linux カーネルが中国語を認識できないことは明らかです。

Linux カーネルは中国語を認識できないとなぜ言われるのですか?ここで明確にする必要がある関係があります:

  • リモート SSH ターミナルでの入力と表示出力はすべて、Windows、MacOS などの SSH ターミナルのホスト マシンによって完了され、Linux とは関係ありません。
  • /dev/tty1 などの Linux ローカル仮想端末での入力および表示出力の動作は、Linux カーネル自体によって処理されます。

たとえば、MacOS 上の iTerm SSH を使用してリモート CentOS Linux に接続しました。iTerm 上のすべてのキーボード入力とディスプレイ出力の動作は、iTerm の MacOS ホスト マシンによって完了しました。

逆に、この CentOS Linux の仮想端末上で直接入力して出力を得ようとすると、この入力と出力は Linux カーネル自体で処理される必要があります。

基本的にはそれだけです。 Linux カーネルが中国語をサポートしない理由については、Linux カーネルが仮想端末の入出力を処理するときに Unicode をどのように扱うかというロジックを理解する必要があります。これには多くの理論的知識が必要であり、非常に面倒です。

とにかく、ここでは中国語を出力することができないので、これをやりません。明らかに、これは完了しなければならない作業タスクではないので、ただ遊んでいるだけです。

この記事の目的は、Linux の仮想端末で中国語を出力できるようにすることです。

たとえ中国語の文字が 1 つだけであっても、中国語を出力します。具体的には、キーボードで文字「A」を入力すると、モニターに中国語の文字が表示されます。

したがって、この記事は、大規模に Linux カーネルを中国語に完全対応させることを意図しているわけではありません。多くの人やコミュニティがすでにこれを行っていますが、プレイアビリティは高くありません。結局のところ、このようなことはお金を稼ぐための個人的な仕事として行うことができます。お金を稼ぐ仕事である限り、速くなければならないため、プレイアビリティは高くありません。

長くて退屈な Unicode エンコードを理解する必要はなく、退屈なフォント形式を理解する必要もありません。ただ、遊び方を見てください。

まずは効果を見てみましょう。 8 × 168\times 168×16 ドットマトリックスの例:

ここに画像の説明を挿入

見た目が良くなかったので、次のようにしました28 × 1628\times 1628×16 ドットマトリックス:

ここに画像の説明を挿入

これは次のように実現されます。

キーボードのキーを押してから、仮想端末のモニターに文字が最終的に表示されるまでの間に、実際には 2 つのマッピングが存在します。

キーボードと文字セットのマッピング

キー イベントを文字セット内のコードに変換します。たとえば、「A」キーが押されたら、0x41 にマップします。

文字セットとフォントマッピング

文字セットのコードワードをドット マトリックスにマップして表示します。たとえば、0x41 は「A」として表示される文字にマッピングされます。 8 × 168\times 168×16 ドットマトリックス。

Linux コンソールは 0x00ff を超える文字セット コードを認識できないため、0x00ff を超える Unicode コードを処理できません。処理できるようにするには、カーネル コードを変更する必要があります。

先ほども言ったように、カーネル コードを大規模に変更して中国語を完全にサポートすることは金儲けのビジネスですが、退屈なだけでなく、誰も共有しません。

そこで、上記の 2 つのマッピングを変更して問題を解決しようとしました。これは表示用だけなので、キーボードと文字セット間のマッピングは変更しません。変更すると、0x00ff を超える文字セット コード ワードの処理に問題が残ります。

つまり、中国語を表示したい場合、残された方法は 1 つしかなく、それは文字セットとフォントのマッピングを変更することです。

このマッピングは、カーネル メモリまたはファイル システムのどこかに保存する必要があります。現在のカーネルの設定ファイルには次の情報が記載されています。

[root@localhost font]# cat /boot/config-3.10.0-862.11.6.el7.x86_64 |grep FONT
# CONFIG_FONTSが設定されていません
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y

/proc/kallsyms に何が入っているか見てみましょう:

[root@localhost font]# cat /proc/kallsyms |grep font.*8x
ffffffffb006a3e0 R フォントvga_8x8
ffffffffb006a420 r フォントデータ_8x8
ffffffffb006ac20 R フォント_vga_8x16
ffffffffb006ac60 r フォントデータ_8x16
ffffffffb0307a10 r __ksymtab_font_vga_8x16
ffffffffb03234b8 r __kcrctab_font_vga_8x16
ffffffffb034246e r __kstrtab_font_vga_8x16

さて、これはカーネルに保存されているフォントです:

[root@localhost rh]# ll ./drivers/video/console/font_8x*
-rw-r--r--. 1 ルート ルート 95976 2018年9月17日 ./drivers/video/console/font_8x16.c
-rw-r--r--. 1 ルート ルート 50858 2018年9月17日 ./drivers/video/console/font_8x8.c

これら 2 つのファイルはここでは分析されません。これは、カーネルが初期化されるときにカーネルが独自のフォントを使用するという事実を確認するだけです。結局のところ、この時点ではカーネル自体以外には何もありません。

問題は、ユーザー モードではフォントを変更して装飾できるということです。これらのフォントは、8x8 と 8x16 の 2 つのフォントだけでは処理できません...

この時点で、ディストリビューションにインストールしたフォント ファイルを見つける必要があります。それを探し出して、その中の特定のフォントの形を変えて中国語に変える必要があります。とても簡単です。

フォントファイルがインストールされて保存されている場所を探す必要はありません。strace setfont コマンドを実行することで見つけることができます。

[root@localhost ~]# strace -F -e trace=open setfont
...
strace: プロセス 6276 が接続されました
[pid 6276] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
...
[pid 6276] open("/lib/kbd/consolefonts/default8x16.psfu.gz", O_RDONLY|O_NOCTTY|O_NONBLOCK) = 4
[pid 6276] +++ 0 で終了しました +++
--- SIGCHLD {si_signo=SIGCHLD、si_code=CLD_EXITED、si_pid=6276、si_uid=0、si_status=0、si_utime=0、si_stime=0} ---
+++ 0 で終了しました +++

以上です。/lib/kbd/consolefonts/default8x16.psfu.gz

psfu 形式ではフォントの形式を検索する必要はなく、パターン認識を通じて特定の文字を見つけることができます。

まず「A」を見つけて、その後ろの「B」と「C」を自分の名前「Zhao」と「Ya」に変更するつもりです。

まず、「赵」と「亚」という文字を作ってドットマトリックスを形成する必要があります。以下は私の作品「趙」です。

00000000
00000000
00100000
11111000
00100101 
00100101
11111010
00100011 
00111010 
01100101 
01100000
10011000
10000111
00000000
00000000
00000000 

ここに画像の説明を挿入

次に、このドットマトリックスを使用して「B」のドットマトリックスを置き換え、同時に「亚」文字を作成して「C」のドットマトリックスを置き換えます。

デフォルト フォントの対応するドット マトリックス図は、次のサイトにあります。
https://www.zap.org.au/software/fonts/console-fonts-distributed/psftx-centos-7.5/default8x16.psfu.large.pdf

ここに画像の説明を挿入

「A」文字のドット マトリックス配列を取得し、この配列を default8x16.psfu ファイルで一致させることができます。コードは次のとおりです。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <文字列.h>

符号なしchar zhaoya[32] = {
			// 最初の行は「Zhao」です
			0x00、0x00、0x20、0xf8、0x25、0x25、0xfa、0x23、0x3a、0x65、0x60、0x98、0x87、0x00、0x00、0x00、
			// 2行目は0x00、0x00、0x00、0x7e、0x24、0x24、0x24、0xa5、0xa5、0x66、0x24、0x24、0x7e、0x00、0x00、0x00
};


int main(int argc, char **argv)
{
	整数 i = 0;
	符号なしcharバッファ[16];
	off_t オフセット = 0;
	整数 s = 0;

	int fd = open("default8x16.psfu", O_RDWR);
	i = pread(fd, buf, 8, オフセット);
	一方(1){
		i = pread(fd, buf, 16, オフセット);
		if (s == 2) { // 'C'を置き換える
			memcpy (buf, &zhaoya[16], 16);
			i = pwrite(fd, buf, 16, オフセット);
			壊す;
		}
		if (s == 1) { // 'B' を置き換える
			memcpy(buf, &zhaoya[0], 16);
			pwrite(fd, buf, 16, オフセット);
			s = 2;
		}
		// 'A' を識別する簡単な方法
		(buf[0] == 0x00 && buf[1] == 0x00 &&
			バッファ[2] == 0x10 && バッファ[3] == 0x38) {
			printf("%d に A が見つかりました !\n", offset);
			s = 1;
		}
		オフセット += 16;
	}
}

直接コンパイルして実行し、この default8x16.psfu をカーネルのパラメータとして設定します。

[root@localhost font]# setfont ./default8x16.psfu

次に、Linux 仮想端末 tty2 に入ります。キーボードで大文字の「B」を入力すると、「Zhao」という単語が表示されます。

それでも16 × 816\times 816×8 偶数8 × 88\times 88×8 でも複雑な中国語のドット マトリックスを生成できますが、見た目が悪すぎます。

そこで、より高解像度のフォントを探すことにします。 Ubuntuで高解像度のものを見つけました28 × 1628\times 1628×16 ドットマトリックスArabic-VGA28x16.psf.gz 。変更方法は前回と全く同じで、ビットマップは次のようになります。
https://www.zap.org.au/software/fonts/console-fonts-distributed/psftx-debian-9.4/Lat7-VGA28x16.psf.pdf

自分でやる必要はない28 × 1628\times 1628×16 ドット マトリックスの場合、GNU uifont の既製のものを使用するだけです。 unifont_sample-12.1.01.hexの「赵」と「亚」の Unicode コード ワードに従って、ドット マトリックスを直接インデックスできます。任意の文字の Unicode コードワードのクエリについては、以下を参照してください。
https://graphemica.com/

フォントを置き換えるコードは次のとおりです。

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <文字列.h>
#include "趙"

#L 28*2 を定義します
整数データ;

int main(int argc, char **argv)
{
	符号なしchar buf[L];
	off_t オフセット = 0;
	// この 0x0e60 はパターン マッチングによって取得されたオフセットです。
	オフセット += 0x0e60;

	fd = open("Lat7-VGA28x16.psf", O_RDWR);
	pread(fd, buf, L, オフセット);
	メモリセット(バッファ, 0, L);
	memcpy(バッファ+8, &code[0], 32);
	pwrite(fd, buf, L, オフセット);

	オフセット += L;
	pread(fd, buf, L, オフセット);
	メモリセット(バッファ, 0, L);
	memcpy(buf+8, &code[32], 32);
	pwrite(fd, buf, L, オフセット);

	オフセット += L;
	pread(fd, buf, L, オフセット);
	メモリセット(バッファ, 0, L);
	memcpy(buf+8, &code[64], 32);
	pwrite(fd, buf, L, オフセット);
}

その効果は次のようになります。

ここに画像の説明を挿入

悪くない。

実際、この記事の内容は次のとおりです。

  1. 粗悪なドットマトリックスを作成します。
  2. キーボード、ASCII/Unicode、フォント間のマッピング関係。
  3. 詳細を知らなくても問題を特定して分析する方法。
  4. シンプルであればあるほど良く、複雑であればあるほど良くない。

実は、3番目と4番目のポイントが最も重要です。

最後に、現在の仮想端末がサポートしているフォントを知りたい場合は、次のように入力します。

[root@localhost フォント]# showconsolefont

次のように表示されます:

ここに画像の説明を挿入

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Linux カーネルの脆弱性の簡単な分析
  • Linuxカーネルのリンクリスト実装プロセス
  • Linuxカーネルで新しいプロセスを作成するプロセス全体についての簡単な説明
  • Linuxカーネルパラメータ調整方法
  • Linuxカーネル空間とユーザー空間の実装と分析
  • Linuxカーネルタイマーについての簡単な説明
  • Linuxカーネルの動作原理を示す図
  • Linuxカーネルのブートパラメータの詳細な説明
  • Linuxカーネルにおける赤黒木アルゴリズムの詳細な実装
  • Linux オペレーティングシステムカーネルのコンパイルの詳細な説明
  • Linuxカーネルモジュールとドライバーの作成

<<:  Vue は水の波紋効果のクリックフィードバック指示を実装します

>>:  MySQL 8.0.13 解凍版のインストールと設定方法のグラフィックチュートリアル

推薦する

Vue3でアイコンを使用する2つの例

目次1. SVGを使用する2. fontAwesomeを使用する3 ソース4 結論テクノロジースタッ...

Nginx10m+の高並列カーネル最適化に関する簡単な説明

高い同時実行性とは何ですか?デフォルトの Linux カーネル パラメータは、最も一般的なシナリオ向...

MySql 5.7.20 のインストールとデータおよび my.ini ファイルの構成

1. まずMySqlの公式サイトからダウンロードします参考: https://www.jb51.ne...

MySQLの外部結合と内部結合クエリの違い

外部結合の構文は次のとおりです。フィールド名を選択FROM テーブル名 1 LEFT|RIGHT|F...

JavaScript を使用して文字列内の最も繰り返しの多い文字を取得する方法

目次トピック分析する使用目的解決:コードは次のように実装されます。分析:配列とポインタ解決:コードは...

Linuxカーネルとデバイスツリーのコンパイルと書き込みを分析する

目次1. 材料を準備する2. Linuxカーネルファイルをダウンロードする3. コンパイル4. TF...

新しい要素を作成する3つの方法のまとめ

1つ目: テキスト/HTML経由var txt1="<h1>テキスト。<...

CSS ボックスモデル内のパディングと略語の詳細な説明

上図のように、パディング値は時計回り(右上、右下)の複合属性であり、パディングの内側の余白がボックス...

ウェブページの表の分割線を削除する方法

<br />Web テーブルの分割線を削除する方法。実際、上記の 3 つの表はいずれも ...

VMware仮想マシンにLinux(CentOS)をインストールするための詳細な構成手順

CentOS7をダウンロード私がダウンロードしたイメージはCentOS-7-x86_64-DVD-1...

Vueコンポーネント間のデータ共有の詳細な説明

目次1. プロジェクト開発において、コンポーネント間の最も一般的な関係は次の 2 つのタイプに分けら...

MySQLデータベースに中国語の文字を保存するときに発生するエラーを解決する方法を教えます

目次1. 遭遇した問題2. 問題を分析する3. 本当の問題4. 解決策5. ソリューション効果1. ...

MySQLが2つのテーブルを関連付ける際のエンコードの問題と解決策

Mysqlが2つのテーブルを関連付けると、次のエラーメッセージが生成されます:照合順序の不正な組み合...

JSはアニメーションのレイアウト変換を実装します

JS でアニメーションを記述する場合、移動前に相対位置を絶対位置に変換してからアニメーション機能を実...

Nginxを使用してストリーミングメディアサーバーを構築し、ライブブロードキャスト機能を実現する

前面に書かれた近年、ライブストリーミング業界は非常に人気が高まっています。伝統的な業界でのライブスト...