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 解凍版のインストールと設定方法のグラフィックチュートリアル

推薦する

sql_mode を変更する際の MySQL エラーの解決方法

目次ERR 1067による殺人事件2番目の問題の原因はsql_modeです3. sql_modeを設...

【HTML要素】画像の埋め込み方法

img 要素を使用すると、HTML ドキュメントに画像を埋め込むことができます。画像を埋め込むには、...

MySQL 8.0.13 手動インストールチュートリアル

この記事では、MySQL 8.0.13の手動インストールチュートリアルを参考までに紹介します。具体的...

Webstorm と Chrome を使用して Vue プロジェクトをデバッグする方法

目次序文1. 新しいVueプロジェクトを作成する2. WebStormの設定1. デバッガポートを設...

MySQL でデータを削除してもテーブル ファイルのサイズが変更されないのはなぜですか?

長期間稼働しているデータベースの場合、テーブルがストレージ領域を占有しすぎるという問題がよく発生しま...

dockerでredis5.0.3をインストールする方法

1. 公式5.0.3イメージを取得する [root@localhost ~]# docker pul...

IIS サーバーから apk ファイルをダウンロードする際の 404 エラーの解決策

最近、IIS をサーバーとして使用すると、apk ファイルがサーバーにアップロードされましたが、ダウ...

リクエストを転送したり、静的リソースファイルにアクセスしたりする複数の場所への nginx の実装

この記事では主に、リクエストを転送したり、静的リソース ファイルにアクセスしたりする nginx の...

Ubuntu の空き容量を増やす 5 つの簡単な方法

序文ほとんどの人は、システム ディスク ストレージが少ないときにこの操作を実行するか、Linux シ...

JavaScript で円形カルーセルを実装する

この記事では、円形カルーセルを実装するためのJavaScriptの具体的なコードを参考までに紹介しま...

ローカル写真をアップロードする前にプレビューコード例を実装するための HTML5 と jQuery

HTML5 と jQuery はアップロード前にローカル画像のプレビューを実装しており、その効果は...

コンテンツの位置をランダムにドラッグするHTMLを実装する2つの方法

テスト: Chrome v80.0.3987.122 は正常です方法は2つあります。通常のラベルの位...

Docker コンテナ データ ボリュームの名前付きマウントと匿名マウントの問題

目次コンテナデータボリュームとはコンテナ データ ボリュームが必要なのはなぜですか?使用データボリュ...

Linux で特殊文字のファイル名やディレクトリを削除する方法

inode番号でファイルを削除するまずls -iを使用して、削除するファイルのinode番号を見つけ...

vsftpdで仮想ユーザーログインを設定する方法

yum で vsftpd をインストールします [root@localhost など]# yum -...