时间:2021-05-19
你在Windows/MacOS的登录Linux的SSH终端上很容易输入中文并且获得中文输出,比如下面这样:
但是却几乎不可能将中文显示在Linux自身的虚拟终端上:
[root@localhost font]# echo 皮鞋 >/dev/tty2显示了两个问号,显然Linux内核并不能识别中文。
为什么说是Linux内核不能识别中文呢?这里需要理清一个关系:
比如,我在MacOS用iTerm SSH连接到了一个远程CentOS Linux,iTerm上的所有的键盘输入,显示器输出行为都是iTerm的这台MacOS宿主机完成的。
相反,如果你直接在这台CentOS Linux的虚拟终端上输入并且企图获得输出,那么这个输入输出则必须由Linux内核自身来处理。
基本上就这些。至于说为什么Linux内核不支持中文,那要了解Linux内核处理虚拟终端输入输出时是如何对待unicode的逻辑,这要涉及一大堆的理论知识,非常烦人。
反正我这里就是无法输出中文,我也不是做这个的,显然这不是一个必然要完成的工作任务,所以,我只是玩玩。
本文的目标就是要让Linux的虚拟终端可以输出中文。
仅仅是输出中文,哪怕是一个中文汉字也好。具体来讲,就是当我在键盘敲入'A'字符时,显示器回显出来的是一个汉字。
所以说,本文并不打算让Linux内核大规模完备地支持中文,这种事已经有很多人和社区做了,但是可玩性并不高,毕竟这种事是可以当私活儿赚钱的,只要是赚钱的活儿,可玩性就不高,因为要快嘛。
不需要懂冗长枯燥的unicode编码,不需要懂枯燥的font字体格式,看看怎么玩。
先展示效果吧,下面是一个8×168\times 168×16的点阵例子:
不是很好看,于是就做了下面一个28×1628\times 1628×16的点阵:
下面说一下这是如何实现的。
从你敲键盘的某个按键开始,到某个字符最终显示在虚拟终端的显示器上,这期间其实有两个映射:
键盘和字符集的映射
将某个按键事件转换为某个字符集里的某个码,比如当按下'A'键时,将其映射到0x41。
字符集和字体的映射
将某个字符集的码字映射到某个点阵用来显示。比如将0x41映射到能让人看出来是一个字符'A'的样子的8×168\times 168×16点阵。
Linux的console并不能识别超过0x00ff的字符集码字,因此就不能处理码字超过0x00ff的unicode,如果希望它能做到,这就要改内核代码了。
刚才说了,修改内核代码大规模全面支持中文,这是可以赚钱的事,不但没意思,也没人会分享。
所以我尝试去修改上面的两个映射来解决问题。由于只是显示,所以我不会去修改键盘和字符集的映射,因为那样仍然会碰到字符集码字超过0x00ff的处理问题。
这意味着要想显示中文,只剩下一条路,那就是修改字符集和字体的映射!
这个映射肯定是保存在内核内存或者文件系统的某个地方。我可以在当前内核的config文件里找到如下的信息:
[root@localhost font]# cat /boot/config-3.10.0-862.11.6.el7.x86_64 |grep FONT# CONFIG_FONTS is not setCONFIG_FONT_8x8=yCONFIG_FONT_8x16=y再去看/proc/kallsyms里有什么:
[root@localhost font]# cat /proc/kallsyms |grep font.*8xffffffffb006a3e0 R font_vga_8x8ffffffffb006a420 r fontdata_8x8ffffffffb006ac20 R font_vga_8x16ffffffffb006ac60 r fontdata_8x16ffffffffb0307a10 r __ksymtab_font_vga_8x16ffffffffb03234b8 r __kcrctab_font_vga_8x16ffffffffb034246e r __kstrtab_font_vga_8x16嗯,这就是内核里保存的字体:
[root@localhost rh]# ll ./drivers/video/console/font_8x*-rw-r--r--. 1 root root 95976 Sep 17 2018 ./drivers/video/console/font_8x16.c-rw-r--r--. 1 root root 50858 Sep 17 2018 ./drivers/video/console/font_8x8.c这里不再分析这两个文件。这里仅仅是确认了一个事实,内核在初始化的时候会使用自己的字体,这个时候毕竟除了内核本身,什么都没有。
问题是到了用户态,这个字体是可以被改变的,可以被改的花里胡哨的,这些个字体可不是仅仅两个8x8和8x16就能hold住的…
这个时候就需要找我们安装在发行版里面的字体文件了。我们要找到它,然后改掉里面的某个字体的形状,将其变成中文!就这么简单。
不必去搜这个字体文件安装保存在什么地方,通过执行strace setfont命令就能找到它。
[root@localhost ~]# strace -F -e trace=open setfont...strace: Process 6276 attached[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] +++ exited with 0 +++--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6276, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---+++ exited with 0 +++就是它了,/lib/kbd/consolefonts/default8x16.psfu.gz
也不必去搜psfu格式的字体的format,通过模式识别就能找到特定的字符。
我准备先找到 ‘A',然后把它后面的'B'和'C'改成我的名字“赵”和“亚”。
首先我要把“赵”和“亚”字做出来,形成一个点阵。以下是我的作品“赵”:
0000000000000000001000001111100000100101 001001011111101000100011 00111010 01100101 011000001001100010000111000000000000000000000000下面就要用这个点阵替换'B'的点阵,同时制作一个“亚”字,替换'C'的点阵,
在下面的站点可以找到该default font的对应点阵图解:
https:///
替换font的代码如下:
#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <string.h>#include "zhao"#define L 28*2int fd;int main(int argc, char **argv){ unsigned char buf[L]; off_t offset = 0; // 这个0x0e60 就是模式匹配获得的偏移。 offset += 0x0e60; fd = open("Lat7-VGA28x16.psf", O_RDWR); pread(fd, buf, L, offset); memset(buf, 0, L); memcpy(buf+8, &code[0], 32); pwrite(fd, buf, L, offset); offset += L; pread(fd, buf, L, offset); memset(buf, 0, L); memcpy(buf+8, &code[32], 32); pwrite(fd, buf, L, offset); offset += L; pread(fd, buf, L, offset); memset(buf, 0, L); memcpy(buf+8, &code[64], 32); pwrite(fd, buf, L, offset);}然后它的效果就是:
还不错。
其实本文的内容仅仅就是:
嗯,其实第三点和第四点是最重要的。
最后,如果你想知道你当前的虚拟终端支持那些字体,输入:
[root@localhost font]# showconsolefont就会显示:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文实例讲述了php自定义函数实现统计中文字符串长度的方法。分享给大家供大家参考,具体如下:中文字符计算为2个字符英文字符计算为1个代码/***可以统计中文字符
前言在日常开发编程中,我们有时从用户那里得到一些输入信息,对于特定应用,部分信息不允许包含中文字符,那如何检测信息字符串中是否包含中文字符呢?方法有很多,这篇文
使用pythonpdfkit生成pdf文件中遇到中文乱码问题1.生成的文件名不能带有中文字符2.生成的pdf内容中文为乱码生成的文件名不能带有中文字符解决方法:
JS中默认中文字符长度和其它字符长度计算方法是一样的,但某些情况下我们需要获取中文字符串的实际长度,代码如下:复制代码代码如下:functionstrLengt
本文实例总结了php中文字符串截取方法,非常实用的技巧。分享给大家供大家参考。具体方法分析如下:用PHP函数substr截取中文字符可能会出现乱码,主要是sub