Windows 与 macOS 加越南语 Simple Telex 第三输入法,双击 Shift 在中英与越南语之间切换,候选旁显示中文译词。 Closes #835
青简 Windows 安装包
用 Inno Setup 打的安装包,把 TSF DLL(64 位与 32 位各一份)、Server、设置程序与随包数据一起装进
C:\Program Files\Qingjian,注册文本服务,并设登录自启。对应 macOS 的 pkg。
安装布局
C:\Program Files\Qingjian\
qingjian_tsf-<版本>.dll TSF 文本服务(64 位;被加载进每个应用进程;按版本起名,见「升级」)
qingjian_tsf-<版本>-x86.dll 同上的 32 位版(企业微信 / WPS / 32 位 QQ 这类 32 位应用只能加载它)
qingjian-server.exe 输入内核 Server(跑在应用进程外)
qingjian-settings.exe 设置程序(apps\settings,三平台共用,不依赖 Windows App Runtime)
qingjian-settings-legacy.exe 旧版设置程序(WinUI,开始菜单「青简旧版设置」,留一个版本作回退)
Microsoft.UI.Xaml.dll … 旧版设置程序自带的 Windows App Runtime(自包含部署,见下节;约 56 MB / 185 个文件)
qingjian.ico 开始菜单 / 启动项快捷方式的图标(exe 里也嵌了一份)
data\generated\ dict.qj / lm.qj / glossary-{en,ja,zh,es,vi}.qj / english.tsv / dicts\*.qj
data\generated\codes\ 随包辅码码表 stroke.qj + LICENSE-CNS11643.txt(tools\dict-convert 的 pack codes 生成)
assets\ emoji\ levels\ sample\
Server 与设置程序按 exe 相对定位随包资源(qingjian_platform::resources):装机时资源与 exe 同级,
开发时是仓库 ime\(exe 在 target\{debug,release}\ 下往上三层)。相对写法两套布局一致,只有根不同。
用户数据仍在 %APPDATA%\Qingjian(config.toml、密钥 .env、学习数据、统计),三个进程的日志在 %LOCALAPPDATA%\Qingjian\logs(server. / tsf. / settings. 前缀,按天,留 7 天);
卸载不动这些。输入法图标由 regsvr32 写到 %ProgramData%\Qingjian\qingjian.ico(DLL 里 include_bytes 内嵌单色深浅两版,按注册时任务栏深浅挑一版;之后 Server 启动与系统切深浅色时改写,任务栏在下次切换输入法时换过来。安装包给这个目录放开了普通用户写权限)。
安装程序做的几件事
- 结束旧进程:
PrepareToInstall里taskkillServer 与两个设置程序(只有这几个 exe 要覆盖)。 - 应用容器权限:
icacls给安装目录加ALL APPLICATION PACKAGES(SID*S-1-15-2-1)读+执行。 不加的话 UWP/AppContainer 应用(任务栏搜索、设置)读不到 DLL,切不到青简。 - 注册文本服务:64 位 DLL 用
regsvr32、32 位 DLL 用SysWOW64\regsvr32,各注册一次(各自写进自己视图的 HKCR,CTF\TIP两边共用;要管理员——安装程序本就提权)。 - 清旧 DLL:装完删历次版本留下的
qingjian_tsf*.dll,仍被应用占用的登记成重启后删(RestartReplace)。 - 登录自启:「启动」文件夹放 Server 快捷方式(Explorer 走 ShellExecute 拉起才拿到 uiAccess;计划任务拿不到)。
- 立即启动:完成页以当前非提升用户 ShellExecute 起一次 Server,装完就能用,不必先注销。
卸载反向:杀 Server / 设置程序 → 反注册当前版本 DLL → 删文件(占用中的 DLL 重启后删,[UninstallDelete] 兜住旧版本的)。
升级:DLL 被占用怎么办
qingjian_tsf.dll 被加载进每一个有文本框的应用进程,文件锁着覆盖不了;Inno 缺省的 CloseApplications
用 Restart Manager 找出所有占用者要求关闭——对输入法 DLL 就是「关掉一切」,所以关掉它(CloseApplications=no),改成:
- DLL 按版本起名并排装(
DestName: qingjian_tsf-<版本>.dll),新文件从不与旧文件撞名; - 只
regsvr32新文件(InprocServer32 指向它)。不要对旧 DLLregsvr32 /u:那会把整个 CLSID / profile 注销掉; - 已开着的应用继续用进程里的旧 DLL 直到重启,Server 两个版本都服务(
OpenSession带协议版本,对不上只记警告); - 装完删旧 DLL,删不掉的登记成重启后删。
旧版设置程序自带 Windows App Runtime
旧版设置界面用 Windows Reactor(WinUI 3)写,而它的框架依赖引导只有 Windows 11 走得通:要 Windows 11 才有的
AppModel API 把框架包加进进程包图,Windows 10 上没有那两个函数(定位见 docs\notes\windows-win10.md)。
所以旧版设置程序用自包含部署——apps\windows\settings\build.rs 让 windows-reactor-setup 把 Windows App Runtime
铺到 target\release\,打包时按 settings-runtime.txt 挑进 target\installer\settings-runtime,本目录的
qingjian.iss 再整个目录装到 {app} 下、与 qingjian-settings-legacy.exe 同级。下个版本删掉旧版设置程序时,这一节、settings-runtime.txt 与运行时文件一起删。
- 这些文件是运行时必需:少一件(或层级装错)设置窗口就起不来,
build.ps1发现缺文件会直接失败。 - 升级
windows-reactor/windows-reactor-setup时,照新版 crate 的assets/runtime.txt核对settings-runtime.txt。 - Server 与 TSF DLL 不依赖它;装机体积的大头仍是随包数据。
windows-reactor-setup在cargo build时用系统curl.exe从 NuGet 下运行时包(无校验,失败只打印),缓存在%LOCALAPPDATA%\windows-reactor-setup;CI 的 runner 每次都会重下一遍。下载失败的后果由build.ps1的缺项检查兜住。
打包(在编译机上)
# 需要 MSVC 工具链 + Inno Setup。数据取自仓库 data\generated 与 assets,打包前先确保 .qj 是最新的。
powershell -ExecutionPolicy Bypass -File apps\windows\installer\build.ps1
脚本 release 构建三个产物、从 apps\windows\server\Cargo.toml 读版本、找 ISCC.exe、编 qingjian.iss,
成品在 target\installer\qingjian-<版本>-windows-x86_64-setup.exe。改了数据 / 脚本但二进制没变时加 -SkipBuild;-Sign 用自签证书签产物
(uiAccess 要求 Server 签名 + 装 Program Files)。
也可手动:iscc /DAppVersion=0.1.0 apps\windows\installer\qingjian.iss。
注意
- Inno 版本:开发机与 CI 统一用 Inno Setup 7.1.0(CI 从 jrsoftware/issrc 的 GitHub Release 钉死下载)。它自带简体中文翻译;
6.x 的安装包不带
Languages\ChineseSimplified.isl,Chocolatey 也只有 6.x,别用。ArchitecturesAllowed=x64compatible需 6.3+。 - 签名:发版证书就绪后在这里加
SignTool(对应 mac 的 Developer ID);开发期用-Sign的自签证书。 - 没证书的包(CI 内测版):先设
$env:QINGJIAN_UIACCESS = '0'再打,Server 不嵌 uiAccess——没签名的 exe 带 uiAccess=true 会起不来。 代价是候选窗在 UWP 宿主里可能被盖住。release.yml的windowsjob 就是这么打的。