20 Commits
Author SHA1 Message Date
Lu Fan(SonnyCalcr) 1b875267db refactor: 移除 WebView2,界面只保留 Direct2D (#1013)
* refactor(engine): 语音独立工具改用原生托盘菜单,移除 WebView2

托盘菜单改用 Win32 弹出菜单,设置项改为用关联编辑器打开 config.toml,关于页改为消息框。删除 window_webview2 与两份 HTML 资源,windows-app 特性不再依赖 webview2 端口。

* refactor(server): 移除 WebView2,候选窗、工具栏、托盘菜单与设置窗口只保留 Direct2D

删除 src/webview2 与 webview_utils,小窗口的置顶、皮肤重载和工具栏状态缓存移到 window/small_windows,presenter 成为唯一路径,D2D 下的置顶时序与 cloak 行为保持不变。设置进程去掉 WebView2 宿主、鼠标转发与启动图,只构建原生窗口;旧快捷方式传入的 --d2d / --webview2 被忽略。删除 appearance.ui_backend 与 appearance.settings_ui_backend(读取、写入、设置页下拉框与两份配置模板),升级时由模板合并丢弃旧值。设置窗口的图片资源移到 server/assets/settings,安装到数据目录的 assets\settings。不再链接 WebView2Loader,vcpkg 去掉 webview2 端口。

* build(installer): 打包与 CI 不再处理 WebView2 页面和运行时

Prepare-PackageFiles 去掉 -UiHtmlDirectory 与 html 暂存,改为暂存 server/assets/settings;安装器不再检查 WebView2 Runtime、不再创建 ProgramData 下的 WebView2 用户数据目录,升级和卸载时清理旧版留下的 webview2 / webview2-settings 与数据目录里的 html。CI 删除设置页构建、契约同步检查和候选窗 DOM 测试,release 的打包任务不再依赖网页产物;dependabot 去掉 npm。第三方声明去掉 WebView2Loader。

* refactor(ui-html): 删除 WebView2 页面与设置页前端工程

候选窗、工具栏、托盘菜单、设置页、主题和契约副本都已没有使用者;设置窗口用到的图片资源已移到 server/assets/settings。sync-contracts.py 与 pnpm/Vite/TypeScript 工程一并删除,契约仍以 engine/contracts/webview 为唯一来源。

* docs(server): 文档改为只描述 Direct2D 界面

仓库地图去掉 ui-html,组件边界、uiAccess 与置顶时序、设置窗口和配置读写的说明改写为 Direct2D 唯一界面;安装说明去掉 WebView2 Runtime 检查,打包命令去掉 -UiHtmlDirectory;engine/contracts/webview 的说明改为设置窗口是唯一使用者,名字是历史遗留。

* docs(skins): 皮肤说明不再区分 WebView2 与 D2D 渲染器

v2 字段去掉「仅 WebView2」,改为说明由 Direct2D 原生渲染、部分字段仍在补全;颜色必须带 # 改为清单格式约定。随包的 skins/niya-demo/skin.toml 不改,免得用户机器上的同名皮肤在升级时被当成已修改而改名备份。

* docs(ui): demo 说明文字不再提 WebView2
2026-10-17 02:48:02 +08:00
Lu Fan(SonnyCalcr) 53649d9d12 feat(server,ui,ui-html): 新增实验性的 Direct2D 设置窗口 (#999)
* feat(ui): 动画时钟、渲染剔除与文本框扩展,并优化 msimeui 性能

- 新增 Animation.h:cubic-bezier 缓动、Tween、颜色插值,Window 提供
  RequestAnimationFrame / GetFrameTime,动画帧随显示刷新率推进
- Window 可选 DirectComposition 渲染(含不透明模式以支持 ClearType)、
  双击按下、捕获丢失时结束按压、悬停刷新、可关闭销毁时退出消息循环
- Scene 把滚轮交给光标下最内层可滚动元素并逐级冒泡
- DeviceResources:裁剪栈驱动的离屏剔除、按帧回收的笔刷缓存、SVG 栅格缓存
- ScrollViewer 可配置外观与平滑滚动;Popup 支持阴影通道与出现动画;
  卡片阴影缓存抽成可复用的 ShadowCache
- TextBox 支持 SetText、密码掩码、多行滚动、字重/字间距/行高与外观设置
- 调试日志默认关闭(MSIMEUI_DEBUG_LOG=1 才写文件),不再在每次点击和
  TSF GetTextExt 时打开文件
- 字体回退在 CJK/emoji 映射之后保留系统回退,缺字不再显示方框
- 新增动画与剔除单元测试

* feat(server): 新增实验性的 Direct2D 设置窗口

设置窗口可通过 appearance.settings_ui_backend 选择渲染方式:默认 webview2,
d2d 为实验性的 msimeui 原生实现(server/src/settings/native/),1:1 复刻
网页设置页,包括侧栏切换时竖向高亮条的滑动动画。

- 两个前端共用同一套 webview 契约消息与 HandleClientMessage,配置读写
  映射仍只在 settings_app.cpp
- 切换渲染方式后设置进程自动以新方式重新打开;--d2d / --webview2 可临时指定
- 新配置项写入出厂模板与开发配置,UiBackendPolicy 与测试同步更新
- METASEQUOIA_IME_SETTINGS_INSTANCE 允许开发版与已安装的设置窗口并存
- 更新 ui-backends 文档与 server/AGENTS.md

* feat(ui-html): 外观页新增设置窗口渲染方式选项
2026-10-16 16:13:13 +08:00
Jia Suiandfanlusky e10f845e04 refactor(server): 移除服务端内嵌设置宿主死代码 (#764)
* refactor(server): 移除服务端内嵌设置宿主死代码

InitWebviewSettingsWnd 全仓无调用点,webviewSettingsWnd 恒空,这条内嵌设置 WebView 宿主及其上的 configUpdate 分发、PostSettingsConfig() 空转调用链从不执行。设置页由独立进程 MetasequoiaImeSettings.exe 承载并自行轮询配置,删死路径与 7 个空转调用点不改变可观察行为。

- 整删 windows_webview2_settings.cpp、ime_windows_settings.cpp
- 清除仅服务该宿主的全局/声明/常量,及 windows_webview2.cpp、windows_webview2_skin.cpp 中的引用
- 删 PostSettingsConfig() 调用点,两处 if 块塌缩为直接调用 setter
- 同步根 AGENTS.md 与 server/AGENTS.md 的「两个设置宿主」表述

* docs: 配置同步规则补回设置页 configSnapshot 字段列表

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-10 21:33:25 +08:00
Jia Sui 2557ee4a63 docs: 修正 AGENTS.md 与注释中与代码不符的五处描述
spec 校对时逐条核对「文件:行号」锚点发现,五处文档描述与代码现状不符:

- windows/AGENTS.md:格式化遵循的是本目录 .clang-format,仓库没有根目录 .clang-format
- 根 AGENTS.md:engine/... 前缀 include 只对 server/ 成立,windows/ 无仓库根,走相对路径
- scripts/format.sh:注释声称 CI 会跑 generate.py --check,实际没有任何 CI 作业调用
- server/AGENTS.md:测试源文件数与三处行号锚点过期
- server/CMakeLists.txt:注释里的 "eleven add_test()" 实际是 24 个,删去具体数字

纯文档与注释改动,无行为变化。
2026-10-03 08:29:50 +08:00
Jia Sui 566ff8b832 feat(engine): 新增加加辅助码(拼音加加),第六套辅助码方案
按笔顺拆前两个部件、各取读音首字母(妈 = 女 n + 马 m = nm),部件用加加俗称读音(亻=d、
扌=t、纟=j、忄=s、攵=f、夂=z、刂=l、彳=s);138 个独体/部首字取「本字声母 + 起笔」。码表
7968 条,覆盖《通用规范汉字表》7846 字,比小鹤少 422 个扩展区生僻字——缺码会让含这些字的
词组拿不到辅助码,是已知取舍。

编码对齐拼音加加 5.x 安装包内的 fzm.bin(双拼键位已换算为声母):6487 字取到两码,6349 字
逐字一致,138 字保留本表规则,覆盖外的 800 字按同一规则重建。来源与非官方性质写在 NOTICE.md
与随包的 THIRD_PARTY_NOTICES.txt。

- engine/contracts/assets 注册 helpcode_jiajia,assets.h 重新生成(5 → 6)
- 设置页两个下拉显示名「加加」,两份配置模板注释同步
- 两侧测试补支持列表;README / README.en.md / server/AGENTS.md 改「六套」

默认值不变(双拼 lantian、全拼 ziranma)。
2026-09-20 22:00:34 +08:00
fanlusky bc37ac9a9e feat(installer): 安装时可自定义数据目录位置
词库、用户配置和皮肤此前固定在 %LOCALAPPDATA%\metasequoiaime,整包几百 MB
全压在 C 盘。安装向导新增一页,允许把这部分数据放到任意盘。

程序本体仍固定装在 Program Files:MetasequoiaImeServer.exe 带 uiAccess=true,
只有在受信任目录里这个标志才生效。

运行期的权威来源是 HKLM\Software\Metasequoia\MetasequoiaIME 的 DataDir。
Server、TSF DLL 和引擎三个组件各自按同一顺序解析:METASEQUOIA_IME_DATA_DIR
环境变量 -> 该注册表值 -> %LOCALAPPDATA%\metasequoiaime。三处各持一份实现,
因为组件边界规则禁止 windows/ 与 server/ 互相 include。32 位 TSF DLL 用
KEY_WOW64_64KEY 读,避开 WOW64 重定向。

安全相关的两个约束:

- 安装器在数据目录里写 .metasequoiaime-data 标记。覆盖安装的清理和卸载的整目录
  删除只在看到这个标记(或目录就是历史默认位置)时才执行——用户可能把数据目录
  指到一个本来就有自己文件的文件夹。
- 选择页与 /DATADIR= 走同一套校验:拒绝相对路径、盘符根目录、不存在的盘、程序
  目录内部,以及 Windows/Program Files/各 AppData/用户主目录本身。

升级时改了位置,PrepareToInstall 在停掉输入法进程后用 robocopy /MOVE 搬运用户
拥有的数据(msime_user.db 及其 WAL/SHM/journal、config.toml、config.base.toml、
skins\),词库和前端资源由本次安装重新写入。跨卷移动目录 MoveFile 会失败,所以用
robocopy。用户词库搬运失败会中止安装:否则新版本对着空的 msime_user.db 启动,
ssPostInstall 的回放只记一句 skipped,用户的自造词就静悄悄没了。

测试侧新增 METASEQUOIA_IME_CONFIG_DIR,只改 config.toml 的位置而不搬词库。原先
靠重定向 LOCALAPPDATA 做隔离的办法在装了正式版的机器上已不再成立——注册表值
的优先级高于它。
2026-09-17 22:49:19 +08:00
fanlusky 88a086a75b perf(build): Release 编译跳过重复 configure,只构建打包用的目标
本地打包每次都要等很久,其中编译这一段有两处纯粹的重复劳动。

Visual Studio 生成器把 ZERO_CHECK 接进了每个目标,CMakeLists.txt 变化时
构建会自己重新生成,所以已有 CMake 缓存时前置的 cmake --preset 不改变任何
结果,只是每个构建目录白等约 10 秒,三个目录就是 30 秒。改成缓存存在就跳过,
需要强制重跑(改了 preset、换了工具链)时传 -Reconfigure。

构建目标也从 ALL_BUILD 收窄到 MetasequoiaImeServer / MetasequoiaImeTsf。
原先会一并构建 MetasequoiaImeServerTests、test_webview_contract、
test_windows_ipc_contract,而 Prepare-PackageFiles.ps1 随后又把它们从包里
删掉。server 目标的依赖闭包已经覆盖 Watchdog、三个面板、Settings、
DictionaryReplay 和 OpenCC 词典,产物一个不少。要连测试一起构建(比如为了
跑 ctest)传 -Target ALL_BUILD,server/AGENTS.md 里的 ctest 段落已注明。

顺带给 cmake --build 加上 --parallel,真正有代码改动时也能并行。

无改动时的增量编译:TSF 18.0s -> 3.7s,Server 21.9s -> 10.9s。
CI 不受影响,它直接调 cmake,不经过这些脚本。
2026-09-13 03:56:40 +08:00
fanlusky a7779d2b05 refactor(engine): 将 engine 从 submodule 内嵌为仓内一等组件
`vendor/MetasequoiaImeEngine` submodule 改为 `engine/` 目录,导入的是
product-lock.json 原本钉住的提交 c810d201,逐文件核对过 blob,因此这是一次
搬迁而不是引擎升级。引擎自己的嵌套 submodule(googlepinyinime-rev、utfcpp、
miniaudio)按各自 gitlink 一并展开,来源与提交见 engine/UPSTREAM.md。

Windows 专门化裁掉了不属于本产品的部分:whisper.cpp 与本地推理 provider、
macOS 示例宿主、整个 dictionary/ 建库流水线、上游 CI 与 release-please 配置。
词库仍按 product-lock.json 在构建时取发布产物。

引擎不再进 product-lock.json:没有 gitlink 就没有可比对的东西,锁里写一个上游
commit 等于宣称这棵树仍等于上游,而第一个 Windows 专门化改动落地时这句话就假了。
verify-contracts / verify-checkout 随之移除,verify-published 保留。

CI 与工具链:引擎源码并入根 scripts/format.sh(删掉引擎自己的那份,避免两套排除
列表分叉);引擎 voice.yml 里的 silero_vad.onnx 摘要校验移到本仓 lock job;
engine-bump-triage 工作流与其测试删除;gitsubmodule 的 dependabot 频率由 daily
改为 monthly。

README、README.en、AGENTS.md、CONTRIBUTING、docs/product-release.md 及各子目录
文档同步说明新的位置与边界。
2026-09-12 03:40:48 +08:00
Evan Hu 0baaf9a1d0 fix(server): 将本地测试入口接回合仓后的主工程 2026-09-06 09:40:36 +09:00
Evan Hu 5f8d75d79e fix(installer): use Engine tables in the local monorepo layout 2026-09-06 04:16:19 +09:00
Evan Hu c3fcc4a515 refactor(product): consume the consolidated Engine data and shared voice capture
Ports metasequoiaime/MSIME-Windows#153 onto the consolidated repository. That pull request was written against the six-repository layout: it edited product-ci.yml, which no longer exists, and re-pinned Server, UiHtml and Installer, which are directories now.

Three of its pinned commits had not reached this repository at all. The consolidation took each source repository at its main, and Server, UiHtml and Installer each landed two more commits afterwards, so dropping the pins as merely obsolete would have silently dropped the work the pull request exists to consume. The two substantive ones are ported here: Server drops its vendored miniaudio.h and builds against the engine's MetasequoiaIme::VoiceCapture, and the installer collects helpcodes from the engine. UiHtml's was an engine gitlink bump, which one submodule resolves on its own.

The engine is pinned to d0dc0c2b rather than to the b7c799ef that pull request named. b7c799ef predates 403b4a4d, which is what this repository pins today and is the commit that added pagination to the settings dictionary contract, so taking the pull request's pin verbatim would have reverted a contract main already depends on and stripped offset, limit and hasMore back out of the generated web bindings. d0dc0c2b is the engine's main and is the same commit the dictionary release declares as its source, so the code and the data now name one commit.

The helpcodes moved into the engine, so MSIME-HelpCode stops being a product input: the gitlink that pins the contracts pins the tables too. product-lock.json is down to the engine and the dictionary release, and the dictionary itself now ships from MSIME-Engine. Its manifest states which commit built the data and whether that tree was clean, and the lock verifies both, so matching digests can no longer stand in for a source nobody can rebuild from. The retired MSIME-Dict repository stays valid for the one tag that shipped from it and nothing else.

The release job that packages now checks out submodules, because the helpcodes it collects live in one.
2026-09-06 04:13:04 +09:00
Evan Hu 05036a763d docs: describe one repository instead of six
The product README was under windows/ after the move, but it was never a component readme: it is the download page, the feature guide and the contribution guide for the whole product, so it goes back to the root and windows/ gets a real component readme.

AGENTS.md at the root now carries the repository map, the component boundaries that used to be cross-repository rules, and the release process, since the scripts that process drives live at the root. The component files keep what is genuinely theirs and say which paths they are relative to. References that named sibling repositories now name sibling directories, and the lock documentation records that Server, the pages, the GUI framework and the installer are no longer inputs to pin.
2026-09-06 02:40:51 +09:00
Evan Hu 6783ff7175 refactor(session): use shared composition and local queries with one candidate view model 2026-09-06 00:26:38 +09:00
Evan Hu b5e8fcf83c refactor(ipc): consume shared protocol and gate main registration on negotiation 2026-09-05 22:31:36 +09:00
Evan Hu 511c0d2df6 docs(agents): use the build-release directory the CI now builds into
#24 moved the Configure, Build and Test steps to build-release, so the commands quoted here were
pointing at a directory the workflow no longer uses.
2026-09-05 20:38:56 +09:00
Evan 3d0d2b2745 docs(agents): the tests do run now, and they need real dictionary data
#22 added Provision dictionary data and Test steps to ci.yml, so the section
saying CI never runs the suite was inverted the moment that landed. ctest runs
on every PR and a failing assertion turns the build red.

The part worth writing down is what #22 had to set up to make that work: the
tests read the real msime.db, others.db and english.db from the data root plus
the full five helpcode schemes, none of which this repository carries. A local
run without that data does not fail with a missing-file error, it fails with
empty candidate sets and assertion messages that read like logic bugs, so the
section now says to check the data root before debugging a failure. Also
records METASEQUOIA_IME_DATA_DIR as the override.

Restores BUILD_TESTING to its previous value after the engine subdirectory
instead of hardcoding ON, the same save-and-restore this file already does with
BUILD_SHARED_LIBS around cpp-pinyin. #26 put the flag back with a literal ON,
which would quietly re-enable this repository's own tests/ for anyone who
configured with -DBUILD_TESTING=OFF.
2026-09-05 20:38:27 +09:00
Evan Hu 8efb7d5cfc fix(build): resolve vcpkg_installed from the binary dir, not a literal build/
CMakeLists.txt hardcoded ${CMAKE_SOURCE_DIR}/build/vcpkg_installed in three places, for the WebView2
loader import library and two include paths, so the binary directory had to be literally named
build. The sqlite3 copy nearby already used ${CMAKE_BINARY_DIR}; the other three now match it.

The symptom is this repository's own vcpkg-release preset, whose binaryDir is build-release:
cmake --preset=vcpkg-release fails to link MetasequoiaImeSettings with LNK1181, and so does
scripts/lcompile-release.ps1, which uses it.

CI now builds into build-release. The two expressions resolve to the same path when the directory
happens to be called build, so leaving CI alone would make this a rename that proves nothing.
Rebased onto #22, whose dictionary provisioning and ctest step are kept as they are.
2026-09-05 20:22:19 +09:00
Evan ca36555efe docs(agents): correct the tests heading and give the ctest command (#21)
The section heading still said CI runs none of the tests, which contradicted
the body right under it: the target is configured and compiled on every run,
and a compile error in tests/src turns CI red. Only the running is missing.

Adds the two facts the section was short of. tests/CMakeLists.txt:78 registers
an add_test entry, so ctest has something to run rather than an empty set, and
the Configure step passes neither -DBUILD_TESTING=OFF nor anything else that
would drop the target, which is why it is always built.

Replaces "手动跑一次测试工程" with the command that actually works against the
build directory CI and the local scripts use.
2026-09-05 19:42:51 +09:00
Evan 261035a33c chore: consume the engine as a library and stop prepare_env clobbering the build (#14)
* chore: consume the engine as a library and stop prepare_env clobbering the build

The engine submodule was pinned at a197746, eight commits behind the engine's
main branch and older than the commit that first gave the engine a CMakeLists
of its own. That is why this repository listed the engine's translation units
by hand: at the pinned commit there was no target to link against. There is
one now, and Apple and Linux already consume it, so do the same here.

- advance the engine submodule from a197746 to 8cc306c
- add_subdirectory the engine and link MetasequoiaIme::Engine from the server,
  the dictionary replay tool and the settings executable, dropping the two
  hand-maintained source lists
- point the engine and msimeui submodule URLs at MSIME-Engine and MSIME-UI,
  and update the README, which still used the pre-rename repository names

prepare_env.py, which the README tells every new contributor to run first,
overwrote four tracked build files from templates under scripts/config_files
that had fallen years behind:

- CMakeLists.txt was replaced by a 147-line copy of what is now a 400-line
  build, dropping opencc, cpp-pinyin, msimeui, settings and the panels
- tests/CMakeLists.txt was replaced by an unrelated generic WinCppTemplate
- CMakePresets.json lost the vcpkg-release preset that llaunch-release.ps1
  needs

Running the documented first build step therefore broke the build. The script
now only writes the two files that are genuinely generated, and rewrites
CMakePresets.json in place instead of copying a stale template over it.

The .clangd generation addressed template lines by index and the indices had
drifted: the Boost path was written over the WebView2 include and the Sciter
path over a comment, leaving clangd unable to resolve the WebView2 headers.
The template now carries named placeholders, and the script fails loudly if
any are left unsubstituted.

Also remove src/sciter. It is a third candidate window backend that no
CMakeLists has referenced for some time; the shipped backends are d2d and
webview2, and those are the only two ui_backend accepts.

* docs: keep the historical checkout directory names in the build steps

The clone URLs had to change, since the old ones only resolved through
GitHub's rename redirect, but cloning without an explicit target would also
have renamed the working directories. MSIME-Windows's AGENTS.md records that
the historical directory names are deliberate: msime-installer's
Prepare-PackageFiles.ps1 expects siblings called MetasequoiaImeServer and
MetasequoiaImeDict, and the release workflow checks the current repositories
out into exactly those paths. Clone into them explicitly instead.

* chore: re-pin the engine at the WIN32_LEAN_AND_MEAN fix

Moves the submodule from 8cc306c to f91cd20. That carries metasequoiaime/MSIME-Engine#14,
which stops the engine exporting WIN32_LEAN_AND_MEAN as a PUBLIC compile definition and so
unblocks MetasequoiaImeSettings, whose WebView2.h include failed with 101 instances of C2146
against the trimmed Windows.h the definition forced on every consumer.

The range also picks up the two dependabot merges the engine took in the meantime: #12 bumps
utfcpp and #13 bumps the pinned action SHAs.

* build(tests): link the engine target instead of listing its sources

The test executable hand-listed the same 41 engine translation units the root
CMakeLists.txt did, and compiled them without NOMINMAX. That went unnoticed
while the pinned engine predated core/key_event.h; now that the engine headers
pull in Windows.h, the min and max macros collide with std::max and the build
fails with C2589 in quanpin_query.cpp.

Linking MetasequoiaIme::Engine fixes it at the source: NOMINMAX is one of the
definitions the engine exports PUBLIC precisely because it changes the declared
API surface.

* docs(agents): correct the tests wiring and describe the new prepare_env

Two sections went stale or were inaccurate.

The tests section said the root CMakeLists.txt does not reference tests/ at
all. It does: include(CTest) at :8 defaults BUILD_TESTING to ON and :411
add_subdirectory(tests) picks it up, so the test target is configured and
compiled on every CI run. This PR proved it from the other side, by breaking
the test target's build with a NOMINMAX regression that CI caught. The real
gap is narrower and still worth the warning: ci.yml has no ctest step, so the
executable is built and never run.

The generated-files section described prepare_env.py copying templates over
CMakeLists.txt and CMakePresets.json by fixed line index. This PR removes that
behaviour, so the section now describes what the script actually does.
2026-09-05 19:02:43 +09:00
Evan Hu 906fbc7eac docs: add an AGENTS.md for this repository
MSIME-Windows carries an AGENTS.md that opens by saying it governs the whole project, but it is
invisible from here. This points at it and records what is specific to the Server.

Two of the entries are defects rather than conventions, written down because they are load-bearing
until someone fixes them. The binary directory has to be literally named build, since CMakeLists.txt
hardcodes CMAKE_SOURCE_DIR/build/vcpkg_installed in three places for the WebView2 loader; the repo's
own vcpkg-release preset sets binaryDir to build-release and therefore does not link. And the 34
test sources under tests/ are a separate project the root CMakeLists.txt never references, with no
ctest step in CI, so a green check says only that the Server compiles.
2026-09-05 17:53:21 +09:00