技術白皮書-手工稿 (v4.8.6)
註:本文提到的 SessionCtl 是 IMKInputController 的派生型別、在小麥注音當中被稱為「InputMethodController」。此前,該型別在唯音當中曾一度被命名為「ctlInputMethod」。自唯音 2.7.5 版開始,ctlInputMethod (ctlIME) 被更名為 SessionCtl,意為「會話控制器」。
更新註記(2026-08-31):本文小麥注音側資料已更新至 v3.1(2026-08-23 發行,macOS 13+);唯音側亦已更新至 v4.7.1(2026-08-31 發行)。
更新註記(2026-09-30):唯音側已更新至 v4.8.6(2026-09-30 發行);小麥注音側對照 v3.1.1(2026-09 版,主要為語彙資料更新)。本次修訂涵蓋已確認的過期敘述:系統需求、原始碼路徑、注音排列計數與各項版本標記,並就 v4.8.5 之變動補上正文——新增〈配置助手(Configuration Assistant)〉一節、於〈其它功能〉表新增該列、並將「偏好設定視窗」一列改以現行頁面數與兩版介面之對位關係重述。
本文目的與讀者對象
本文件旨在以技術與產品設計層面之客觀差異,回應少部分將「唯音」與「小麥注音」視為「前者抄襲後者」關係的外部討論。本文希望:
- 為進階使用者 / 開發者提供清晰的模組級與架構級對照。
- 說明兩個專案在分支來源後所採取的重寫、改良與安全策略。
- 釐清哪些功能是承襲、哪些屬重構、哪些屬全新設計(例如:單結構態械 IMEState、Tekkon 聲韻並擊引擎、CandidatePool 前後端分離式選字窗、強化型浮動組字窗安全模式等)。
- 提供後續審視、延伸研究或移植評估時可引用的術語與範例依據。
讀者預期背景:熟悉 macOS 輸入法基本概念、了解 InputMethodKit (IMK) 名詞,或具備一般文字輸入法使用經驗並對內部原理好奇的使用者。
[消歧義]
OpenVanilla 團隊有三套產品,但很多 OpenVanilla 早期產品使用者會將這些產品搞混。如果算上團隊骨幹的同期的商業作品的話,則還要加算石磬軟體開發的奇摩輸入法。
- OpenVanilla 輸入法框架:以 CIN 表格為主的輸入法框架。該框架的早期版本會同捆香草注音(下文會提到),但後來香草注音模組被停止維護、就沒再被同捆入 OpenVanilla。OpenVanilla 旗下的組句型注音輸入法的職責由後來被 MJHsieh 發起的小麥注音專案繼任。
- 香草注音(SpaceChewing / OVIMChewing):新酷音輸入法模組被 Zonble 等人移植到 OpenVanilla 框架上的形態。香草注音身為注音輸入法而言的所有程式碼著作權均屬於新酷音專案,OpenVanilla 團隊僅擁有移植工作的著作權。除了可能會共用相同款式的安裝程式以外,這個專案與小麥注音連一根毛的關係都沒有。
- 奇摩輸入法:Zonble 與 Lukhnos Liu 二人開設石磬軟體公司,成為了雅虎奇摩的輸入法外包開發商,開發了奇摩輸入法。奇摩輸入法使用由 Sinica Corpus 生成的 Bigram 語料庫。此期間 Lukhnos 完成了 OVMandarin MK1 注拼引擎與 Manjusri(文殊)組字引擎的開發。文殊引擎採貪婪組句算法。後來,Lukhnos 完成了開源的 Gramambular MK1 組字引擎的第一代版本的開發,將該組字引擎與 OVMandarin MK1 合併為 LibFormosa 開發套件。
- 小麥注音一開始是 MJHsieh 在 2011 年開發的個人作品(Zonble 從這時起就有參與)。該輸入法被視為 LibFormosa 開發套件的典型輸入法開發實踐。後來,小麥注音被併入 OpenVanilla。小麥注音真正開始進入堪用期則是 2022 年,此期間 Lukhnos Liu 為小麥注音完成了 Formosa::Mandarin(注拼引擎)與 Gramambular MK2 的開發、以享受近代 C++ 版本所帶來的便利。Gramambular MK2 改採 DAG-Vertex Topological 排序鬆弛算法來組句,以因應貪婪組句算法在效能上的先天不足。再到 2026 年 2 月初,Chiahong 的 PR#777 給 Gramambular MK2 更換到了 DAG-DP 算法、但用的是他們自己的探索實作方式。
本文僅討論「小麥注音」與「唯音」的功能模組差異,不涉及下述風馬牛不相及的內容:奇摩輸入法、香草注音、OpenVanilla 輸入法框架。至於為什麼上文將這些內容講這麼細緻,是因為真的有不少糊塗人把這些東西都徹徹底底地搞混了、然後在那裡講豪洨話,非常耽誤交流效率。
引文&專案演進時間軸(精簡)
有人可能對唯音「自何時起從小麥注音 fork 出來」感興趣。雖然倉庫顯示的時間可能比較早,但實際上(拿 1.3.0 版來講)是 fork 自 2022 年 2 月初版本的小麥注音。1.2.x 版只能說是草稿版,自 2021 年底開始(到 2022 年 2 月中旬 1.3.0 版為止)一直在嘗試手動同步來自上游的一些修改,且在此同時試圖實現唯音自己的產品設計意圖。
以下列出唯音自自立分支後至 v4.8.6 之關鍵里程碑(日期以實際開發活動階段為準,非全部為正式發佈日):
- 2021 Q4:威注音 1.2.x 草稿期,嘗試手動同步上游(小麥注音早期版本)並試驗自有功能。
- 2022-02 上旬:以小麥注音 2022 年 2 月初狀態為基準,形成 1.3.0 分支起點。
- 2022-03 末:展開全面 Swift 重寫(InputHandler、後續 Megrez 第一代、逐步淘汰 ObjC++ / C++ 區塊)。
- 2022-05 ~ 06:Tekkon 並擊(聲韻並擊)引擎原型完成。
- 2022-08 初:加入 IMK 矩陣選字窗支援(後續在 3.5.4 移除)。
- 2022-09 ~ 10:SwiftUI 版田所(Tadokoro)選字窗首版(橫排+縱排矩陣)。
- 2023:CandidatePool 架構穩定,進行多輪 UI 效能重寫(移除 SwiftUI 捲動、改以 Cocoa + CoreGraphics 提升繪製效率)。
- 2024:Megrez 第二代優化、就地加詞 / 刪詞 / 降頻流程與 UTF8 精準範圍計算落地。
- 2025-01(3.9.0 海燈節):Megrez 第三代採 Dijkstra 路徑評分實作與排序優化。
- 2025-10(4.0.0):改採 DAG-DP 組字算法、FolderMonitor 行為 Actor 化與 Debounce、直書提示新方案生效。
- 2025-11(4.1.0):修復 ARC 物件釋放管理設計、引入防抖機制改良能耗、新增羅馬數字輸入模式與候選字朗讀功能。
- 2026-04(4.4.0):Megrez 組字引擎全面替換為 Homa 次世代組字引擎;LMPerceptionOverride 升級為 LX_Perceptor;原廠辭典棄用 SQLite,全面改用 VanguardTrie.TextMapTrie;拼音模式新增無調 auto-chop 與 tone bucket 查詢;LMCoreEX 新增輕量前綴索引;多輪長句效能優化。
- 2026-05(4.5.1):田所選字窗進化到第四代「我修院」(原生捲動)、空格鍵三態行為。
- 2026-07(4.5.7):IMK 交互層全面 MRC 化、CapsLock 切換卡頓與孤棄 controller 記憶體堆積修復。
- 2026-08(4.6.0~4.6.3):CIN v2.7 磁帶支援、狂拼模式首發、棄用同捆 SQLite 與 LineReader。
- 2026-08(4.7.0~4.7.1):簡拼整詞與替代切分候選、漢字轉換三態(當代繁體/康熙/JIS)、Homa trigram 支援。
- 2026-09(4.8.0~4.8.4):先鋒引擎套件正式啟用(可跨作業系統建置)、授權調整為「先鋒引擎 LGPLv3+其餘部分 MulanPSLv2」、Aqua 紀念版改由主流倉庫建置;中英混打判定持續強化(英數閂滯狀態、依槽序鍵入判定讀音)。
- 2026-09(4.8.5):內建「唯音輸入法配置助手」(以分支問卷產生可匯入的配置包)、偏好設定頁面重新歸類;修復組字狀態下功能鍵(F1~F20)會令未遞交內容消失的故障、修復辭典檢索快取的作廢缺口、並令中英混打模式的空白鍵貫徹空格鍵偏好。
- 2026-09(4.8.6):「狂拼模式」擴充為「狂打模式」,分為拼音側與注音側兩個各自獨立的開關(拼音側沿用舊制並承接既有設定值、注音側新增且預設停用);中英混打的 ASCII 內容改於組字區內顯示。
- 2025-11-30(4.1.3):從這一版開始改用《唯音輸入法》作為中文產品名稱。
註:vChewing-macOS 專案歷史於提交 8de659f 之後重新整理(該提交 cherry-pick 自上游,未被上游正式版本收錄);此前紀錄對應小麥注音至 ddbe363 為止之歷史。
自 2022 年三月底開始,唯音嘗試繼續之前上游的 Swift 化計畫所未完成的內容:用 Swift 將整個專案的 ObjC(++) 與 C++ 的部分用 Swift 徹底重寫。先是重寫了輸入調度模組,之後是組字引擎「Megrez」,最後唯音又有了自己原創的功能更豐富的聲韻並擊引擎「(齊)鐵恨 Tekkon」。此外,唯音當時嘗試用 C# 語言重寫這些模組,但因為 Windows「沒有與 InputMethodKit 一樣方便的輸入法開發套裝體驗」而只能作罷,相關倉庫荒廢至今。在此之後,Megrez 引擎做過一輪技術升級。
然後就是到了 2022 年八月初,唯音實現了 IMK 矩陣選字窗的支援。之後,唯音緊接著開始將輸入法本體的所有「直接從上游繼承來的 Swift 模組」全部淘汰,且用 SwiftUI 完成了唯音自家的全新的田所選字窗:這套選字窗同時實現了(類似 IMK 選字窗的)橫排矩陣佈局與(類似微軟新注音的)縱排矩陣佈局。
然後是 2025 年 1 月,唯音輸入法的 Megrez 組字引擎放棄使用 Lukhnos Liu 的基於 DAG-Relax 組字算法的組字方法,轉而使用經過效能最佳化的 Dijkstra 算法。這套新的組字方法實作在效能上比小麥注音更優,但有著記憶體管理上的難點。於是,唯音輸入法在 v4.0.0 版更換了 DAG-DP 算法。4.1.0 版則進一步針對 ARC 物件釋放管理進行優化,並引入防抖機制改良能耗。
這篇技術白皮書主要是為了讓部分使用者明白小麥注音與唯音至少有哪些技術上與產品功能上的不同。至於 Homa 組字引擎與 Gramambular 組字引擎的差異,請洽《Homa vs. MegrezNT vs. Gramambular2 Whitepaper》一文。
P.S.: IMK 選字窗一度受唯音支援,但因為其利用方式太複雜不利於唯音輸入法長遠發展的原因、而在唯音 3.5.4 版內遭到了移除。
總括概述
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 |
|---|---|---|---|
| 資料截取日期 | 2026-09-22 | 2026-09-30 | 小麥注音側依 v3.1.1、唯音側依 v4.8.6 更新 |
系統支援與資訊安全
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 |
|---|---|---|---|
| 支援作業系統範圍 | macOS 13 起算(自 3.1 起) | 主流發行版 macOS 12 起算 Aqua 紀念版 macOS 10.9 起算 | 小麥注音 3.0 為 macOS 11 起算;3.1 起調升為 macOS 13。macOS 10.9 是 Swift 5.9 能支援的最早的系統版本。Swift 6 開始將不再支援 macOS 10.9 等任何需要 libArcLite 的系統版本。 |
| 強化型組字區安全防護 | 無 | 有(強烈推薦使用) | 會有 App 或網站提前獲取內文組字區的內容給遠端伺服器、來遠端預判使用者的下一步操作。唯音的這個模式會以浮動組字窗取代內文組字區,使得接收文字輸入的客體軟體再也無法擅自利用組字區的內容來觸發使用者不想觸發的事件。您也可以藉由「客體管理器」僅對部分客體 App 啟用這種限制。 這個功能所啟用的浮動組字窗也可以變相解決在某些對 InputMethodKit 內文組字區支援不佳的軟體內的文字輸入體驗問題(比如 ChatGPT 的 macOS 桌面端)。 |
| Sandboxing 沙箱 | 無 | 有 | 利用 macOS Sandbox 約束檔案與進程存取範圍,降低未授權腳本執行與資料外洩風險。 |
| 允許設定在就地加詞之後自動執行指定腳本 | 允許,且腳本位址存於 UserDefaults Plist 當中 | 不允許 | 一兩道 Defaults write 指令就可以讓小麥注音在每次加詞時自動執行有害腳本。更甚者,小麥注音沒有 Sandbox 設計、無法控制這種情況下的被害目錄範圍。 |
| 讀取網路資料 | 僅在新版軟體檢查時才會聯網,且該功能自動啟用、會在安裝完畢後首次執行時主動聯網 | 僅在新版軟體檢查時才會聯網,需使用者手動啟用新版軟體檢查之功能 | |
| 將本地資料上傳 | 無 | 無 | 唯音另有與此有關的 Sandbox 行為約束。 |
基礎大模組與處理單元
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 |
|---|---|---|---|
| CIN 模組 | 不具備 | 支援 CIN2(v2.7)標準 | 小麥注音團隊另有 OpenVanilla 輸入法專門使用 CIN 表格工作。 |
| 內碼輸入 | 具備 | 具備 | 兩者各自對此的實現方式不同; 唯音在簡體模式下有支援 GB 內碼輸入。 |
| 輸入調度模組 | KeyHandler (Objective-C++) | InputHandler (Swift) | 職能很相似 |
| 按鍵訊號承載單位 | KeyHandlerInput | NSEvent及其私有功能拓展 以及其對等克隆體 KBEvent Struct | 唯音利用 NSEvent / KBEvent 的 characters ignoring modifiers 參數塞入狀態上下文情境描述用中繼資料。 |
| 組字引擎 | Gramambular 2 (C++) by Lukhnos Liu 2026-02-02(PR#777)為止採 DAG-Relax 組字算法;之後被 Chiahong 換成 DAG-DP(Viterbi 動態規劃)。 | Homa (Swift) by Shiki Suen 2025 年 10 月改採 DAG-DP 算法(前身 Megrez 3.9.x 曾用 Dijkstra);2026 年 4 月升級為 Homa,內建候選輪替、上下文鞏固與感知觀測 API。 | Homa 擁有包括對就地加詞功能要用到的標記游標的管理等獨特功能。DAG-DP 算法無須 Vertex Topological 排序。 |
| 注音並擊引擎 | Formosa::Mandarin (C++) by Lukhnos Liu | Tekkon (Swift) 支援更多注音排列與拼音種類 | 均無允許使用者自行設計注音排列之能力 。 |
| 詞庫管理模組 | Objective-C++ & C++ ParselessLM 採 TXT 格式的原廠辭典 | Swift 採 VanguardTrie.TextMapTrie 格式的原廠辭典 使用者片語辭典採 txt 格式 | |
| 態械引擎 | 多型別狀態策略設計模式 無專有內部資料型別 | 單結構狀態策略設計模式 有專有內部資料型別 | 雙方的開發習慣不同、導致各自的取捨不同。 |
| 資料截取日期 | 2026-09-22 | 2026-09-30 | 小麥注音側依 v3.1.1、唯音側依 v4.8.6 更新 |
選字窗
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 | |
|---|---|---|---|---|
| IMK 選字窗支援 | 無 | 無 | 雙方均在不同的年代曾經分別支援過 IMK 選字窗,但因技術維護方面的各自苦衷而先後放棄支援。 | |
| 輸入法內建選字窗 | Voltaire MK2 (Swift Cocoa) | Tadokoro 田所選字窗(第四代「我修院」) | 田所選字窗支援展頁等特性,且完美重現了微軟新注音輸入法(2003 至今)與 macOS 內建注音輸入法(macOS 10.13)對候選字的陳列行為。 | |
| 內建選字窗是否有支援矩陣佈局 | 否 | 橫排矩陣(類似 IMK) 縱排矩陣(類似新注音) | 田所選字窗自 4.5.1(第四代「我修院」)起原生支援捲動條捲動體驗。 | |
| 內建選字窗是否有專有內部資料型別 | 否 | 是 | 唯音的設計更易於維護 | |
| 頁碼支援 | 否 | 否(Voltaire MK3 有支援過) | 田所選字窗另支援對當前選中的候選字的總索引編號顯示 | |
| 針對簡繁體輸入模式以對應的系統介面字型顯示候選字 | 無 | 僅限田所選字窗(需在偏好設定內的開發道場當中手動啟用) | macOS 11 因為系統 Bug 的原因不支援該特性。 | |
| 針對簡繁體輸入模式以不同的高亮候選字背景色 | 否 | 僅限田所選字窗(Voltaire MK3 有支援過) | ||
| CIN 字根反查 | 無(Voltaire 選字窗不支援) | 有 僅限田所選字窗 | 該功能自 2.9.4 開始才算成熟。 | |
| Unicode 萬國碼資訊顯示 | 常駐顯示無;選字窗按「?」可查字元資訊(3.1 起含 Unihan 名稱/讀音/倉頡/日韓讀音等) | 有 僅限田所選字窗 | 該功能自 3.8.1 版開始實裝。 | |
| 候選字朗讀 | ✅(2.9.4+)VoiceOver 可朗讀候選字詞(系統 SQLite 輔助功能資料庫);「?」鍵選單可主動朗讀(2.7+) | ✅(4.1.0+ 可設定)查詢使用者自訂關聯詞語資料庫 | 唯音沿用了自身本來就有的語音朗讀模組 | |
| 選字窗畫面控頻/刪詞 | 自 v2.9.3 起於選字窗內以熱鍵 +/= 升頻、-/_ 排除詞彙(寫入使用者詞庫/排除清單) | 右鍵選單控頻刪詞 僅限田所選字窗(註:自 v4.2.0 起,對單個漢字的升頻/降頻/排除操作之開關已移至「偏好設定 → 開發道場」,預設關閉;當未啟用時,使用者片語辭典內的單漢字升降頻覆寫不再生效。此前啟用過該選項的使用者在升級到該版本時,該選項會被強制取消勾選;使用者可在升級後重新啟用,但後果自負。) | 不支援臨時漂浮客體, 比如 Spotlight 與 NSMenu 等。 |
文字輸入方式
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 |
|---|---|---|---|
| 支援注音排列種類 | 大千傳統、倚天傳統、倚天26、許氏、IBM | 大千傳統、倚天傳統、IBM、神通、精業、偽精業、倚天26、酷音大千26、許氏、星光、劉氏 | 下述排列為動態注音排列:倚天26、酷音大千 26 、許氏、星光、劉氏 |
| 支援拼音輸入種類 | 僅一種漢語拼音模式(鍵盤排列,聲調以數字 1–5 標記),缺乏介紹資料 | 漢語拼音、國音二式、華羅拼音、耶魯拼音、通用拼音、韋氏拼音;狂打連續組句(拼音側 4.6.3+、注音側 4.8.6+)並支援簡拼整詞(4.7.0+) | 「趙元任國語羅馬字」無法作為支援對象,因為無法設計「固定的」用以確認聲調的按鍵 |
| 拼音並擊模式 | 無 | 有 | 就是在敲注音的時候在組字區內顯示拼音 |
| 字母輸入 | Shift+字母鍵可定義兩種輸入方式,僅允許對大寫字母直接地教 | Shift+字母鍵可定義三種輸入方式,其中允許對小寫字母的直接遞交 | |
| 全形數字輸入 | 尚無直接支援 | Alt+Shift+數字鍵 | Alt+數字鍵輸入半形數字 |
| 羅馬數字輸入 | ✅(2.9.4+ Ctrl+\)三種風格:ASCII 小寫、Unicode 大寫、Unicode 小寫 | ✅(4.1.0+ Shift+Cmd+R)1-3999 範圍,Unicode 大小寫 & ASCII 大小寫 | 兩者的實作方式與各自在輸入法當中的集成方式各異,用以呼叫該功能的方法也不一樣。 |
| 大鍵盤數字鍵區支援 | 無法正確處理 | 直接忽略輸入,或者用作選字鍵 | 唯音有針對 JIS 的數字小鍵盤特有的按鍵做過針對處理 |
| Emoji 模式 | 僅原廠 Emoji,無開關 自訂 Emoji 到使用者片語辭典內的話,會與漢字詞搶頻 | 有專門的使用者 Emoji 辭典檔案,有開關 | |
| Alt 切換「熱鍵專用鍵盤佈局」 | 有支援(需使用終端機) | 故意放棄支援 | 與該功能有關的 Alt 鍵操作會因為 NSMenu 的按鍵攔截干擾、而無法保證使用體驗 |
| 用 Shift + BackSpace 析構游標後方的漢字的讀音 | 不支援 | 支援 | |
| 用聲調鍵複寫游標後方的漢字的聲調 | 自 2.9.5 起支援(終端機開啟) | 支援 | |
| 允許以聲調鍵開頭敲字 | 支援 | 支援 | |
| 在用選字窗選字時,先鞏固操作範圍上下文 | 不支援 | 支援 | 類似 macOS 內建注音輸入法的體驗。但是,唯音只會在藉由選字窗選字時鞏固上下文。 |
| CIN 表格支援 | 無 | 有 | 藉由唯音特有的磁帶模式來支援。 |
| 漢音符號輸入支援 | 自 3.1 起支援漢音式符號輸入(「`」鍵進入標點清單,逐鍵對應符號組) | 全部支援。 | 後者包括漢音鍵盤符號模式在內。 |
| 內碼輸入支援 | 有(僅 Big5,要求 2.4.2 之後的版本) | 有 | 後者可連續輸入。 |
| 資料截取日期 | 2026-09-22 | 2026-09-30 | 小麥注音側依 v3.1.1、唯音側依 v4.8.6 更新 |
| 允許忽略掉 CapsLock 的強制英文輸入 | 無 | 有 | 唯音此舉可照顧到微軟新注音輸入法的使用者的習慣。 |
| 聯想詞 | 有,且能在組字區內工作 | 有,但脫離組字區工作 | 唯音此舉看似不便利,但躲開了「拿破音字自動匹配讀音」這種永遠無法正確實作的產品功能需求。 |
就地加詞刪詞
該部分的功能介紹特指不需要叫出選字窗就能完成的功能行為。
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 |
|---|---|---|---|
| 就地加詞刪詞功能 | 僅就地加詞 | 就地加詞/刪詞/升頻/降頻(註:自 v4.2.0 起,對單漢字的升權/降頻/排除操作之開關已被移至「偏好設定 → 開發道場」,預設為關閉;當未啟用時,使用者片語辭典內的單漢字升降頻覆寫不再生效。) | |
| 就地加詞操作方式 | Shift+前後方向鍵選取範圍,再敲 Enter 操作 | Shift+前後方向鍵選取範圍,再敲 Enter 加詞 / 升頻、敲 BkSp / Del 就地刪詞、摁 Shift + Command + Enter 降頻 | 該功能與該操作方法的搭配乃微軟新注音 2003 首創、且漢音從未支援過這種操作方法。 |
| 對字詞數與讀音數不等的情況的支援 | 無 | 有 | |
| 加詞刪詞範圍運算管理 | 僅位於態械內,以 UTF16 為範圍長度單位,需 NSStringUtils。 | 態械、組字引擎、輸入調度模組同時協作,以 UTF8 為範圍長度單位,不需要 NSStringUtils。 | 唯音的做法更精確,也只有這樣才能實現對字詞數與讀音數不等的情況的支援 |
漢字模式支援與審音支援
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 |
|---|---|---|---|
| 簡體中文輸入支援 | 轉換 | 原生簡體中文詞庫+通用規範漢字表支援,与原生繁體中文詞庫分离。 | 繁轉簡也存在失真,比如「著->着」。 |
| 簡體中文使用者片語支援 | (跑題了) | 簡繁模式下就地加詞時會做交叉轉換、確保在某一個模式下加詞時也會讓另一個模式受益。 | 沒有別的好辦法。 |
| 漢字轉換引擎 | OpenCC(詞組級轉換) | 步天歌 Hotenka(支援詞組轉換) | 步天歌引擎不適合用來做大篇幅的簡繁轉換 |
| 全字庫支援 | 有(2011 版) | 有(2022 版) | 宜每年更新一次。 |
| 其它漢字支援 | 無 | 漢字轉換模式(當代繁體/康熙/JIS 三態) | 4.7.0 起原康熙/JIS 獨立模式整併為單一三態轉換模式(Ctrl+Command+Shift+K 輪替);轉換準確度有限 |
| 組字區與選字窗內的漢字反應當前的簡繁模式或 JIS / 康熙轉換模式 | 否 | 是 | |
| 審音 | 僅台澎金馬民間讀音 | 兩岸審音與台澎金馬常用讀音均兼顧 | |
| 大寫漢字數字輸出 | 無 | 有 | 銀行等場合會用到 |
其它功能
| 差異項 | 小麥注音 (3.1.1) | 唯音 (4.8.6) | 補記 | |
|---|---|---|---|---|
| 对「不認真遵守 IMKTextInput 協定」的軟體的支援 | 無 | 有(需要在客體管理器內針對具體的客體 App 啟用浮動組字窗) | 比如 VSCode 與 Naver Line 等。 | |
| 使用者片語辭典格式主動整理 | 無,只會在就地加詞時套用檔案 EOF 檢查修正 | 有,會主動整理 | ||
| 使用者片語辭典目錄狀況監測 | 有:FSEventStream | 有:Dispatch Source File System Object (DSFSO) | DSFSO 無法監測 App 自身對目錄內的檔案的修改,但這反而使程式行為更加可控。 | |
| 偏好設定視窗 | 自 3.1 起改為 SwiftUI(Basic/User Phrases/Advanced 三頁籤) | 主流發行版採 SwiftUI 版偏好設定視窗(共 12 頁,需 macOS 14 以上、預設啟用);另有一套以唯音自訂之 SwiftUI 風格 DSL 建構的 AppKit 版,供 macOS 10.9 起的 Aqua 紀念版與舊系統使用,其選項集合與頁面歸屬與 SwiftUI 版逐頁對位。 | 兩版之對位關係由設定介面套件內的 PaneLayoutTests 守住。 | |
| 敲字讀音錯誤提示 | 僅系統蜂鳴生效 | 有專門的SFX,會在啟用偵錯模式時生效。 | 唯音的廉恥模式的開關會影響 SFX,但這個開關只會在愚人節才能看到。 | |
| ㄅ半模式支援 | 單獨的輸入法模式副本 | 輸入法功能選單內切換 | 唯音的關聯詞語模式可自訂詞庫 | |
| 倚天中文 DOS 候選字順序 | 有(僅限傳統注音模式) | 有(v4.2.0 之前僅限逐字選字模式;自 v4.2.0 起新增偏好開關「對所有單漢字候選字強制施加倚天中文DOS系統排序」,預設啟用,會覆蓋打字學習模組對單漢字候選字排序的影響) | Windows 內建的ㄅ半注音用的也是這個排序。 | |
| 自訂語彙長度限制 | 八個字 | 十個字 | ||
| 符號選單 | 類似漢音的符號選單 | 類似漢音的符號選單+類似新酷音的分層符號選單,但內容更豐富 | 後者可藉由自己撰寫 symbols.dat 的方式自訂 | |
| 使用者片語置換及過濾 | 有 | 有 | 雙方功能行為一致 | |
| 使用者打字習慣觀測學習模組的算法 | 半衰期記憶曲線 | 基於野獸常數的偽二次多項式衰減 | 唯音的打字習慣學習模組有對 Gram 數量的不同採用不同的計分方式。 | |
| 使用者打字習慣觀測學習模組資料的可持續利用 | 暫無 | 有 (JSON) | 唯音可在輸入法選單內清空該資料 | |
| 工具提示視窗的縱排顯示支援 | 無 | 有 | 唯音對此要求至少 macOS 10.13+ | |
| W3C Ruby 注音讀音標記 | mac 版自 2.7 起可輸出注音 HTML Ruby(Ctrl+Enter),linux 版亦有;不支援教科書聲調寫法 | 有,且支援教科書聲調寫法 | 唯音也可輸出漢語拼音的 Ruby 標記 | |
| 介面語言種類 | 僅繁體中文與英文 | 簡體中文/繁體中文/日文/英文 | ||
| 是否容忍橫跨游標的候選字的出現 | 是 | 否 | 無論漢音還是微軟新注音都不會容忍橫跨游標的候選字的出現 | |
| 輪替候選字 | 僅 (Shift+)Tab | Shift(+Alt)+SpaceAlt+↑ 或 Alt+↓(Shift+)Tab | 縱排輸入時為 Alt+← 或 Alt+→;4.5.1 起空格鍵行為可設為三態(插入空格/呼出選字窗/輪替候選) | |
| 以組字區內的字詞節點為單位移動游標 | 無 | 有:Alt+前後方向鍵 | ||
| 允許自己卸除自己 | 不允許,必須要求使用者手動操作 | 需摁 Alt 點輸入法選單,才可以看到該功能的入口 | ||
| 使用者片語編輯器 | 不具備;會依賴外部編輯器 | 內建一套語彙編輯器 | ||
| GraphViz 輸出支援 | 不支援(以前曾經支援過) | 支援(得先開啟偵錯模式) | ||
| 日期時間便捷輸入 | 不支援 | 支援 | ||
| Emacs Key | 在輸入調度模組內部處理 | 在水源入口處理:發現 Emacs Key 就直接將原始 KBEvent 換成翻譯後的 KBEvent | ||
| 配置助手(新手配置嚮導) | 無 | 有(v4.8.5 起同捆一套網頁式分支問卷,產出的「配置包」可經剪貼簿匯入;偏好設定亦可整個匯出/匯入為 JSON 檔案) | 助手之題庫僅涵蓋設定介面已曝露的選項,且以契約測試確保其產出值一概能被唯音接受 |
個別詳細介紹
組字算法(歷代策略與現行方案)
小麥注音從 2.0 版開始由 Lukhnos Liu 更換了具備全新DAG-Relax 組字算法的 Gramambular 2 組字引擎。
截至 2024 年底,唯音輸入法也都有在用相同的組字方法。然而,2025 年 1 月底的海燈節更新的 3.9.0 版唯音輸入法的第三代 Megrez 組字引擎改用了全新的基於 Dijkstra 算法的組字方法,同時針對 Sandy Bridge 時代的老電腦做過效能最佳化。這樣一來,在組字組句的速度上,唯音更快。
Dijkstra 算法的實作難免需要一個專門用來排序的機器。Swift Foundation 原生的排序算法並非最高效的方案。所以,第三代 Megrez 組字引擎針對輸入法的使用情景重新訂製了這個排序過程、藉此縮短了 Dijkstra 的運算耗時。
然而,Dijkstra 算法有著記憶體管理上的難點。於是,唯音輸入法在 v4.0.0 版(2025 年 10 月)更換了 DAG-DP 算法。這個算法不需要 Vertex Topological 排序。此實作時間點(2025 年 10 月)早於小麥注音社群貢獻者 Chiahong 於次年二月初提交的 相同算法實作 PR#777。儘管兩者最終都採用了 DAG-DP 這一公有領域的成熟算法,但唯音的的 Swift 實作架構(基於 Value Type 與 ARC 優化)與小麥注音的 C++ 實作(基於 Class 與指針管理)截然不同。時間軸的先後順序與代碼實作的本質差異,足以證明唯音並未參考或抄襲小麥注音的該項改動。與此有關的反向抄襲指控也不成立,因為 Chiahong 有著自己的實作探究過程,故不應將兩者之間就 DAG-DP 算法一致的事情做 Copycat 之定性。
到了 2026 年 4 月,唯音輸入法在 v4.4.0 版將 Megrez 全面升級為 Homa。Homa 不僅繼承了 DAG-DP 的核心優勢,更進一步內建了候選輪替(revolveCandidate)、上下文鞏固(consolidateCandidateCursorContext)、感知觀測(PerceptionIntel)生成等上層 API,大幅精簡了 Typewriter / InputHandler 層的程式碼複雜度。Homa 的 CandidatePair 亦純化為僅含身份資訊的型別,權重語義統一由 CandidatePairWeighted 承載,消除了 Megrez 時代 score 欄位在身份比較與雜湊行為上製造的語意債。v4.7.0 起 Homa 新增對 trigram 語言模型查詢的支援。
組字算法對照表(摘要)
| 項目 | DAG-Relax | Dijkstra(最佳化版) | DAG-DP |
|---|---|---|---|
| 使用世代 | 唯音早期、小麥注音2.0 (~2026-01) | 唯音 3.9.x | 唯音 4.0.0+(現行為 Homa)、小麥注音 (2026-02+) |
| 核心思路 | 對 DAG 中邊進行鬆弛求最優路徑 | 最短路徑優先擴展 | 以 DP 自底向上計分決策 |
| 主要資料結構 | DAG(節點=切分位置) | 優先佇列 + 鄰接表 | 線性索引節點陣列 |
| 需拓撲排序 | 是 | 否 | 否 |
| 時間複雜度(概略) | O(V+E) 鬆弛 + 路徑回溯 | O(E log V)(優先佇列最佳化後) | O(V+E) 線性 DP |
| 空間特性 | 需保存多層鬆弛狀態 | 佇列 + 路徑記錄 | 緊湊,可預測 |
| 優點 | 演算法直觀、成熟 | 對長詞串耗時降低 | 緊湊,可預測 |
| 局限 / 棄用原因 | 增量輸入時重算成本偏高 | 記憶體佔用與釋放管理複雜 | 需針對多讀音詞再行擴張節點映射 |
(複雜度為理論近似;實際效能視輸入長度、候選詞數量與剪枝策略而定。)
Tekkon 排列與拼音支援一覽
| 分類 | 內容 |
|---|---|
| 注音排列 | 大千傳統、倚天傳統、IBM、神通、精業、偽精業、倚天26、酷音大千26、許氏、星光、劉氏 |
| 動態排列(編碼與位置會根據上下文或模式調整) | 倚天26、酷音大千26、許氏、星光、劉氏 |
| 拼音系統 | 漢語拼音、國音二式、華羅拼音、耶魯拼音、通用拼音、韋氏拼音 |
| 並擊提示 | 注音輸入時同步顯示對應拼音(可選) |
| 不支援 | 趙元任國語羅馬字(無法定義穩定聲調鍵位) |
田所選字窗
迄唯音 2.7.5 版為止,這個備選的選字窗都是自上游繼承過來的 Voltaire MK2 (Swift) 選字窗修改來的。唯音在此之上做了介面美工,加上頁碼顯示,變成 MK3 版:

唯音自 2.8.0 版起,對 macOS 11 及之前的系統,僅提供 IMK 選字窗可用。本來唯音是不用再另起爐灶的。然而,IMK 選字窗在未來可能會因為改了某個內部 API 而導致新的故障出現,所以必須得有一個非 IMK 的選字窗作為備選。但如果要把 Voltaire 選字窗重寫成類似 macOS 內建輸入法那種捲動矩陣佈局的話,只用 Cocoa 技術實現的話,技術難度太大。
幸好,SwiftUI 讓事情變得簡單了一些。雖然很多要用到的 SwiftUI API 要求至少 macOS 12 才可以用得上。田所選字窗的工作原理與筆者下文當中提到的 IMEState 差不多:有一個專門處理資料變化的內部型別,且與負責介面顯示的型別徹底分離。這樣一來,負責介面顯示的型別(其實是 SwiftUI 結構)在程式維護方面就會輕鬆不少。
(本文所示田所選字窗擷圖只是示範。其美術設計在後來又經過了一些小調整。)
先看田所選字窗的橫排矩陣佈局:

唯音不滿足於對橫排矩陣選字窗的支援,於是又完成了縱排矩陣選字窗、提供了類似微軟新注音 2003 的體驗:

一開始的田所選字窗是有做得跟 macOS 內建的選字窗幾乎雷同的。但是,SwiftUI 的繪製效能並不好,使得選字窗的操作流暢度欠佳、嚴重影響了ㄅ半輸入模式的體驗。於是,田所選字窗的滑鼠滾動檢視特性就被移除了、且僅顯示三列矩陣。
後來,田所選字窗又經過了幾次徹底重寫,最近的一次重寫利用了 Cocoa 以及 CoreGraphics、極大地提升了介面繪製效率。這也允許田所選字窗在 macOS 10.9 Mavericks 系統下完美運作。

田所選字窗採前後端分離的設計:所有與選字窗的顯示行為控制和資料統整都是藉由後端的 CandidatePool 來完成的,而前端則負責將後端當圖紙依據、由前端自動繪製圖形介面內容。到了 4.5.1 版,田所選字窗進化到第四代(研發代號「我修院」),重新引入了類似 IMK 選字窗的原生捲動條捲動體驗。
通知飄窗
唯音輸入法用到 2.7.0 為止的通知飄窗,是由小麥注音的通知飄窗修改了 NSWindow 的配色屬性之後而成的。而論及唯音 2.7.5 版引入的新款通知飄窗,則擁有如下新特性:
- 新通知始終顯示在螢幕右上角、且舊通知會自動變淡+位置下移。原因:使用了更好的飄窗通知副本管理方法。
- 飄窗文本排版及動畫動畫效果受到了 Call of Duty: MWII 2022 的影響,但也兼顧了 Cocoa 應用的顯示風格、使之不太出戲。
- 對 DispatchQueue Async 的相容。之前上游的通知飄窗在 DispatchQueue Async 內呼叫時會讓輸入法直接崩潰掉。
此外,考慮到有使用者在濫用這個功能的情況下出現的記憶體洩漏、CPU 高佔用率的問題,唯音輸入法在 2.8.0 SP3 當中對此做了專門的修正:最多只會殘留四條近期通知。(後來又再縮減到兩條通知。)

工具提示視窗
小麥注音與奇摩輸入法的實現只適合橫排輸入時的顯示。一旦縱排輸入,整個文字提示視窗就還是橫排顯示的。唯音 2.5.0 版對該模組做了重寫,引入了 NSAttributedTextView 這個可以縱排顯示文字的 NSView (在 Fuziki 的同款功能的 UIView 的基礎上改來,且得到他本人的准許)。但是呢,因為系統字型的 vert 特性在顯示注音、漢語拼音、英文、阿拉伯數字時的效果非常糟糕,使得筆者決定做出如下處置:
- 在使用英文介面時,始終使用橫排顯示的工具提示。
- 在使用中文或日文介面時,允許使用者在偏好設定內啟用「始終使用橫排顯示的工具提示」。
- 縱排工具提示視窗內的按鍵名稱都使用符號來顯示。
- 縱排工具提示視窗內以全形空格來分隔每個漢字的讀音。
- 縱排工具提示視窗內僅顯示注音、而不顯示漢語拼音。
另外,新版工具提示視窗在任何場合都不會遮住使用者正在輸入的文字。

再後來,自唯音輸入法 v4.0.0 起,Fuziki 的方案被換掉,新的方案允許這個直書顯示效果對 macOS 10.13 High Sierra 生效。
按鍵訊號載體單位 & 對 EmacsKey 的支援
小麥注音的 KeyHanderInput 是把 NSEvent 讀取且翻譯成這麼一個新的按鍵訊號載體單位類型。該組件在唯音當中被更名為 InputSignal,但與 InputSignalProtocol 是兩碼事情:前者遵循後者這個協議所規定的規範,而 KeyHandler 輸入調度模組當中的函式可以處理任何符合該規範的物件。
唯音在 v2.3.1 當中淘汰了該模組,轉而直接對 NSEvent 做了符合 InputSignalProtocol 的擴展。主要原因在於「IMK 選字窗只能處理 NSEvent」這個客觀事實。更何況,KeyHanderInput 當中的很多實現,對目前的唯音而言並不經濟。
對 NSEvent 做了這種擴展處理之後,就明顯減少了 NSEvent 按鍵訊號流從 SessionCtl 流往 IMKCandidates 的過程當中的任何不必要的類型轉換。在此之上,唯音 v2.4.0 又引入了「讓 NSEvent 迅速改掉自身的其中任意一處屬性」的全新重構函式(Reconstructor)、進一步減少了 SessionCtl 與 ctlCandidateIMK 的篇幅。唯音還藉由 charactersIgnoringModifiers 這個參數,實現了「往 NSEvent 裡面塞入諸如『當前是否是縱排輸入』等資料」這種特性需求。
不過呢,唯音從業火五筆輸入法承襲來的「用來判定 Shift 鍵是否有被敲過」的特殊按鍵判定函式要求傳入的 NSEvent 必須是 SessionCtl.handle(event:) 吃到的 raw event 且做過 guard-let 處理、然後直接交給特殊按鍵判定函式。不然的話,判定會失效。這與該判定函式本身所使用的方法有關(涉及到對 NX_DEVICELSHIFTKEYMASK 等 NX Mask 的判定處理),且 NSEvent 不是 Struct 而是 Class、在 Swift 當中就容易出現這方面的鬧鬼情況。
上文有提到唯音利用 NSEvent 作為基礎按鍵訊號單位、且引入了自我重構函式的事情,那麼對 EmacsKey 的判定就簡單了:直接在接收訊號的第一道關口將符合條件的 Emacs Key NSEvent 重構為對應訊號的 NSEvent 即可,省去了之後的一切判斷處理步驟。
後來唯音做了另一個擴展「KBEvent」,算是 NSEvent 的重新實作、且身為 Struct 更易於在輸入法內部拿來處理。再後來,唯音 4.0.0 引入了 Ctrl+N 與 Ctrl+P 這兩套 Emacs 熱鍵的支援。
InputState 有限態械系統+NSStringUtils+就地增刪詞
先提一下:唯音相比小麥注音而言,新增了就地刪詞、就地降頻的功能。
小麥注音 InputState 的設計
mcbopomofo/Source/InputState.swift 採用 Objective-C 類別階層來表達狀態:InputState 為根類別,Inputting、Marking、SelectingFeature 等十餘種子類別各自封裝 UI 資料與行為。狀態物件一律繼承 NSObject、並仰賴 NSStringUtils 來換算 UTF-16 字元範圍;在 Marking 狀態中,為了對齊選取範圍與注音讀音,需要大量 NSString 轉換。候選介面呈現也直接在狀態類別內建立 NSAttributedString,導致狀態邏輯與 UI 緊密耦合。這套做法在當年 Objective-C++ 專案內維持了彈性,但面對 Swift 化後的語言特性與 struct value semantics,就顯得偏重。更甚者,這在原理上無法正確處理「某個 Segment 的讀音數量與廣義上的字符數量不相等(Emoji 數量也算)」的情況,因為一切都是在組字引擎之外的推斷操作、且該操作與組字引擎彼此被隔離開了。
唯音 IMEState 的重構
唯音於 Packages/vChewing_OSNeutral_LibVanguard/Sources/LibVanguard/Session/IMEState.swift 以純 Swift struct 重新定義態械,並由 IMEStateProtocol / IMEStateDataProtocol 將狀態介面與數據載體拆分。IMEState 僅承載列舉型別 StateType、候選陣列與游標資訊;真正的文字、標記範圍、提示樣式等資料轉移到 IMEStateData,集中處理 UTF-8 / UTF-16 對應、候選過濾條件與 Tooltip 顏色狀態等衍生值。
這樣的分層帶來幾個直接效果:
- Swift 原生字串計算即可涵蓋 emoji 等高位字元,
IMEStateData僅在需要回饋 IMK 時以utf16投影,原專案所依賴的NSStringUtils不再需要。- 更甚者,Marking 游標不是計算出來的,而是由 Homa 組字引擎直接給出的:Homa 組字引擎同時管理打字游標與 Marking 游標,且提供了專門的 API 來完成與這些內容有關的交互體驗。
- UI 呈現改由
IMEStateData.attributedString*()生成,輸入調度程式 (InputHandler_HandleStates.swift) 可以自由組裝displayTextSegments、tooltip再交給狀態結構,候選窗 / 浮動組字窗只需根據資料渲染。 - 新增的
ofAssociates、ofSymbolTable、convertedToInputting等建構器讓SessionCtl可以在同一個 value-type 狀態上進行快照切換,並支援就地刪詞、降頻與磁帶模式的特殊流程。 tooltipColorState、markedTargetIsCurrentlyFiltered等欄位被納入標準狀態資料,使得handleMarkingState()這類函式能夠在切換回輸入狀態時直接展示操作結果,減少跨模組依賴。
整體差異摘要
| 面向 | 小麥注音 (InputState) | 唯音 (IMEState + IMEStateData) |
|---|---|---|
| 狀態定義 | NSObject 子類別樹,每一種狀態一個類別 | 單一 struct + StateType 列舉,建構器建立不同語境 |
| 字串與範圍 | 依賴 NSStringUtils / UTF-16 索引 | Swift String + utf16 投影,預設 UTF-8 游標 |
| UI 維度 | 狀態類別內建 NSAttributedString | IMEStateData 統一產生,前端僅需繪製 |
| 候選處理 | 以 CandidateProvider 協議回傳字串 | [(keyArray, value)] 保留讀音陣列,方便後續過濾 |
| 擴充性 | 新增狀態需建立子類別並處理 KVC | 透過建構器與資料欄位擴充,value semantics 便於複製與比較 |
整體而言,唯音態械的 value-type 重構使狀態切換更容易測試與推導,也為 Swift Concurrency、Actor 化模組(例如 FolderMonitor)打下基礎,並直接支撐了就地降頻 / 過濾、開發者模式提示等新功能。
配置助手(Configuration Assistant)
小麥注音側:無對應實作。其偏好設定的選項數量相對收斂,故一直不需要這類引導工具。
唯音輸入法的偏好設定自 v4.8.0 版起已超過一百個選項(現行 119 條偏好鍵),新手要在其中找到「與自己打字習慣有關的那幾項」頗為吃力。故唯音自 v4.8.5 版起內建一套「唯音輸入法配置助手」——一套以分支問卷形式整理出「配置包」的網頁工具。其使用者介面刻意採 Windows 2000/Windows ME 時代的問卷精靈風格,並只使用 CSS2.1 之寫法(3D 邊框用 outset/inset/groove、不使用 flexbox 與 grid),以便在 macOS 10.9 的 Safari 7 下亦能正常呈現。
職責切分:助手不做什麼
助手與輸入法之間沒有 IPC、也沒有 URL scheme,唯一的傳遞媒介是剪貼簿。助手生成的「配置包」是一份 JSON 文檔,亦即唯音既有偏好交換格式(UserDef.exportAsJSON())的超集:多了一個承載配置名稱與說明之中介辭典 __UserDefMeta。助手不自稱能替使用者決定其未表態之項目——每個單選題的預設選項一律是「維持不變」,未表態即不輸出該鍵。
唯音側為此新增的交換格式 API 落於 Shared 模組:destructureExchange(_:)(無條件摘除根層一切以 __ 起首之鍵)、importFromDictionary(_:)(逐鍵驗證之真源)、diffAgainstCurrent(_:)(純查詢之差異計算)與 PrefMgr.reconcileAfterExternalPrefsImport()(匯入後之和解)。後者補上了一處長年缺口:UserDef.importFromJSON(_:) 係直接對 UserDefaults 寫值、不經 PrefMgr 的屬性包裝器,故 13 條帶有 didSet 副作用之偏好鍵(辭典資源重載、語音服務刷新、左右 Shift 偵測器同步、選字鍵之小寫化與去重等)一概不會被觸發。現行四條匯入路徑——設定介面之檔案匯入、檔案拖放、剪貼簿匯入、CLI 之 --import-prefs-json——皆以同一收尾統一處理。
助手亦同時補足了「偏好設定的可攜性」:整份偏好設定現在可以匯出為 JSON 檔案、再匯入另一台機器。
助手本體與防漂移機制
助手以 TypeScript 撰寫、零 npm 相依,產物是單檔自足之 HTML(CSS 與 JS 皆已內聯),可雙擊開啟、可離線使用、亦可直接嵌入官方網站。其工具鏈的外部相依只有一個 tsc 編譯器(且須為原生版——npm 版之 tsc 只是個 node 啟動器),工具宿主改用 macOS 內建的 JXA(osascript -l JavaScript)。
為免助手的題庫與選項標籤與輸入法本體漂移,唯音加入了三處防護:vChewingSharedCLI 新增 dump-userdef-metadata 動詞、導出 119 條偏好鍵之型別/值域/預設值/四語系標籤供助手取用;助手的題庫僅涵蓋「設定介面已曝露」的選項(該集合由掃描 SettingsUI 與 SettingsCocoa 之源碼生成),並以測試守住「題庫 ⊆ 曝露面」之不變式;助手的產出值則由 Swift 側之契約測試(AssistantContractTests)確認唯音一概收得下。助手首頁並標示其所適配的輸入法版本,由建置期的 version-check 與倉根之版本宣告逐值比對。
助手之產物在輸入法建置時會一併收進 App Bundle(Contents/Resources/assistant/assistant.html),但此步驟以偵測得到 tsc 為唯一前提——未偵測到時只印警告、不中斷輸入法的建置。故「當前安裝的輸入法未同捆助手」是設計上之常態;此時設定介面會引導使用者改用官方網站的最新版本。
檔案目錄異動檢查模組
該模組用來監測任何發生在使用者片語辭典目錄內的變化。上游的這套模組使用了 FSEventStream,但比較麻煩。更危險的是,這是 Carbon API,沒準哪天就被 Apple 從系統當中徹底割掉。
唯音 v2.5.0 更換了新的 FolderMonitor 監視模組,利用了 DispatchSourceFileSystemObject。這個方法不會偵測由輸入法本體對目錄做出的修改,所以筆者又在 LMMgr (Language Model Manager) 當中對「使用者手動加詞」的情況又補上了手動重新載入使用者片語的動作。這也解決了迄今為止 FSEventStreamHelper 與「唯音的使用者片語辭典格式自動整理模組」彼此的行為衝突問題。
唯音 v4.0.0 對 FolderMonitor 做了改良,使其將觀測響應行為全部放在專有的 Actor 當中完成、且經過 Debouncer 處理。這不至於讓輸入法因為 iCloud 資料同步不順利的情況、而導致所有試圖接收唯音鍵盤事件輸入的軟體全部 hang 到死。
附錄 A:W3C Ruby 標記範例
以下示例展示唯音產生的繁體漢字 + 注音(教科書式聲調)與漢語拼音 Ruby 標記(簡化示例)。實際輸出會依偏好設定與模式而異。
- 注音(教科書式):
<ruby> 漢<rt>ㄏㄢˋ</rt> 字<rt>ㄗˋ</rt> </ruby> - 漢語拼音(附調號):
<ruby> 漢<rt>hàn</rt> 字<rt>zì</rt> </ruby>
附錄 B:組字流程(概念示意)
[鍵盤事件 NSEvent]
│ (擴展 + 可能的 KBEvent 克隆)
▼
[InputHandler]
- 解析佈局 / 並擊
- 更新 IMEState (單結構態械)
│ (請求路徑評分)
▼
[Homa 組字引擎 (DAG-DP)]
- 建立 / 更新節點圖 SegmentGraph
- 動態規劃計分與最佳路徑回溯
- 支援詞音不等長 / 標記游標 / 候選輪替 / 上下文鞏固
│ (候選資料集)
▼
[CandidatePool]
- 排序 / 分頁 / 佈局資訊
│
├──> 田所選字窗 (橫/縱排矩陣渲染)
└──> 浮動組字窗(強化安全模式)
│
▼
[提交/組字結果 -> 客體 App]
附錄 C:術語速覽
- IMK:InputMethodKit,macOS 輸入法框架。
- 浮動組字窗(強化型):以獨立視窗暫存尚未提交文字,防客體過度探查 markedText。
- 態械(有限狀態機 FSM):本文特用「態械」指單一 Struct IMEState 之狀態管理實作。
- 就地加詞 / 刪詞 / 升頻 / 降頻:不喚出選字窗直接操作使用者片語權重或移除語彙。
- 詞音不等長:字詞字數與其對應讀音(注音單位或拼音音節)數量不一致的情況。
- DAG-Relax / Dijkstra / DAG-DP:不同世代的組字圖路徑求解策略。現行為 DAG-DP。
- Tekkon:唯音自研聲韻並擊引擎,支援多注音排列與多種拼音系統提示。
- CandidatePool:前後端分離模式下的候選資料與佈局中樞。
- FolderMonitor:以 DispatchSourceFileSystemObject 監測使用者片語辭典目錄變更並 Debounce。
- 教科書式聲調:注音 / 拼音顯示中使用正式的調號標記形式。
- 升頻 / 降頻:調整語彙在語言模型中的相對排序權重。
- Emacs Key 支援:Ctrl+N、Ctrl+P 等對應游標或選字行為的熱鍵翻譯。
- Unicode 資訊:田所選字窗對候選字提供碼點、區段等元資料顯示。
附錄 D:已知限制與後續規劃(摘錄)
- 大篇幅簡繁轉換:Hotenka 適合詞組級互換,非全文批次轉換;建議外部工具處理長文。
- Emacs Key 範圍:目前僅涵蓋常用游標移動;未對全文編輯類(如 Ctrl+K)做語義映射。
- SwiftUI 選字窗版本:為效能取捨已退場;未來若 SwiftUI 繪製效率顯著提升,將再評估回歸混合渲染策略可能性。
- Sandboxing:雖阻斷就地腳本注入,但仍無法防禦使用者層級全域鍵盤側錄工具。
附錄 E:安全場景補充
典型風險:
- 客體 App 於組字過程輪詢 markedText,預判輸入以觸發建議或上傳雲端。
- 外掛或代理進程試圖在組字尚未提交前讀取暫存緩衝。
緩解策略(浮動組字窗 + Sandboxing):
- 不向客體回填中間組字(或僅回填最少 placeholder),降低未提交內容被側取概率。
- Sandbox 限制檔案與進程互動,避免腳本化連鎖操作。
- Dictionary 目錄監測採 Debounce,防資源抖動造成拒絕服務。
殘餘風險(不屬於唯音輸入法可以控制的範圍):
- 系統層級輸入監聽(Accessibility / 內核層工具)仍可擷取終端輸入。
- 使用者授權的第三方安全/效率工具若刻意攔截事件,仍可能行為分析。
附錄 F:「廉恥模式」註解
本文正文為正式語氣,所謂「廉恥模式」係節日彩蛋開關,僅影響部份音效啟用條件,對核心功能與安全無影響;爰保留於此作為社群文化註腳。
附錄 G:性能觀測(由 Codex 設計測量策略之後總結)
量測環境:macOS 14.0(arm64e)實機,swift test --skip-build(Apple Swift 5.10 toolchain)。時間一律為秒(s),記憶體以 MiB 換算最大常駐集(RSS)。
| 指標 | 描述 | 量測方法 | 量測結果(v4.0.0) | 備註 |
|---|---|---|---|---|
| 候選生成平均延遲 | 從敲擊第 n 個鍵到候選列表渲染完成 | swift test --skip-build --filter HomaTests_Advanced/test08_Compositor_WordSegmentation | 0.005 s(約 5 ms) | 5 個漢字輸入、含組句+候選回溯 |
| 最大路徑計算耗時 | DAG-DP 求解長句(1,919 鍵) | test09_Compositor_StressBench(XCTest log) | 0.0030 s | 測試前置建圖耗時 24.6 s,表格僅列核心計分時間 |
| 記憶體峰值 | 組字壓力測試階段的 RSS | /usr/bin/time -l swift test --skip-build --filter …test09… | 117 MiB RSS | maximum resident set size = 123,027,456 bytes |
| 學習權重更新耗時 | 提交候選後至語言模型寫入完成 | /usr/bin/time -l swift test --skip-build --filter …test10… | 0.010 s / 52.7 MiB RSS | assignNodes(updateExisting:) 更新單元圖 |
| FolderMonitor 事件抖動率 | 120 次建立+刪除產生的原始事件數 | Swift 腳本(DispatchSourceFileSystemObject + 250 ms 去抖) | 360 → 1 | 360 筆 raw event 併成 1 次回呼,去抖效率 99.7% |
| FolderMonitor 事件抖動率 | Debounce 截流比(快速增刪 240 檔) | swift -e 'DispatchSource.makeFileSystemObjectSource(...)' | 360 原始事件 → 1 通知(99.7% 抑制) | Debounce 0.25 s;TMP 目錄模擬 iCloud 抖動 |
以上測試均於 Apple Silicon (arm64e) macOS 14.0、Swift Package Manager 5.10 工具鏈下執行。
$ EOF.