1.7.0 // Renovation. Merge Gitee PR!40 from upd/1.7.0

This commit is contained in:
ShikiSuen 2022-06-05 15:36:55 +00:00 committed by Gitee
commit b0650de948
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
72 changed files with 1741 additions and 1763 deletions

View File

@ -29,7 +29,7 @@
<key>LSMinimumSystemVersion</key>
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
<key>NSHumanReadableCopyright</key>
<string>© 2011-2022 OpenVanilla Project &amp; © 2021-2022 vChewing Project.</string>
<string>© 2021-2022 vChewing Project.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View File

@ -1,5 +1,5 @@
/* Localized versions of Info.plist keys */
CFBundleName = "vChewing Installer";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
CFEULAContent = "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n2. No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements above.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n";

View File

@ -56,8 +56,8 @@
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
"QYf-Nf-hoi.title" = "Derived from OpenVanilla McBopopmofo Project.";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine.";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.";
/* Class = "NSTextFieldCell"; title = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
// "eo3-TK-0rB.title" = "Placeholder for showing copyright information.";

View File

@ -1,5 +1,5 @@
/* Localized versions of Info.plist keys */
CFBundleName = "威注音入力 実装用アプリ";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
CFEULAContent = "以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。\n\nイ上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。\n\nロ上記の通知要件を満たすために必要な場合を除き、コントリビューターの商号、商標、サービスマーク、または製品名を使用するための商標ライセンスは付与されていません。\n\nソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供されます。ここでいう保証とは、商品性、特定の目的への適合性、および権利非侵害についての保証も含みますが、それに限定されるものではありません。\n作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。";

View File

@ -56,8 +56,8 @@
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
"QYf-Nf-hoi.title" = "OpenVanilla 小麦注音プロジェクトから派生。";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "鉄恨ボポモフォエンジン開発Shiki Suen。\n入力状態管理システム開発Zonble Yang。\nmacOS 版威注音の開発Shiki Suen, Isaac Xen, Hiraku Wang, など。\n威注音語彙データの維持Shiki Suen。\nMegrez 辞書処理エンジンShiki SuenLukhnos の Gramambular C++ エンジンを Swift で再開発したものである)。";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "macOS 版威注音の開発Shiki Suen, Isaac Xen, Hiraku Wang, など。\n威注音語彙データの維持Shiki Suen。";
/* Class = "NSTextFieldCell"; title = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
"eo3-TK-0rB.title" = "Placeholder for showing copyright information.";

View File

@ -1,5 +1,5 @@
/* Localized versions of Info.plist keys */
CFBundleName = "威注音安装程式";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
CFEULAContent = "软件之著作权利人依此麻理授权条款,将其对于软件之著作权利授权释出,只须使用者践履以下二项麻理授权条款叙明之义务性规定,其即享有对此软件程式及其相关说明文档自由不受限制地进行利用之权利,范围包括「使用、重制、修改、合并、出版、散布、再授权、及贩售程式重制作品」等诸多方面之应用,而散布程式之人、更可将上述权利传递予其后收受程式之后手,倘若其后收受程式之人亦服膺以下二项麻理授权条款之义务性规定,则其对程式亦享有与前手运用范围相同之同一权利。\n\n甲、散布此一软件程式者须将本条款其上之「著作权声明」及以下之「免责声明」内嵌于软件程式及其重制作品之实体之中。\n\n乙、敝授权合约不提供对「贡献者」之商品名称、商标、服务标志或产品名称之商标许可除非用以满足履行上文所述义务之必要。\n\n因麻理软件程式之授权模式乃是无偿提供是以在现行法律之架构下可以主张合理之免除担保责任。麻理软件之著作权人或任何之后续散布者对于其所散布之麻理软件程式皆不负任何形式上实质上之担保责任明示亦或隐喻、商业利用性亦或特定目之使用性这些均不在保障之列。利用麻理软件程式之所有风险均由使用者自行担负。假如所使用之麻理程式发生缺陷性问题使用者需自行担负修正、改正及必要之服务支出。麻理软件程式之著作权人不负任何形式上实质上之担保责任无论任何一般之、特殊之、偶发之、因果关系式之损害或是麻理软件程式之不适用性均须由使用者自行负担。\n";

View File

@ -56,8 +56,8 @@
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
"QYf-Nf-hoi.title" = "该专案由 OpenVanilla 小麦注音专案衍生而来。";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "铁恨注音并击输入处理引擎研发Shiki Suen。\n输入法状态管理引擎研发Zonble Yang。\n威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护Shiki Suen。\n天权星语汇引擎Shiki Suen用 Swift 将 Lukhnos 的 C++ Gramambular 重写而得。";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护Shiki Suen。";
/* Class = "NSTextFieldCell"; title = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
// "eo3-TK-0rB.title" = "Placeholder for showing copyright information.";

View File

@ -1,5 +1,5 @@
/* Localized versions of Info.plist keys */
CFBundleName = "威注音安裝程式";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
CFEULAContent = "軟體之著作權利人依此麻理授權條款,將其對於軟體之著作權利授權釋出,只須使用者踐履以下二項麻理授權條款敘明之義務性規定,其即享有對此軟體程式及其相關說明文檔自由不受限制地進行利用之權利,範圍包括「使用、重製、修改、合併、出版、散布、再授權、及販售程式重製作品」等諸多方面之應用,而散布程式之人、更可將上述權利傳遞予其後收受程式之後手,倘若其後收受程式之人亦服膺以下二項麻理授權條款之義務性規定,則其對程式亦享有與前手運用範圍相同之同一權利。\n\n甲、散布此一軟體程式者須將本條款其上之「著作權聲明」及以下之「免責聲明」內嵌於軟體程式及其重製作品之實體之中。\n\n乙、敝授權合約不提供對「貢獻者」之商品名稱、商標、服務標誌或產品名稱之商標許可除非用以滿足履行上文所述義務之必要。\n\n因麻理軟體程式之授權模式乃是無償提供是以在現行法律之架構下可以主張合理之免除擔保責任。麻理軟體之著作權人或任何之後續散布者對於其所散布之麻理軟體程式皆不負任何形式上實質上之擔保責任明示亦或隱喻、商業利用性亦或特定目之使用性這些均不在保障之列。利用麻理軟體程式之所有風險均由使用者自行擔負。假如所使用之麻理程式發生缺陷性問題使用者需自行擔負修正、改正及必要之服務支出。麻理軟體程式之著作權人不負任何形式上實質上之擔保責任無論任何一般之、特殊之、偶發之、因果關係式之損害或是麻理軟體程式之不適用性均須由使用者自行負擔。\n";

View File

