TTY模式下的中文显示与输入解决方案
Mr.Cookie Lv2

最近在折腾Sony的口袋本(P17H),那可怜的Z530处理器和2G的内存,再加上GMA500的驱动支持,想跑Wayland是不可能了,虽然可以DWM跑起来没什么大问题,但在那块8寸的屏幕上,有时候我们可能只希望在TTY下做点顺手的事情(SSH到服务器/vim编辑个文件)

纯 TTY / Console 下要同时解决两件事:

  1. 显示:内核VT对 CJK / UTF-8 显示支持。
  2. 输入:无图形会话时,中文输入问题。

本文记录 Arch kmscon + uim-fep(五笔 wb86,可选拼音 py),含 systemd、kmscon.conf、uim 配置,以及 lastline 分段状态栏的本地 patch。

可选方案与取舍

方案 显示栈 输入
FbTerm + fcitx-fbterm /dev/fb Fcitx 4 前端
kmscon + uim-fep DRM/KMS + pango uim(console)

FbTerm + Fcitx现状

在中文互联网上 FbTerm + fcitx-fbterm 是常见解决方案。然尔在当下时间段问题不在「FbTerm 能不能画中文」,而在 输入前端供应链

  1. fcitx-fbterm 依赖 Fcitx 4。主流发行版仓库已清理 Fcitx 4 / fcitx-fbterm;Fcitx 5 没有 fbterm 前端(架构面向 X11/Wayland IM)。
  2. 源码编译等于自维护 Fcitx 4 整栈:先编 fcitx4 运行时与头文件,再编 fcitx-fbterm;旧代码在现代 GCC/glibc 下常需额外 patch;与包管理器并存成本高。
  3. 显示侧:FbTerm 走 framebuffer;kmscon 走 DRM/KMS + pango/fontconfig,与当前内核图形栈一致。输入若已不能靠仓库里的 Fcitx 前端闭环,继续绑定 FbTerm 收益有限。

纯 framebuffer 若仍要用 FbTerm,更现实的输入是 UCIMF(fbterm -e ucimf),而不是复活 Fcitx 4。需要 Fcitx 5 / Rime 全功能时,应改用微型合成器路径(如 cage + foot),不在本文范围。

kmscon + uim-fep

相对 FbTerm + 自编 fcitx-fbterm:依赖为 pango / uim 等仍在主仓库维护的库,无需引入 Fcitx 4。
相对 cage + fcitx5:不启动 Wayland/X;代价是 uim 词库与智能弱于 Fcitx 5,且 py 为单字码表。

实现上使用 uim-fep 包壳,不是假定 kmscon –im=uim。

安装

1
2
3
4
5
6
7
8
9
10
# 显示层
sudo pacman -S kmscon
# 字体:英文 + CJK(按你习惯替换)
# 例:Maple Mono(AUR)+ noto-fonts-cjk
# 或:ttf-dejavu wqy-microhei

# 输入层
yay -S uim
uim-module-manager --register xmload # wb86 五笔
uim-module-manager --register py # 拼音(可选)

确认 locale 为 UTF-8,例如 /etc/locale.conf 中 LANG=zh_CN.UTF-8。

若要用后文的 分段状态栏 patch,不要直接装仓库/AUR 原包了事,见「uim-fep 分段状态栏」一节用本地 PKGBUILD 构建。

启用 kmscon(systemd)

按需替换 tty。下面以 tty3 为例(保留 tty1/tty2 给图形或普通 getty):

1
2
sudo systemctl disable getty@tty3.service
sudo systemctl enable --now kmsconvt@tty3.service

注意:

  • 改 /etc/kmscon/kmscon.conf 后必须 重启对应服务 才生效,例如 sudo systemctl restart kmsconvt@tty3.service
  • 重启前先切到别的 VT,避免把自己踢下线。
  • 若用 display manager 占着某些 tty,不要和 kmscon 抢同一号。

切到该 VT:Ctrl+Alt+F3,登录后 echo $TERM 应为 kmscon。

配置 kmscon

文件:/etc/kmscon/kmscon.conf(没有就建)。内核的 setfont / loadkeys 对 kmscon 无效

1
2
3
4
5
6
7
8
9
### Fonts
## CJK 必须用 pango;freetype 对多字体回退不可靠
font-engine=pango
## 英文在前,中文 fallback 在后
font-name=Maple Mono, Noto Sans Mono CJK SC
font-size=18

### Input(按需)
#xkb-layout=us

说明:

作用
font-engine=pango 按字符选字体、拼布局;ArchWiki 做 CJK 也走这条路
font-name=A, B 拉丁走 A,缺字再找 B
font-size 字号;改完要重启服务

也可用系统/用户 fontconfig 给 monospace 配同样的链;kmscon 侧仍建议写明 font-engine=pango 和 font-name。

已知限制:vim/neovim 里侧栏改宽、大量双宽 CJK 时,kmscon/libtsm 偶发重绘错位(半个汉字像英文)。这是终端层问题,不是 fontconfig 配错;暂无干净配置解法,可接受或改用 float 侧栏。

运行 uim-fep

在 kmscon 会话里:

1
uim-fep -s lastline