@ -56,8 +56,8 @@
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
"QYf-Nf-hoi.title" = "該專案由 OpenVanilla 小麥注音專案衍生而來。";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "鐵恨注音並擊輸入處理引擎研發Shiki Suen。\n輸入法狀態管理引擎研發Zonble Yang。\n威注音 macOS 程式研發Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音詞庫維護Shiki Suen。\n天權星語彙引擎Shiki Suen用 Swift 將 Lukhnos 的 C++ Gramambular 重寫而得。";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */
"VW8-s5-Wpn.title" = "威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护Shiki Suen。";
/* Class = "NSTextFieldCell"; title = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
// "eo3-TK-0rB.title" = "Placeholder for showing copyright information.";

View File

@ -2,12 +2,9 @@
vChewing macOS: MIT-NTL License 麻理(去商标)授权合约
© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.
铁恨注音并击输入处理引擎研发Shiki Suen。
输入法状态管理引擎研发Zonble Yang。
© 2021-2022 vChewing Project.
威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。
威注音词库维护Shiki Suen。
天权星语汇引擎Shiki Suen用 Swift 将 Lukhnos 的 C++ Gramambular 重写而得。
软件之著作权利人依此麻理授权条款,将其对于软件之著作权利授权释出,只须使用者践履以下二项麻理授权条款叙明之义务性规定,其即享有对此软件程式及其相关说明文档自由不受限制地进行利用之权利,范围包括「使用、重制、修改、合并、出版、散布、再授权、及贩售程式重制作品」等诸多方面之应用,而散布程式之人、更可将上述权利传递予其后收受程式之后手,倘若其后收受程式之人亦服膺以下二项麻理授权条款之义务性规定,则其对程式亦享有与前手运用范围相同之同一权利。

View File

@ -2,12 +2,9 @@
vChewing macOS: MIT-NTL License 麻理(去商標)授權合約
© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.
鐵恨注音並擊輸入處理引擎研發Shiki Suen。
輸入法狀態管理引擎研發Zonble Yang。
© 2021-2022 vChewing Project.
威注音 macOS 程式研發Shiki Suen, Isaac Xen, Hiraku Wang, 等。
威注音詞庫維護Shiki Suen。
天權星語彙引擎Shiki Suen用 Swift 將 Lukhnos 的 C++ Gramambular 重寫而得。
軟體之著作權利人依此麻理授權條款,將其對於軟體之著作權利授權釋出,只須使用者踐履以下二項麻理授權條款敘明之義務性規定,其即享有對此軟體程式及其相關說明文檔自由不受限制地進行利用之權利,範圍包括「使用、重製、修改、合併、出版、散布、再授權、及販售程式重製作品」等諸多方面之應用,而散布程式之人、更可將上述權利傳遞予其後收受程式之後手,倘若其後收受程式之人亦服膺以下二項麻理授權條款之義務性規定,則其對程式亦享有與前手運用範圍相同之同一權利。

View File

@ -2,11 +2,9 @@
vChewing macOS: MIT商標不許可ライセンス (MIT-NTL License)
鉄恨ボポモフォエンジン開発Shiki Suen。
入力状態管理システム開発Zonble Yang。
© 2021-2022 vChewing Project.
macOS 版威注音の開発Shiki Suen, Isaac Xen, Hiraku Wang, など。
威注音語彙データの維持Shiki Suen。
Megrez 辞書処理エンジンShiki SuenLukhnos の Gramambular C++ エンジンを Swift で再開発したものである)。
以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。

View File

@ -2,12 +2,9 @@ DISCLAIMER: The vChewing project, having no relationship of cooperation or affil
vChewing macOS: MIT-NTL License
© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.
Tekkon Syllable Composition Engine by Shiki Suen.
Input State Management Architecture by Zonble Yang.
© 2021-2022 vChewing Project.
vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
vChewing Phrase Database Maintained by Shiki Suen.
Megrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

117
README-CHT.md Normal file
View File

@ -0,0 +1,117 @@
語言:[简体中文](./README.md) | *繁體中文*
---
因不可控原因,該倉庫只能保證在 Gitee 有最新的內容可用:
- 下載https://gitee.com/vchewing/vChewing-macOS/releases
- 程式碼倉庫https://gitee.com/vchewing/vChewing-macOS
# vChewing 威注音輸入法
威注音輸入法基於小麥注音二次開發,是**原生簡體中文、原生繁體中文注音輸入法**
- 威注音是業界現階段支援注音排列種類數量與輸入用拼音種類數量最多的注音輸入法。
- 受威注音自家的鐵恨注音並擊引擎加持。
- 威注音的原廠詞庫內不存在任何可以妨礙該輸入法在世界上任何地方傳播的內容。
- 相比中州韻(鼠須管)而言,威注音能夠做到真正的大千聲韻並擊。
- 擁有拼音並擊模式,不懂注音的人群也可以受益於該輸入法所帶來的穩定的平均輸入速度。
- 相比小鶴雙拼等雙拼方案而言,威注音雙手聲韻分工明確、且重碼率只有雙拼的五分之一。
- 威注音對陸規審音完全相容:不熟悉台澎金馬審音的大陸用戶不會遇到與漢字讀音有關的不便。
- 反之亦然。
>威注音有很多特色功能。在此僅列舉部分:
>- 支援 macOS 螢幕模擬鍵盤(僅傳統大千與傳統倚天佈局)。
>- 可以將自己打的繁體中文自動轉成日本 JIS 新字體來輸出(包括基礎的字詞轉換)、也可以轉成康熙繁體來輸出。
>- 簡繁體中文語料庫彼此分離,徹底杜絕任何繁簡轉換過程可能造成的失誤。
>- 支援近年的全字庫漢字輸入。
>- 可以自動整理使用者語彙檔案格式、自訂聯想詞。
>- ……
威注音分支專案及威注音詞庫由孫志貴Shiki Suen維護。小麥注音官方原始倉庫內的詞庫的內容均與孫志貴無關。
## 系統需求
建置用系統需求:至少 macOS 10.15 Catalina & Xcode 12。// 原因Swift 封包管理支援所需。
編譯出的成品對應系統需求:
- 至少 macOS El Capitan 10.11.5,否則無法處理 Unicode 8.0 的漢字。即便如此,仍需手動升級蘋方至至少 macOS 10.12 開始隨贈的版本、以支援 Unicode 8.0 的通用規範漢字表用字(全字庫沒有「𫫇」字)。
- 保留該系統支援的原因:非 Unibody 體型的 MacBook Pro 支援的最後一版 macOS 就是 El Capitan。
- **推薦最低系統版本**macOS 10.12 Sierra對 Unicode 8.0 開始的《通用規範漢字表》漢字有原生的蘋方支援。
- 同時建議**系統記憶體應至少 4GB**。威注音輸入法佔用記憶體約 115MB 左右簡繁雙模式、75MB左右單模式供參考。
- 請務必使用 SSD 硬碟,否則可能會影響每次開機之後輸入法首次載入的速度。從 10.10 Yosemite 開始macOS 就已經是針對機械硬碟負優化的作業系統了。
- 注:能裝 macOS 10.13 High Sierra 就不要去碰 macOS 10.12 Sierra 這個半成品。
- 關於全字庫支援,因下述事實而在理論上很難做到最完美:
- 很可惜 GB18030-2005 並沒有官方提供的逐字讀音對照表,所以目前才用了全字庫。然而全字庫並不等於完美。
- 有條件者可以安裝全字庫字型與花園明朝,否則全字庫等高萬國碼碼位漢字恐無法在輸入法的選字窗內完整顯示。
- 全字庫漢字顯示支援會受到具體系統版本對萬國碼版本的支援的限制。
- 有些全字庫漢字一開始會依賴萬國碼的私人造字區,且在之後被新版本萬國碼所支援。
## 建置流程
安裝 Xcode 之後,請先配置 Xcode 允許其直接構建在專案所在的資料夾下的 build 資料夾內。步驟:
```
「Xcode」->「Preferences...」->「Locations」
「File」->「Project/WorkspaceSettings...」->「Advanced」
選「Custom」->「Relative to Workspace」即可。不選的話make 的過程會出錯。
```
在終端機內定位到威注音的克隆本地專案的本地倉庫的目錄之後,執行 `make update` 以獲取最新詞庫。
接下來就是直接開 Xcode 專案Product -> Scheme 選「vChewingInstaller」編譯即可。
> 之前說「在成功之後執行 `make` 即可組建、再執行 `make install` 可以觸發威注音的安裝程式」,這對新版威注音而言**當且僅當**使用純 Swift 編譯腳本工序時方可使用。目前的 libvchewing-data 模組已經針對 macOS 版威注音實裝了純 Swift 詞庫編譯腳本。
第一次安裝完,日後程式碼或詞庫有任何修改,只要重覆上述流程,再次安裝威注音即可。
要注意的是 macOS 可能會限制同一次 login session 能終結同一個輸入法的執行進程的次數(安裝程式透過 kill input method process 來讓新版的輸入法生效)。如果安裝若干次後,發現程式修改的結果並沒有出現、或甚至輸入法已無法再選用,只需要登出目前的 macOS 系統帳號、再重新登入即可。
補記: 該輸入法是在 2021 年 11 月初「28ae7deb4092f067539cff600397292e66a5dd56」這一版小麥注音建置的基礎上完成的。因為在清洗詞庫的時候清洗了全部的 git commit 歷史,所以無法自動從小麥注音官方倉庫上游繼承任何改動,只能手動同步任何在此之後的程式修正。最近一次同步參照是上游主倉庫的 2.2.2 版、以及 zonble 的分支「5cb6819e132a02bbcba77dbf083ada418750dab7」。
## 應用授權
威注音專案僅用到小麥注音的下述程式組件MIT License
- 狀態管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang)。
- 半衰記憶模組,因故障暫時無法啟用 (by Mengjuei Hsieh)。
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang)。
- Voltaire MK2 選字窗、飄雲通知視窗、工具提示 (by Zonble Yang),有大幅度修改。
威注音輸入法 macOS 版以 MIT-NTL License 授權釋出 (與 MIT 相容):© 2021-2022 vChewing 專案。
- 威注音輸入法 macOS 版程式維護Shiki Suen。特別感謝 Isaac Xen 與 Hiraku Wong 等人的技術協力。
- 鐵恨注音並擊處理引擎Shiki Suen (MIT-NTL License)。
- 天權星語彙處理引擎Shiki Suen (MIT-NTL License)。
- 威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。
使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權、且一旦經過修改便不可以再繼續使用威注音的產品名稱。
## 格式規範等與參與研發時需要注意的事項:
該專案對源碼格式有規範,且 Swift 與其他 (Obj)C(++) 系語言持不同規範:
請洽該倉庫內的「[CONTRIBUTING.md](./CONTRIBUTING.md)」檔案。
## 其他
為了您的精神衛生,任何使用威注音輸入法時遇到的產品問題、請勿提報至小麥注音。哪怕您確信小麥注音也有該問題。
濫用沉默權來浪費對方的時間與熱情,也是一種暴力。**當對方最最最開始就把你當敵人的時候,你連呼吸都是錯的**。
$ EOF.

126
README.md
View File

@ -1,119 +1,117 @@
因不可控原因,該倉庫只能保證在 Gitee 有最新的內容可用:
语言:*简体中文* | [繁體中文](./README-CHT.md)
- 下載https://gitee.com/vchewing/vChewing-macOS/releases
- 程式碼倉庫https://gitee.com/vchewing/vChewing-macOS
---
# vChewing 威注音輸入法
因不可控原因,该仓库只能保证在 Gitee 有最新的内容可用:
威注音輸入法基於小麥注音二次開發,是**原生簡體中文、原生繁體中文注音輸入法**
- 下载https://gitee.com/vchewing/vChewing-macOS/releases
- 代码仓库https://gitee.com/vchewing/vChewing-macOS
- 威注音是業界現階段支援注音排列種類數量與輸入用拼音種類數量最多的注音輸入法。
- 受威注音自家的鐵恨注音並擊引擎加持。
- 威注音的原廠詞庫內不存在任何可以妨礙該輸入法在世界上任何地方傳播的內容。
- 相比中州韻(鼠須管)而言,威注音能夠做到真正的大千聲韻並擊。
- 擁有拼音並擊模式,不懂注音的人群也可以受益於該輸入法所帶來的穩定的平均輸入速度。
- 相比小鶴雙拼等雙拼方案而言,威注音雙手聲韻分工明確、且重碼率只有雙拼的五分之一。
- 威注音對陸規審音完全相容:不熟悉台澎金馬審音的大陸用戶不會遇到與漢字讀音有關的不便。
# vChewing 威注音输入法
威注音输入法基于小麦注音二次开发,是**原生简体中文/繁体中文注音输入法**
- 威注音是业界现阶段支持注音排列种类数量与输入用拼音种类数量最多的注音输入法。
- 受威注音自家的铁恨注音并击引擎加持。
- 威注音的原厂词库内不存在任何可以妨碍该输入法在世界上任何地方传播的内容。
- 相比中州韵(鼠须管)而言,威注音能够做到真正的大千声韵并击。
- 拥有拼音并击模式,不懂注音的人群也可以受益于该输入法所带来的稳定的平均输入速度。
- 相比小鹤双拼等双拼方案而言,威注音双手声韵分工明确、且重码率只有双拼的五分之一。
- 威注音对陆规审音完全兼容:不熟悉台澎金马审音的大陆用户不会遇到与汉字读音有关的不便。
- 反之亦然。
>威注音有很多特色功能。在此僅列舉部分:
>- 支援 macOS 螢幕模擬鍵盤(僅傳統大千與傳統倚天佈局)。
>- 可以將自己打的繁體中文自動轉成日本 JIS 新字體來輸出(包括基礎的字詞轉換)、也可以轉成康熙繁體來輸出。
>- 簡繁體中文語料庫彼此分離,徹底杜絕任何繁簡轉換過程可能造成的失誤
>- 支援近年的全字庫漢字輸入。
>- 可以自動整理使用者語彙檔案格式、自訂聯想詞
>威注音有很多特色功能。在此仅枚举部分:
>- 支持 macOS 屏幕仿真键盘(仅传统大千与传统倚天布局)。
>- 可以将自己打的繁体中文自动转成日本 JIS 新字体来输出(包括基础的字词转换),也可以转成康熙繁体来输出。
>- 简繁体中文语料库彼此分离,彻底杜绝任何繁简转换过程可能造成的失误
>- 支持近年的全字库汉字输入。
>- 可以自动整理用户语汇文档格式、自订联想词
>- ……
威注音分支專案及威注音詞庫由孫志貴Shiki Suen維護。小麥注音官方原始倉庫內的詞庫的內容均與孫志貴無關
威注音分支专案及威注音词库由孙志贵Shiki Suen维护。小麦注音官方原始仓库内的词库的内容均与孙志贵无关
## 系需求
## 系需求
建置用系統需求:至少 macOS 10.15 Catalina & Xcode 12。// 原因Swift 封包管理支援所需。
建置用系统需求:至少 macOS 10.15 Catalina & Xcode 12。// 原因Swift 包管理器支持所需。
編譯出的成品對應系統需求:
编译出的成品对应系统需求:
- 至少 macOS El Capitan 10.11.5,否則無法處理 Unicode 8.0 的漢字。即便如此,仍需手動升級蘋方至至少 macOS 10.12 開始隨贈的版本、以支援 Unicode 8.0 的通用規範漢字表用字(全字庫沒有「𫫇」字)。
- 至少 macOS El Capitan 10.11.5,否则无法处理 Unicode 8.0 的汉字。即便如此,仍需手动升级苹方至至少 macOS 10.12 开始随附的版本、以支持 Unicode 8.0 的通用规范汉字表用字(全字库没有「𫫇」字)。
- 保留該系統支援的原因:非 Unibody 體型的 MacBook Pro 支援的最後一版 macOS 就是 El Capitan。
- 保留该系统支持的原因:非 Unibody 体型的 MacBook Pro 支持的最后一版 macOS 就是 El Capitan。
- **推薦最低系統版本**macOS 10.12 Sierra對 Unicode 8.0 開始的《通用規範漢字表》漢字有原生的蘋方支援
- **推荐最低系统版本**macOS 10.12 Sierra对 Unicode 8.0 开始的《通用规范汉字表》汉字有原生的苹方支持
- 同時建議**系統記憶體應至少 4GB**。威注音輸入法佔用記憶體約 115MB 左右簡繁雙模式、75MB左右單模式供參考。
- 同时建议**系统运存应至少 4GB**。威注音输入法占用运存约 115MB 左右简繁双模式、75MB左右单模式供参考。
- 請務必使用 SSD 硬碟,否則可能會影響每次開機之後輸入法首次載入的速度。從 10.10 Yosemite 開始macOS 就已經是針對機械硬碟負優化的作業系統了。
- 请务必使用 SSD 硬盘,否则可能会影响每次开机之后输入法首次加载的速度。从 10.10 Yosemite 开始macOS 就已经是针对机械硬盘负优化的操作系统了。
- 注:能裝 macOS 10.13 High Sierra 就不要去碰 macOS 10.12 Sierra 這個半成品。
- 注:能装 macOS 10.13 High Sierra 就不要去碰 macOS 10.12 Sierra 这个半成品。
- 關於全字庫支援,因下述事實而在理論上很難做到最完美:
- 关于全字库支持,因下述事实而在理论上很难做到最完美:
- 很可惜 GB18030-2005 並沒有官方提供的逐字讀音對照表,所以目前才用了全字庫。然而全字庫並不等於完美。
- 很可惜 GB18030-2005 并没有官方提供的逐字读音对照表,所以目前才用了全字库。然而全字库并不等于完美。
- 有條件者可以安裝全字庫字型與花園明朝,否則全字庫等高萬國碼碼位漢字恐無法在輸入法的選字窗內完整顯示。
- 有条件者可以安装全字库字体与花园明朝,否则全字库等高万国码码位汉字可能无法在输入法的选字窗内完整显示。
- 全字庫漢字顯示支援會受到具體系統版本對萬國碼版本的支援的限制。
- 全字库汉字显示支持会受到具体系统版本对万国码版本的支持的限制。
- 有些全字庫漢字一開始會依賴萬國碼的私人造字區,且在之後被新版本萬國碼所支援
- 有些全字库汉字一开始会依赖万国码的私人造字区,且在之后被新版本万国码所支持
## 建置流程
裝 Xcode 之後,請先配置 Xcode 允許其直接構建在專案所在的資料夾下的 build 資料夾內。步驟
装 Xcode 之后,请先配置 Xcode 允许其直接构建在专案所在的文档夹下的 build 文档夹内。步骤
```
「Xcode」->「Preferences...」->「Locations」
「File」->「Project/WorkspaceSettings...」->「Advanced」
選「Custom」->「Relative to Workspace」即可。不選的話make 的過程會出錯
选「Custom」->「Relative to Workspace」即可。否则make 的过程会出错
```
終端機內定位到威注音的克隆本地專案的本地倉庫的目錄之後,執行 `make update` 以獲取最新詞庫
终端机内定位到威注音的克隆本地专案的本地仓库的目录之后,运行 `make update` 以获取最新词库
接下來就是直接開 Xcode 專案Product -> Scheme 選「vChewingInstaller」編譯即可。
接下来就是直接开 Xcode 专案Product -> Scheme 选「vChewingInstaller」编译即可。
> 之前說「在成功之後執行 `make` 即可組建、再執行 `make install` 可以觸發威注音的安裝程式」,這對新版威注音而言**當且僅當**使用純 Swift 編譯腳本工序時方可使用。目前的 libvchewing-data 模組已經針對 macOS 版威注音實裝了純 Swift 詞庫編譯腳本。
> 之前说「在成功之后运行 `make` 即可组建、再运行 `make install` 可以触发威注音的安装程序」,这对新版威注音而言**当且仅当**使用纯 Swift 编译脚本工序时方可使用。目前的 libvchewing-data 模块已经针对 macOS 版威注音实装了纯 Swift 词库编译脚本。
第一次安裝完,日後程式碼或詞庫有任何修改,只要重覆上述流程,再次安裝威注音即可。
第一次安装完,日后代码或词库有任何修改,只要重复上述流程,再次安装威注音即可。
要注意的是 macOS 可能會限制同一次 login session 能終結同一個輸入法的執行進程的次數(安裝程式透過 kill input method process 來讓新版的輸入法生效)。如果安裝若干次後,發現程式修改的結果並沒有出現、或甚至輸入法已無法再選用,只需要登出目前的 macOS 系統帳號、再重新登入即可。
要注意的是 macOS 可能会限制同一次 login session 能终结同一个输入法的进程的次数(安装程序通过 kill input method process 来让新版的输入法生效)。如果安装若干次后,发现程序修改的结果并没有出现、或甚至输入法已无法再选用,只需要登出目前的 macOS 系统帐号、再重新登入即可。
補記: 該輸入法是在 2021 年 11 月初「28ae7deb4092f067539cff600397292e66a5dd56」這一版小麥注音建置的基礎上完成的。因為在清洗詞庫的時候清洗了全部的 git commit 歷史,所以無法自動從小麥注音官方倉庫上游繼承任何改動,只能手動同步任何在此之後的程式修正。最近一次同步參照是上游主倉庫的 2.2.2 版、以及 zonble 的分支「5cb6819e132a02bbcba77dbf083ada418750dab7」。
补记: 该输入法是在 2021 年 11 月初「28ae7deb4092f067539cff600397292e66a5dd56」这一版小麦注音建置的基础上完成的。因为在清洗词库的时候清洗了全部的 git commit 历史,所以无法自动从小麦注音官方仓库上游继承任何改动,只能手动同步任何在此之后的程序修正。最近一次同步参照是上游主仓库的 2.2.2 版、以及 zonble 的分支「5cb6819e132a02bbcba77dbf083ada418750dab7」。
## 應用授權
## 应用授权
小麥注音引擎程式版權MIT 授權):© 2011-2021 OpenVanilla 專案團隊Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等)。
威注音专案仅用到小麦注音的下述程序组件MIT License
威注音專案僅用到小麥注音的下述程式組件:
- 状态管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang)。
- 狀態管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang)。
- 半衰记忆模块,因故障暂时无法激活 (by Mengjuei Hsieh)。
- 半衰記憶模組,因故障暫時無法啟用 (by Mengjuei Hsieh)。
- 仅供研发人员调试方便而使用的 App 版安装程序 (by Zonble Yang)。
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang)
- Voltaire MK2 选字窗、飘云通知窗口、工具提示 (by Zonble Yang),有大幅度修改
- Voltaire MK2 選字窗、飄雲通知視窗、工具提示 (by Zonble Yang),有大幅度修改
威注音输入法 macOS 版以 MIT-NTL License 授权发布 (与 MIT 兼容):© 2021-2022 vChewing 专案
威注音輸入法 macOS 版以 MIT-NTL License 授權釋出 (與 MIT 相容):© 2021-2022 vChewing 專案
- 威注音输入法 macOS 版程序维护Shiki Suen。特别感谢 Isaac Xen 与 Hiraku Wong 等人的技术协力
- 威注音輸入法 macOS 版程式維護Shiki Suen。特別感謝 Isaac Xen 與 Hiraku Wong 等人的技術協力
- 铁恨注音并击处理引擎Shiki Suen (MIT-NTL License)
- 鐵恨注音並擊處理引擎Shiki Suen (MIT-NTL License)。
- 天权星语汇处理引擎Shiki Suen (MIT-NTL License)。
- 天權星語彙處理引擎Shiki Suen (MIT-NTL License)針對「Lukhnos Liu 用 C++ 寫的 Gramambular」用 Swift 徹底重寫而成
- 威注音词库由 Shiki Suen 维护,以 3-Clause BSD License 授权发布。其中的词频数据[由 NAER 授权用于非商业用途](https://twitter.com/ShikiSuen/status/1479329302713831424)
- 威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)
用户可自由使用、散播本软件,惟散播时必须完整保留版权声明及软件授权、且一旦经过修改便不可以再继续使用威注音的产品名称
使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權、且一旦經過修改便不可以再繼續使用威注音的產品名稱。
## 格式规范等与参与研发时需要注意的事项
## 格式規範等與參與研發時需要注意的事項
该专案对源码格式有规范,且 Swift 与其他 (Obj)C(++) 系语言持不同规范
該專案對源碼格式有規範,且 Swift 與其他 (Obj)C(++) 系語言持不同規範:
請洽該倉庫內的「[CONTRIBUTING.md](./CONTRIBUTING.md)」檔案。
请查看该仓库内的「[CONTRIBUTING.md](./CONTRIBUTING.md)」文档。
## 其他
為了您的精神衛生,任何使用威注音輸入法時遇到的產品問題、請勿提報至小麥注音,除非您確信小麥注音也有該問題。即便如此,也請在他們那邊不要提及威注音
为了您的精神卫生,任何使用威注音输入法时遇到的产品问题、请勿提报至小麦注音。哪怕您确信小麦注音也有该问题
濫用沉默權來浪費對方的時間與熱情,也是一種暴力。**當對方最最最開始就把你當敵人的時候,你連呼吸都是錯的**。
其實我滿懷念上游專案還沒被 Lukhnos Liu 接管收入 OpenVanilla 的那個年代。MJHsieh 主導開發小麥注音的時候且不討論他立場怎樣但基礎的技術交流是完全沒問題的。LibChewing 那邊也是,正常交流完全沒問題。
有些事情,繼續爭論下去也沒用。本來我想著重寫 ctlInputMethod 撤掉 zonble 的狀態管理引擎的,畢竟有大陸同鄉寫的火山五筆輸入法的框架套上我的鐵恨注音並擊引擎可以直接用。但這樣賭氣對誰都沒好處。眼下,威注音 macOS 版還需要一些小維護。之後我就得開始考慮用 Windows 平台可用的除了 C++ 以外的語言重寫鐵恨注音並擊引擎與天權星語彙引擎、方便接下來威注音的 Windows 版本的研發。能將 Lukhnos 的 C++ 內容全部換掉、徹底砸碎套在威注音身上的名為 C++ 的枷鎖、讓威注音有一個自由的未來,我已經知足了。讓更多的人用上好用的輸入法,才是最重要的。**這個重要性,不是 zonble 用「私人需求」這種帽子扣過來、就可以泯滅了的**。
滥用沉默权来浪费对方的时间与热情,也是一种暴力。**当对方最最最开始就把你当敌人的时候,你连呼吸都是错的**。
$ EOF.

View File

@ -23,8 +23,8 @@ import SwiftUI
@available(macOS 10.15, *)
extension Preferences {
/**
Function builder for `Preferences` components used in order to restrict types of child views to be of type `Section`.
*/
Function builder for `Preferences` components used in order to restrict types of child views to be of type `Section`.
*/
@resultBuilder
public enum SectionBuilder {
public static func buildBlock(_ sections: Section...) -> [Section] {
@ -33,8 +33,8 @@ extension Preferences {
}
/**
A view which holds `Preferences.Section` views and does all the alignment magic similar to `NSGridView` from AppKit.
*/
A view which holds `Preferences.Section` views and does all the alignment magic similar to `NSGridView` from AppKit.
*/
public struct Container: View {
private let sectionBuilder: () -> [Section]
private let contentWidth: Double
@ -42,15 +42,15 @@ extension Preferences {
@State private var maximumLabelWidth = 0.0
/**
Creates an instance of container component, which handles layout of stacked `Preferences.Section` views.
Creates an instance of container component, which handles layout of stacked `Preferences.Section` views.
Custom alignment requires content width to be specified beforehand.
Custom alignment requires content width to be specified beforehand.
- Parameters:
- contentWidth: A fixed width of the container's content (excluding paddings).
- minimumLabelWidth: A minimum width for labels within this container. By default, it will fit to the largest label.
- builder: A view builder that creates `Preferences.Section`'s of this container.
*/
- Parameters:
- contentWidth: A fixed width of the container's content (excluding paddings).
- minimumLabelWidth: A minimum width for labels within this container. By default, it will fit to the largest label.
- builder: A view builder that creates `Preferences.Section`'s of this container.
*/
public init(
contentWidth: Double,
minimumLabelWidth: Double = 0,

View File

@ -112,12 +112,12 @@ struct Localization {
]
/**
Returns the localized version of the given string.
Returns the localized version of the given string.
- Parameter identifier: Identifier of the string to localize.
- Parameter identifier: Identifier of the string to localize.
- Note: If the system's locale can't be determined, the English localization of the string will be returned.
*/
- Note: If the system's locale can't be determined, the English localization of the string will be returned.
*/
static subscript(identifier: Identifier) -> String {
// Force-unwrapped since all of the involved code is under our control.
let localizedDict = Localization.localizedStrings[identifier]!

View File

@ -25,18 +25,18 @@ import SwiftUI
/// Acts as type-eraser for `Preferences.Pane<T>`.
public protocol PreferencePaneConvertible {
/**
Convert `self` to equivalent `PreferencePane`.
*/
Convert `self` to equivalent `PreferencePane`.
*/
func asPreferencePane() -> PreferencePane
}
@available(macOS 10.15, *)
extension Preferences {
/**
Create a SwiftUI-based preference pane.
Create a SwiftUI-based preference pane.
SwiftUI equivalent of the `PreferencePane` protocol.
*/
SwiftUI equivalent of the `PreferencePane` protocol.
*/
public struct Pane<Content: View>: View, PreferencePaneConvertible {
let identifier: PaneIdentifier
let title: String
@ -63,8 +63,8 @@ extension Preferences {
}
/**
Hosting controller enabling `Preferences.Pane` to be used alongside AppKit `NSViewController`'s.
*/
Hosting controller enabling `Preferences.Pane` to be used alongside AppKit `NSViewController`'s.
*/
public final class PaneHostingController<Content: View>: NSHostingController<Content>, PreferencePane {
public let preferencePaneIdentifier: PaneIdentifier
public let preferencePaneTitle: String
@ -102,8 +102,8 @@ extension Preferences {
@available(macOS 10.15, *)
extension View {
/**
Applies font and color for a label used for describing a preference.
*/
Applies font and color for a label used for describing a preference.
*/
public func preferenceDescription() -> some View {
font(.system(size: 11.0))
// TODO: Use `.foregroundStyle` when targeting macOS 12.

View File

@ -97,17 +97,17 @@ public final class PreferencesWindowController: NSWindowController {
}
/**
Show the preferences window and brings it to front.
Show the preferences window and brings it to front.
If you pass a `Preferences.PaneIdentifier`, the window will activate the corresponding tab.
If you pass a `Preferences.PaneIdentifier`, the window will activate the corresponding tab.
- Parameter preferencePane: Identifier of the preference pane to display, or `nil` to show the tab that was open when the user last closed the window.
- Parameter preferencePane: Identifier of the preference pane to display, or `nil` to show the tab that was open when the user last closed the window.
- Note: Unless you need to open a specific pane, prefer not to pass a parameter at all or `nil`.
- Note: Unless you need to open a specific pane, prefer not to pass a parameter at all or `nil`.
- See `close()` to close the window again.
- See `showWindow(_:)` to show the window without the convenience of activating the app.
*/
- See `close()` to close the window again.
- See `showWindow(_:)` to show the window without the convenience of activating the app.
*/
public func show(preferencePane preferenceIdentifier: Preferences.PaneIdentifier? = nil) {
if let preferenceIdentifier = preferenceIdentifier {
tabViewController.activateTab(preferenceIdentifier: preferenceIdentifier, animated: false)
@ -168,8 +168,8 @@ extension PreferencesWindowController {
@available(macOS 10.15, *)
extension PreferencesWindowController {
/**
Create a preferences window from only SwiftUI-based preference panes.
*/
Create a preferences window from only SwiftUI-based preference panes.
*/
public convenience init(
panes: [PreferencePaneConvertible],
style: Preferences.Style = .toolbarItems,

View File

@ -23,13 +23,13 @@ import SwiftUI
@available(macOS 10.15, *)
extension Preferences {
/**
Represents a section with right-aligned title and optional bottom divider.
*/
Represents a section with right-aligned title and optional bottom divider.
*/
@available(macOS 10.15, *)
public struct Section: View {
/**
Preference key holding max width of section labels.
*/
Preference key holding max width of section labels.
*/
private struct LabelWidthPreferenceKey: PreferenceKey {
typealias Value = Double
@ -42,8 +42,8 @@ extension Preferences {
}
/**
Convenience overlay for finding a label's dimensions using `GeometryReader`.
*/
Convenience overlay for finding a label's dimensions using `GeometryReader`.
*/
private struct LabelOverlay: View {
var body: some View {
GeometryReader { geometry in
@ -54,8 +54,8 @@ extension Preferences {
}
/**
Convenience modifier for applying `LabelWidthPreferenceKey`.
*/
Convenience modifier for applying `LabelWidthPreferenceKey`.
*/
struct LabelWidthModifier: ViewModifier {
@Binding var maximumWidth: Double
@ -73,15 +73,15 @@ extension Preferences {
public let verticalAlignment: VerticalAlignment
/**
A section is responsible for controlling a single preference.
A section is responsible for controlling a single preference.
- Parameters:
- bottomDivider: Whether to place a `Divider` after the section content. Default is `false`.
- verticalAlignement: The vertical alignment of the section content.
- verticalAlignment:
- label: A view describing preference handled by this section.
- content: A content view.
*/
- Parameters:
- bottomDivider: Whether to place a `Divider` after the section content. Default is `false`.
- verticalAlignement: The vertical alignment of the section content.
- verticalAlignment:
- label: A view describing preference handled by this section.
- content: A content view.
*/
public init<Label: View, Content: View>(
bottomDivider: Bool = false,
verticalAlignment: VerticalAlignment = .firstTextBaseline,
@ -98,15 +98,15 @@ extension Preferences {
}
/**
Creates instance of section, responsible for controling single preference with `Text` as a `Label`.
Creates instance of section, responsible for controling single preference with `Text` as a `Label`.
- Parameters:
- title: A string describing preference handled by this section.
- bottomDivider: Whether to place a `Divider` after the section content. Default is `false`.
- verticalAlignement: The vertical alignment of the section content.
- verticalAlignment:
- content: A content view.
*/
- Parameters:
- title: A string describing preference handled by this section.
- bottomDivider: Whether to place a `Divider` after the section content. Default is `false`.
- verticalAlignement: The vertical alignment of the section content.
- verticalAlignment:
- content: A content view.
*/
public init<Content: View>(
title: String,
bottomDivider: Bool = false,

View File

@ -130,8 +130,8 @@ class UserInteractionPausableWindow: NSWindow {
@available(macOS 10.15, *)
extension View {
/**
Equivalent to `.eraseToAnyPublisher()` from the Combine framework.
*/
Equivalent to `.eraseToAnyPublisher()` from the Combine framework.
*/
func eraseToAnyView() -> AnyView {
AnyView(self)
}

@ -1 +1 @@
Subproject commit 924c8f4156edf2f034b45f5f06d488e5e81d351c
Subproject commit 06d16d8a468668278ad9f50cc8629983c490fa42

View File

@ -74,7 +74,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega
mgrPrefs.setMissingDefaults()
// 使
if (UserDefaults.standard.object(forKey: VersionUpdateApi.kCheckUpdateAutomatically) != nil) == true {
if mgrPrefs.checkUpdateAutomatically {
checkForUpdate()
}
}
@ -113,7 +113,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega
// time for update?
if !forced {
if UserDefaults.standard.bool(forKey: VersionUpdateApi.kCheckUpdateAutomatically) == false {
if !mgrPrefs.checkUpdateAutomatically {
return
}
let now = Date()

View File

@ -110,15 +110,18 @@ enum KeyCodeBlackListed: UInt16 {
}
// CharCodes: https://theasciicode.com.ar/ascii-control-characters/horizontal-tab-ascii-code-9.html
enum CharCode: UInt /* 16 */ {
case yajuusenpai = 114_514_191_191_810_893
enum CharCode: UInt16 {
case yajuusenpaiA = 114
case yajuusenpaiB = 514
case yajuusenpaiC = 1919
case yajuusenpaiD = 810
// CharCode is not reliable at all. KeyCode is the most appropriate choice due to its accuracy.
// KeyCode doesn't give a phuque about the character sent through macOS keyboard layouts ...
// ... but only focuses on which physical key is pressed.
}
struct InputSignal: CustomStringConvertible {
private(set) var useVerticalMode: Bool
private(set) var isTypingVertical: Bool
private(set) var inputText: String?
private(set) var inputTextIgnoringModifiers: String?
private(set) var charCode: UInt16
@ -130,12 +133,12 @@ struct InputSignal: CustomStringConvertible {
private var extraChooseCandidateKey: KeyCode = .kNone
private var extraChooseCandidateKeyReverse: KeyCode = .kNone
private var absorbedArrowKey: KeyCode = .kNone
private var verticalModeOnlyChooseCandidateKey: KeyCode = .kNone
private var verticalTypingOnlyChooseCandidateKey: KeyCode = .kNone
private(set) var emacsKey: vChewingEmacsKey
public init(
inputText: String?, keyCode: UInt16, charCode: UInt16, flags: NSEvent.ModifierFlags,
isVerticalMode: Bool, inputTextIgnoringModifiers: String? = nil
isVerticalTyping: Bool, inputTextIgnoringModifiers: String? = nil
) {
let inputText = AppleKeyboardConverter.cnvStringApple2ABC(inputText ?? "")
let inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC(
@ -144,7 +147,7 @@ struct InputSignal: CustomStringConvertible {
self.inputTextIgnoringModifiers = inputTextIgnoringModifiers
self.flags = flags
isFlagChanged = false
useVerticalMode = isVerticalMode
isTypingVertical = isVerticalTyping
self.keyCode = keyCode
self.charCode = AppleKeyboardConverter.cnvApple2ABC(charCode)
emacsKey = EmacsKeyHelper.detect(
@ -154,14 +157,14 @@ struct InputSignal: CustomStringConvertible {
defineArrowKeys()
}
public init(event: NSEvent, isVerticalMode: Bool) {
public init(event: NSEvent, isVerticalTyping: Bool) {
inputText = AppleKeyboardConverter.cnvStringApple2ABC(event.characters ?? "")
inputTextIgnoringModifiers = AppleKeyboardConverter.cnvStringApple2ABC(
event.charactersIgnoringModifiers ?? "")
keyCode = event.keyCode
flags = event.modifierFlags
isFlagChanged = (event.type == .flagsChanged) ? true : false
useVerticalMode = isVerticalMode
isTypingVertical = isVerticalTyping
let charCode: UInt16 = {
// count > 0!isEmpty滿
guard let inputText = event.characters, !inputText.isEmpty else {
@ -179,16 +182,16 @@ struct InputSignal: CustomStringConvertible {
}
mutating func defineArrowKeys() {
cursorForwardKey = useVerticalMode ? .kDownArrow : .kRightArrow
cursorBackwardKey = useVerticalMode ? .kUpArrow : .kLeftArrow
extraChooseCandidateKey = useVerticalMode ? .kLeftArrow : .kDownArrow
extraChooseCandidateKeyReverse = useVerticalMode ? .kRightArrow : .kUpArrow
absorbedArrowKey = useVerticalMode ? .kRightArrow : .kUpArrow
verticalModeOnlyChooseCandidateKey = useVerticalMode ? absorbedArrowKey : .kNone
cursorForwardKey = isTypingVertical ? .kDownArrow : .kRightArrow
cursorBackwardKey = isTypingVertical ? .kUpArrow : .kLeftArrow
extraChooseCandidateKey = isTypingVertical ? .kLeftArrow : .kDownArrow
extraChooseCandidateKeyReverse = isTypingVertical ? .kRightArrow : .kUpArrow
absorbedArrowKey = isTypingVertical ? .kRightArrow : .kUpArrow
verticalTypingOnlyChooseCandidateKey = isTypingVertical ? absorbedArrowKey : .kNone
}
var description: String {
"<inputText:\(String(describing: inputText)), inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)) charCode:\(charCode), keyCode:\(keyCode), flags:\(flags), cursorForwardKey:\(cursorForwardKey), cursorBackwardKey:\(cursorBackwardKey), extraChooseCandidateKey:\(extraChooseCandidateKey), extraChooseCandidateKeyReverse:\(extraChooseCandidateKeyReverse), absorbedArrowKey:\(absorbedArrowKey), verticalModeOnlyChooseCandidateKey:\(verticalModeOnlyChooseCandidateKey), emacsKey:\(emacsKey), useVerticalMode:\(useVerticalMode)>"
"<inputText:\(String(describing: inputText)), inputTextIgnoringModifiers:\(String(describing: inputTextIgnoringModifiers)) charCode:\(charCode), keyCode:\(keyCode), flags:\(flags), cursorForwardKey:\(cursorForwardKey), cursorBackwardKey:\(cursorBackwardKey), extraChooseCandidateKey:\(extraChooseCandidateKey), extraChooseCandidateKeyReverse:\(extraChooseCandidateKeyReverse), absorbedArrowKey:\(absorbedArrowKey), verticalTypingOnlyChooseCandidateKey:\(verticalTypingOnlyChooseCandidateKey), emacsKey:\(emacsKey), isTypingVertical:\(isTypingVertical)>"
}
// ANSI charCode Swift KeyHandler
@ -331,8 +334,8 @@ struct InputSignal: CustomStringConvertible {
KeyCode(rawValue: keyCode) == extraChooseCandidateKeyReverse
}
var isVerticalModeOnlyChooseCandidateKey: Bool {
KeyCode(rawValue: keyCode) == verticalModeOnlyChooseCandidateKey
var isverticalTypingOnlyChooseCandidateKey: Bool {
KeyCode(rawValue: keyCode) == verticalTypingOnlyChooseCandidateKey
}
var isUpperCaseASCIILetterKey: Bool {

View File

@ -110,9 +110,9 @@ class InputState {
/// Represents that the composing buffer is not empty.
class NotEmpty: InputState {
private(set) var composingBuffer: String
private(set) var cursorIndex: UInt
private(set) var cursorIndex: Int = 0 { didSet { cursorIndex = max(cursorIndex, 0) } }
init(composingBuffer: String, cursorIndex: UInt) {
init(composingBuffer: String, cursorIndex: Int) {
self.composingBuffer = composingBuffer
self.cursorIndex = cursorIndex
}
@ -129,7 +129,7 @@ class InputState {
var poppedText: String = ""
var tooltip: String = ""
override init(composingBuffer: String, cursorIndex: UInt) {
override init(composingBuffer: String, cursorIndex: Int) {
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
}
@ -151,91 +151,68 @@ class InputState {
// MARK: -
private let kMinMarkRangeLength = 2
private let kMaxMarkRangeLength = mgrPrefs.maxCandidateLength
/// Represents that the user is marking a range in the composing buffer.
class Marking: NotEmpty {
private(set) var markerIndex: UInt
private(set) var markedRange: NSRange
private var allowedMarkRange: ClosedRange<Int> = mgrPrefs.minCandidateLength...mgrPrefs.maxCandidateLength
private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } }
private(set) var markedRange: Range<Int>
private var literalMarkedRange: Range<Int> {
let lowerBoundLiteral = composingBuffer.charIndexLiteral(from: markedRange.lowerBound)
let upperBoundLiteral = composingBuffer.charIndexLiteral(from: markedRange.upperBound)
return lowerBoundLiteral..<upperBoundLiteral
}
private var deleteTargetExists = false
var tooltip: String {
if composingBuffer.count != readings.count {
TooltipController.backgroundColor = NSColor(
red: 0.55, green: 0.00, blue: 0.00, alpha: 1.00
)
TooltipController.textColor = NSColor.white
ctlInputMethod.tooltipController.setColor(state: .redAlert)
return NSLocalizedString(
"⚠︎ Unhandlable: Chars and Readings in buffer doesn't match.", comment: ""
)
}
if mgrPrefs.phraseReplacementEnabled {
TooltipController.backgroundColor = NSColor.purple
TooltipController.textColor = NSColor.white
ctlInputMethod.tooltipController.setColor(state: .warning)
return NSLocalizedString(
"⚠︎ Phrase replacement mode enabled, interfering user phrase entry.", comment: ""
)
}
if markedRange.length == 0 {
if markedRange.isEmpty {
return ""
}
let text = (composingBuffer as NSString).substring(with: markedRange)
if markedRange.length < kMinMarkRangeLength {
TooltipController.backgroundColor = NSColor(
red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00
)
TooltipController.textColor = NSColor(
red: 0.86, green: 0.86, blue: 0.86, alpha: 1.00
)
let text = composingBuffer.utf16SubString(with: markedRange)
if literalMarkedRange.count < allowedMarkRange.lowerBound {
ctlInputMethod.tooltipController.setColor(state: .denialInsufficiency)
return String(
format: NSLocalizedString(
"\"%@\" length must ≥ 2 for a user phrase.", comment: ""
), text
)
} else if markedRange.length > kMaxMarkRangeLength {
TooltipController.backgroundColor = NSColor(
red: 0.26, green: 0.16, blue: 0.00, alpha: 1.00
)
TooltipController.textColor = NSColor(
red: 1.00, green: 0.60, blue: 0.00, alpha: 1.00
)
} else if literalMarkedRange.count > allowedMarkRange.upperBound {
ctlInputMethod.tooltipController.setColor(state: .denialOverflow)
return String(
format: NSLocalizedString(
"\"%@\" length should ≤ %d for a user phrase.", comment: ""
),
text, kMaxMarkRangeLength
text, allowedMarkRange.upperBound
)
}
let (exactBegin, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location)
let (exactEnd, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location + markedRange.length)
let selectedReadings = readings[exactBegin..<exactEnd]
let selectedReadings = readings[literalMarkedRange]
let joined = selectedReadings.joined(separator: "-")
let exist = mgrLangModel.checkIfUserPhraseExist(
userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined
)
if exist {
deleteTargetExists = exist
TooltipController.backgroundColor = NSColor(
red: 0.00, green: 0.18, blue: 0.13, alpha: 1.00
)
TooltipController.textColor = NSColor(
red: 0.00, green: 1.00, blue: 0.74, alpha: 1.00
)
ctlInputMethod.tooltipController.setColor(state: .prompt)
return String(
format: NSLocalizedString(
"\"%@\" already exists: ENTER to boost, \n SHIFT+CMD+ENTER to exclude.", comment: ""
), text
)
}
TooltipController.backgroundColor = NSColor(
red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00
)
TooltipController.textColor = NSColor.white
ctlInputMethod.tooltipController.resetColor()
return String(
format: NSLocalizedString("\"%@\" selected. ENTER to add user phrase.", comment: ""),
text
@ -245,30 +222,34 @@ class InputState {
var tooltipForInputting: String = ""
private(set) var readings: [String]
init(composingBuffer: String, cursorIndex: UInt, markerIndex: UInt, readings: [String]) {
init(composingBuffer: String, cursorIndex: Int, markerIndex: Int, readings: [String]) {
self.markerIndex = markerIndex
let begin = min(cursorIndex, markerIndex)
let end = max(cursorIndex, markerIndex)
markedRange = NSRange(location: Int(begin), length: Int(end - begin))
markedRange = begin..<end
self.readings = readings
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
}
var attributedString: NSAttributedString {
let attributedString = NSMutableAttributedString(string: composingBuffer)
let end = markedRange.location + markedRange.length
let end = markedRange.upperBound
attributedString.setAttributes(
[
.underlineStyle: NSUnderlineStyle.single.rawValue,
.markedClauseSegment: 0,
], range: NSRange(location: 0, length: markedRange.location)
], range: NSRange(location: 0, length: markedRange.lowerBound)
)
attributedString.setAttributes(
[
.underlineStyle: NSUnderlineStyle.thick.rawValue,
.markedClauseSegment: 1,
], range: markedRange
],
range: NSRange(
location: markedRange.lowerBound,
length: markedRange.upperBound - markedRange.lowerBound
)
)
attributedString.setAttributes(
[
@ -277,7 +258,7 @@ class InputState {
],
range: NSRange(
location: end,
length: (composingBuffer as NSString).length - end
length: composingBuffer.utf16.count - end
)
)
return attributedString
@ -298,56 +279,34 @@ class InputState {
/// from the amount of Bopomofo readings. In this case, the range
/// in the composing buffer and the readings could not match, so
/// we disable the function to write user phrases in this case.
if composingBuffer.count != readings.count {
return false
}
if markedRange.length < kMinMarkRangeLength {
return false
}
if markedRange.length > kMaxMarkRangeLength {
return false
}
if ctlInputMethod.areWeDeleting, !deleteTargetExists {
return false
}
return markedRange.length >= kMinMarkRangeLength
&& markedRange.length <= kMaxMarkRangeLength
/// deleteTargetExists 使
/// 使
((composingBuffer.count != readings.count)
|| (ctlInputMethod.areWeDeleting && !deleteTargetExists))
? false
: allowedMarkRange.contains(literalMarkedRange.count)
}
var chkIfUserPhraseExists: Bool {
let text = (composingBuffer as NSString).substring(with: markedRange)
let (exactBegin, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location)
let (exactEnd, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location + markedRange.length)
let selectedReadings = readings[exactBegin..<exactEnd]
let text = composingBuffer.utf16SubString(with: markedRange)
let selectedReadings = readings[literalMarkedRange]
let joined = selectedReadings.joined(separator: "-")
return mgrLangModel.checkIfUserPhraseExist(
userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined
)
== true
}
var userPhrase: String {
let text = (composingBuffer as NSString).substring(with: markedRange)
let (exactBegin, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location)
let (exactEnd, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location + markedRange.length)
let selectedReadings = readings[exactBegin..<exactEnd]
let text = composingBuffer.utf16SubString(with: markedRange)
let selectedReadings = readings[literalMarkedRange]
let joined = selectedReadings.joined(separator: "-")
return "\(text) \(joined)"
}
var userPhraseConverted: String {
let text =
OpenCCBridge.crossConvert(
(composingBuffer as NSString).substring(with: markedRange)) ?? ""
let (exactBegin, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location)
let (exactEnd, _) = (composingBuffer as NSString).characterIndex(
from: markedRange.location + markedRange.length)
let selectedReadings = readings[exactBegin..<exactEnd]
OpenCCBridge.crossConvert(composingBuffer.utf16SubString(with: markedRange)) ?? ""
let selectedReadings = readings[literalMarkedRange]
let joined = selectedReadings.joined(separator: "-")
let convertedMark = "#𝙊𝙥𝙚𝙣𝘾𝘾"
return "\(text) \(joined)\t\(convertedMark)"
@ -359,11 +318,11 @@ class InputState {
/// Represents that the user is choosing in a candidates list.
class ChoosingCandidate: NotEmpty {
private(set) var candidates: [String]
private(set) var useVerticalMode: Bool
private(set) var isTypingVertical: Bool
init(composingBuffer: String, cursorIndex: UInt, candidates: [String], useVerticalMode: Bool) {
init(composingBuffer: String, cursorIndex: Int, candidates: [String], isTypingVertical: Bool) {
self.candidates = candidates
self.useVerticalMode = useVerticalMode
self.isTypingVertical = isTypingVertical
super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex)
}
@ -379,7 +338,7 @@ class InputState {
}
override var description: String {
"<InputState.ChoosingCandidate, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
"<InputState.ChoosingCandidate, candidates:\(candidates), isTypingVertical:\(isTypingVertical), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
}
}
@ -389,27 +348,27 @@ class InputState {
/// in the associated phrases mode.
class AssociatedPhrases: InputState {
private(set) var candidates: [String] = []
private(set) var useVerticalMode: Bool = false
init(candidates: [String], useVerticalMode: Bool) {
private(set) var isTypingVertical: Bool = false
init(candidates: [String], isTypingVertical: Bool) {
self.candidates = candidates
self.useVerticalMode = useVerticalMode
self.isTypingVertical = isTypingVertical
super.init()
}
var description: String {
"<InputState.AssociatedPhrases, candidates:\(candidates), useVerticalMode:\(useVerticalMode)>"
"<InputState.AssociatedPhrases, candidates:\(candidates), isTypingVertical:\(isTypingVertical)>"
}
}
class SymbolTable: ChoosingCandidate {
var node: SymbolNode
init(node: SymbolNode, useVerticalMode: Bool) {
init(node: SymbolNode, isTypingVertical: Bool) {
self.node = node
let candidates = node.children?.map(\.title) ?? [String]()
super.init(
composingBuffer: "", cursorIndex: 0, candidates: candidates,
useVerticalMode: useVerticalMode
isTypingVertical: isTypingVertical
)
}
@ -430,7 +389,7 @@ class InputState {
}
override var description: String {
"<InputState.SymbolTable, candidates:\(candidates), useVerticalMode:\(useVerticalMode), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
"<InputState.SymbolTable, candidates:\(candidates), isTypingVertical:\(isTypingVertical), composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
}
}
}

View File

@ -35,10 +35,10 @@ public enum InputMode: String {
// MARK: - Delegate.
protocol KeyHandlerDelegate {
func ctlCandidate(for _: KeyHandler) -> Any
func ctlCandidate() -> ctlCandidate
func keyHandler(
_: KeyHandler, didSelectCandidateAt index: Int,
ctlCandidate controller: Any
ctlCandidate controller: ctlCandidate
)
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputState)
-> Bool

View File

@ -37,7 +37,7 @@ extension KeyHandler {
) -> Bool {
let inputText = input.inputText
let charCode: UniChar = input.charCode
if let ctlCandidateCurrent = delegate!.ctlCandidate(for: self) as? ctlCandidate {
if let ctlCandidateCurrent = delegate?.ctlCandidate() {
// MARK: Cancel Candidate
let cancelCandidateKey =
@ -71,7 +71,7 @@ extension KeyHandler {
}
delegate!.keyHandler(
self,
didSelectCandidateAt: Int(ctlCandidateCurrent.selectedCandidateIndex),
didSelectCandidateAt: ctlCandidateCurrent.selectedCandidateIndex,
ctlCandidate: ctlCandidateCurrent
)
return true
@ -138,18 +138,21 @@ extension KeyHandler {
// MARK: Left Arrow
if input.isLeft {
if ctlCandidateCurrent is ctlCandidateHorizontal {
let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate()
if !updated {
IME.prtDebugIntel("1145148D")
errorCallback()
}
} else {
let updated: Bool = ctlCandidateCurrent.showPreviousPage()
if !updated {
IME.prtDebugIntel("1919810D")
errorCallback()
}
switch ctlCandidateCurrent.currentLayout {
case .horizontal:
do {
if !ctlCandidateCurrent.highlightPreviousCandidate() {
IME.prtDebugIntel("1145148D")
errorCallback()
}
}
case .vertical:
do {
if !ctlCandidateCurrent.showPreviousPage() {
IME.prtDebugIntel("1919810D")
errorCallback()
}
}
}
return true
}
@ -168,18 +171,21 @@ extension KeyHandler {
// MARK: Right Arrow
if input.isRight {
if ctlCandidateCurrent is ctlCandidateHorizontal {
let updated: Bool = ctlCandidateCurrent.highlightNextCandidate()
if !updated {
IME.prtDebugIntel("9B65138D")
errorCallback()
}
} else {
let updated: Bool = ctlCandidateCurrent.showNextPage()
if !updated {
IME.prtDebugIntel("9244908D")
errorCallback()
}
switch ctlCandidateCurrent.currentLayout {
case .horizontal:
do {
if !ctlCandidateCurrent.highlightNextCandidate() {
IME.prtDebugIntel("9B65138D")
errorCallback()
}
}
case .vertical:
do {
if !ctlCandidateCurrent.showNextPage() {
IME.prtDebugIntel("9244908D")
errorCallback()
}
}
}
return true
}
@ -198,18 +204,21 @@ extension KeyHandler {
// MARK: Up Arrow
if input.isUp {
if ctlCandidateCurrent is ctlCandidateHorizontal {
let updated: Bool = ctlCandidateCurrent.showPreviousPage()
if !updated {
IME.prtDebugIntel("9B614524")
errorCallback()
}
} else {
let updated: Bool = ctlCandidateCurrent.highlightPreviousCandidate()
if !updated {
IME.prtDebugIntel("ASD9908D")
errorCallback()
}
switch ctlCandidateCurrent.currentLayout {
case .horizontal:
do {
if !ctlCandidateCurrent.showPreviousPage() {
IME.prtDebugIntel("9B614524")
errorCallback()
}
}
case .vertical:
do {
if !ctlCandidateCurrent.highlightPreviousCandidate() {
IME.prtDebugIntel("ASD9908D")
errorCallback()
}
}
}
return true
}
@ -217,18 +226,21 @@ extension KeyHandler {
// MARK: Down Arrow
if input.isDown {
if ctlCandidateCurrent is ctlCandidateHorizontal {
let updated: Bool = ctlCandidateCurrent.showNextPage()
if !updated {
IME.prtDebugIntel("92B990DD")
errorCallback()
}
} else {
let updated: Bool = ctlCandidateCurrent.highlightNextCandidate()
if !updated {
IME.prtDebugIntel("6B99908D")
errorCallback()
}
switch ctlCandidateCurrent.currentLayout {
case .horizontal:
do {
if !ctlCandidateCurrent.showNextPage() {
IME.prtDebugIntel("92B990DD")
errorCallback()
}
}
case .vertical:
do {
if !ctlCandidateCurrent.highlightNextCandidate() {
IME.prtDebugIntel("6B99908D")
errorCallback()
}
}
}
return true
}
@ -260,11 +272,11 @@ extension KeyHandler {
return false
} else { // count > 0!isEmpty滿
if input.isEnd || input.emacsKey == vChewingEmacsKey.end {
if ctlCandidateCurrent.selectedCandidateIndex == UInt(candidates.count - 1) {
if ctlCandidateCurrent.selectedCandidateIndex == candidates.count - 1 {
IME.prtDebugIntel("9B69AAAD")
errorCallback()
} else {
ctlCandidateCurrent.selectedCandidateIndex = UInt(candidates.count - 1)
ctlCandidateCurrent.selectedCandidateIndex = candidates.count - 1
}
}
}
@ -294,10 +306,10 @@ extension KeyHandler {
}
if index != NSNotFound {
let candidateIndex: UInt = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(UInt(index))
if candidateIndex != UInt.max {
let candidateIndex = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(index)
if candidateIndex != Int.max {
delegate!.keyHandler(
self, didSelectCandidateAt: Int(candidateIndex), ctlCandidate: ctlCandidateCurrent
self, didSelectCandidateAt: candidateIndex, ctlCandidate: ctlCandidateCurrent
)
return true
}
@ -342,11 +354,11 @@ extension KeyHandler {
}
if shouldAutoSelectCandidate {
let candidateIndex: UInt = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(0)
if candidateIndex != UInt.max {
let candidateIndex = ctlCandidateCurrent.candidateIndexAtKeyLabelIndex(0)
if candidateIndex != Int.max {
delegate!.keyHandler(
self,
didSelectCandidateAt: Int(candidateIndex),
didSelectCandidateAt: candidateIndex,
ctlCandidate: ctlCandidateCurrent
)
clear()

View File

@ -200,7 +200,7 @@ extension KeyHandler {
if mgrPrefs.useSCPCTypingMode {
let choosingCandidates: InputState.ChoosingCandidate = buildCandidate(
state: inputting,
useVerticalMode: input.useVerticalMode
isTypingVertical: input.isTypingVertical
)
if choosingCandidates.candidates.count == 1 {
clear()
@ -213,7 +213,7 @@ extension KeyHandler {
if let associatedPhrases =
buildAssociatePhraseState(
withKey: text,
useVerticalMode: input.useVerticalMode
isTypingVertical: input.isTypingVertical
), !associatedPhrases.candidates.isEmpty
{
stateCallback(associatedPhrases)
@ -243,7 +243,7 @@ extension KeyHandler {
if let currentState = state as? InputState.NotEmpty, _composer.isEmpty,
input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace
|| input.isPageDown || input.isPageUp || (input.isTab && mgrPrefs.specifyShiftTabKeyBehavior)
|| (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey))
|| (input.isTypingVertical && (input.isverticalTypingOnlyChooseCandidateKey))
{
if input.isSpace {
// If the Space key is NOT set to be a selection key
@ -266,7 +266,7 @@ extension KeyHandler {
return true
}
}
stateCallback(buildCandidate(state: currentState, useVerticalMode: input.useVerticalMode))
stateCallback(buildCandidate(state: currentState, isTypingVertical: input.isTypingVertical))
return true
}
@ -368,7 +368,7 @@ extension KeyHandler {
let inputting = buildInputtingState
inputting.poppedText = poppedText
stateCallback(inputting)
stateCallback(buildCandidate(state: inputting, useVerticalMode: input.useVerticalMode))
stateCallback(buildCandidate(state: inputting, isTypingVertical: input.isTypingVertical))
} else { // If there is still unfinished bpmf reading, ignore the punctuation
IME.prtDebugIntel("17446655")
errorCallback()
@ -380,7 +380,7 @@ extension KeyHandler {
// Enter 使 commit buffer
// bool _ =
_ = handleEnter(state: state, stateCallback: stateCallback, errorCallback: errorCallback)
stateCallback(InputState.SymbolTable(node: SymbolNode.root, useVerticalMode: input.useVerticalMode))
stateCallback(InputState.SymbolTable(node: SymbolNode.root, isTypingVertical: input.isTypingVertical))
return true
}
}
@ -411,7 +411,7 @@ extension KeyHandler {
if handlePunctuation(
customPunctuation,
state: state,
usingVerticalMode: input.useVerticalMode,
usingVerticalTyping: input.isTypingVertical,
stateCallback: stateCallback,
errorCallback: errorCallback
) {
@ -425,7 +425,7 @@ extension KeyHandler {
if handlePunctuation(
punctuation,
state: state,
usingVerticalMode: input.useVerticalMode,
usingVerticalTyping: input.isTypingVertical,
stateCallback: stateCallback,
errorCallback: errorCallback
) {
@ -438,7 +438,7 @@ extension KeyHandler {
if handlePunctuation(
letter,
state: state,
usingVerticalMode: input.useVerticalMode,
usingVerticalTyping: input.isTypingVertical,
stateCallback: stateCallback,
errorCallback: errorCallback
) {

View File

@ -34,18 +34,18 @@ extension KeyHandler {
var buildInputtingState: InputState.Inputting {
// "Updating the composing buffer" means to request the client
// to "refresh" the text input buffer with our "composing text"
var tooltipParameterRef: [String] = ["", ""]
var composingBuffer = ""
var composedStringCursorIndex = 0
var readingCursorIndex = 0
// We must do some Unicode codepoint counting to find the actual cursor location for the client
// i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars
// locations. These processes are inherited from the ObjC++ version of this class and might be
// unnecessary in Swift, but this deduction requires further experiments.
// locations. Since we are using Swift, we use .utf16 as the equivalent of NSString.length().
for walkedNode in _walkedNodes {
if let theNode = walkedNode.node {
let strNodeValue = theNode.currentKeyValue.value
composingBuffer += strNodeValue
let arrSplit: [NSString] = (strNodeValue as NSString).split()
let arrSplit: [String] = Array(strNodeValue).map { String($0) }
let codepointCount = arrSplit.count
// This re-aligns the cursor index in the composed string
// (the actual cursor on the screen) with the builder's logical
@ -55,23 +55,39 @@ extension KeyHandler {
// index.
let spanningLength: Int = walkedNode.spanningLength
if readingCursorIndex + spanningLength <= builderCursorIndex {
composedStringCursorIndex += (strNodeValue as NSString).length
composedStringCursorIndex += strNodeValue.utf16.count
readingCursorIndex += spanningLength
} else {
if codepointCount == spanningLength {
var i = 0
while i < codepointCount, readingCursorIndex < builderCursorIndex {
composedStringCursorIndex += arrSplit[i].length
composedStringCursorIndex += arrSplit[i].utf16.count
readingCursorIndex += 1
i += 1
}
} else {
if readingCursorIndex < builderCursorIndex {
composedStringCursorIndex += (strNodeValue as NSString).length
composedStringCursorIndex += strNodeValue.utf16.count
readingCursorIndex += spanningLength
if readingCursorIndex > builderCursorIndex {
readingCursorIndex = builderCursorIndex
}
// Now we start preparing the contents of the tooltips used
// in cases of moving cursors across certain emojis which emoji
// char count is inequal to the reading count.
// Example in McBopomofo: Typing (3 readings) gets a tree emoji.
// Example in vChewing: Typing (2 readings) gets a pasta emoji.
switch builderCursorIndex {
case _builder.readings.count...:
tooltipParameterRef[0] = _builder.readings[_builder.readings.count - 1]
case 0:
tooltipParameterRef[1] = _builder.readings[builderCursorIndex]
default:
do {
tooltipParameterRef[0] = _builder.readings[builderCursorIndex - 1]
tooltipParameterRef[1] = _builder.readings[builderCursorIndex]
}
}
}
}
}
@ -81,26 +97,63 @@ extension KeyHandler {
// Now, we gather all the intel, separate the composing buffer to two parts (head and tail),
// and insert the reading text (the Mandarin syllable) in between them.
// The reading text is what the user is typing.
let head = String((composingBuffer as NSString).substring(to: composedStringCursorIndex))
let reading = _composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
let tail = String((composingBuffer as NSString).substring(from: composedStringCursorIndex))
let composedText = head + reading + tail
let cursorIndex = composedStringCursorIndex + reading.count
var arrHead = [String.UTF16View.Element]()
var arrTail = [String.UTF16View.Element]()
return InputState.Inputting(composingBuffer: composedText, cursorIndex: UInt(cursorIndex))
for (i, n) in composingBuffer.utf16.enumerated() {
if i < composedStringCursorIndex {
arrHead.append(n)
} else {
arrTail.append(n)
}
}
let head = String(utf16CodeUnits: arrHead, count: arrHead.count)
let reading = _composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
let tail = String(utf16CodeUnits: arrTail, count: arrTail.count)
let composedText = head + reading + tail
let cursorIndex = composedStringCursorIndex + reading.utf16.count
let stateResult = InputState.Inputting(composingBuffer: composedText, cursorIndex: cursorIndex)
// Now we start weaving the contents of the tooltip.
if tooltipParameterRef[0].isEmpty, tooltipParameterRef[1].isEmpty {
stateResult.tooltip = ""
} else if tooltipParameterRef[0].isEmpty {
stateResult.tooltip = String(
format: NSLocalizedString("Cursor is to the rear of \"%@\".", comment: ""),
tooltipParameterRef[1]
)
} else if tooltipParameterRef[1].isEmpty {
stateResult.tooltip = String(
format: NSLocalizedString("Cursor is in front of \"%@\".", comment: ""),
tooltipParameterRef[0]
)
} else {
stateResult.tooltip = String(
format: NSLocalizedString("Cursor is between \"%@\" and \"%@\".", comment: ""),
tooltipParameterRef[0], tooltipParameterRef[1]
)
}
if !stateResult.tooltip.isEmpty {
ctlInputMethod.tooltipController.setColor(state: .denialOverflow)
}
return stateResult
}
// MARK: -
func buildCandidate(
state currentState: InputState.NotEmpty,
useVerticalMode: Bool = false
isTypingVertical: Bool = false
) -> InputState.ChoosingCandidate {
InputState.ChoosingCandidate(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
candidates: candidatesArray,
useVerticalMode: useVerticalMode
isTypingVertical: isTypingVertical
)
}
@ -115,11 +168,11 @@ extension KeyHandler {
//
func buildAssociatePhraseState(
withKey key: String!,
useVerticalMode: Bool
isTypingVertical: Bool
) -> InputState.AssociatedPhrases! {
//  Xcode
InputState.AssociatedPhrases(
candidates: buildAssociatePhraseArray(withKey: key), useVerticalMode: useVerticalMode
candidates: buildAssociatePhraseArray(withKey: key), isTypingVertical: isTypingVertical
)
}
@ -153,7 +206,7 @@ extension KeyHandler {
if input.isCursorBackward || input.emacsKey == vChewingEmacsKey.backward, input.isShiftHold {
var index = state.markerIndex
if index > 0 {
index = UInt((state.composingBuffer as NSString).previousUtf16Position(for: Int(index)))
index = state.composingBuffer.utf16PreviousPosition(for: index)
let marking = InputState.Marking(
composingBuffer: state.composingBuffer,
cursorIndex: state.cursorIndex,
@ -161,7 +214,7 @@ extension KeyHandler {
readings: state.readings
)
marking.tooltipForInputting = state.tooltipForInputting
stateCallback(marking.markedRange.length == 0 ? marking.convertedToInputting : marking)
stateCallback(marking.markedRange.isEmpty ? marking.convertedToInputting : marking)
} else {
IME.prtDebugIntel("1149908D")
errorCallback()
@ -173,10 +226,8 @@ extension KeyHandler {
// Shift + Right
if input.isCursorForward || input.emacsKey == vChewingEmacsKey.forward, input.isShiftHold {
var index = state.markerIndex
// NSString Zonble NSStringUtils
// 9B51408D
if index < ((state.composingBuffer as NSString).length) {
index = UInt((state.composingBuffer as NSString).nextUtf16Position(for: Int(index)))
if index < (state.composingBuffer.utf16.count) {
index = state.composingBuffer.utf16NextPosition(for: index)
let marking = InputState.Marking(
composingBuffer: state.composingBuffer,
cursorIndex: state.cursorIndex,
@ -184,7 +235,7 @@ extension KeyHandler {
readings: state.readings
)
marking.tooltipForInputting = state.tooltipForInputting
stateCallback(marking.markedRange.length == 0 ? marking.convertedToInputting : marking)
stateCallback(marking.markedRange.isEmpty ? marking.convertedToInputting : marking)
} else {
IME.prtDebugIntel("9B51408D")
errorCallback()
@ -200,7 +251,7 @@ extension KeyHandler {
func handlePunctuation(
_ customPunctuation: String,
state: InputState,
usingVerticalMode useVerticalMode: Bool,
usingVerticalTyping isTypingVertical: Bool,
stateCallback: @escaping (InputState) -> Void,
errorCallback: @escaping () -> Void
) -> Bool {
@ -218,7 +269,7 @@ extension KeyHandler {
if mgrPrefs.useSCPCTypingMode, _composer.isEmpty {
let candidateState = buildCandidate(
state: inputting,
useVerticalMode: useVerticalMode
isTypingVertical: isTypingVertical
)
if candidateState.candidates.count == 1 {
clear()
@ -512,13 +563,13 @@ extension KeyHandler {
if input.isShiftHold {
// Shift + Right
if currentState.cursorIndex < (currentState.composingBuffer as NSString).length {
let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position(
for: Int(currentState.cursorIndex))
if currentState.cursorIndex < currentState.composingBuffer.utf16.count {
let nextPosition = currentState.composingBuffer.utf16NextPosition(
for: currentState.cursorIndex)
let marking: InputState.Marking! = InputState.Marking(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(nextPosition),
markerIndex: nextPosition,
readings: currentReadings
)
marking.tooltipForInputting = currentState.tooltip
@ -562,12 +613,12 @@ extension KeyHandler {
if input.isShiftHold {
// Shift + left
if currentState.cursorIndex > 0 {
let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position(
for: Int(currentState.cursorIndex))
let previousPosition = currentState.composingBuffer.utf16PreviousPosition(
for: currentState.cursorIndex)
let marking: InputState.Marking! = InputState.Marking(
composingBuffer: currentState.composingBuffer,
cursorIndex: currentState.cursorIndex,
markerIndex: UInt(previousPosition),
markerIndex: previousPosition,
readings: currentReadings
)
marking.tooltipForInputting = currentState.tooltip

View File

@ -26,50 +26,47 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Cocoa
extension NSString {
/// Converts the index in an NSString to the index in a Swift string.
/// Shiki's Notes: The cursor index in the IMK inline composition buffer
/// still uses UTF16 index measurements. This means that any attempt of
/// using Swift native UTF8 handlings to replace Zonble's NSString (or
/// .utf16) handlings below will still result in unavoidable necessities
/// of solving the UTF16->UTF8 conversions in another approach. Therefore,
/// I strongly advise against any attempt of such until the day that IMK is
/// capable of handling the cursor index in its inline composition buffer using
/// UTF8 measurements.
extension String {
/// Converts the index in an NSString or .utf16 to the index in a Swift string.
///
/// An Emoji might be compose by more than one UTF-16 code points, however
/// An Emoji might be compose by more than one UTF-16 code points. However,
/// the length of an NSString is only the sum of the UTF-16 code points. It
/// causes that the NSString and Swift string representation of the same
/// string have different lengths once the string contains such Emoji. The
/// method helps to find the index in a Swift string by passing the index
/// in an NSString.
public func characterIndex(from utf16Index: Int) -> (Int, String) {
let string = (self as String)
/// in an NSString (or .utf16).
public func charIndexLiteral(from utf16Index: Int) -> Int {
var length = 0
for (i, character) in string.enumerated() {
for (i, character) in self.enumerated() {
length += character.utf16.count
if length > utf16Index {
return (i, string)
return (i)
}
}
return (string.count, string)
return count
}
public func nextUtf16Position(for index: Int) -> Int {
var (fixedIndex, string) = characterIndex(from: index)
if fixedIndex < string.count {
fixedIndex += 1
}
return string[..<string.index(string.startIndex, offsetBy: fixedIndex)].utf16.count
public func utf16NextPosition(for index: Int) -> Int {
let fixedIndex = min(charIndexLiteral(from: index) + 1, count)
return self[..<self.index(startIndex, offsetBy: fixedIndex)].utf16.count
}
public func previousUtf16Position(for index: Int) -> Int {
var (fixedIndex, string) = characterIndex(from: index)
if fixedIndex > 0 {
fixedIndex -= 1
}
return string[..<string.index(string.startIndex, offsetBy: fixedIndex)].utf16.count
public func utf16PreviousPosition(for index: Int) -> Int {
let fixedIndex = max(charIndexLiteral(from: index) - 1, 0)
return self[..<self.index(startIndex, offsetBy: fixedIndex)].utf16.count
}
public var count: Int {
(self as String).count
}
public func split() -> [NSString] {
Array(self as String).map {
NSString(string: String($0))
}
func utf16SubString(with r: Range<Int>) -> String {
let arr = Array(self.utf16)[r].map { $0 }
return String(utf16CodeUnits: arr, count: arr.count)
}
}

View File

@ -670,7 +670,7 @@ public struct Tekkon {
default: break
}
}
case "":
case "":
if intonation.isEmpty {
switch incomingPhonabet {
case "": consonant = "" //
@ -718,7 +718,6 @@ public struct Tekkon {
consonant.selfReplace("", "")
consonant.selfReplace("", "")
}
if vowel == "", semivowel.isEmpty { consonant.selfReplace("", "") }
if consonant == "", semivowel.isEmpty, vowel.isEmpty {
consonant = ""
vowel = ""
@ -1289,7 +1288,7 @@ public struct Tekkon {
///
static let mapHsuStaticKeys: [String: String] = [
"a": "", "b": "", "c": "", "d": "", "e": "", "f": "", "g": "", "h": "", "i": "", "j": "", "k": "",
"l": "", "m": "", "n": "", "o": "", "p": "", "r": "", "s": "", "t": "", "u": "", "v": "", "w": "",
"l": "", "m": "", "n": "", "o": "", "p": "", "r": "", "s": "", "t": "", "u": "", "v": "", "w": "",
"x": "", "y": "", "z": "", " ": " ",
]

View File

@ -355,9 +355,16 @@ extension RangeReplaceableCollection where Element: Hashable {
}
}
// MARK: - Error Extension
// MARK: - String Tildes Expansion Extension
extension String {
public var expandingTildeInPath: String {
(self as NSString).expandingTildeInPath
}
}
// MARK: - String Localized Error Extension
extension String: Error {}
extension String: LocalizedError {
public var errorDescription: String? {
self

View File

@ -29,18 +29,13 @@ import InputMethodKit
private let kMinKeyLabelSize: CGFloat = 10
private var ctlCandidateCurrent: ctlCandidate?
extension ctlCandidate {
fileprivate static let horizontal = ctlCandidateHorizontal()
fileprivate static let vertical = ctlCandidateVertical()
}
private var ctlCandidateCurrent = ctlCandidateUniversal.init(.horizontal)
@objc(ctlInputMethod)
class ctlInputMethod: IMKInputController {
@objc static var areWeDeleting = false
private static let tooltipController = TooltipController()
static let tooltipController = TooltipController()
// MARK: -
@ -173,7 +168,7 @@ class ctlInputMethod: IMKInputController {
forCharacterIndex: 0, lineHeightRectangle: &textFrame
)
let useVerticalMode =
let isTypingVertical =
(attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false
if client.bundleIdentifier()
@ -184,7 +179,7 @@ class ctlInputMethod: IMKInputController {
IME.areWeUsingOurOwnPhraseEditor = false
}
let input = InputSignal(event: event, isVerticalMode: useVerticalMode)
let input = InputSignal(event: event, isVerticalTyping: isTypingVertical)
//
// KeyHandler
@ -286,8 +281,8 @@ extension ctlInputMethod {
_ = state // Stop clang-format from ruining the parameters of this function.
currentClient = nil
ctlCandidateCurrent?.delegate = nil
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.delegate = nil
ctlCandidateCurrent.visible = false
hideTooltip()
if let previous = previous as? InputState.NotEmpty {
@ -301,7 +296,7 @@ extension ctlInputMethod {
private func handle(state: InputState.Empty, previous: InputState, client: Any?) {
_ = state // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
hideTooltip()
guard let client = client as? IMKTextInput else {
@ -324,7 +319,7 @@ extension ctlInputMethod {
) {
_ = state // Stop clang-format from ruining the parameters of this function.
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
hideTooltip()
guard let client = client as? IMKTextInput else {
@ -339,7 +334,7 @@ extension ctlInputMethod {
private func handle(state: InputState.Committing, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
hideTooltip()
guard let client = client as? IMKTextInput else {
@ -358,7 +353,7 @@ extension ctlInputMethod {
private func handle(state: InputState.Inputting, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
hideTooltip()
guard let client = client as? IMKTextInput else {
@ -373,7 +368,7 @@ extension ctlInputMethod {
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
// i.e. the client app needs to take care of where to put this composing buffer
client.setMarkedText(
state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0),
state.attributedString, selectionRange: NSRange(location: state.cursorIndex, length: 0),
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
)
if !state.tooltip.isEmpty {
@ -386,7 +381,7 @@ extension ctlInputMethod {
private func handle(state: InputState.Marking, previous: InputState, client: Any?) {
_ = previous // Stop clang-format from ruining the parameters of this function.
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
guard let client = client as? IMKTextInput else {
hideTooltip()
return
@ -395,7 +390,7 @@ extension ctlInputMethod {
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
// i.e. the client app needs to take care of where to put this composing buffer
client.setMarkedText(
state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0),
state.attributedString, selectionRange: NSRange(location: state.cursorIndex, length: 0),
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
)
@ -413,14 +408,14 @@ extension ctlInputMethod {
_ = previous // Stop clang-format from ruining the parameters of this function.
hideTooltip()
guard let client = client as? IMKTextInput else {
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
return
}
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
// i.e. the client app needs to take care of where to put this composing buffer
client.setMarkedText(
state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0),
state.attributedString, selectionRange: NSRange(location: state.cursorIndex, length: 0),
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
)
show(candidateWindowWith: state, client: client)
@ -430,14 +425,14 @@ extension ctlInputMethod {
_ = previous // Stop clang-format from ruining the parameters of this function.
hideTooltip()
guard let client = client as? IMKTextInput else {
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
return
}
// the selection range is where the cursor is, with the length being 0 and replacement range NSNotFound,
// i.e. the client app needs to take care of where to put this composing buffer
client.setMarkedText(
state.attributedString, selectionRange: NSRange(location: Int(state.cursorIndex), length: 0),
state.attributedString, selectionRange: NSRange(location: state.cursorIndex, length: 0),
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
)
show(candidateWindowWith: state, client: client)
@ -447,7 +442,7 @@ extension ctlInputMethod {
_ = previous // Stop clang-format from ruining the parameters of this function.
hideTooltip()
guard let client = client as? IMKTextInput else {
ctlCandidateCurrent?.visible = false
ctlCandidateCurrent.visible = false
return
}
client.setMarkedText(
@ -462,47 +457,48 @@ extension ctlInputMethod {
extension ctlInputMethod {
private func show(candidateWindowWith state: InputState, client: Any!) {
let useVerticalMode: Bool = {
var useVerticalMode = false
var isTypingVertical: Bool {
if let state = state as? InputState.ChoosingCandidate {
return state.isTypingVertical
} else if let state = state as? InputState.AssociatedPhrases {
return state.isTypingVertical
}
return false
}
var isCandidateWindowVertical: Bool {
var candidates: [String] = []
if let state = state as? InputState.ChoosingCandidate {
useVerticalMode = state.useVerticalMode
candidates = state.candidates
} else if let state = state as? InputState.AssociatedPhrases {
useVerticalMode = state.useVerticalMode
candidates = state.candidates
}
if useVerticalMode == true {
return true
}
if isTypingVertical { return true }
// 使
candidates.sort {
$0.count > $1.count
}
if let candidateFirst = candidates.first {
// If there is a candidate which is too long, we use the vertical
// candidate list window automatically.
if candidateFirst.count > 8 {
// return true //
}
}
// 使
// for
for candidate in candidates {
if ["顏文字", "颜文字"].contains(candidate), mgrPrefs.symbolInputEnabled {
return true
}
}
return false
}()
// 使
// Beer emoji
let maxCandidatesPerPage = mgrPrefs.candidateKeys.count
let firstPageCandidates = candidates[0..<min(maxCandidatesPerPage, candidates.count)]
return firstPageCandidates.joined().count > Int(round(Double(maxCandidatesPerPage) * 1.8))
// true
}
ctlCandidateCurrent?.delegate = nil
ctlCandidateCurrent.delegate = nil
if useVerticalMode {
ctlCandidateCurrent = .vertical
/// currentLayout
/// ctlCandidate() SymbolTable
///
/// layoutCandidateView
/// macOS 10.x SwiftUI
if isCandidateWindowVertical { // 使
ctlCandidateCurrent = .init(.vertical)
} else if mgrPrefs.useHorizontalCandidateList {
ctlCandidateCurrent = .horizontal
ctlCandidateCurrent = .init(.horizontal)
} else {
ctlCandidateCurrent = .vertical
ctlCandidateCurrent = .init(.vertical)
}
// set the attributes for the candidate panel (which uses NSAttributedString)
@ -530,10 +526,10 @@ extension ctlInputMethod {
return finalReturnFont
}
ctlCandidateCurrent?.keyLabelFont = labelFont(
ctlCandidateCurrent.keyLabelFont = labelFont(
name: mgrPrefs.candidateKeyLabelFontName, size: keyLabelSize
)
ctlCandidateCurrent?.candidateFont = candidateFont(
ctlCandidateCurrent.candidateFont = candidateFont(
name: mgrPrefs.candidateTextFontName, size: textSize
)
@ -541,21 +537,21 @@ extension ctlInputMethod {
let keyLabels =
candidateKeys.count > 4 ? Array(candidateKeys) : Array(mgrPrefs.defaultCandidateKeys)
let keyLabelSuffix = state is InputState.AssociatedPhrases ? "^" : ""
ctlCandidateCurrent?.keyLabels = keyLabels.map {
ctlCandidateCurrent.keyLabels = keyLabels.map {
CandidateKeyLabel(key: String($0), displayedText: String($0) + keyLabelSuffix)
}
ctlCandidateCurrent?.delegate = self
ctlCandidateCurrent?.reloadData()
ctlCandidateCurrent.delegate = self
ctlCandidateCurrent.reloadData()
currentClient = client
ctlCandidateCurrent?.visible = true
ctlCandidateCurrent.visible = true
var lineHeightRect = NSRect(x: 0.0, y: 0.0, width: 16.0, height: 16.0)
var cursor = 0
if let state = state as? InputState.ChoosingCandidate {
cursor = Int(state.cursorIndex)
cursor = state.cursorIndex
if cursor == state.composingBuffer.count, cursor != 0 {
cursor -= 1
}
@ -568,24 +564,24 @@ extension ctlInputMethod {
cursor -= 1
}
if useVerticalMode {
ctlCandidateCurrent?.set(
if isTypingVertical {
ctlCandidateCurrent.set(
windowTopLeftPoint: NSPoint(
x: lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, y: lineHeightRect.origin.y - 4.0
),
bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0
)
} else {
ctlCandidateCurrent?.set(
ctlCandidateCurrent.set(
windowTopLeftPoint: NSPoint(x: lineHeightRect.origin.x, y: lineHeightRect.origin.y - 4.0),
bottomOutOfScreenAdjustmentHeight: lineHeightRect.size.height + 4.0
)
}
}
private func show(tooltip: String, composingBuffer: String, cursorIndex: UInt, client: Any!) {
private func show(tooltip: String, composingBuffer: String, cursorIndex: Int, client: Any!) {
var lineHeightRect = NSRect(x: 0.0, y: 0.0, width: 16.0, height: 16.0)
var cursor = Int(cursorIndex)
var cursor = cursorIndex
if cursor == composingBuffer.count, cursor != 0 {
cursor -= 1
}
@ -606,19 +602,13 @@ extension ctlInputMethod {
// MARK: -
extension ctlInputMethod: KeyHandlerDelegate {
func ctlCandidate(for keyHandler: KeyHandler) -> Any {
_ = keyHandler // Stop clang-format from ruining the parameters of this function.
return ctlCandidateCurrent ?? .vertical
}
func ctlCandidate() -> ctlCandidate { ctlCandidateCurrent }
func keyHandler(
_ keyHandler: KeyHandler, didSelectCandidateAt index: Int,
ctlCandidate controller: Any
_: KeyHandler, didSelectCandidateAt index: Int,
ctlCandidate controller: ctlCandidate
) {
_ = keyHandler // Stop clang-format from ruining the parameters of this function.
if let controller = controller as? ctlCandidate {
ctlCandidate(controller, didSelectCandidateAtIndex: UInt(index))
}
ctlCandidate(controller, didSelectCandidateAtIndex: index)
}
func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputState)
@ -653,38 +643,39 @@ extension ctlInputMethod: KeyHandlerDelegate {
// MARK: -
extension ctlInputMethod: ctlCandidateDelegate {
func candidateCountForController(_ controller: ctlCandidate) -> UInt {
func candidateCountForController(_ controller: ctlCandidate) -> Int {
_ = controller // Stop clang-format from ruining the parameters of this function.
if let state = state as? InputState.ChoosingCandidate {
return UInt(state.candidates.count)
return state.candidates.count
} else if let state = state as? InputState.AssociatedPhrases {
return UInt(state.candidates.count)
return state.candidates.count
}
return 0
}
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: UInt)
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: Int)
-> String
{
_ = controller // Stop clang-format from ruining the parameters of this function.
if let state = state as? InputState.ChoosingCandidate {
return state.candidates[Int(index)]
return state.candidates[index]
} else if let state = state as? InputState.AssociatedPhrases {
return state.candidates[Int(index)]
return state.candidates[index]
}
return ""
}
func ctlCandidate(_ controller: ctlCandidate, didSelectCandidateAtIndex index: UInt) {
func ctlCandidate(_ controller: ctlCandidate, didSelectCandidateAtIndex index: Int) {
_ = controller // Stop clang-format from ruining the parameters of this function.
let client = currentClient
if let state = state as? InputState.SymbolTable,
let node = state.node.children?[Int(index)]
let node = state.node.children?[index]
{
if let children = node.children, !children.isEmpty {
handle(state: .Empty(), client: client) //
handle(
state: .SymbolTable(node: node, useVerticalMode: state.useVerticalMode),
state: .SymbolTable(node: node, isTypingVertical: state.isTypingVertical),
client: currentClient
)
} else {
@ -695,7 +686,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
}
if let state = state as? InputState.ChoosingCandidate {
let selectedValue = state.candidates[Int(index)]
let selectedValue = state.candidates[index]
keyHandler.fixNode(value: selectedValue, respectCursorPushing: true)
let inputting = keyHandler.buildInputtingState
@ -706,7 +697,7 @@ extension ctlInputMethod: ctlCandidateDelegate {
handle(state: .Committing(poppedText: composingBuffer), client: client)
if mgrPrefs.associatedPhrasesEnabled,
let associatePhrases = keyHandler.buildAssociatePhraseState(
withKey: composingBuffer, useVerticalMode: state.useVerticalMode
withKey: composingBuffer, isTypingVertical: state.isTypingVertical
), !associatePhrases.candidates.isEmpty
{
handle(state: associatePhrases, client: client)
@ -720,11 +711,11 @@ extension ctlInputMethod: ctlCandidateDelegate {
}
if let state = state as? InputState.AssociatedPhrases {
let selectedValue = state.candidates[Int(index)]
let selectedValue = state.candidates[index]
handle(state: .Committing(poppedText: selectedValue), client: currentClient)
if mgrPrefs.associatedPhrasesEnabled,
let associatePhrases = keyHandler.buildAssociatePhraseState(
withKey: selectedValue, useVerticalMode: state.useVerticalMode
withKey: selectedValue, isTypingVertical: state.isTypingVertical
), !associatePhrases.candidates.isEmpty
{
handle(state: associatePhrases, client: client)

View File

@ -50,6 +50,7 @@ struct UserDef {
static let kEscToCleanInputBuffer = "EscToCleanInputBuffer"
static let kSpecifyShiftTabKeyBehavior = "SpecifyShiftTabKeyBehavior"
static let kSpecifyShiftSpaceKeyBehavior = "SpecifyShiftSpaceKeyBehavior"
static let kAllowBoostingSingleKanjiAsUserPhrase = "AllowBoostingSingleKanjiAsUserPhrase"
static let kUseSCPCTypingMode = "UseSCPCTypingMode"
static let kMaxCandidateLength = "MaxCandidateLength"
static let kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep"
@ -266,6 +267,9 @@ public enum mgrPrefs {
UserDefaults.standard.setDefault(
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin
)
UserDefaults.standard.setDefault(
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase, forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase
)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeySCPC, forKey: UserDef.kUsingHotKeySCPC)
UserDefaults.standard.setDefault(mgrPrefs.usingHotKeyAssociates, forKey: UserDef.kUsingHotKeyAssociates)
@ -337,6 +341,13 @@ public enum mgrPrefs {
@UserDefault(key: UserDef.kChooseCandidateUsingSpace, defaultValue: true)
static var chooseCandidateUsingSpace: Bool
@UserDefault(key: UserDef.kAllowBoostingSingleKanjiAsUserPhrase, defaultValue: false)
static var allowBoostingSingleKanjiAsUserPhrase: Bool
static var minCandidateLength: Int {
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase ? 1 : 2
}
@UserDefault(key: UserDef.kUseSCPCTypingMode, defaultValue: false)
static var useSCPCTypingMode: Bool
@ -346,7 +357,7 @@ public enum mgrPrefs {
return useSCPCTypingMode
}
@UserDefault(key: UserDef.kMaxCandidateLength, defaultValue: kDefaultComposingBufferSize * 2)
@UserDefault(key: UserDef.kMaxCandidateLength, defaultValue: 10)
static var maxCandidateLength: Int
@UserDefault(key: UserDef.kShouldNotFartInLieuOfBeep, defaultValue: true)

View File

@ -145,7 +145,7 @@ extension vChewing {
for netaSet in arrRangeRecords {
let strNetaSet = String(decoding: netaSet, as: UTF8.self)
let neta = Array(strNetaSet.split(separator: " ").reversed())
let theValue: String = String(neta[0])
let theValue: String = .init(neta[0])
let kvPair = Megrez.KeyValuePair(key: key, value: theValue)
var theScore = defaultScore
if neta.count >= 2, !shouldForceDefaultScore {

View File

@ -357,10 +357,9 @@ enum mgrLangModel {
static func dataFolderPath(isDefaultFolder: Bool) -> String {
let appSupportPath = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0].path
var userDictPathSpecified = (mgrPrefs.userDataFolderSpecified as NSString).expandingTildeInPath
var userDictPathSpecified = mgrPrefs.userDataFolderSpecified.expandingTildeInPath
var userDictPathDefault =
(URL(fileURLWithPath: appSupportPath).appendingPathComponent("vChewing").path as NSString)
.expandingTildeInPath
URL(fileURLWithPath: appSupportPath).appendingPathComponent("vChewing").path.expandingTildeInPath
userDictPathDefault.ensureTrailingSlash()
userDictPathSpecified.ensureTrailingSlash()

View File

@ -1,6 +1,6 @@
CFBundleName = "vChewing";
CFBundleDisplayName = "vChewing";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
"org.atelierInmu.inputmethod.vChewing.IMECHT" = "vChewing-CHT";
"org.atelierInmu.inputmethod.vChewing.IMECHS" = "vChewing-CHS";
CFEULAContent = "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n2. No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements above.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n";

View File

@ -57,6 +57,8 @@
"Edit User Symbol & Emoji Data…" = "Edit User Symbol & Emoji Data…";
"Choose your desired user data folder." = "Choose your desired user data folder.";
"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\".";
"Cursor is to the rear of \"%@\"." = "Cursor is to the rear of \"%@\".";
"Cursor is in front of \"%@\"." = "Cursor is in front of \"%@\".";
"Loading CHS Core Dict..." = "Loading CHS Core Dict...";
"Loading CHT Core Dict..." = "Loading CHT Core Dict...";
"Core Dict loading complete." = "Core Dict loading complete.";
@ -80,6 +82,7 @@
// SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)Space:";
"Allow boosting / excluding a candidate of single kanji" = "Allow boosting / excluding a candidate of single kanji";
"An accomodation for elder computer users." = "An accomodation for elder computer users.";
"Apple ABC (equivalent to English US)" = "Apple ABC (equivalent to English US)";
"Apple Chewing - Dachen" = "Apple Chewing - Dachen";

View File

@ -106,7 +106,7 @@
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>© 2011-2022 OpenVanilla Project &amp; © 2021-2022 vChewing Project.</string>
<string>© 2021-2022 vChewing Project.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View File

@ -1,6 +1,6 @@
CFBundleName = "vChewing";
CFBundleDisplayName = "vChewing";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
"org.atelierInmu.inputmethod.vChewing.IMECHT" = "vChewing-CHT";
"org.atelierInmu.inputmethod.vChewing.IMECHS" = "vChewing-CHS";
CFEULAContent = "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n2. No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements above.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n";

View File

@ -57,6 +57,8 @@
"Edit User Symbol & Emoji Data…" = "Edit User Symbol & Emoji Data…";
"Choose your desired user data folder." = "Choose your desired user data folder.";
"Cursor is between \"%@\" and \"%@\"." = "Cursor is between \"%@\" and \"%@\".";
"Cursor is to the rear of \"%@\"." = "Cursor is to the rear of \"%@\".";
"Cursor is in front of \"%@\"." = "Cursor is in front of \"%@\".";
"Loading CHS Core Dict..." = "Loading CHS Core Dict...";
"Loading CHT Core Dict..." = "Loading CHT Core Dict...";
"Core Dict loading complete." = "Core Dict loading complete.";
@ -80,6 +82,7 @@
// SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)Space:";
"Allow boosting / excluding a candidate of single kanji" = "Allow boosting / excluding a candidate of single kanji";
"An accomodation for elder computer users." = "An accomodation for elder computer users.";
"Apple ABC (equivalent to English US)" = "Apple ABC (equivalent to English US)";
"Apple Chewing - Dachen" = "Apple Chewing - Dachen";

View File

@ -1,6 +1,6 @@
CFBundleName = "威注音";
CFBundleDisplayName = "威注音";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
"org.atelierInmu.inputmethod.vChewing.IMECHT" = "繁体威注音";
"org.atelierInmu.inputmethod.vChewing.IMECHS" = "簡体威注音";
CFEULAContent = "以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。\n\nイ上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。\n\nロ上記の通知要件を満たすために必要な場合を除き、コントリビューターの商号、商標、サービスマーク、または製品名を使用するための商標ライセンスは付与されていません。\n\nソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供されます。ここでいう保証とは、商品性、特定の目的への適合性、および権利非侵害についての保証も含みますが、それに限定されるものではありません。\n作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。";

View File

@ -57,6 +57,8 @@
"Edit User Symbol & Emoji Data…" = "ユーザー符号&絵文字辞書を編集…";
"Choose your desired user data folder." = "欲しがるユーザー辞書フォルダをお選びください。";
"Cursor is between \"%@\" and \"%@\"." = "カーソルは「%@」と「%@」に間れ。";
"Cursor is to the rear of \"%@\"." = "カーソルは「%@」の後ろに。";
"Cursor is in front of \"%@\"." = "カーソルは「%@」の前に。";
"Loading CHS Core Dict..." = "簡体中国語核心辞書読込中…";
"Loading CHT Core Dict..." = "繁体中国語核心辞書読込中…";
"Core Dict loading complete." = "核心辞書読込完了";
@ -80,6 +82,7 @@
// SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)Space:";
"Allow boosting / excluding a candidate of single kanji" = "即排除/即最優先にできる候補の文字数の最低限は1字とする";
"An accomodation for elder computer users." = "年配なるユーザーのために提供した機能である。";
"Apple ABC (equivalent to English US)" = "Apple ABC (Apple U.S. キーボードと同じ)";
"Apple Chewing - Dachen" = "Apple 大千注音キーボード";

View File

@ -1,6 +1,6 @@
CFBundleName = "威注音";
CFBundleDisplayName = "威注音";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
"org.atelierInmu.inputmethod.vChewing.IMECHT" = "威注音-繁";
"org.atelierInmu.inputmethod.vChewing.IMECHS" = "威注音-简";
CFEULAContent = "软件之著作权利人依此麻理授权条款,将其对于软件之著作权利授权释出,只须使用者践履以下二项麻理授权条款叙明之义务性规定,其即享有对此软件程式及其相关说明文档自由不受限制地进行利用之权利,范围包括「使用、重制、修改、合并、出版、散布、再授权、及贩售程式重制作品」等诸多方面之应用,而散布程式之人、更可将上述权利传递予其后收受程式之后手,倘若其后收受程式之人亦服膺以下二项麻理授权条款之义务性规定,则其对程式亦享有与前手运用范围相同之同一权利。\n\n甲、散布此一软件程式者须将本条款其上之「著作权声明」及以下之「免责声明」内嵌于软件程式及其重制作品之实体之中。\n\n乙、敝授权合约不提供对「贡献者」之商品名称、商标、服务标志或产品名称之商标许可除非用以满足履行上文所述义务之必要。\n\n因麻理软件程式之授权模式乃是无偿提供是以在现行法律之架构下可以主张合理之免除担保责任。麻理软件之著作权人或任何之后续散布者对于其所散布之麻理软件程式皆不负任何形式上实质上之担保责任明示亦或隐喻、商业利用性亦或特定目之使用性这些均不在保障之列。利用麻理软件程式之所有风险均由使用者自行担负。假如所使用之麻理程式发生缺陷性问题使用者需自行担负修正、改正及必要之服务支出。麻理软件程式之著作权人不负任何形式上实质上之担保责任无论任何一般之、特殊之、偶发之、因果关系式之损害或是麻理软件程式之不适用性均须由使用者自行负担。\n";

View File

@ -57,6 +57,8 @@
"Edit User Symbol & Emoji Data…" = "编辑自订符号&绘文字资料…";
"Choose your desired user data folder." = "请选择您想指定的使用者语汇档案目录。";
"Cursor is between \"%@\" and \"%@\"." = "游标介于「%@」与「%@」之间。";
"Cursor is to the rear of \"%@\"." = "游标在「%@」的后方。";
"Cursor is in front of \"%@\"." = "游标在「%@」的前方。.";
"Loading CHS Core Dict..." = "载入简体中文核心辞典…";
"Loading CHT Core Dict..." = "载入繁体中文核心辞典…";
"Core Dict loading complete." = "核心辞典载入完毕";
@ -80,6 +82,7 @@
// SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)空格键:";
"Allow boosting / excluding a candidate of single kanji" = "将可以就地升权/排除的候选字词的最短词长设为单个汉字";
"An accomodation for elder computer users." = "针对年长使用者的习惯而提供。";
"Apple ABC (equivalent to English US)" = "Apple ABC (与 Apple 美规键盘等价)";
"Apple Chewing - Dachen" = "Apple 大千注音键盘排列";

View File

@ -1,6 +1,6 @@
CFBundleName = "威注音";
CFBundleDisplayName = "威注音";
NSHumanReadableCopyright = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
NSHumanReadableCopyright = "© 2021-2022 vChewing Project.";
"org.atelierInmu.inputmethod.vChewing.IMECHT" = "威注音-繁";
"org.atelierInmu.inputmethod.vChewing.IMECHS" = "威注音-簡";
CFEULAContent = "軟體之著作權利人依此麻理授權條款,將其對於軟體之著作權利授權釋出,只須使用者踐履以下二項麻理授權條款敘明之義務性規定,其即享有對此軟體程式及其相關說明文檔自由不受限制地進行利用之權利,範圍包括「使用、重製、修改、合併、出版、散布、再授權、及販售程式重製作品」等諸多方面之應用,而散布程式之人、更可將上述權利傳遞予其後收受程式之後手,倘若其後收受程式之人亦服膺以下二項麻理授權條款之義務性規定,則其對程式亦享有與前手運用範圍相同之同一權利。\n\n甲、散布此一軟體程式者須將本條款其上之「著作權聲明」及以下之「免責聲明」內嵌於軟體程式及其重製作品之實體之中。\n\n乙、敝授權合約不提供對「貢獻者」之商品名稱、商標、服務標誌或產品名稱之商標許可除非用以滿足履行上文所述義務之必要。\n\n因麻理軟體程式之授權模式乃是無償提供是以在現行法律之架構下可以主張合理之免除擔保責任。麻理軟體之著作權人或任何之後續散布者對於其所散布之麻理軟體程式皆不負任何形式上實質上之擔保責任明示亦或隱喻、商業利用性亦或特定目之使用性這些均不在保障之列。利用麻理軟體程式之所有風險均由使用者自行擔負。假如所使用之麻理程式發生缺陷性問題使用者需自行擔負修正、改正及必要之服務支出。麻理軟體程式之著作權人不負任何形式上實質上之擔保責任無論任何一般之、特殊之、偶發之、因果關係式之損害或是麻理軟體程式之不適用性均須由使用者自行負擔。\n";

View File

@ -57,6 +57,8 @@
"Edit User Symbol & Emoji Data…" = "編輯自訂符號&繪文字資料…";
"Choose your desired user data folder." = "請選擇您想指定的使用者語彙檔案目錄。";
"Cursor is between \"%@\" and \"%@\"." = "游標介於「%@」與「%@」之間。";
"Cursor is to the rear of \"%@\"." = "游標在「%@」的後方。";
"Cursor is in front of \"%@\"." = "游標在「%@」的前方。.";
"Loading CHS Core Dict..." = "載入簡體中文核心辭典…";
"Loading CHT Core Dict..." = "載入繁體中文核心辭典…";
"Core Dict loading complete." = "核心辭典載入完畢";
@ -80,6 +82,7 @@
// SwiftUI Preferences
"(Shift+)Space:" = "(Shift+)空格鍵:";
"Allow boosting / excluding a candidate of single kanji" = "將可以就地升權/排除的候選字詞的最短詞長設為單個漢字";
"An accomodation for elder computer users." = "針對年長使用者的習慣而提供。";
"Apple ABC (equivalent to English US)" = "Apple ABC (與 Apple 美規鍵盤等價)";
"Apple Chewing - Dachen" = "Apple 大千注音鍵盤佈局";

View File

@ -38,22 +38,27 @@ public class CandidateKeyLabel: NSObject {
}
public protocol ctlCandidateDelegate: AnyObject {
func candidateCountForController(_ controller: ctlCandidate) -> UInt
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: UInt)
func candidateCountForController(_ controller: ctlCandidate) -> Int
func ctlCandidate(_ controller: ctlCandidate, candidateAtIndex index: Int)
-> String
func ctlCandidate(
_ controller: ctlCandidate, didSelectCandidateAtIndex index: UInt
_ controller: ctlCandidate, didSelectCandidateAtIndex index: Int
)
}
public class ctlCandidate: NSWindowController {
public enum Layout {
case horizontal
case vertical
}
public var currentLayout: Layout = .horizontal
public weak var delegate: ctlCandidateDelegate? {
didSet {
reloadData()
}
}
public var selectedCandidateIndex: UInt = .max
public var selectedCandidateIndex: Int = .max
public var visible: Bool = false {
didSet {
NSObject.cancelPreviousPerformRequests(withTarget: self)
@ -108,8 +113,8 @@ public class ctlCandidate: NSWindowController {
false
}
public func candidateIndexAtKeyLabelIndex(_: UInt) -> UInt {
UInt.max
public func candidateIndexAtKeyLabelIndex(_: Int) -> Int {
Int.max
}
/// Sets the location of the candidate window.

View File

@ -1,473 +0,0 @@
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. No trademark license is granted to use the trade names, trademarks, service
marks, or product names of Contributor, except as required to fulfill notice
requirements above.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import Cocoa
private class HorizontalCandidateView: NSView {
var highlightedIndex: UInt = 0
var action: Selector?
weak var target: AnyObject?
private var keyLabels: [String] = []
private var displayedCandidates: [String] = []
private var dispCandidatesWithLabels: [String] = []
private var keyLabelHeight: CGFloat = 0
private var keyLabelWidth: CGFloat = 0
private var candidateTextHeight: CGFloat = 0
private var cellPadding: CGFloat = 0
private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var elementWidths: [CGFloat] = []
private var trackingHighlightedIndex: UInt = .max
override var isFlipped: Bool {
true
}
var sizeForView: NSSize {
var result = NSSize.zero
if !elementWidths.isEmpty {
result.width = elementWidths.reduce(0, +) + CGFloat(elementWidths.count)
result.height = candidateTextHeight + cellPadding
}
return result
}
@objc(setKeyLabels:displayedCandidates:)
func set(keyLabels labels: [String], displayedCandidates candidates: [String]) {
let count = min(labels.count, candidates.count)
keyLabels = Array(labels[0..<count])
displayedCandidates = Array(candidates[0..<count])
dispCandidatesWithLabels = zip(keyLabels, displayedCandidates).map { $0 + $1 }
var newWidths = [CGFloat]()
let baseSize = NSSize(width: 10240.0, height: 10240.0)
for index in 0..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
with: baseSize, options: .usesLineFragmentOrigin,
attributes: candidateWithLabelAttrDict
)
var cellWidth = rctCandidate.size.width + cellPadding
let cellHeight = rctCandidate.size.height + cellPadding
if cellWidth < cellHeight * 1.35 {
cellWidth = cellHeight * 1.35
}
newWidths.append(round(cellWidth))
}
elementWidths = newWidths
}
@objc(setKeyLabelFont:candidateFont:)
func set(keyLabelFont labelFont: NSFont, candidateFont: NSFont) {
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .center
candidateWithLabelAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // We still need this dummy section to make sure that
// the space occupations of the candidates are correct.
keyLabelAttrDict = [
.font: labelFont,
.paragraphStyle: paraStyle,
.verticalGlyphForm: true as AnyObject,
.foregroundColor: NSColor.secondaryLabelColor,
] // Candidate phrase text color
candidateAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // Candidate index text color
let labelFontSize = labelFont.pointSize
let candidateFontSize = candidateFont.pointSize
let biggestSize = max(labelFontSize, candidateFontSize)
keyLabelWidth = ceil(labelFontSize)
keyLabelHeight = ceil(labelFontSize * 2)
candidateTextHeight = ceil(candidateFontSize * 1.20)
cellPadding = ceil(biggestSize / 4.0) * 2
}
override func draw(_: NSRect) {
let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds)
NSColor.systemGray.withAlphaComponent(0.75).setStroke()
NSBezierPath.strokeLine(
from: NSPoint(x: bounds.size.width, y: 0.0),
to: NSPoint(x: bounds.size.width, y: bounds.size.height)
)
var accuWidth: CGFloat = 0
for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth
let rctCandidateArea = NSRect(
x: accuWidth, y: 0.0, width: currentWidth + 1.0,
height: candidateTextHeight + cellPadding
)
let rctLabel = NSRect(
x: accuWidth + cellPadding / 2 - 1, y: cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: accuWidth + keyLabelWidth - 1, y: cellPadding / 2 - 1,
width: currentWidth - keyLabelWidth,
height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex {
let colorBlendAmount: CGFloat = IME.isDarkMode() ? 0.25 : 0
// The background color of the highlightened candidate
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
NSColor.systemRed.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
case InputMode.imeModeCHT:
NSColor.systemBlue.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
default:
NSColor.alternateSelectedControlColor.setFill()
}
// Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84)
// Highlightened phrase text color
activeCandidateAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
} else {
NSColor.controlBackgroundColor.setFill()
}
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case InputMode.imeModeCHT:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hant" as AnyObject
}
default:
break
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuWidth += currentWidth + 1.0
}
}
private func findHitIndex(event: NSEvent) -> UInt? {
let location = convert(event.locationInWindow, to: nil)
if !bounds.contains(location) {
return nil
}
var accuWidth: CGFloat = 0.0
for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth
if location.x >= accuWidth, location.x <= accuWidth + currentWidth {
return UInt(index)
}
accuWidth += currentWidth + 1.0
}
return nil
}
override func mouseUp(with event: NSEvent) {
trackingHighlightedIndex = highlightedIndex
guard let newIndex = findHitIndex(event: event) else {
return
}
highlightedIndex = newIndex
setNeedsDisplay(bounds)
}
override func mouseDown(with event: NSEvent) {
guard let newIndex = findHitIndex(event: event) else {
return
}
var triggerAction = false
if newIndex == highlightedIndex {
triggerAction = true
} else {
highlightedIndex = trackingHighlightedIndex
}
trackingHighlightedIndex = 0
setNeedsDisplay(bounds)
if triggerAction {
if let target = target as? NSObject, let action = action {
target.perform(action, with: self)
}
}
}
}
public class ctlCandidateHorizontal: ctlCandidate {
private var candidateView: HorizontalCandidateView
private var prevPageButton: NSButton
private var nextPageButton: NSButton
private var currentPageIndex: UInt = 0
public init() {
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
let panel = NSPanel(
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
)
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1)
panel.hasShadow = true
panel.isOpaque = false
panel.backgroundColor = NSColor.clear
contentRect.origin = NSPoint.zero
candidateView = HorizontalCandidateView(frame: contentRect)
candidateView.wantsLayer = true
candidateView.layer?.borderColor =
NSColor.selectedMenuItemTextColor.withAlphaComponent(0.10).cgColor
candidateView.layer?.borderWidth = 1.0
if #available(macOS 10.13, *) {
candidateView.layer?.cornerRadius = 6.0
}
panel.contentView?.addSubview(candidateView)
contentRect.size = NSSize(width: 20.0, height: 10.0) // Reduce the button width
let buttonAttribute: [NSAttributedString.Key: Any] = [.font: NSFont.systemFont(ofSize: 9.0)]
nextPageButton = NSButton(frame: contentRect)
NSColor.controlBackgroundColor.setFill()
NSBezierPath.fill(nextPageButton.bounds)
nextPageButton.wantsLayer = true
nextPageButton.layer?.masksToBounds = true
nextPageButton.layer?.borderColor = NSColor.clear.cgColor
nextPageButton.layer?.borderWidth = 0.0
nextPageButton.setButtonType(.momentaryLight)
nextPageButton.bezelStyle = .disclosure
nextPageButton.userInterfaceLayoutDirection = .leftToRight
nextPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Next Page Arrow
prevPageButton = NSButton(frame: contentRect)
NSColor.controlBackgroundColor.setFill()
NSBezierPath.fill(prevPageButton.bounds)
prevPageButton.wantsLayer = true
prevPageButton.layer?.masksToBounds = true
prevPageButton.layer?.borderColor = NSColor.clear.cgColor
prevPageButton.layer?.borderWidth = 0.0
prevPageButton.setButtonType(.momentaryLight)
prevPageButton.bezelStyle = .disclosure
prevPageButton.userInterfaceLayoutDirection = .rightToLeft
prevPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Previous Page Arrow
panel.contentView?.addSubview(nextPageButton)
panel.contentView?.addSubview(prevPageButton)
super.init(window: panel)
candidateView.target = self
candidateView.action = #selector(candidateViewMouseDidClick(_:))
nextPageButton.target = self
nextPageButton.action = #selector(pageButtonAction(_:))
prevPageButton.target = self
prevPageButton.action = #selector(pageButtonAction(_:))
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func reloadData() {
candidateView.highlightedIndex = 0
currentPageIndex = 0
layoutCandidateView()
}
override public func showNextPage() -> Bool {
guard delegate != nil else { return false }
if pageCount == 1 { return highlightNextCandidate() }
if currentPageIndex + 1 >= pageCount { clsSFX.beep() }
currentPageIndex = (currentPageIndex + 1 >= pageCount) ? 0 : currentPageIndex + 1
candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
override public func showPreviousPage() -> Bool {
guard delegate != nil else { return false }
if pageCount == 1 { return highlightPreviousCandidate() }
if currentPageIndex == 0 { clsSFX.beep() }
currentPageIndex = (currentPageIndex == 0) ? pageCount - 1 : currentPageIndex - 1
candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
override public func highlightNextCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex + 1 >= delegate.candidateCountForController(self))
? 0 : selectedCandidateIndex + 1
return true
}
override public func highlightPreviousCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex == 0)
? delegate.candidateCountForController(self) - 1 : selectedCandidateIndex - 1
return true
}
override public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt {
guard let delegate = delegate else {
return UInt.max
}
let result = currentPageIndex * UInt(keyLabels.count) + index
return result < delegate.candidateCountForController(self) ? result : UInt.max
}
override public var selectedCandidateIndex: UInt {
get {
currentPageIndex * UInt(keyLabels.count) + candidateView.highlightedIndex
}
set {
guard let delegate = delegate else {
return
}
let keyLabelCount = UInt(keyLabels.count)
if newValue < delegate.candidateCountForController(self) {
currentPageIndex = newValue / keyLabelCount
candidateView.highlightedIndex = newValue % keyLabelCount
layoutCandidateView()
}
}
}
}
extension ctlCandidateHorizontal {
private var pageCount: UInt {
guard let delegate = delegate else {
return 0
}
let totalCount = delegate.candidateCountForController(self)
let keyLabelCount = UInt(keyLabels.count)
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
}
private func layoutCandidateView() {
guard let delegate = delegate else {
return
}
candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont)
var candidates = [String]()
let count = delegate.candidateCountForController(self)
let keyLabelCount = UInt(keyLabels.count)
let begin = currentPageIndex * keyLabelCount
for index in begin..<min(begin + keyLabelCount, count) {
let candidate = delegate.ctlCandidate(self, candidateAtIndex: index)
candidates.append(candidate)
}
candidateView.set(
keyLabels: keyLabels.map(\.displayedText), displayedCandidates: candidates
)
var newSize = candidateView.sizeForView
var frameRect = candidateView.frame
frameRect.size = newSize
candidateView.frame = frameRect
if pageCount > 1, mgrPrefs.showPageButtonsInCandidateWindow {
var buttonRect = nextPageButton.frame
let spacing: CGFloat = 0.0
buttonRect.size.height = floor(newSize.height / 2)
let buttonOriginY = (newSize.height - (buttonRect.size.height * 2.0 + spacing)) / 2.0
buttonRect.origin = NSPoint(x: newSize.width, y: buttonOriginY)
nextPageButton.frame = buttonRect
buttonRect.origin = NSPoint(
x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing
)
prevPageButton.frame = buttonRect
newSize.width += 20
nextPageButton.isHidden = false
prevPageButton.isHidden = false
} else {
nextPageButton.isHidden = true
prevPageButton.isHidden = true
}
frameRect = window?.frame ?? NSRect.zero
let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height)
frameRect.size = newSize
frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height)
window?.setFrame(frameRect, display: false)
candidateView.setNeedsDisplay(candidateView.bounds)
}
@objc private func pageButtonAction(_ sender: Any) {
guard let sender = sender as? NSButton else {
return
}
if sender == nextPageButton {
_ = showNextPage()
} else if sender == prevPageButton {
_ = showPreviousPage()
}
}
@objc private func candidateViewMouseDidClick(_: Any) {
delegate?.ctlCandidate(self, didSelectCandidateAtIndex: selectedCandidateIndex)
}
}

View File

@ -0,0 +1,683 @@
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. No trademark license is granted to use the trade names, trademarks, service
marks, or product names of Contributor, except as required to fulfill notice
requirements above.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import Cocoa
// Zonble Voltaire
private class vwrCandidateUniversal: NSView {
var highlightedIndex: Int = 0 { didSet { highlightedIndex = max(highlightedIndex, 0) } }
var action: Selector?
weak var target: AnyObject?
var isVerticalLayout: Bool = false
var fractionFontSize: CGFloat = 12.0
private var keyLabels: [String] = []
private var displayedCandidates: [String] = []
private var dispCandidatesWithLabels: [String] = []
private var keyLabelHeight: CGFloat = 0
private var keyLabelWidth: CGFloat = 0
private var candidateTextHeight: CGFloat = 0
private var cellPadding: CGFloat = 0
private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var windowWidth: CGFloat = 0 //
private var elementWidths: [CGFloat] = []
private var elementHeights: [CGFloat] = [] //
private var trackingHighlightedIndex: Int = .max {
didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) }
}
override var isFlipped: Bool {
true
}
var sizeForView: NSSize {
var result = NSSize.zero
if !elementWidths.isEmpty {
switch isVerticalLayout {
case true:
result.width = windowWidth
result.height = elementHeights.reduce(0, +)
case false:
result.width = elementWidths.reduce(0, +) + CGFloat(elementWidths.count)
result.height = candidateTextHeight + cellPadding
}
}
return result
}
@objc(setKeyLabels:displayedCandidates:)
func set(keyLabels labels: [String], displayedCandidates candidates: [String]) {
let count = min(labels.count, candidates.count)
keyLabels = Array(labels[0..<count])
displayedCandidates = Array(candidates[0..<count])
dispCandidatesWithLabels = zip(keyLabels, displayedCandidates).map { $0 + $1 }
var newWidths = [CGFloat]()
var calculatedWindowWidth = CGFloat()
var newHeights = [CGFloat]()
let baseSize = NSSize(width: 10240.0, height: 10240.0)
for index in 0..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
with: baseSize, options: .usesLineFragmentOrigin,
attributes: candidateWithLabelAttrDict
)
var cellWidth = rctCandidate.size.width + cellPadding
let cellHeight = rctCandidate.size.height + cellPadding
switch isVerticalLayout {
case true:
if calculatedWindowWidth < rctCandidate.size.width {
calculatedWindowWidth = rctCandidate.size.width + cellPadding
}
case false:
if cellWidth < cellHeight * 1.35 {
cellWidth = cellHeight * 1.35
}
}
newWidths.append(round(cellWidth))
newHeights.append(round(cellHeight)) //
}
elementWidths = newWidths
elementHeights = newHeights
//
windowWidth = round(calculatedWindowWidth + cellPadding)
}
@objc(setKeyLabelFont:candidateFont:)
func set(keyLabelFont labelFont: NSFont, candidateFont: NSFont) {
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = isVerticalLayout ? .left : .center
candidateWithLabelAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // We still need this dummy section to make sure that
// the space occupations of the candidates are correct.
keyLabelAttrDict = [
.font: labelFont,
.paragraphStyle: paraStyle,
.verticalGlyphForm: true as AnyObject,
.foregroundColor: NSColor.secondaryLabelColor,
] // Candidate phrase text color
candidateAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // Candidate index text color
let labelFontSize = labelFont.pointSize
let candidateFontSize = candidateFont.pointSize
let biggestSize = max(labelFontSize, candidateFontSize)
fractionFontSize = round(biggestSize * 0.75)
keyLabelWidth = ceil(labelFontSize)
keyLabelHeight = ceil(labelFontSize * 2)
candidateTextHeight = ceil(candidateFontSize * 1.20)
cellPadding = ceil(biggestSize / 4.0) * 2
}
override func draw(_: NSRect) {
let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds)
NSColor.systemGray.withAlphaComponent(0.75).setStroke()
NSBezierPath.strokeLine(
from: NSPoint(x: bounds.size.width, y: 0.0),
to: NSPoint(x: bounds.size.width, y: bounds.size.height)
)
switch isVerticalLayout {
case true:
do {
var accuHeight: CGFloat = 0
for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight
let rctCandidateArea = NSRect(
x: 0.0, y: accuHeight, width: windowWidth, height: candidateTextHeight + cellPadding
)
let rctLabel = NSRect(
x: cellPadding / 2 - 1, y: accuHeight + cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: cellPadding / 2 - 1 + keyLabelWidth, y: accuHeight + cellPadding / 2 - 1,
width: windowWidth - keyLabelWidth, height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex {
let colorBlendAmount: CGFloat = IME.isDarkMode() ? 0.25 : 0
// The background color of the highlightened candidate
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
NSColor.systemRed.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
case InputMode.imeModeCHT:
NSColor.systemBlue.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
default:
NSColor.alternateSelectedControlColor.setFill()
}
// Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84)
// Highlightened phrase text color
activeCandidateAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
} else {
NSColor.controlBackgroundColor.setFill()
}
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case InputMode.imeModeCHT:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hant" as AnyObject
}
default:
break
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuHeight += currentHeight
}
}
case false:
do {
var accuWidth: CGFloat = 0
for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth
let rctCandidateArea = NSRect(
x: accuWidth, y: 0.0, width: currentWidth + 1.0,
height: candidateTextHeight + cellPadding
)
let rctLabel = NSRect(
x: accuWidth + cellPadding / 2 - 1, y: cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: accuWidth + keyLabelWidth - 1, y: cellPadding / 2 - 1,
width: currentWidth - keyLabelWidth,
height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex {
let colorBlendAmount: CGFloat = IME.isDarkMode() ? 0.25 : 0
// The background color of the highlightened candidate
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
NSColor.systemRed.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
case InputMode.imeModeCHT:
NSColor.systemBlue.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
default:
NSColor.alternateSelectedControlColor.setFill()
}
// Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84)
// Highlightened phrase text color
activeCandidateAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
} else {
NSColor.controlBackgroundColor.setFill()
}
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case InputMode.imeModeCHT:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hant" as AnyObject
}
default:
break
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuWidth += currentWidth + 1.0
}
}
}
}
private func findHitIndex(event: NSEvent) -> Int {
let location = convert(event.locationInWindow, to: nil)
if !bounds.contains(location) {
return NSNotFound
}
switch isVerticalLayout {
case true:
do {
var accuHeight: CGFloat = 0.0
for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight
if location.y >= accuHeight, location.y <= accuHeight + currentHeight {
return index
}
accuHeight += currentHeight
}
}
case false:
do {
var accuWidth: CGFloat = 0.0
for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth
if location.x >= accuWidth, location.x <= accuWidth + currentWidth {
return index
}
accuWidth += currentWidth + 1.0
}
}
}
return NSNotFound
}
override func mouseUp(with event: NSEvent) {
trackingHighlightedIndex = highlightedIndex
let newIndex = findHitIndex(event: event)
guard newIndex != NSNotFound else {
return
}
highlightedIndex = newIndex
setNeedsDisplay(bounds)
}
override func mouseDown(with event: NSEvent) {
let newIndex = findHitIndex(event: event)
guard newIndex != NSNotFound else {
return
}
var triggerAction = false
if newIndex == highlightedIndex {
triggerAction = true
} else {
highlightedIndex = trackingHighlightedIndex
}
trackingHighlightedIndex = 0
setNeedsDisplay(bounds)
if triggerAction {
if let target = target as? NSObject, let action = action {
target.perform(action, with: self)
}
}
}
}
public class ctlCandidateUniversal: ctlCandidate {
private var candidateView: vwrCandidateUniversal
private var prevPageButton: NSButton
private var nextPageButton: NSButton
private var pageCounterLabel: NSTextField
private var currentPageIndex: Int = 0
override public var currentLayout: Layout {
get { candidateView.isVerticalLayout ? .vertical : .horizontal }
set {
switch newValue {
case .vertical: candidateView.isVerticalLayout = true
case .horizontal: candidateView.isVerticalLayout = false
}
}
}
public init(_ layout: Layout = .horizontal) {
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
let panel = NSPanel(
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
)
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1)
panel.hasShadow = true
panel.isOpaque = false
panel.backgroundColor = NSColor.clear
contentRect.origin = NSPoint.zero
candidateView = vwrCandidateUniversal(frame: contentRect)
candidateView.wantsLayer = true
candidateView.layer?.borderColor =
NSColor.selectedMenuItemTextColor.withAlphaComponent(0.10).cgColor
candidateView.layer?.borderWidth = 1.0
if #available(macOS 10.13, *) {
candidateView.layer?.cornerRadius = 6.0
}
panel.contentView?.addSubview(candidateView)
// MARK: Add Buttons
contentRect.size = NSSize(width: 20.0, height: 10.0) // Reduce the button width
let buttonAttribute: [NSAttributedString.Key: Any] = [.font: NSFont.systemFont(ofSize: 9.0)]
nextPageButton = .init(frame: contentRect)
NSColor.controlBackgroundColor.setFill()
NSBezierPath.fill(nextPageButton.bounds)
nextPageButton.wantsLayer = true
nextPageButton.layer?.masksToBounds = true
nextPageButton.layer?.borderColor = NSColor.clear.cgColor
nextPageButton.layer?.borderWidth = 0.0
nextPageButton.setButtonType(.momentaryLight)
nextPageButton.bezelStyle = .disclosure
nextPageButton.userInterfaceLayoutDirection = .leftToRight
nextPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Next Page Arrow
prevPageButton = .init(frame: contentRect)
NSColor.controlBackgroundColor.setFill()
NSBezierPath.fill(prevPageButton.bounds)
prevPageButton.wantsLayer = true
prevPageButton.layer?.masksToBounds = true
prevPageButton.layer?.borderColor = NSColor.clear.cgColor
prevPageButton.layer?.borderWidth = 0.0
prevPageButton.setButtonType(.momentaryLight)
prevPageButton.bezelStyle = .disclosure
prevPageButton.userInterfaceLayoutDirection = .rightToLeft
prevPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Previous Page Arrow
panel.contentView?.addSubview(nextPageButton)
panel.contentView?.addSubview(prevPageButton)
// MARK: Add Page Counter
contentRect.size = NSSize(width: 40.0, height: 20.0)
pageCounterLabel = .init(frame: contentRect)
pageCounterLabel.isEditable = false
pageCounterLabel.isSelectable = false
pageCounterLabel.isBezeled = false
pageCounterLabel.textColor = NSColor(
red: 0.86, green: 0.86, blue: 0.86, alpha: 1.00
)
pageCounterLabel.drawsBackground = true
pageCounterLabel.backgroundColor = NSColor(
red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00
)
panel.contentView?.addSubview(pageCounterLabel)
// MARK: Post-Init()
super.init(window: panel)
currentLayout = layout
candidateView.target = self
candidateView.action = #selector(candidateViewMouseDidClick(_:))
nextPageButton.target = self
nextPageButton.action = #selector(pageButtonAction(_:))
prevPageButton.target = self
prevPageButton.action = #selector(pageButtonAction(_:))
pageCounterLabel.font = pageCounterFont
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func reloadData() {
candidateView.highlightedIndex = 0
currentPageIndex = 0
layoutCandidateView()
}
override public func showNextPage() -> Bool {
guard delegate != nil else { return false }
if pageCount == 1 { return highlightNextCandidate() }
if currentPageIndex + 1 >= pageCount { clsSFX.beep() }
currentPageIndex = (currentPageIndex + 1 >= pageCount) ? 0 : currentPageIndex + 1
candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
override public func showPreviousPage() -> Bool {
guard delegate != nil else { return false }
if pageCount == 1 { return highlightPreviousCandidate() }
if currentPageIndex == 0 { clsSFX.beep() }
currentPageIndex = (currentPageIndex == 0) ? pageCount - 1 : currentPageIndex - 1
candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
override public func highlightNextCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex + 1 >= delegate.candidateCountForController(self))
? 0 : selectedCandidateIndex + 1
return true
}
override public func highlightPreviousCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex == 0)
? delegate.candidateCountForController(self) - 1 : selectedCandidateIndex - 1
return true
}
override public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int {
guard let delegate = delegate else {
return Int.max
}
let result = currentPageIndex * keyLabels.count + index
return result < delegate.candidateCountForController(self) ? result : Int.max
}
override public var selectedCandidateIndex: Int {
get {
currentPageIndex * keyLabels.count + candidateView.highlightedIndex
}
set {
guard let delegate = delegate else {
return
}
let keyLabelCount = keyLabels.count
if newValue < delegate.candidateCountForController(self) {
currentPageIndex = newValue / keyLabelCount
candidateView.highlightedIndex = newValue % keyLabelCount
layoutCandidateView()
}
}
}
}
extension ctlCandidateUniversal {
private var pageCount: Int {
guard let delegate = delegate else {
return 0
}
let totalCount = delegate.candidateCountForController(self)
let keyLabelCount = keyLabels.count
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
}
// NSFont nil guard-let
private var pageCounterFont: NSFont? {
var pointSize: CGFloat { candidateView.fractionFontSize }
let systemFontDesc = NSFont.systemFont(ofSize: pointSize, weight: .light).fontDescriptor
let fractionFontDesc = systemFontDesc.addingAttributes(
[
NSFontDescriptor.AttributeName.traits: [
[
NSFontDescriptor.FeatureKey.typeIdentifier: kFractionsType,
NSFontDescriptor.FeatureKey.selectorIdentifier: kDiagonalFractionsSelector,
]
]
]
)
return NSFont(descriptor: fractionFontDesc, size: pointSize) ?? nil
}
//
// TODO: pageCount 調
private var pageCounterText: String {
if pageCount < 2 { return .init() }
return "\(currentPageIndex + 1)/"
}
private func layoutCandidateView() {
guard let delegate = delegate else {
return
}
candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont)
var candidates = [String]()
let count = delegate.candidateCountForController(self)
let keyLabelCount = keyLabels.count
let begin = currentPageIndex * keyLabelCount
for index in begin..<min(begin + keyLabelCount, count) {
let candidate = delegate.ctlCandidate(self, candidateAtIndex: index)
candidates.append(candidate)
}
candidateView.set(
keyLabels: keyLabels.map(\.displayedText), displayedCandidates: candidates
)
var newSize = candidateView.sizeForView
var frameRect = candidateView.frame
frameRect.size = newSize
candidateView.frame = frameRect
let counterHeight: CGFloat = newSize.height - 24
if pageCount > 1, mgrPrefs.showPageButtonsInCandidateWindow {
var buttonRect = nextPageButton.frame
let spacing: CGFloat = 0.0
if currentLayout == .horizontal { buttonRect.size.height = floor(newSize.height / 2) }
let buttonOriginY: CGFloat = {
if currentLayout == .vertical {
return counterHeight
}
return (newSize.height - (buttonRect.size.height * 2.0 + spacing)) / 2.0
}()
buttonRect.origin = NSPoint(x: newSize.width, y: buttonOriginY)
nextPageButton.frame = buttonRect
buttonRect.origin = NSPoint(
x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing
)
prevPageButton.frame = buttonRect
newSize.width += 20
nextPageButton.isHidden = false
prevPageButton.isHidden = false
} else {
nextPageButton.isHidden = true
prevPageButton.isHidden = true
}
if !pageCounterText.isEmpty {
let attrString = NSAttributedString(
string: pageCounterText.appending(String(pageCount)),
attributes: [
.font: pageCounterFont as AnyObject
]
)
pageCounterLabel.attributedStringValue = attrString
var rect = attrString.boundingRect(
with: NSSize(width: 1600.0, height: 1600.0),
options: .usesLineFragmentOrigin
)
rect.size.height += 3
let rectOriginY: CGFloat =
(currentLayout == .horizontal)
? (newSize.height - rect.height) / 2
: counterHeight
let rectOriginX: CGFloat =
mgrPrefs.showPageButtonsInCandidateWindow
? newSize.width
: newSize.width + 4
rect.origin = NSPoint(x: rectOriginX, y: rectOriginY)
pageCounterLabel.frame = rect
newSize.width += rect.width + 4
pageCounterLabel.isHidden = false
} else {
pageCounterLabel.isHidden = true
}
frameRect = window?.frame ?? NSRect.zero
let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height)
frameRect.size = newSize
frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height)
window?.setFrame(frameRect, display: false)
candidateView.setNeedsDisplay(candidateView.bounds)
}
@objc private func pageButtonAction(_ sender: Any) {
guard let sender = sender as? NSButton else {
return
}
if sender == nextPageButton {
_ = showNextPage()
} else if sender == prevPageButton {
_ = showPreviousPage()
}
}
@objc private func candidateViewMouseDidClick(_: Any) {
delegate?.ctlCandidate(self, didSelectCandidateAtIndex: selectedCandidateIndex)
}
}

View File

@ -1,478 +0,0 @@
// Copyright (c) 2011 and onwards The OpenVanilla Project (MIT License).
// All possible vChewing-specific modifications are of:
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
2. No trademark license is granted to use the trade names, trademarks, service
marks, or product names of Contributor, except as required to fulfill notice
requirements above.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import Cocoa
private class VerticalCandidateView: NSView {
var highlightedIndex: UInt = 0
var action: Selector?
weak var target: AnyObject?
private var keyLabels: [String] = []
private var displayedCandidates: [String] = []
private var dispCandidatesWithLabels: [String] = []
private var keyLabelHeight: CGFloat = 0
private var keyLabelWidth: CGFloat = 0
private var candidateTextHeight: CGFloat = 0
private var cellPadding: CGFloat = 0
private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var windowWidth: CGFloat = 0
private var elementWidths: [CGFloat] = []
private var elementHeights: [CGFloat] = []
private var trackingHighlightedIndex: UInt = .max
override var isFlipped: Bool {
true
}
var sizeForView: NSSize {
var result = NSSize.zero
if !elementWidths.isEmpty {
result.width = windowWidth
result.height = elementHeights.reduce(0, +)
}
return result
}
@objc(setKeyLabels:displayedCandidates:)
func set(keyLabels labels: [String], displayedCandidates candidates: [String]) {
let count = min(labels.count, candidates.count)
keyLabels = Array(labels[0..<count])
displayedCandidates = Array(candidates[0..<count])
dispCandidatesWithLabels = zip(keyLabels, displayedCandidates).map { $0 + $1 }
var newWidths = [CGFloat]()
var calculatedWindowWidth = CGFloat()
var newHeights = [CGFloat]()
let baseSize = NSSize(width: 10240.0, height: 10240.0)
for index in 0..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
with: baseSize, options: .usesLineFragmentOrigin,
attributes: candidateWithLabelAttrDict
)
let cellWidth = rctCandidate.size.width + cellPadding
let cellHeight = rctCandidate.size.height + cellPadding
if calculatedWindowWidth < rctCandidate.size.width {
calculatedWindowWidth = rctCandidate.size.width + cellPadding
}
newWidths.append(cellWidth)
newHeights.append(cellHeight)
}
elementWidths = newWidths
elementHeights = newHeights
windowWidth = round(calculatedWindowWidth + cellPadding) //
}
@objc(setKeyLabelFont:candidateFont:)
func set(keyLabelFont labelFont: NSFont, candidateFont: NSFont) {
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .left
candidateWithLabelAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // We still need this dummy section to make sure that
// the space occupations of the candidates are correct.
keyLabelAttrDict = [
.font: labelFont,
.paragraphStyle: paraStyle,
.verticalGlyphForm: true as AnyObject,
.foregroundColor: NSColor.secondaryLabelColor,
] // Candidate phrase text color
candidateAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // Candidate index text color
let labelFontSize = labelFont.pointSize
let candidateFontSize = candidateFont.pointSize
let biggestSize = max(labelFontSize, candidateFontSize)
keyLabelWidth = ceil(labelFontSize)
keyLabelHeight = ceil(labelFontSize * 2)
candidateTextHeight = ceil(candidateFontSize * 1.20)
cellPadding = ceil(biggestSize / 4.0) * 2
}
override func draw(_: NSRect) {
let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds)
NSColor.systemGray.withAlphaComponent(0.75).setStroke()
NSBezierPath.strokeLine(
from: NSPoint(x: bounds.size.width, y: 0.0),
to: NSPoint(x: bounds.size.width, y: bounds.size.height)
)
var accuHeight: CGFloat = 0
for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight
let rctCandidateArea = NSRect(
x: 0.0, y: accuHeight, width: windowWidth, height: candidateTextHeight + cellPadding
)
let rctLabel = NSRect(
x: cellPadding / 2 - 1, y: accuHeight + cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: cellPadding / 2 - 1 + keyLabelWidth, y: accuHeight + cellPadding / 2 - 1,
width: windowWidth - keyLabelWidth, height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex {
let colorBlendAmount: CGFloat = IME.isDarkMode() ? 0.25 : 0
// The background color of the highlightened candidate
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
NSColor.systemRed.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
case InputMode.imeModeCHT:
NSColor.systemBlue.blended(
withFraction: colorBlendAmount,
of: NSColor.controlBackgroundColor
)!
.setFill()
default:
NSColor.alternateSelectedControlColor.setFill()
}
// Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84)
// Highlightened phrase text color
activeCandidateAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
} else {
NSColor.controlBackgroundColor.setFill()
}
switch ctlInputMethod.currentKeyHandler.inputMode {
case InputMode.imeModeCHS:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hans" as AnyObject
}
case InputMode.imeModeCHT:
if #available(macOS 12.0, *) {
activeCandidateAttr[.languageIdentifier] = "zh-Hant" as AnyObject
}
default:
break
}
NSBezierPath.fill(rctCandidateArea)
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuHeight += currentHeight
}
}
private func findHitIndex(event: NSEvent) -> UInt? {
let location = convert(event.locationInWindow, to: nil)
if !bounds.contains(location) {
return nil
}
var accuHeight: CGFloat = 0.0
for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight
if location.y >= accuHeight, location.y <= accuHeight + currentHeight {
return UInt(index)
}
accuHeight += currentHeight
}
return nil
}
override func mouseUp(with event: NSEvent) {
trackingHighlightedIndex = highlightedIndex
guard let newIndex = findHitIndex(event: event) else {
return
}
highlightedIndex = newIndex
setNeedsDisplay(bounds)
}
override func mouseDown(with event: NSEvent) {
guard let newIndex = findHitIndex(event: event) else {
return
}
var triggerAction = false
if newIndex == highlightedIndex {
triggerAction = true
} else {
highlightedIndex = trackingHighlightedIndex
}
trackingHighlightedIndex = 0
setNeedsDisplay(bounds)
if triggerAction {
if let target = target as? NSObject, let action = action {
target.perform(action, with: self)
}
}
}
}
public class ctlCandidateVertical: ctlCandidate {
private var candidateView: VerticalCandidateView
private var prevPageButton: NSButton
private var nextPageButton: NSButton
private var currentPageIndex: UInt = 0
public init() {
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
let panel = NSPanel(
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
)
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1)
panel.hasShadow = true
panel.isOpaque = false
panel.backgroundColor = NSColor.clear
contentRect.origin = NSPoint.zero
candidateView = VerticalCandidateView(frame: contentRect)
candidateView.wantsLayer = true
candidateView.layer?.borderColor =
NSColor.selectedMenuItemTextColor.withAlphaComponent(0.10).cgColor
candidateView.layer?.borderWidth = 1.0
if #available(macOS 10.13, *) {
candidateView.layer?.cornerRadius = 6.0
}
panel.contentView?.addSubview(candidateView)
contentRect.size = NSSize(width: 20.0, height: 10.0) // Reduce the button width
let buttonAttribute: [NSAttributedString.Key: Any] = [.font: NSFont.systemFont(ofSize: 9.0)]
nextPageButton = NSButton(frame: contentRect)
NSColor.controlBackgroundColor.setFill()
NSBezierPath.fill(nextPageButton.bounds)
nextPageButton.wantsLayer = true
nextPageButton.layer?.masksToBounds = true
nextPageButton.layer?.borderColor = NSColor.clear.cgColor
nextPageButton.layer?.borderWidth = 0.0
nextPageButton.setButtonType(.momentaryLight)
nextPageButton.bezelStyle = .disclosure
nextPageButton.userInterfaceLayoutDirection = .leftToRight
nextPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Next Page Arrow
prevPageButton = NSButton(frame: contentRect)
NSColor.controlBackgroundColor.setFill()
NSBezierPath.fill(prevPageButton.bounds)
prevPageButton.wantsLayer = true
prevPageButton.layer?.masksToBounds = true
prevPageButton.layer?.borderColor = NSColor.clear.cgColor
prevPageButton.layer?.borderWidth = 0.0
prevPageButton.setButtonType(.momentaryLight)
prevPageButton.bezelStyle = .disclosure
prevPageButton.userInterfaceLayoutDirection = .rightToLeft
prevPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Previous Page Arrow
panel.contentView?.addSubview(nextPageButton)
panel.contentView?.addSubview(prevPageButton)
super.init(window: panel)
candidateView.target = self
candidateView.action = #selector(candidateViewMouseDidClick(_:))
nextPageButton.target = self
nextPageButton.action = #selector(pageButtonAction(_:))
prevPageButton.target = self
prevPageButton.action = #selector(pageButtonAction(_:))
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func reloadData() {
candidateView.highlightedIndex = 0
currentPageIndex = 0
layoutCandidateView()
}
override public func showNextPage() -> Bool {
guard delegate != nil else { return false }
if pageCount == 1 { return highlightNextCandidate() }
if currentPageIndex + 1 >= pageCount { clsSFX.beep() }
currentPageIndex = (currentPageIndex + 1 >= pageCount) ? 0 : currentPageIndex + 1
candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
override public func showPreviousPage() -> Bool {
guard delegate != nil else { return false }
if pageCount == 1 { return highlightPreviousCandidate() }
if currentPageIndex == 0 { clsSFX.beep() }
currentPageIndex = (currentPageIndex == 0) ? pageCount - 1 : currentPageIndex - 1
candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
override public func highlightNextCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex + 1 >= delegate.candidateCountForController(self))
? 0 : selectedCandidateIndex + 1
return true
}
override public func highlightPreviousCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex == 0)
? delegate.candidateCountForController(self) - 1 : selectedCandidateIndex - 1
return true
}
override public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt {
guard let delegate = delegate else {
return UInt.max
}
let result = currentPageIndex * UInt(keyLabels.count) + index
return result < delegate.candidateCountForController(self) ? result : UInt.max
}
override public var selectedCandidateIndex: UInt {
get {
currentPageIndex * UInt(keyLabels.count) + candidateView.highlightedIndex
}
set {
guard let delegate = delegate else {
return
}
let keyLabelCount = UInt(keyLabels.count)
if newValue < delegate.candidateCountForController(self) {
currentPageIndex = newValue / keyLabelCount
candidateView.highlightedIndex = newValue % keyLabelCount
layoutCandidateView()
}
}
}
}
extension ctlCandidateVertical {
private var pageCount: UInt {
guard let delegate = delegate else {
return 0
}
let totalCount = delegate.candidateCountForController(self)
let keyLabelCount = UInt(keyLabels.count)
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
}
private func layoutCandidateView() {
guard let delegate = delegate else {
return
}
candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont)
var candidates = [String]()
let count = delegate.candidateCountForController(self)
let keyLabelCount = UInt(keyLabels.count)
let begin = currentPageIndex * keyLabelCount
for index in begin..<min(begin + keyLabelCount, count) {
let candidate = delegate.ctlCandidate(self, candidateAtIndex: index)
candidates.append(candidate)
}
candidateView.set(
keyLabels: keyLabels.map(\.displayedText), displayedCandidates: candidates
)
var newSize = candidateView.sizeForView
var frameRect = candidateView.frame
frameRect.size = newSize
candidateView.frame = frameRect
if pageCount > 1, mgrPrefs.showPageButtonsInCandidateWindow {
var buttonRect = nextPageButton.frame
let spacing: CGFloat = 0.0
// buttonRect.size.height = floor(candidateTextHeight + cellPadding / 2)
let buttonOriginY = (newSize.height - (buttonRect.size.height * 2.0 + spacing)) // / 2.0
buttonRect.origin = NSPoint(x: newSize.width, y: buttonOriginY)
nextPageButton.frame = buttonRect
buttonRect.origin = NSPoint(
x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing
)
prevPageButton.frame = buttonRect
newSize.width += 20
nextPageButton.isHidden = false
prevPageButton.isHidden = false
} else {
nextPageButton.isHidden = true
prevPageButton.isHidden = true
}
frameRect = window?.frame ?? NSRect.zero
let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height)
frameRect.size = newSize
frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height)
window?.setFrame(frameRect, display: false)
candidateView.setNeedsDisplay(candidateView.bounds)
}
@objc private func pageButtonAction(_ sender: Any) {
guard let sender = sender as? NSButton else {
return
}
if sender == nextPageButton {
_ = showNextPage()
} else if sender == prevPageButton {
_ = showPreviousPage()
}
}
@objc private func candidateViewMouseDidClick(_: Any) {
delegate?.ctlCandidate(self, didSelectCandidateAtIndex: selectedCandidateIndex)
}
}

View File

@ -35,6 +35,8 @@ struct suiPrefPaneDictionary: View {
@State private var selEnableCNS11643: Bool = UserDefaults.standard.bool(forKey: UserDef.kCNS11643Enabled)
@State private var selEnableSymbolInputSupport: Bool = UserDefaults.standard.bool(
forKey: UserDef.kSymbolInputEnabled)
@State private var selAllowBoostingSingleKanjiAsUserPhrase: Bool = UserDefaults.standard.bool(
forKey: UserDef.kAllowBoostingSingleKanjiAsUserPhrase)
private let contentWidth: Double = {
switch mgrPrefs.appleLanguages[0] {
case "ja":
@ -65,7 +67,7 @@ struct suiPrefPaneDictionary: View {
IME.dlgOpenPath.canChooseDirectories = true
let bolPreviousFolderValidity = mgrLangModel.checkIfSpecifiedUserDataFolderValid(
NSString(string: mgrPrefs.userDataFolderSpecified).expandingTildeInPath)
mgrPrefs.userDataFolderSpecified.expandingTildeInPath)
if let window = ctlPrefUI.shared.controller.window {
IME.dlgOpenPath.beginSheetModal(for: window) { result in
@ -113,11 +115,14 @@ struct suiPrefPaneDictionary: View {
mgrPrefs.shouldAutoReloadUserDataFiles = value
}
Divider()
Toggle(LocalizedStringKey("Enable CNS11643 Support (2022-04-27)"), isOn: $selEnableCNS11643)
.onChange(of: selEnableCNS11643) { value in
mgrPrefs.cns11643Enabled = value
mgrLangModel.setCNSEnabled(value)
}
Toggle(
LocalizedStringKey("Enable CNS11643 Support (2022-04-27)"),
isOn: $selEnableCNS11643
)
.onChange(of: selEnableCNS11643) { value in
mgrPrefs.cns11643Enabled = value
mgrLangModel.setCNSEnabled(value)
}
Toggle(
LocalizedStringKey("Enable symbol input support (incl. certain emoji symbols)"),
isOn: $selEnableSymbolInputSupport
@ -126,6 +131,13 @@ struct suiPrefPaneDictionary: View {
mgrPrefs.symbolInputEnabled = value
mgrLangModel.setSymbolEnabled(value)
}
Toggle(
LocalizedStringKey("Allow boosting / excluding a candidate of single kanji"),
isOn: $selAllowBoostingSingleKanjiAsUserPhrase
)
.onChange(of: selAllowBoostingSingleKanjiAsUserPhrase) { value in
mgrPrefs.allowBoostingSingleKanjiAsUserPhrase = value
}
}
}
}

View File

@ -126,7 +126,13 @@ struct suiPrefPaneGeneral: View {
.preferenceDescription()
Toggle(
LocalizedStringKey("Show page buttons in candidate window"), isOn: $selShowPageButtonsInCandidateUI
).controlSize(.small)
).onChange(
of: selShowPageButtonsInCandidateUI,
perform: { value in
mgrPrefs.showPageButtonsInCandidateWindow = value
}
)
.controlSize(.small)
}
Preferences.Section(bottomDivider: true, label: { Text(LocalizedStringKey("Output Settings:")) }) {
Toggle(

View File

@ -27,8 +27,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import Cocoa
public class TooltipController: NSWindowController {
static var backgroundColor = NSColor.windowBackgroundColor
static var textColor = NSColor.windowBackgroundColor
public enum ColorStates {
case normal
case redAlert
case warning
case denialOverflow
case denialInsufficiency
case prompt
}
private var backgroundColor = NSColor.windowBackgroundColor
private var textColor = NSColor.windowBackgroundColor
private var messageTextField: NSTextField
private var tooltip: String = "" {
didSet {
@ -50,12 +59,11 @@ public class TooltipController: NSWindowController {
messageTextField.isEditable = false
messageTextField.isSelectable = false
messageTextField.isBezeled = false
messageTextField.textColor = TooltipController.textColor
messageTextField.textColor = textColor
messageTextField.drawsBackground = true
messageTextField.backgroundColor = TooltipController.backgroundColor
messageTextField.backgroundColor = backgroundColor
messageTextField.font = .systemFont(ofSize: NSFont.systemFontSize(for: .small))
panel.contentView?.addSubview(messageTextField)
super.init(window: panel)
}
@ -65,13 +73,56 @@ public class TooltipController: NSWindowController {
}
public func show(tooltip: String, at point: NSPoint) {
messageTextField.textColor = TooltipController.textColor
messageTextField.backgroundColor = TooltipController.backgroundColor
messageTextField.textColor = textColor
messageTextField.backgroundColor = backgroundColor
self.tooltip = tooltip
window?.orderFront(nil)
set(windowLocation: point)
}
public func setColor(state: ColorStates) {
switch state {
case .normal:
backgroundColor = NSColor(
red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00
)
textColor = NSColor.white
case .redAlert:
backgroundColor = NSColor(
red: 0.55, green: 0.00, blue: 0.00, alpha: 1.00
)
textColor = NSColor.white
case .warning:
backgroundColor = NSColor.purple
textColor = NSColor.white
case .denialOverflow:
backgroundColor = NSColor(
red: 0.13, green: 0.08, blue: 0.00, alpha: 1.00
)
textColor = NSColor(
red: 1.00, green: 0.60, blue: 0.00, alpha: 1.00
)
case .denialInsufficiency:
backgroundColor = NSColor(
red: 0.18, green: 0.18, blue: 0.18, alpha: 1.00
)
textColor = NSColor(
red: 0.86, green: 0.86, blue: 0.86, alpha: 1.00
)
case .prompt:
backgroundColor = NSColor(
red: 0.00, green: 0.18, blue: 0.13, alpha: 1.00
)
textColor = NSColor(
red: 0.00, green: 1.00, blue: 0.74, alpha: 1.00
)
}
}
public func resetColor() {
setColor(state: .normal)
}
@objc
public func hide() {
window?.orderOut(nil)

View File

@ -44,7 +44,8 @@ class ctlNonModalAlertWindow: NSWindowController {
title: String, content: String, confirmButtonTitle: String, cancelButtonTitle: String?,
cancelAsDefault: Bool, delegate: ctlNonModalAlertWindowDelegate?
) {
if window?.isVisible == true {
guard let window = window else { return }
if window.isVisible == true {
self.delegate?.ctlNonModalAlertWindowDidCancel(self)
}
@ -76,13 +77,13 @@ class ctlNonModalAlertWindow: NSWindowController {
if cancelButtonTitle != nil {
if cancelAsDefault {
window?.defaultButtonCell = cancelButton.cell as? NSButtonCell
window.defaultButtonCell = cancelButton.cell as? NSButtonCell
} else {
cancelButton.keyEquivalent = " "
window?.defaultButtonCell = confirmButton.cell as? NSButtonCell
window.defaultButtonCell = confirmButton.cell as? NSButtonCell
}
} else {
window?.defaultButtonCell = confirmButton.cell as? NSButtonCell
window.defaultButtonCell = confirmButton.cell as? NSButtonCell
}
titleTextField.stringValue = title
@ -103,12 +104,12 @@ class ctlNonModalAlertWindow: NSWindowController {
newFrame.origin.y -= (newFrame.size.height - oldFrame.size.height)
contentTextField.frame = newFrame
var windowFrame = window?.frame ?? NSRect.zero
var windowFrame = window.frame
windowFrame.size.height += (newFrame.size.height - oldFrame.size.height)
window?.level = NSWindow.Level(Int(CGShieldingWindowLevel()) + 1)
window?.setFrame(windowFrame, display: true)
window?.center()
window?.makeKeyAndOrderFront(self)
window.level = NSWindow.Level(Int(CGShieldingWindowLevel()) + 1)
window.setFrame(windowFrame, display: true)
window.center()
window.makeKeyAndOrderFront(self)
NSApp.activate(ignoringOtherApps: true)
}

View File

@ -263,7 +263,7 @@ class ctlPrefWindow: NSWindowController {
IME.dlgOpenPath.canChooseDirectories = true
let bolPreviousFolderValidity = mgrLangModel.checkIfSpecifiedUserDataFolderValid(
NSString(string: mgrPrefs.userDataFolderSpecified).expandingTildeInPath)
mgrPrefs.userDataFolderSpecified.expandingTildeInPath)
if window != nil {
IME.dlgOpenPath.beginSheetModal(for: window!) { result in

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -680,9 +681,9 @@
</connections>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="p7V-IN-OTr">
<rect key="frame" x="19" y="295.5" width="406" height="17"/>
<rect key="frame" x="19" y="296.5" width="406" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="KGx-QR-wgI"/>
<constraint firstAttribute="height" constant="16" id="Ieq-hl-01l"/>
</constraints>
<buttonCell key="cell" type="check" title="Automatically reload user data files if changes detected" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="f8i-69-zxm">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -693,9 +694,9 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="O4B-Z2-XYi">
<rect key="frame" x="19" y="273.5" width="406" height="17"/>
<rect key="frame" x="19" y="274.5" width="406" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="60g-xI-n1n"/>
<constraint firstAttribute="height" constant="16" id="2gi-B5-vjz"/>
</constraints>
<buttonCell key="cell" type="check" title="Enable symbol input support (incl. certain emoji symbols)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="hSv-LJ-Cq3" userLabel="chkSymbolEnabled">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -735,9 +736,9 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Yaj-QY-7xV" userLabel="chkCNSSupport">
<rect key="frame" x="19" y="251.5" width="406" height="17"/>
<rect key="frame" x="19" y="252.5" width="406" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="XP3-SR-9Ha"/>
<constraint firstAttribute="height" constant="16" id="vin-Cj-dDq"/>
</constraints>
<buttonCell key="cell" type="check" title="Enable CNS11643 Support (2022-04-27)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="W24-T4-cg0">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -748,28 +749,44 @@
<binding destination="32" name="value" keyPath="values.CNS11643Enabled" id="Pbx-Gt-upm"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Hyc-Nw-dET">
<rect key="frame" x="19" y="230.5" width="406" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="drz-HW-cX1"/>
</constraints>
<buttonCell key="cell" type="check" title="Allow boosting / excluding a candidate of single kanji" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="chkAllowBoostingSingleKanjiAsUserPhrase" userLabel="chkAllowBoostingSingleKanjiAsUserPhrase">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
<connections>
<binding destination="32" name="value" keyPath="values.AllowBoostingSingleKanjiAsUserPhrase" id="jiw-1V-C7x"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="s7t-Kk-EPu" firstAttribute="bottom" secondItem="MPN-np-SbT" secondAttribute="bottom" id="0Fo-ya-hQ9"/>
<constraint firstItem="O4B-Z2-XYi" firstAttribute="trailing" secondItem="Yaj-QY-7xV" secondAttribute="trailing" id="2VU-kM-5xJ"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="leading" secondItem="O4B-Z2-XYi" secondAttribute="leading" id="6GG-yw-MYi"/>
<constraint firstItem="O4B-Z2-XYi" firstAttribute="top" secondItem="p7V-IN-OTr" secondAttribute="bottom" constant="6" symbolic="YES" id="6H0-cT-DDa"/>
<constraint firstAttribute="trailing" secondItem="FUV-qx-xkC" secondAttribute="trailing" constant="20" symbolic="YES" id="6QR-tj-5cH"/>
<constraint firstItem="O4B-Z2-XYi" firstAttribute="top" secondItem="p7V-IN-OTr" secondAttribute="bottom" constant="6" id="6tf-H0-CKc"/>
<constraint firstItem="Yaj-QY-7xV" firstAttribute="trailing" secondItem="Hyc-Nw-dET" secondAttribute="trailing" id="6ty-e2-2yl"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="leading" secondItem="s7t-Kk-EPu" secondAttribute="leading" id="7KG-BW-e6E"/>
<constraint firstItem="s7t-Kk-EPu" firstAttribute="leading" secondItem="MPN-np-SbT" secondAttribute="trailing" constant="-376" id="9at-E8-Bt1"/>
<constraint firstItem="FUV-qx-xkC" firstAttribute="top" secondItem="cy4-aV-hhk" secondAttribute="top" constant="15" id="BZE-dD-V2R"/>
<constraint firstItem="MPN-np-SbT" firstAttribute="top" secondItem="FUV-qx-xkC" secondAttribute="bottom" constant="14" id="Bp9-2u-f9E"/>
<constraint firstItem="Yaj-QY-7xV" firstAttribute="leading" secondItem="Hyc-Nw-dET" secondAttribute="leading" id="DJV-E7-Wgv"/>
<constraint firstItem="Yaj-QY-7xV" firstAttribute="top" secondItem="O4B-Z2-XYi" secondAttribute="bottom" constant="6" symbolic="YES" id="F6l-lB-OT5"/>
<constraint firstItem="FUV-qx-xkC" firstAttribute="leading" secondItem="cy4-aV-hhk" secondAttribute="leading" constant="20" symbolic="YES" id="Hy2-ZC-cvb"/>
<constraint firstItem="Hyc-Nw-dET" firstAttribute="top" secondItem="Yaj-QY-7xV" secondAttribute="bottom" constant="6" symbolic="YES" id="OCz-SW-av6"/>
<constraint firstItem="s7t-Kk-EPu" firstAttribute="firstBaseline" secondItem="MPN-np-SbT" secondAttribute="baseline" id="OYH-gA-WcA"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="trailing" secondItem="O4B-Z2-XYi" secondAttribute="trailing" id="Phu-Qi-Xup"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="top" secondItem="s7t-Kk-EPu" secondAttribute="bottom" constant="15" id="PyP-N9-MWb"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="leading" secondItem="s7t-Kk-EPu" secondAttribute="leading" id="QMQ-hR-c5W"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="trailing" secondItem="jXe-xz-9Sd" secondAttribute="trailing" id="QQv-cA-dO9"/>
<constraint firstItem="FUV-qx-xkC" firstAttribute="leading" secondItem="MPN-np-SbT" secondAttribute="leading" constant="-346" id="Zet-wH-kmC"/>
<constraint firstItem="O4B-Z2-XYi" firstAttribute="leading" secondItem="Yaj-QY-7xV" secondAttribute="leading" id="aI8-ll-ybr"/>
<constraint firstItem="jXe-xz-9Sd" firstAttribute="leading" secondItem="MPN-np-SbT" secondAttribute="trailing" constant="-1" id="cYQ-Rx-tuG"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="leading" secondItem="O4B-Z2-XYi" secondAttribute="leading" id="dm5-TK-PRw"/>
<constraint firstItem="O4B-Z2-XYi" firstAttribute="leading" secondItem="Yaj-QY-7xV" secondAttribute="leading" id="qHY-fz-P9H"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="trailing" secondItem="jXe-xz-9Sd" secondAttribute="trailing" id="uuG-Bg-2Vi"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="top" secondItem="s7t-Kk-EPu" secondAttribute="bottom" constant="14.5" id="hJ9-p8-clP"/>
<constraint firstItem="O4B-Z2-XYi" firstAttribute="trailing" secondItem="Yaj-QY-7xV" secondAttribute="trailing" id="pZC-Vr-DTa"/>
<constraint firstItem="p7V-IN-OTr" firstAttribute="trailing" secondItem="O4B-Z2-XYi" secondAttribute="trailing" id="s0C-8F-wWy"/>
<constraint firstItem="s7t-Kk-EPu" firstAttribute="trailing" secondItem="FUV-qx-xkC" secondAttribute="trailing" constant="-60" id="vIO-x1-7Q2"/>
<constraint firstItem="jXe-xz-9Sd" firstAttribute="baseline" secondItem="MPN-np-SbT" secondAttribute="baseline" id="wys-ML-2Q2"/>
<constraint firstItem="Yaj-QY-7xV" firstAttribute="top" secondItem="O4B-Z2-XYi" secondAttribute="bottom" constant="6" symbolic="YES" id="zZg-M3-hSk"/>
</constraints>
</view>
</box>

View File

@ -20,8 +20,8 @@
/* Class = "NSTextFieldCell"; title = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, are not included in vChewing official phrase database."; ObjectID = "lblDisclaimer"; */
"lblDisclaimer.title" = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, are not included in vChewing official phrase database.";
/* Class = "NSTextFieldCell"; title = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "© 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "lblCredits"; */
"lblCredits.title" = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine.";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "lblCredits"; */
"lblCredits.title" = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.";

View File

@ -1,22 +1,33 @@
"1.title" = "vChewing Preferences";
"sZx-18-8dO.title" = "Debug Mode";
"5.title" = "OtherViews";
"6.title" = "Microsoft, Dachen, Wang, etc.";
"7.title" = "ETen";
"8.title" = "Hsu";
"9.title" = "ETen26";
"10.title" = "Hanyu Pinyin with Numeral Intonation";
"100.title" = "64";
"101.title" = "96";
"110.title" = "Enable Space key for calling candidate window";
"12.title" = "BPMF Parser:";
"126.title" = "Basic Layout:";
"128.title" = "OtherViews";
"137.title" = "IBM";
"14.title" = "Choose the cursor position where you want to list possible candidates.";
"16.title" = "Cursor in front of the phrase (like macOS built-in Zhuyin IME)";
"17.title" = "Cursor at the rear of the phrase (like Microsoft New Phonetic)";
"18.title" = "Radio";
"1AW-xf-c2f.label" = "Keyboard";
"20.title" = "Radio";
"21.title" = "Horizontal";
"22.title" = "Vertical";
"shc-Nu-UsM.title" = "Show page buttons in candidate list";
"24.title" = "Candidate List Layout:";
"27F-8T-FkQ.title" = "Fake Seigyou (similar to JinYei)";
"29.title" = "Candidate UI font size:";
"2iG-Ic-gbl.label" = "Dictionary";
"2pS-nv-te4.title" = "Choose which keys you prefer for selecting candidates.";
"2Y6-Am-WM1.title" = "General Settings";
"5.title" = "OtherViews";
"6.title" = "Microsoft, Dachen, Wang, etc.";
"62u-jY-BRh.title" = "Stop farting (when typed phonetic combination is invalid, etc.)";
"7.title" = "ETen";
"7fV-x8-WHQ.title" = "MiTAC";
"8.title" = "Hsu";
"9.title" = "ETen26";
"92.title" = "OtherViews";
"93.title" = "12";
"94.title" = "14";
@ -24,68 +35,58 @@
"96.title" = "18";
"98.title" = "24";
"99.title" = "32";
"100.title" = "64";
"101.title" = "96";
"110.title" = "Enable Space key for calling candidate window";
"126.title" = "Basic Layout:";
"128.title" = "OtherViews";
"137.title" = "IBM";
"7fV-x8-WHQ.title" = "MiTAC";
"27F-8T-FkQ.title" = "Fake Seigyou (similar to JinYei)";
"1AW-xf-c2f.label" = "Keyboard";
"2Y6-Am-WM1.title" = "General Settings";
"2pS-nv-te4.title" = "Choose which keys you prefer for selecting candidates.";
"62u-jY-BRh.title" = "Stop farting (when typed phonetic combination is invalid, etc.)";
"9DS-Rc-TXq.title" = "UI language setting:";
"akC-2g-ybz.title" = "Simplified Chinese";
"ArK-Vk-OoT.title" = "Emulating select-candidate-per-character mode";
"BSK-bH-Gct.title" = "Auto-convert traditional Chinese glyphs to KangXi characters";
"eia-1F-Do0.title" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters";
"cf2-se-PDO.title" = "Dictionary and Language Models";
"chkAllowBoostingSingleKanjiAsUserPhrase.title" = "Allow boosting / excluding a candidate of single kanji";
"dIN-TZ-67g.title" = "Space to +cycle candidates, Shift+Space to +cycle pages";
"E1l-m8-xgb.title" = "Advanced Settings";
"FSG-lN-CJO.title" = "English";
"FnD-oH-El5.title" = "Selection Keys:";
"GlJ-Ns-9eE.title" = "Auto-Select";
"QUQ-oY-4Hc.label" = "General";
"RQ6-MS-m4C.title" = "Choose your preferred keyboard layout and phonetic parser.";
"RUG-ls-KyA.title" = "Push the cursor in front of the phrase after selection";
"TXr-FF-ehw.title" = "Traditional Chinese";
"Uyz-xL-TVN.title" = "Output Settings";
"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-04-27)";
"Wvt-HE-LOv.title" = "Keyboard Layout";
"Z9t-P0-BLF.title" = "Check for updates automatically";
"ZEv-Q2-mYL.title" = "Change user interface language (will reboot the IME).";
"akC-2g-ybz.title" = "Simplified Chinese";
"eia-1F-Do0.title" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters";
"f2j-xD-4xK.title" = "Use ESC key to clear the entire input buffer";
"f8i-69-zxm.title" = "Automatically reload user data files if changes detected";
"FnD-oH-El5.title" = "Selection Keys:";
"FSG-lN-CJO.title" = "English";
"FVC-br-H57.title" = "Cycling Candidates";
"GlJ-Ns-9eE.title" = "Auto-Select";
"hSv-LJ-Cq3.title" = "Enable symbol input support (incl. certain emoji symbols)";
"iRg-wx-Nx2.title" = "Change UI font size of candidate window for a better visual clarity.";
"iWy-Nw-QKB.title" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
"jQC-12-UuK.ibShadowedObjectValues[0]" = "Item 1";
"jQC-12-UuK.ibShadowedObjectValues[1]" = "Item 2";
"jQC-12-UuK.ibShadowedObjectValues[2]" = "Item 3";
"rVQ-Hx-cGi.title" = "Japanese";
"cf2-se-PDO.title" = "Dictionary and Language Models";
"xC5-yV-1W1.title" = "Choose your preferred layout of the candidate window.";
"xrE-8T-WKO.label" = "Advanced";
"2iG-Ic-gbl.label" = "Dictionary";
"wQ9-px-b07.title" = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";
"ueU-Rz-a1C.title" = "Choose the behavior of (Shift+)Tab key in the candidate window.";
"s7u-Fm-dVg.title" = "Cycling Pages";
"FVC-br-H57.title" = "Cycling Candidates";
"Pg5-G9-pY5.title" = "Choose the behavior of (Shift+)Space key with candidates.";
"XqL-rf-X6d.title" = "Space to +cycle pages, Shift+Space to +cycle candidates";
"dIN-TZ-67g.title" = "Space to +cycle candidates, Shift+Space to +cycle pages";
"hSv-LJ-Cq3.title" = "Enable symbol input support (incl. certain emoji symbols)";
"wN3-k3-b2a.title" = "Choose your desired user data folder path. Will be omitted if invalid.";
"wFR-zX-M8H.title" = "Show Hanyu-Pinyin in the inline composition buffer";
"iWy-Nw-QKB.title" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
"xjP-r7-GaK.title" = "Dachen 26 (libChewing)";
"Parser11.title" = "Secondary Pinyin with Numeral Intonation";
"Parser12.title" = "Yale Pinyin with Numeral Intonation";
"Parser13.title" = "Hualuo Pinyin with Numeral Intonation";
"Parser14.title" = "Universal Pinyin with Numeral Intonation";
"Pg5-G9-pY5.title" = "Choose the behavior of (Shift+)Space key with candidates.";
"QUQ-oY-4Hc.label" = "General";
"RQ6-MS-m4C.title" = "Choose your preferred keyboard layout and phonetic parser.";
"RUG-ls-KyA.title" = "Push the cursor in front of the phrase after selection";
"rVQ-Hx-cGi.title" = "Japanese";
"s7u-Fm-dVg.title" = "Cycling Pages";
"shc-Nu-UsM.title" = "Show page buttons in candidate list";
"sZx-18-8dO.title" = "Debug Mode";
"TXr-FF-ehw.title" = "Traditional Chinese";
"ueU-Rz-a1C.title" = "Choose the behavior of (Shift+)Tab key in the candidate window.";
"Uyz-xL-TVN.title" = "Output Settings";
"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-04-27)";
"wFR-zX-M8H.title" = "Show Hanyu-Pinyin in the inline composition buffer";
"wN3-k3-b2a.title" = "Choose your desired user data folder path. Will be omitted if invalid.";
"wQ9-px-b07.title" = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";
"Wvt-HE-LOv.title" = "Keyboard Layout";
"xC5-yV-1W1.title" = "Choose your preferred layout of the candidate window.";
"xibKeyboardShortcuts.title" = "Keyboard Shortcuts";
"xibUsingHotKeySCPC.title" = "Per-Char Select Mode";
"xibLabelBufferLimit.title" = "Buffer Limit:";
"xibUsingHotKeyAssociates.title" = "Per-Char Associated Phrases";
"xibUsingHotKeyCNS.title" = "CNS11643 Mode";
"xibUsingHotKeyKangXi.title" = "Force KangXi Writing";
"xibUsingHotKeyJIS.title" = "JIS Shinjitai Output";
"xibUsingHotKeyHalfWidthASCII.title" = "Half-Width Punctuation Mode";
"xibLabelBufferLimit.title" = "Buffer Limit:";
"xibUsingHotKeyJIS.title" = "JIS Shinjitai Output";
"xibUsingHotKeyKangXi.title" = "Force KangXi Writing";
"xibUsingHotKeySCPC.title" = "Per-Char Select Mode";
"xjP-r7-GaK.title" = "Dachen 26 (libChewing)";
"XqL-rf-X6d.title" = "Space to +cycle pages, Shift+Space to +cycle candidates";
"xrE-8T-WKO.label" = "Advanced";
"Z9t-P0-BLF.title" = "Check for updates automatically";
"ZEv-Q2-mYL.title" = "Change user interface language (will reboot the IME).";

View File

@ -20,8 +20,8 @@
/* Class = "NSTextFieldCell"; title = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, are not included in vChewing official phrase database."; ObjectID = "lblDisclaimer"; */
"lblDisclaimer.title" = "免責事項vChewing Project は、OpenVanilla と協力関係や提携関係にあるわけではなく、OpenVanilla が小麦注音プロジェクトに同梱した辞書データについて、vChewing Project は一切責任負い兼ねる。特定な地政学的・観念形態的な内容は、vChewing アプリの世界的な普及に妨害する恐れがあるため、vChewing 公式辞書データに不収録。";
/* Class = "NSTextFieldCell"; title = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "© 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "lblCredits"; */
"lblCredits.title" = "鉄恨ボポモフォエンジン開発Shiki Suen。\n入力状態管理システム開発Zonble Yang。\nmacOS 版威注音の開発Shiki Suen, Isaac Xen, Hiraku Wang, など。\n威注音語彙データの維持Shiki Suen。\nMegrez 辞書処理エンジンShiki SuenLukhnos の Gramambular C++ エンジンを Swift で再開発したものである)。";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "lblCredits"; */
"lblCredits.title" = "macOS 版威注音の開発Shiki Suen, Isaac Xen, Hiraku Wang, など。\n威注音語彙データの維持Shiki Suen。";

View File

@ -1,22 +1,33 @@
"1.title" = "威注音アプリ機能設定";
"sZx-18-8dO.title" = "欠陥辿着モード";
"5.title" = "OtherViews";
"6.title" = "大千配列Microsoft 標準・王安など)";
"7.title" = "倚天伝統配列";
"8.title" = "許氏国音自然配列";
"9.title" = "倚天形忘れ配列 (26キー)";
"10.title" = "漢語弁音(ローマ字+数字音調)";
"100.title" = "64";
"101.title" = "96";
"110.title" = "Space キーで入力候補を呼び出す";
"12.title" = "注音配列:";
"126.title" = "基礎キーボード:";
"128.title" = "OtherViews";
"137.title" = "IBM 配列";
"14.title" = "カーソルはどこで入力候補を呼び出すかとご選択ください:";
"16.title" = "単語の前で // macOS 内蔵注音入力のやり方";
"17.title" = "単語の後で // Microsoft 新注音入力のやり方";
"18.title" = "Radio";
"1AW-xf-c2f.label" = "キーボード";
"20.title" = "Radio";
"21.title" = "横型陳列";
"22.title" = "縦型陳列";
"shc-Nu-UsM.title" = "ページボタンを表示";
"24.title" = "入力候補陳列の仕様:";
"27F-8T-FkQ.title" = "偽精業配列";
"29.title" = "候補文字の字号:";
"2iG-Ic-gbl.label" = "辞書";
"2pS-nv-te4.title" = "お好きなる言選り用キー陣列をお選びください。";
"2Y6-Am-WM1.title" = "全般設定";
"5.title" = "OtherViews";
"6.title" = "大千配列Microsoft 標準・王安など)";
"62u-jY-BRh.title" = "マナーモード // 外すと入力間違の時に変な音が出る";
"7.title" = "倚天伝統配列";
"7fV-x8-WHQ.title" = "神通配列";
"8.title" = "許氏国音自然配列";
"9.title" = "倚天形忘れ配列 (26キー)";
"92.title" = "OtherViews";
"93.title" = "12";
"94.title" = "14";
@ -24,68 +35,58 @@
"96.title" = "18";
"98.title" = "24";
"99.title" = "32";
"100.title" = "64";
"101.title" = "96";
"110.title" = "Space キーで入力候補を呼び出す";
"126.title" = "基礎キーボード:";
"128.title" = "OtherViews";
"137.title" = "IBM 配列";
"7fV-x8-WHQ.title" = "神通配列";
"27F-8T-FkQ.title" = "偽精業配列";
"1AW-xf-c2f.label" = "キーボード";
"2Y6-Am-WM1.title" = "全般設定";
"2pS-nv-te4.title" = "お好きなる言選り用キー陣列をお選びください。";
"62u-jY-BRh.title" = "マナーモード // 外すと入力間違の時に変な音が出る";
"9DS-Rc-TXq.title" = "アプリ表示用言語:";
"akC-2g-ybz.title" = "簡体中国語";
"ArK-Vk-OoT.title" = "漢字1つづつ全候補選択入力モード";
"BSK-bH-Gct.title" = "入力した繁体字を康熙字体と自動変換";
"eia-1F-Do0.title" = "入力した繁体字を日文 JIS 新字体と自動変換";
"cf2-se-PDO.title" = "辞書と言語モデル";
"chkAllowBoostingSingleKanjiAsUserPhrase.title" = "即排除/即最優先にできる候補の文字数の最低限は1字とする";
"dIN-TZ-67g.title" = "Shift+Space で次のページ、Space で次の候補文字を";
"E1l-m8-xgb.title" = "詳細設定";
"FSG-lN-CJO.title" = "英語";
"FnD-oH-El5.title" = "言選り用キー:";
"GlJ-Ns-9eE.title" = "システム設定に準ずる";
"QUQ-oY-4Hc.label" = "全般";
"RQ6-MS-m4C.title" = "お好きなるキーボードとそれに相応しい注音配列をお選びください。";
"RUG-ls-KyA.title" = "候補選択の直後、すぐカーソルを単語の向こうに推す";
"TXr-FF-ehw.title" = "繁体中国語";
"Uyz-xL-TVN.title" = "出力設定";
"W24-T4-cg0.title" = "全字庫モード // 入力可能の漢字数倍増 (2022-04-27)";
"Wvt-HE-LOv.title" = "キーボード";
"Z9t-P0-BLF.title" = "アプリの更新通知を受く";
"ZEv-Q2-mYL.title" = "アプリ表示用言語をご指定ください、そして入力アプリは自動的に再起動。";
"akC-2g-ybz.title" = "簡体中国語";
"eia-1F-Do0.title" = "入力した繁体字を日文 JIS 新字体と自動変換";
"f2j-xD-4xK.title" = "ESC キーで入力緩衝列を消す";
"f8i-69-zxm.title" = "変更されたユーザー辞書データを自動的に再読込";
"FnD-oH-El5.title" = "言選り用キー:";
"FSG-lN-CJO.title" = "英語";
"FVC-br-H57.title" = "候補文字そのもの";
"GlJ-Ns-9eE.title" = "システム設定に準ずる";
"hSv-LJ-Cq3.title" = "僅かなる絵文字も含む符号入力サポートを起用";
"iRg-wx-Nx2.title" = "入力候補陣列の候補文字の字号をご指定ください。";
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter で出すのを漢語弁音と変換";
"jQC-12-UuK.ibShadowedObjectValues[0]" = "Item 1";
"jQC-12-UuK.ibShadowedObjectValues[1]" = "Item 2";
"jQC-12-UuK.ibShadowedObjectValues[2]" = "Item 3";
"rVQ-Hx-cGi.title" = "和語";
"cf2-se-PDO.title" = "辞書と言語モデル";
"xC5-yV-1W1.title" = "入力候補陳列の仕様をご指定ください。";
"xrE-8T-WKO.label" = "詳細";
"2iG-Ic-gbl.label" = "辞書";
"wQ9-px-b07.title" = "Apple 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の注音配列を大千と設定すべきである。";
"ueU-Rz-a1C.title" = "入力候補陳列での (Shift+)Tab キーの輪番切替対象をご指定ください。";
"s7u-Fm-dVg.title" = "ページ";
"FVC-br-H57.title" = "候補文字そのもの";
"Pg5-G9-pY5.title" = "入力候補についての (Shift+)Space キーの輪番切替対象をご指定ください。";
"XqL-rf-X6d.title" = "Space で次のページ、Shift+Space で次の候補文字を";
"dIN-TZ-67g.title" = "Shift+Space で次のページ、Space で次の候補文字を";
"hSv-LJ-Cq3.title" = "僅かなる絵文字も含む符号入力サポートを起用";
"wN3-k3-b2a.title" = "欲しがるユーザー辞書保存先をご指定ください。無効の保存先設定は効かぬ。";
"wFR-zX-M8H.title" = "弁音合併入力(入力緩衝列で代わりに漢語弁音の音読み)";
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter で出すのを漢語弁音と変換";
"xjP-r7-GaK.title" = "酷音大千 26 キー配列";
"Parser11.title" = "国音二式 (ローマ字+数字音調)";
"Parser12.title" = "イェール弁音 (ローマ字+数字音調)";
"Parser13.title" = "中華ローマ弁音 (ローマ字+数字音調)";
"Parser14.title" = "汎用弁音 (ローマ字+数字音調)";
"Pg5-G9-pY5.title" = "入力候補についての (Shift+)Space キーの輪番切替対象をご指定ください。";
"QUQ-oY-4Hc.label" = "全般";
"RQ6-MS-m4C.title" = "お好きなるキーボードとそれに相応しい注音配列をお選びください。";
"RUG-ls-KyA.title" = "候補選択の直後、すぐカーソルを単語の向こうに推す";
"rVQ-Hx-cGi.title" = "和語";
"s7u-Fm-dVg.title" = "ページ";
"shc-Nu-UsM.title" = "ページボタンを表示";
"sZx-18-8dO.title" = "欠陥辿着モード";
"TXr-FF-ehw.title" = "繁体中国語";
"ueU-Rz-a1C.title" = "入力候補陳列での (Shift+)Tab キーの輪番切替対象をご指定ください。";
"Uyz-xL-TVN.title" = "出力設定";
"W24-T4-cg0.title" = "全字庫モード // 入力可能の漢字数倍増 (2022-04-27)";
"wFR-zX-M8H.title" = "弁音合併入力(入力緩衝列で代わりに漢語弁音の音読み)";
"wN3-k3-b2a.title" = "欲しがるユーザー辞書保存先をご指定ください。無効の保存先設定は効かぬ。";
"wQ9-px-b07.title" = "Apple 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の注音配列を大千と設定すべきである。";
"Wvt-HE-LOv.title" = "キーボード";
"xC5-yV-1W1.title" = "入力候補陳列の仕様をご指定ください。";
"xibKeyboardShortcuts.title" = "ショートカット";
"xibUsingHotKeySCPC.title" = "全候補入力モード";
"xibLabelBufferLimit.title" = "緩衝列の容量:";
"xibUsingHotKeyAssociates.title" = "全候補入力で連想語彙";
"xibUsingHotKeyCNS.title" = "全字庫モード";
"xibUsingHotKeyKangXi.title" = "康熙文字変換モード";
"xibUsingHotKeyJIS.title" = "JIS 新字体モード";
"xibUsingHotKeyHalfWidthASCII.title" = "半角句読モード";
"xibLabelBufferLimit.title" = "緩衝列の容量:";
"xibUsingHotKeyJIS.title" = "JIS 新字体モード";
"xibUsingHotKeyKangXi.title" = "康熙文字変換モード";
"xibUsingHotKeySCPC.title" = "全候補入力モード";
"xjP-r7-GaK.title" = "酷音大千 26 キー配列";
"XqL-rf-X6d.title" = "Space で次のページ、Shift+Space で次の候補文字を";
"xrE-8T-WKO.label" = "詳細";
"Z9t-P0-BLF.title" = "アプリの更新通知を受く";
"ZEv-Q2-mYL.title" = "アプリ表示用言語をご指定ください、そして入力アプリは自動的に再起動。";

View File

@ -20,8 +20,8 @@
/* Class = "NSTextFieldCell"; title = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, are not included in vChewing official phrase database."; ObjectID = "lblDisclaimer"; */
"lblDisclaimer.title" = "免责声明:威注音专案对小麦注音官方专案内赠的小麦注音原版词库内容不负任何责任。威注音输入法专用的威注音官方词库不包含任何「会在法理上妨碍威注音在全球传播」的「与地缘政治及政治意识形态有关的」内容。威注音专案与 OpenVanilla 专案之间无合作关系、无隶属关系。";
/* Class = "NSTextFieldCell"; title = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "© 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "lblCredits"; */
"lblCredits.title" = "铁恨注音并击输入处理引擎研发Shiki Suen。\n输入法状态管理引擎研发Zonble Yang。\n威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护Shiki Suen。\n天权星语汇引擎Shiki Suen用 Swift 将 Lukhnos 的 C++ Gramambular 重写而得。";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "lblCredits"; */
"lblCredits.title" = "威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护Shiki Suen。";

View File

@ -1,22 +1,33 @@
"1.title" = "威注音偏好设定";
"sZx-18-8dO.title" = "侦错模式";
"5.title" = "OtherViews";
"6.title" = "微软/大千/王安/国乔/零壹/仲鼎";
"7.title" = "倚天传统";
"8.title" = "许氏(国音&自然)";
"9.title" = "倚天二十六键";
"10.title" = "汉语拼音+数字标调";
"100.title" = "64";
"101.title" = "96";
"110.title" = "敲空格键以选字";
"12.title" = "基础键盘布局:";
"126.title" = "英数键盘布局:";
"128.title" = "OtherViews";
"137.title" = "IBM";
"14.title" = "用以触发选字的光标相对位置:";
"16.title" = "光标置于词语前方 // macOS 内建注音风格";
"17.title" = "光标置于词语后方 // Windows 微软新注音风格";
"18.title" = "Radio";
"1AW-xf-c2f.label" = "键盘";
"20.title" = "Radio";
"21.title" = "横向布局";
"22.title" = "纵向布局";
"shc-Nu-UsM.title" = "在选字窗内显示翻页按钮";
"24.title" = "候选字窗布局:";
"27F-8T-FkQ.title" = "伪精业";
"29.title" = "字型大小设定:";
"2iG-Ic-gbl.label" = "辞典";
"2pS-nv-te4.title" = "选择您所偏好的用来选字的按键组合。";
"2Y6-Am-WM1.title" = "一般设定";
"5.title" = "OtherViews";
"6.title" = "微软/大千/王安/国乔/零壹/仲鼎";
"62u-jY-BRh.title" = "廉耻模式 // 取消勾选的话,敲错字时会有异音";
"7.title" = "倚天传统";
"7fV-x8-WHQ.title" = "神通";
"8.title" = "许氏(国音&自然)";
"9.title" = "倚天二十六键";
"92.title" = "OtherViews";
"93.title" = "12";
"94.title" = "14";
@ -24,68 +35,59 @@
"96.title" = "18";
"98.title" = "24";
"99.title" = "32";
"100.title" = "64";
"101.title" = "96";
"110.title" = "敲空格键以选字";
"126.title" = "英数键盘布局:";
"128.title" = "OtherViews";
"137.title" = "IBM";
"7fV-x8-WHQ.title" = "神通";
"27F-8T-FkQ.title" = "伪精业";
"1AW-xf-c2f.label" = "键盘";
"2Y6-Am-WM1.title" = "一般设定";
"2pS-nv-te4.title" = "选择您所偏好的用来选字的按键组合。";
"62u-jY-BRh.title" = "廉耻模式 // 取消勾选的话,敲错字时会有异音";
"9DS-Rc-TXq.title" = "接口语言设定:";
"akC-2g-ybz.title" = "简体中文";
"ArK-Vk-OoT.title" = "仿真 90 年代前期注音逐字选字输入风格";
"BSK-bH-Gct.title" = "自动将繁体中文字转换为康熙正体字";
"eia-1F-Do0.title" = "自动将繁体中文字转换为日本简化字JIS 新字体)";
"cf2-se-PDO.title" = "辞典&語言模型";
"chkAllowBoostingSingleKanjiAsUserPhrase.title" = "将可以就地升权/排除的候选字词的最短词长设为单个汉字";
"chkAllowBoostingSingleKanjiAsUserPhrase.title" = "Allow boosting / excluding a candidate of single kanji";
"dIN-TZ-67g.title" = "Shift+Space 换下一页Space 换选下一个候选字。";
"E1l-m8-xgb.title" = "进阶设定";
"FSG-lN-CJO.title" = "英文";
"FnD-oH-El5.title" = "选字键:";
"GlJ-Ns-9eE.title" = "自动选择";
"QUQ-oY-4Hc.label" = "一般";
"RQ6-MS-m4C.title" = "选择您所偏好的系统键盘布局与注音分析器排列。";
"RUG-ls-KyA.title" = "在选字后将光标置于该字词的前方";
"TXr-FF-ehw.title" = "繁体中文";
"Uyz-xL-TVN.title" = "输出设定";
"W24-T4-cg0.title" = "启用 CNS11643 全字库支援 (2022-04-27)";
"Wvt-HE-LOv.title" = "键盘布局";
"Z9t-P0-BLF.title" = "自动检查软件更新";
"ZEv-Q2-mYL.title" = "变更使用者接口语言,会自动重新启动输入法。";
"akC-2g-ybz.title" = "简体中文";
"eia-1F-Do0.title" = "自动将繁体中文字转换为日本简化字JIS 新字体)";
"f2j-xD-4xK.title" = "敲 ESC 键以清空整个输入缓冲区";
"f8i-69-zxm.title" = "自动重新加载变更过的使用者资料内容";
"FnD-oH-El5.title" = "选字键:";
"FSG-lN-CJO.title" = "英文";
"FVC-br-H57.title" = "轮替候选字";
"GlJ-Ns-9eE.title" = "自动选择";
"hSv-LJ-Cq3.title" = "启用包括少许绘文字在内的符号输入支援";
"iRg-wx-Nx2.title" = "变更候选字窗的字型大小。";
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 输出汉语拼音而非注音";
"jQC-12-UuK.ibShadowedObjectValues[0]" = "Item 1";
"jQC-12-UuK.ibShadowedObjectValues[1]" = "Item 2";
"jQC-12-UuK.ibShadowedObjectValues[2]" = "Item 3";
"rVQ-Hx-cGi.title" = "和语";
"cf2-se-PDO.title" = "辞典&語言模型";
"xC5-yV-1W1.title" = "选择您所偏好的候选字窗布局。";
"xrE-8T-WKO.label" = "进阶";
"2iG-Ic-gbl.label" = "辞典";
"wQ9-px-b07.title" = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器的注音排列得配置为大千排列。";
"ueU-Rz-a1C.title" = "指定 (Shift+)Tab 热键在选字窗内的轮替操作对象。";
"s7u-Fm-dVg.title" = "轮替页面";
"FVC-br-H57.title" = "轮替候选字";
"Pg5-G9-pY5.title" = "指定 (Shift+)Space 热键对候选字词而言的轮替操作对象。";
"XqL-rf-X6d.title" = "Space 换下一页Shift+Space 换选下一个候选字。";
"dIN-TZ-67g.title" = "Shift+Space 换下一页Space 换选下一个候选字。";
"hSv-LJ-Cq3.title" = "启用包括少许绘文字在内的符号输入支援";
"wN3-k3-b2a.title" = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。";
"wFR-zX-M8H.title" = "拼音并击模式(组字区内看到的是汉语拼音)";
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 输出汉语拼音而非注音";
"xjP-r7-GaK.title" = "酷音大千二十六键";
"Parser11.title" = "国音二式+数字标调";
"Parser12.title" = "耶鲁拼音+数字标调";
"Parser13.title" = "华罗拼音+数字标调";
"Parser14.title" = "通用拼音+数字标调";
"Pg5-G9-pY5.title" = "指定 (Shift+)Space 热键对候选字词而言的轮替操作对象。";
"QUQ-oY-4Hc.label" = "一般";
"RQ6-MS-m4C.title" = "选择您所偏好的系统键盘布局与注音分析器排列。";
"RUG-ls-KyA.title" = "在选字后将光标置于该字词的前方";
"rVQ-Hx-cGi.title" = "和语";
"s7u-Fm-dVg.title" = "轮替页面";
"shc-Nu-UsM.title" = "在选字窗内显示翻页按钮";
"sZx-18-8dO.title" = "侦错模式";
"TXr-FF-ehw.title" = "繁体中文";
"ueU-Rz-a1C.title" = "指定 (Shift+)Tab 热键在选字窗内的轮替操作对象。";
"Uyz-xL-TVN.title" = "输出设定";
"W24-T4-cg0.title" = "启用 CNS11643 全字库支援 (2022-04-27)";
"wFR-zX-M8H.title" = "拼音并击模式(组字区内看到的是汉语拼音)";
"wN3-k3-b2a.title" = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。";
"wQ9-px-b07.title" = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器的注音排列得配置为大千排列。";
"Wvt-HE-LOv.title" = "键盘布局";
"xC5-yV-1W1.title" = "选择您所偏好的候选字窗布局。";
"xibKeyboardShortcuts.title" = "键盘快捷键";
"xibUsingHotKeySCPC.title" = "模拟逐字选字输入";
"xibLabelBufferLimit.title" = "组字区容量:";
"xibUsingHotKeyAssociates.title" = "逐字选字联想模式";
"xibUsingHotKeyCNS.title" = "全字库模式";
"xibUsingHotKeyKangXi.title" = "康熙正体字模式";
"xibUsingHotKeyJIS.title" = "JIS 新字体模式";
"xibUsingHotKeyHalfWidthASCII.title" = "半形标点模式";
"xibLabelBufferLimit.title" = "组字区容量:";
"xibUsingHotKeyJIS.title" = "JIS 新字体模式";
"xibUsingHotKeyKangXi.title" = "康熙正体字模式";
"xibUsingHotKeySCPC.title" = "模拟逐字选字输入";
"xjP-r7-GaK.title" = "酷音大千二十六键";
"XqL-rf-X6d.title" = "Space 换下一页Shift+Space 换选下一个候选字。";
"xrE-8T-WKO.label" = "进阶";
"Z9t-P0-BLF.title" = "自动检查软件更新";
"ZEv-Q2-mYL.title" = "变更使用者接口语言,会自动重新启动输入法。";

View File

@ -20,8 +20,8 @@
/* Class = "NSTextFieldCell"; title = "DISCLAIMER: The vChewing project, having no relationship of cooperation or affiliation with the OpenVanilla project, is not responsible for the phrase database shipped in the original McBopomofo project. Certain geopolitical and ideological contents, which are potentially harmful to the global spread of this software, are not included in vChewing official phrase database."; ObjectID = "lblDisclaimer"; */
"lblDisclaimer.title" = "免責聲明:威注音專案對小麥注音官方專案內贈的小麥注音原版詞庫內容不負任何責任。威注音輸入法專用的威注音官方詞庫不包含任何「會在法理上妨礙威注音在全球傳播」的「與地緣政治及政治意識形態有關的」內容。威註音專案與 OpenVanilla 專案之間無合作關係、無隸屬關係。";
/* Class = "NSTextFieldCell"; title = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "© 2021-2022 vChewing Project."; ObjectID = "lblCopyright"; */
// "lblCopyright.title" = "© 2021-2022 vChewing Project.";
/* Class = "NSTextFieldCell"; title = "Tekkon Syllable Composition Engine by Shiki Suen.\nInput State Management Architecture by Zonble Yang.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen.\nMegrez is a rewritten unigram engine by Shiki Suen using Swift, replacing Lukhnos' C++ Gramambular engine."; ObjectID = "lblCredits"; */
"lblCredits.title" = "鐵恨注音並擊輸入處理引擎研發Shiki Suen。\n輸入法狀態管理引擎研發Zonble Yang。\n威注音 macOS 程式研發Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音詞庫維護Shiki Suen。\n天權星語彙引擎Shiki Suen用 Swift 將 Lukhnos 的 C++ Gramambular 重寫而得。";
/* Class = "NSTextFieldCell"; title = "vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.\nvChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "lblCredits"; */
"lblCredits.title" = "威注音 macOS 程式研发Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护Shiki Suen。";

View File

@ -1,22 +1,33 @@
"1.title" = "威注音偏好設定";
"sZx-18-8dO.title" = "偵錯模式";
"5.title" = "OtherViews";
"6.title" = "微軟/大千/王安/國喬/零壹/仲鼎";
"7.title" = "倚天傳統";
"8.title" = "許氏(國音&自然)";
"9.title" = "倚天二十六鍵";
"10.title" = "漢語拼音+數字標調";
"100.title" = "64";
"101.title" = "96";
"110.title" = "敲空格鍵以選字";
"12.title" = "注音排列:";
"126.title" = "基礎鍵盤佈局:";
"128.title" = "OtherViews";
"137.title" = "IBM";
"14.title" = "用以觸發選字的游標相對位置:";
"16.title" = "游標置於詞語前方 // macOS 內建注音風格";
"17.title" = "游標置於詞語後方 // Windows 微軟新注音風格";
"18.title" = "Radio";
"1AW-xf-c2f.label" = "鍵盤";
"20.title" = "Radio";
"21.title" = "橫向佈局";
"22.title" = "縱向佈局";
"shc-Nu-UsM.title" = "在選字窗內顯示翻頁按鈕";
"24.title" = "候選字窗佈局:";
"27F-8T-FkQ.title" = "偽精業";
"29.title" = "字型大小設定:";
"2iG-Ic-gbl.label" = "辭典";
"2pS-nv-te4.title" = "選擇您所偏好的用來選字的按鍵組合。";
"2Y6-Am-WM1.title" = "一般設定";
"5.title" = "OtherViews";
"6.title" = "微軟/大千/王安/國喬/零壹/仲鼎";
"62u-jY-BRh.title" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音";
"7.title" = "倚天傳統";
"7fV-x8-WHQ.title" = "神通";
"8.title" = "許氏(國音&自然)";
"9.title" = "倚天二十六鍵";
"92.title" = "OtherViews";
"93.title" = "12";
"94.title" = "14";
@ -24,68 +35,58 @@
"96.title" = "18";
"98.title" = "24";
"99.title" = "32";
"100.title" = "64";
"101.title" = "96";
"110.title" = "敲空格鍵以選字";
"126.title" = "基礎鍵盤佈局:";
"128.title" = "OtherViews";
"137.title" = "IBM";
"7fV-x8-WHQ.title" = "神通";
"27F-8T-FkQ.title" = "偽精業";
"1AW-xf-c2f.label" = "鍵盤";
"2Y6-Am-WM1.title" = "一般設定";
"2pS-nv-te4.title" = "選擇您所偏好的用來選字的按鍵組合。";
"62u-jY-BRh.title" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音";
"9DS-Rc-TXq.title" = "介面語言設定:";
"akC-2g-ybz.title" = "簡體中文";
"ArK-Vk-OoT.title" = "模擬 90 年代前期注音逐字選字輸入風格";
"BSK-bH-Gct.title" = "自動將繁體中文字轉換為康熙正體字";
"eia-1F-Do0.title" = "自動將繁體中文字轉換為日本簡化字JIS 新字體)";
"cf2-se-PDO.title" = "辭典&語言模型";
"chkAllowBoostingSingleKanjiAsUserPhrase.title" = "將可以就地升權/排除的候選字詞的最短詞長設為單個漢字";
"dIN-TZ-67g.title" = "Shift+Space 換下一頁Space 換選下一個候選字";
"E1l-m8-xgb.title" = "進階設定";
"FSG-lN-CJO.title" = "英文";
"FnD-oH-El5.title" = "選字鍵:";
"GlJ-Ns-9eE.title" = "自動選擇";
"QUQ-oY-4Hc.label" = "一般";
"RQ6-MS-m4C.title" = "選擇您所偏好的系統鍵盤佈局與注音分析器排列。";
"RUG-ls-KyA.title" = "在選字後將游標置於該字詞的前方";
"TXr-FF-ehw.title" = "繁體中文";
"Uyz-xL-TVN.title" = "輸出設定";
"W24-T4-cg0.title" = "啟用 CNS11643 全字庫支援 (2022-04-27)";
"Wvt-HE-LOv.title" = "鍵盤佈局";
"Z9t-P0-BLF.title" = "自動檢查軟體更新";
"ZEv-Q2-mYL.title" = "變更使用者介面語言,會自動重新啟動輸入法。";
"akC-2g-ybz.title" = "簡體中文";
"eia-1F-Do0.title" = "自動將繁體中文字轉換為日本簡化字JIS 新字體)";
"f2j-xD-4xK.title" = "敲 ESC 鍵以清空整個輸入緩衝區";
"f8i-69-zxm.title" = "自動重新載入變更過的使用者數據內容";
"FnD-oH-El5.title" = "選字鍵:";
"FSG-lN-CJO.title" = "英文";
"FVC-br-H57.title" = "輪替候選字";
"GlJ-Ns-9eE.title" = "自動選擇";
"hSv-LJ-Cq3.title" = "啟用包括少許繪文字在內的符號輸入支援";
"iRg-wx-Nx2.title" = "變更候選字窗的字型大小。";
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 輸出漢語拼音而非注音";
"jQC-12-UuK.ibShadowedObjectValues[0]" = "Item 1";
"jQC-12-UuK.ibShadowedObjectValues[1]" = "Item 2";
"jQC-12-UuK.ibShadowedObjectValues[2]" = "Item 3";
"rVQ-Hx-cGi.title" = "和語";
"cf2-se-PDO.title" = "辭典&語言模型";
"xC5-yV-1W1.title" = "選擇您所偏好的候選字窗佈局。";
"xrE-8T-WKO.label" = "進階";
"2iG-Ic-gbl.label" = "辭典";
"wQ9-px-b07.title" = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器的注音排列得配置為大千排列。";
"ueU-Rz-a1C.title" = "指定 (Shift+)Tab 熱鍵在選字窗內的輪替操作對象。";
"s7u-Fm-dVg.title" = "輪替頁面";
"FVC-br-H57.title" = "輪替候選字";
"Pg5-G9-pY5.title" = "指定 (Shift+)Space 熱鍵對候選字詞而言的輪替操作對象。";
"XqL-rf-X6d.title" = "Space 換下一頁Shift+Space 換選下一個候選字";
"dIN-TZ-67g.title" = "Shift+Space 換下一頁Space 換選下一個候選字";
"hSv-LJ-Cq3.title" = "啟用包括少許繪文字在內的符號輸入支援";
"wN3-k3-b2a.title" = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。";
"wFR-zX-M8H.title" = "拼音並擊模式(組字區內看到的是漢語拼音)";
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 輸出漢語拼音而非注音";
"xjP-r7-GaK.title" = "酷音大千二十六鍵";
"Parser11.title" = "國音二式+數字標調";
"Parser12.title" = "耶魯拼音+數字標調";
"Parser13.title" = "華羅拼音+數字標調";
"Parser14.title" = "通用拼音+數字標調";
"Pg5-G9-pY5.title" = "指定 (Shift+)Space 熱鍵對候選字詞而言的輪替操作對象。";
"QUQ-oY-4Hc.label" = "一般";
"RQ6-MS-m4C.title" = "選擇您所偏好的系統鍵盤佈局與注音分析器排列。";
"RUG-ls-KyA.title" = "在選字後將游標置於該字詞的前方";
"rVQ-Hx-cGi.title" = "和語";
"s7u-Fm-dVg.title" = "輪替頁面";
"shc-Nu-UsM.title" = "在選字窗內顯示翻頁按鈕";
"sZx-18-8dO.title" = "偵錯模式";
"TXr-FF-ehw.title" = "繁體中文";
"ueU-Rz-a1C.title" = "指定 (Shift+)Tab 熱鍵在選字窗內的輪替操作對象。";
"Uyz-xL-TVN.title" = "輸出設定";
"W24-T4-cg0.title" = "啟用 CNS11643 全字庫支援 (2022-04-27)";
"wFR-zX-M8H.title" = "拼音並擊模式(組字區內看到的是漢語拼音)";
"wN3-k3-b2a.title" = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。";
"wQ9-px-b07.title" = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器的注音排列得配置為大千排列。";
"Wvt-HE-LOv.title" = "鍵盤佈局";
"xC5-yV-1W1.title" = "選擇您所偏好的候選字窗佈局。";
"xibKeyboardShortcuts.title" = "鍵盤快速鍵";
"xibUsingHotKeySCPC.title" = "模擬逐字選字輸入";
"xibLabelBufferLimit.title" = "組字區容量:";
"xibUsingHotKeyAssociates.title" = "逐字選字聯想模式";
"xibUsingHotKeyCNS.title" = "全字庫模式";
"xibUsingHotKeyKangXi.title" = "康熙正體字模式";
"xibUsingHotKeyJIS.title" = "JIS 新字體模式";
"xibUsingHotKeyHalfWidthASCII.title" = "半形標點模式";
"xibLabelBufferLimit.title" = "組字區容量:";
"xibUsingHotKeyJIS.title" = "JIS 新字體模式";
"xibUsingHotKeyKangXi.title" = "康熙正體字模式";
"xibUsingHotKeySCPC.title" = "模擬逐字選字輸入";
"xjP-r7-GaK.title" = "酷音大千二十六鍵";
"XqL-rf-X6d.title" = "Space 換下一頁Shift+Space 換選下一個候選字";
"xrE-8T-WKO.label" = "進階";
"Z9t-P0-BLF.title" = "自動檢查軟體更新";
"ZEv-Q2-mYL.title" = "變更使用者介面語言,會自動重新啟動輸入法。";

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>1.6.3</string>
<string>1.7.0</string>
<key>CFBundleVersion</key>
<string>1963</string>
<string>1970</string>
<key>UpdateInfoEndpoint</key>
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
<key>UpdateInfoSite</key>

View File

@ -726,7 +726,7 @@
<key>USE_HFS+_COMPRESSION</key>
<false/>
<key>VERSION</key>
<string>1.6.3</string>
<string>1.7.0</string>
</dict>
<key>TYPE</key>
<integer>0</integer>

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
5B0AF8B527B2C8290096FE54 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0AF8B427B2C8290096FE54 /* StringExtension.swift */; };
5B11328927B94CFB00E58451 /* AppleKeyboardConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B11328827B94CFB00E58451 /* AppleKeyboardConverter.swift */; };
5B242403284B0D6500520FE4 /* ctlCandidateUniversal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */; };
5B3133BF280B229700A4A505 /* KeyHandler_States.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3133BE280B229700A4A505 /* KeyHandler_States.swift */; };
5B38F59A281E2E49007D5F5D /* 6_Unigram.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1D15FC0EB100ABF4B3 /* 6_Unigram.swift */; };
5B38F59B281E2E49007D5F5D /* 7_KeyValuePair.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1815FC0EB100ABF4B3 /* 7_KeyValuePair.swift */; };
@ -28,11 +29,9 @@
5B62A32927AE77D100A19448 /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */; };
5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */; };
5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* mgrPrefs.swift */; };
5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33727AE79CD00A19448 /* NSStringUtils.swift */; };
5B62A33827AE79CD00A19448 /* StringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33727AE79CD00A19448 /* StringUtils.swift */; };
5B62A33D27AE7CC100A19448 /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */; };
5B62A34627AE7CD900A19448 /* ctlCandidateHorizontal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */; };
5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */; };
5B62A34827AE7CD900A19448 /* ctlCandidateVertical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34127AE7CD900A19448 /* ctlCandidateVertical.swift */; };
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34327AE7CD900A19448 /* TooltipController.swift */; };
5B62A34A27AE7CD900A19448 /* NotifierController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A34527AE7CD900A19448 /* NotifierController.swift */; };
5B62A35327AE89C400A19448 /* InputSourceHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */; };
@ -191,6 +190,7 @@
5B18BA7227C7BD8B0056EB19 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-JPN.txt"; sourceTree = "<group>"; };
5B18BA7427C7BD8C0056EB19 /* LICENSE-CHT.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-CHT.txt"; sourceTree = "<group>"; };
5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlCandidateUniversal.swift; sourceTree = "<group>"; };
5B2DB17127AF8771006D874E /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Data/Makefile; sourceTree = "<group>"; };
5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = vChewingKeyLayout.bundle; sourceTree = "<group>"; };
5B3133BE280B229700A4A505 /* KeyHandler_States.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = KeyHandler_States.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
@ -202,13 +202,12 @@
5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33127AE792F00A19448 /* InputSourceHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSourceHelper.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33727AE79CD00A19448 /* NSStringUtils.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = NSStringUtils.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33727AE79CD00A19448 /* StringUtils.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = StringUtils.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidateHorizontal.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A34127AE7CD900A19448 /* ctlCandidateVertical.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidateVertical.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A34327AE7CD900A19448 /* TooltipController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = TooltipController.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B62A34527AE7CD900A19448 /* NotifierController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = NotifierController.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B65B919284D0185007C558B /* README-CHT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "README-CHT.md"; sourceTree = "<group>"; };
5B707CE527D9F3A10099EF99 /* SwiftyOpenCC */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SwiftyOpenCC; path = Packages/SwiftyOpenCC; sourceTree = "<group>"; };
5B707CE727D9F4590099EF99 /* OpenCCBridge.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = OpenCCBridge.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5B73FB5427B2BD6900E9BF49 /* PhraseEditor-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "PhraseEditor-Info.plist"; path = "UserPhraseEditor/PhraseEditor-Info.plist"; sourceTree = SOURCE_ROOT; };
@ -373,6 +372,7 @@
5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */,
5B18BA7227C7BD8B0056EB19 /* LICENSE.txt */,
5B18BA7127C7BD8B0056EB19 /* README.md */,
5B65B919284D0185007C558B /* README-CHT.md */,
);
name = MiscRootFiles;
sourceTree = "<group>";
@ -421,7 +421,7 @@
5B7F225C2808501000DDD3CB /* KeyHandler_HandleInput.swift */,
5B61B0C9280BEFD4002E3CFA /* KeyHandler_Misc.swift */,
5B3133BE280B229700A4A505 /* KeyHandler_States.swift */,
5B62A33727AE79CD00A19448 /* NSStringUtils.swift */,
5B62A33727AE79CD00A19448 /* StringUtils.swift */,
5BAA8FBD282CAF380066C406 /* SyllableComposer.swift */,
5BF8423027BAA942008E7E4C /* vChewingKanjiConverter.swift */,
);
@ -526,8 +526,7 @@
isa = PBXGroup;
children = (
5B62A34027AE7CD900A19448 /* ctlCandidate.swift */,
5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */,
5B62A34127AE7CD900A19448 /* ctlCandidateVertical.swift */,
5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */,
);
path = CandidateUI;
sourceTree = "<group>";
@ -896,7 +895,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1320;
LastUpgradeCheck = 1330;
LastUpgradeCheck = 1340;
TargetAttributes = {
5BD05BB727B2A429004C4F1D = {
CreatedOnToolsVersion = 13.2;
@ -1074,10 +1073,11 @@
5B38F5A4281E2E49007D5F5D /* 5_LanguageModel.swift in Sources */,
5BAEFAD028012565001F42C9 /* mgrLangModel.swift in Sources */,
5B782EC4280C243C007276DE /* KeyHandler_HandleCandidate.swift in Sources */,
5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */,
5B62A33827AE79CD00A19448 /* StringUtils.swift in Sources */,
5BA9FD0F27FEDB6B002DE248 /* suiPrefPaneGeneral.swift in Sources */,
5BA9FD4927FEF3C9002DE248 /* Section.swift in Sources */,
5BA9FD3E27FEF3C8002DE248 /* Utilities.swift in Sources */,
5B242403284B0D6500520FE4 /* ctlCandidateUniversal.swift in Sources */,
5BA9FD1127FEDB6B002DE248 /* ctlPrefUI.swift in Sources */,
5B38F59C281E2E49007D5F5D /* 2_Grid.swift in Sources */,
5B40730D281672610023DFFF /* lmReplacements.swift in Sources */,
@ -1087,7 +1087,6 @@
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */,
5B61B0CA280BEFD4002E3CFA /* KeyHandler_Misc.swift in Sources */,
5B38F59A281E2E49007D5F5D /* 6_Unigram.swift in Sources */,
5B62A34827AE7CD900A19448 /* ctlCandidateVertical.swift in Sources */,
5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */,
5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */,
5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */,
@ -1096,7 +1095,6 @@
5BF8423127BAA942008E7E4C /* vChewingKanjiConverter.swift in Sources */,
5B949BDB2816DDBC00D87B5D /* LMConsolidator.swift in Sources */,
5B38F59F281E2E49007D5F5D /* 3_NodeAnchor.swift in Sources */,
5B62A34627AE7CD900A19448 /* ctlCandidateHorizontal.swift in Sources */,
5B62A34727AE7CD900A19448 /* ctlCandidate.swift in Sources */,
5BA9FD3F27FEF3C8002DE248 /* Pane.swift in Sources */,
5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */,
@ -1296,7 +1294,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1963;
CURRENT_PROJECT_VERSION = 1970;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
@ -1319,7 +1317,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.6.3;
MARKETING_VERSION = 1.7.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1352,7 +1350,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1963;
CURRENT_PROJECT_VERSION = 1970;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -1371,7 +1369,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.6.3;
MARKETING_VERSION = 1.7.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
@ -1407,6 +1405,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
@ -1449,6 +1448,7 @@
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@ -1486,7 +1486,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1963;
CURRENT_PROJECT_VERSION = 1970;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1521,7 +1521,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.6.3;
MARKETING_VERSION = 1.7.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1553,7 +1553,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1963;
CURRENT_PROJECT_VERSION = 1970;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1583,11 +1583,12 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.6.3;
MARKETING_VERSION = 1.7.0;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = singlefile;
SWIFT_OBJC_BRIDGING_HEADER = "Source/Headers/vChewing-Bridging-Header.h";
SWIFT_VERSION = 5.0;
WRAPPER_EXTENSION = app;
@ -1666,7 +1667,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1963;
CURRENT_PROJECT_VERSION = 1970;
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
@ -1691,7 +1692,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.6.3;
MARKETING_VERSION = 1.7.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1718,7 +1719,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1963;
CURRENT_PROJECT_VERSION = 1970;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1738,7 +1739,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
MARKETING_VERSION = 1.6.3;
MARKETING_VERSION = 1.7.0;
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
LastUpgradeVersion = "1340"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"