-s lastline 把状态行放在最后一行。可写入 shell rc,仅在 TERM=kmscon 时启动,例如:

1
2
3
if [ "$TERM" = "kmscon" ] && [ -z "$UIM_FEP_PID" ]; then
exec uim-fep -s lastline
fi

注意:只在 uim-fep 包起来的进程树里生效;不要和图形会话的 GTK_IM_MODULE 混配。

配置 uim

文件 放什么
~/.uim.d/customs/custom-global.scm 启用哪些 IM、是否热键切换 IM
~/.uim 默认 IM、开/关、切换、上屏、候选

不要在 custom-global.scm 里写 (define switch-im-key? (make-key-predicate …)),会导致 uim-fep 段错误。切换键放在 ~/.uim 用 define-key。

custom-global.scm

1
mkdir -p ~/.uim.d/customs
1
2
3
;; 仅启用:英文 / 五笔 / 拼音,Ctrl+\ 在此三者间轮换
(define enabled-im-list '(direct wb86 py))
(define enable-im-switch? #t)

enabled-im-list 不能写在 ~/.uim 里(写了也不生效)。

~/.uim

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
;; 1. 默认五笔
(define default-im-name 'wb86)

;; 2. 开/关 IME(默认 Shift+Space 在 fep 里不可用)
(define-key generic-on-key? '("<Control> "))
(define-key generic-off-key? '("<Control> "))

;; 3. 切换 IM
(define-key switch-im-key? '("<Control>\\"))

;; 4. 空格上屏;候选 ↑/↓
(define generic-commit-key '(" "))
(define generic-commit-key? (make-key-predicate '(" ")))

(define generic-prev-candidate-key '("up"))
(define generic-prev-candidate-key? (make-key-predicate '("up")))

(define generic-next-candidate-key '("down"))
(define generic-next-candidate-key? (make-key-predicate '("down")))

(define-key generic-prev-page-key? '("<Shift>," "prior"))
(define-key generic-next-page-key? '("<Shift>." "next"))

;; 5. 候选窗(分段状态栏依赖候选串)
(define generic-use-candidate-window? #t)
(define generic-nr-candidate-max 5)
(define generic-show-prediction-candidates? #f)
(define generic-commit-candidate-by-numeral-key? #t)

改完后:

1
2
uim-sh ~/.uim
uim-sh -e enabled-im-list

应看到 (direct wb86 py)。每次改配置需 退出并重新进入 uim-fep。

快捷键

操作 快捷键
开/关输入法 Ctrl+Space
切换 direct / 五笔 / 拼音 Ctrl+\
上屏 Space
上一/下一候选 ↑ / ↓

踩坑:fep 能捕获哪些键

说明
Ctrl+Space、Ctrl+\ 可用
纯 Ctrl+Shift、Shift+Space 不可用
Ctrl+Alt+* Alt 常丢失;Ctrl+Alt+M 会像 Enter
Ctrl+字母(I/M/N 等) 常变成 ^X
Ctrl+Tab 会段错误

开/关、切换用 define-key + “…”;上屏、候选用 define + make-key-predicate

半角标点与拼音能力

  • wb86:码表里标点常是全角;要半角需关 IME 或切到 direct。
  • py:uim 自带的是 Unihan 单字表,不能连拼词组;要词组需换引擎(anthy/rime 等),不是配置写错。

uim-fep 分段状态栏(patch)

默认 lastline 上,候选串和 wb86[…] 都从第 0 列画,kmscon 双宽重绘时会出现「候选盖住提示、露出半个汉字」之类的脏迹。配置无法真正分区,于是改了 fep/draw.c:

1
[ 五笔 ][ A:字 B:字 ... ][ 开 ]
内容 配色(256 色)
五笔 / 拼音 / 英文(去掉 […] 状态) 亮灰字 / 深灰底
候选;当前项再反色 + bold 深灰字 / 亮灰底
开 / 关 同左底;开=绿字、关=红字

补丁与本地 PKGBUILD 备份在:

1
2
~/git/uim/uim-fep-kmscon.patch
~/git/uim/PKGBUILD

构建示例(在 yay 缓存目录或任意空目录):

1
2
3
4
cp ~/git/uim/{PKGBUILD,uim-fep-kmscon.patch} .
# 确保 source 里的上游 tarball 可下载,或放到同目录
makepkg -si
sudo systemctl restart kmsconvt@tty3.service # 按你的 tty 改

装好后重新登录进 uim-fep 即可看到新状态栏。

小结

  • 显示:kmscon + font-engine=pango + 英/中 font-name 链;kmsconvt@ttyX 替换 getty,改 conf 后重启服务。
  • 输入:uim-fep + wb86(可选 py);配置分 custom-global.scm 与 ~/.uim;快捷键受 fep 可捕获键限制。
  • 不采用 FbTerm + Fcitx:无可用的 fcitx5-fbterm,续命 fcitx-fbterm 需自维护 Fcitx 4。
  • lastline 候选与模式串重叠:用 ~/git/uim 中的分段状态栏 patch。

至此,TTY模式下中文显示与输入已经基本完成. 下一步,我们可以感受一下cage在这台口袋本下的使用体验了