From 06e9ea1711d44c709955819d14d1203e8ece981e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E8=AF=ADwindwords?= Date: Sun, 5 Jun 2022 10:20:28 +0000 Subject: [PATCH 01/42] =?UTF-8?q?Readme=20//=20Merge=20Gitee=20PR!42=20fro?= =?UTF-8?q?m=20=E9=A3=8E=E8=AF=ADwindwords/main=20-=20Separate=20the=20REA?= =?UTF-8?q?DME.MD=20into=20zh-Hans=20and=20zh-Hant=20variants.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-CHT.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 126 ++++++++++++++++++++++++++------------------------ 2 files changed, 188 insertions(+), 61 deletions(-) create mode 100644 README-CHT.md diff --git a/README-CHT.md b/README-CHT.md new file mode 100644 index 00000000..d8020107 --- /dev/null +++ b/README-CHT.md @@ -0,0 +1,123 @@ +语言:[简体中文](https://gitee.com/windwords/vChewing-macOS/blob/main/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 授權):© 2011-2021 OpenVanilla 專案團隊(Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等)。 + +威注音專案僅用到小麥注音的下述程式組件: + +- 狀態管理引擎 & 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),針對「Lukhnos Liu 用 C++ 寫的 Gramambular」用 Swift 徹底重寫而成。 + +- 威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。 + +使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權、且一旦經過修改便不可以再繼續使用威注音的產品名稱。 + +## 格式規範等與參與研發時需要注意的事項: + +該專案對源碼格式有規範,且 Swift 與其他 (Obj)C(++) 系語言持不同規範: + +請洽該倉庫內的「[CONTRIBUTING.md](./CONTRIBUTING.md)」檔案。 + +## 其他 + +為了您的精神衛生,任何使用威注音輸入法時遇到的產品問題、請勿提報至小麥注音,除非您確信小麥注音也有該問題。即便如此,也請在他們那邊不要提及威注音。 + +濫用沉默權來浪費對方的時間與熱情,也是一種暴力。**當對方最最最開始就把你當敵人的時候,你連呼吸都是錯的**。 + +其實我滿懷念上游專案還沒被 Lukhnos Liu 接管收入 OpenVanilla 的那個年代。MJHsieh 主導開發小麥注音的時候,且不討論他立場怎樣,但基礎的技術交流是完全沒問題的。LibChewing 那邊也是,正常交流完全沒問題。 + +有些事情,繼續爭論下去也沒用。本來我想著重寫 ctlInputMethod 撤掉 zonble 的狀態管理引擎的,畢竟有大陸同鄉寫的火山五筆輸入法的框架套上我的鐵恨注音並擊引擎可以直接用。但這樣賭氣對誰都沒好處。眼下,威注音 macOS 版還需要一些小維護。之後我就得開始考慮用 Windows 平台可用的除了 C++ 以外的語言重寫鐵恨注音並擊引擎與天權星語彙引擎、方便接下來威注音的 Windows 版本的研發。能將 Lukhnos 的 C++ 內容全部換掉、徹底砸碎套在威注音身上的名為 C++ 的枷鎖、讓威注音有一個自由的未來,我已經知足了。讓更多的人用上好用的輸入法,才是最重要的。**這個重要性,不是 zonble 用「私人需求」這種帽子扣過來、就可以泯滅了的**。 + +$ EOF. diff --git a/README.md b/README.md index 167c9904..58ca2148 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,123 @@ -因不可控原因,該倉庫只能保證在 Gitee 有最新的內容可用: +语言:*简体中文* | [繁体中文](https://gitee.com/windwords/vChewing-macOS/blob/main/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 授权):© 2011-2021 OpenVanilla 项目团队(Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等)。 -威注音專案僅用到小麥注音的下述程式組件: +威注音项目仅用到小麦注音的下述进程组件: -- 狀態管理引擎 & 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),針對「Lukhnos Liu 用 C++ 寫的 Gramambular」用 Swift 徹底重寫而成。 +- 天权星语汇处理引擎: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 那邊也是,正常交流完全沒問題。 +其实我满怀念上游项目还没被 Lukhnos Liu 接管收入 OpenVanilla 的那个年代。MJHsieh 主导开发小麦注音的时候,且不讨论他立场怎样,但基础的技术交流是完全没问题的。LibChewing 那边也是,正常交流完全没问题。 -有些事情,繼續爭論下去也沒用。本來我想著重寫 ctlInputMethod 撤掉 zonble 的狀態管理引擎的,畢竟有大陸同鄉寫的火山五筆輸入法的框架套上我的鐵恨注音並擊引擎可以直接用。但這樣賭氣對誰都沒好處。眼下,威注音 macOS 版還需要一些小維護。之後我就得開始考慮用 Windows 平台可用的除了 C++ 以外的語言重寫鐵恨注音並擊引擎與天權星語彙引擎、方便接下來威注音的 Windows 版本的研發。能將 Lukhnos 的 C++ 內容全部換掉、徹底砸碎套在威注音身上的名為 C++ 的枷鎖、讓威注音有一個自由的未來,我已經知足了。讓更多的人用上好用的輸入法,才是最重要的。**這個重要性,不是 zonble 用「私人需求」這種帽子扣過來、就可以泯滅了的**。 +有些事情,继续争论下去也没用。本来我想着重写 ctlInputMethod 撤掉 zonble 的状态管理引擎的,毕竟有大陆同乡写的火山五笔输入法的框架套上我的铁恨注音并击引擎可以直接用。但这样赌气对谁都没好处。眼下,威注音 macOS 版还需要一些小维护。之后我就得开始考虑用 Windows 平台可用的除了 C++ 以外的语言重写铁恨注音并击引擎与天权星语汇引擎、方便接下来威注音的 Windows 版本的研发。能将 Lukhnos 的 C++ 内容全部换掉、彻底砸碎套在威注音身上的名为 C++ 的枷锁、让威注音有一个自由的未来,我已经知足了。让更多的人用上好用的输入法,才是最重要的。**这个重要性,不是 zonble 用「私人需求」这种帽子扣过来、就可以泯灭了的**。 $ EOF. From 209cdcedb455f89b711c8946749cd5c9055654bc Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 19:19:17 +0800 Subject: [PATCH 02/42] Readme // Additional fix. --- README-CHT.md | 4 ++-- README.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README-CHT.md b/README-CHT.md index d8020107..69161357 100644 --- a/README-CHT.md +++ b/README-CHT.md @@ -1,4 +1,4 @@ -语言:[简体中文](https://gitee.com/windwords/vChewing-macOS/blob/main/README.md) | *繁体中文* +語言:[简体中文](./README.md) | *繁體中文* --- @@ -112,7 +112,7 @@ ## 其他 -為了您的精神衛生,任何使用威注音輸入法時遇到的產品問題、請勿提報至小麥注音,除非您確信小麥注音也有該問題。即便如此,也請在他們那邊不要提及威注音。 +為了您的精神衛生,任何使用威注音輸入法時遇到的產品問題、請勿提報至小麥注音。哪怕您確信小麥注音也有該問題。 濫用沉默權來浪費對方的時間與熱情,也是一種暴力。**當對方最最最開始就把你當敵人的時候,你連呼吸都是錯的**。 diff --git a/README.md b/README.md index 58ca2148..80169e8f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -语言:*简体中文* | [繁体中文](https://gitee.com/windwords/vChewing-macOS/blob/main/README-CHT.md) +语言:*简体中文* | [繁體中文](./README-CHT.md) --- @@ -42,7 +42,7 @@ - **推荐最低系统版本**:macOS 10.12 Sierra,对 Unicode 8.0 开始的《通用规范汉字表》汉字有原生的苹方支持。 - - 同时建议**系统内存应至少 4GB**。威注音输入法占用内存约 115MB 左右(简繁双模式)、75MB左右(单模式),供参考。 + - 同时建议**系统运存应至少 4GB**。威注音输入法占用运存约 115MB 左右(简繁双模式)、75MB左右(单模式),供参考。 - 请务必使用 SSD 硬盘,否则可能会影响每次开机之后输入法首次加载的速度。从 10.10 Yosemite 开始,macOS 就已经是针对机械硬盘负优化的操作系统了。 @@ -112,7 +112,7 @@ ## 其他 -为了您的精神卫生,任何使用威注音输入法时遇到的产品问题、请勿提报至小麦注音,除非您确信小麦注音也有该问题。即便如此,也请在他们那边不要提及威注音。 +为了您的精神卫生,任何使用威注音输入法时遇到的产品问题、请勿提报至小麦注音。哪怕您确信小麦注音也有该问题。 滥用沉默权来浪费对方的时间与热情,也是一种暴力。**当对方最最最开始就把你当敌人的时候,你连呼吸都是错的**。 From 6d1bd824517870b7cd4a19d9882f73eb924f5fc3 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 1 Jun 2022 19:00:59 +0800 Subject: [PATCH 03/42] KeyHandler // Add tooltips for rare cursor position cases. --- .../ControllerModules/KeyHandler_States.swift | 44 +++++++++++++++++-- .../Resources/Base.lproj/Localizable.strings | 2 + Source/Resources/en.lproj/Localizable.strings | 2 + Source/Resources/ja.lproj/Localizable.strings | 2 + .../zh-Hans.lproj/Localizable.strings | 2 + .../zh-Hant.lproj/Localizable.strings | 2 + 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index 752faad0..fa8693f4 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -34,13 +34,13 @@ 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. Even if we are using Swift, NSString is still necessary here. for walkedNode in _walkedNodes { if let theNode = walkedNode.node { let strNodeValue = theNode.currentKeyValue.value @@ -72,6 +72,22 @@ extension KeyHandler { 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 義麵 (two 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] + } + } } } } @@ -87,7 +103,29 @@ extension KeyHandler { let composedText = head + reading + tail let cursorIndex = composedStringCursorIndex + reading.count - return InputState.Inputting(composingBuffer: composedText, cursorIndex: UInt(cursorIndex)) + let stateResult = InputState.Inputting(composingBuffer: composedText, cursorIndex: UInt(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] + ) + } + + return stateResult } // MARK: - 用以生成候選詞陣列及狀態 diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index 7c518d3b..55469beb 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -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."; diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index 7c518d3b..55469beb 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -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."; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index 36d79218..1d0f6f16 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -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." = "核心辞書読込完了"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index 20e7847c..89b4c435 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -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." = "核心辞典载入完毕"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index dd8a587d..232da7f1 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -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." = "核心辭典載入完畢"; From 0f769c9203d52dba23053e14e1a8782c1e7fa007 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 1 Jun 2022 22:08:32 +0800 Subject: [PATCH 04/42] KeyHandler // Use Swift native UTF16 handling in buildInputtingState(). --- .../ControllerModules/KeyHandler_States.swift | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index fa8693f4..555a33ec 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -40,12 +40,12 @@ extension KeyHandler { 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. Even if we are using Swift, NSString is still necessary here. + // 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,19 +55,19 @@ 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 @@ -76,7 +76,7 @@ extension KeyHandler { // 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 義麵 (two readings) gets a pasta 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] @@ -97,11 +97,22 @@ 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)) + var arrHead = [String.UTF16View.Element]() + var arrTail = [String.UTF16View.Element]() + + 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((composingBuffer as NSString).substring(from: composedStringCursorIndex)) + let tail = String(utf16CodeUnits: arrTail, count: arrTail.count) let composedText = head + reading + tail - let cursorIndex = composedStringCursorIndex + reading.count + let cursorIndex = composedStringCursorIndex + reading.utf16.count let stateResult = InputState.Inputting(composingBuffer: composedText, cursorIndex: UInt(cursorIndex)) From 52317ba623f679453444e61dff25adcdc621a246 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 1 Jun 2022 22:57:28 +0800 Subject: [PATCH 05/42] TooltipUI // Handle tooltip color states. --- Source/UI/TooltipUI/TooltipController.swift | 65 ++++++++++++++++++--- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/Source/UI/TooltipUI/TooltipController.swift b/Source/UI/TooltipUI/TooltipController.swift index 626b3fa7..1d070288 100644 --- a/Source/UI/TooltipUI/TooltipController.swift +++ b/Source/UI/TooltipUI/TooltipController.swift @@ -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) From 300214be92d5e8e3737be33dff2f8104ec69af6c Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 1 Jun 2022 22:58:41 +0800 Subject: [PATCH 06/42] ctlIME // Expose the tooltipController instance to public. --- Source/Modules/IMEModules/ctlInputMethod.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index 88dab5e0..5022f49f 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -40,7 +40,7 @@ extension ctlCandidate { class ctlInputMethod: IMKInputController { @objc static var areWeDeleting = false - private static let tooltipController = TooltipController() + static let tooltipController = TooltipController() // MARK: - From a029460f9684ec771b5a94840a04e3823aa23031 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 1 Jun 2022 22:59:22 +0800 Subject: [PATCH 07/42] InputState // Remove deprecated color definition codes. --- .../ControllerModules/InputState.swift | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 50044dbc..83b5e684 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -161,18 +161,13 @@ class InputState { 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: "" ) @@ -183,24 +178,14 @@ class InputState { 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 - ) + 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 - ) + ctlInputMethod.tooltipController.setColor(state: .denialOverflow) return String( format: NSLocalizedString( "\"%@\" length should ≤ %d for a user phrase.", comment: "" @@ -220,22 +205,14 @@ class InputState { ) 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 From 97c7918940a0ff27b47755e73860461409bd49b1 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Wed, 1 Jun 2022 22:59:48 +0800 Subject: [PATCH 08/42] KeyHandler // Reset tooltipUI color state when necessary. --- Source/Modules/ControllerModules/KeyHandler_States.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index 555a33ec..59d06a31 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -136,6 +136,10 @@ extension KeyHandler { ) } + if !stateResult.tooltip.isEmpty { + ctlInputMethod.tooltipController.setColor(state: .denialOverflow) + } + return stateResult } From c30cc6697fb3d445034b249a8247eb6e236af651 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 00:42:23 +0800 Subject: [PATCH 09/42] Repo // NSStringUtils -> StringUtils. --- .../ControllerModules/InputState.swift | 31 ++++++++----------- .../ControllerModules/KeyHandler_States.swift | 14 ++++----- ...{NSStringUtils.swift => StringUtils.swift} | 26 +++++++--------- .../LangModelRelated/mgrLangModel.swift | 5 ++- vChewing.xcodeproj/project.pbxproj | 8 ++--- 5 files changed, 37 insertions(+), 47 deletions(-) rename Source/Modules/ControllerModules/{NSStringUtils.swift => StringUtils.swift} (79%) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 83b5e684..c322ab20 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -176,7 +176,7 @@ class InputState { return "" } - let text = (composingBuffer as NSString).substring(with: markedRange) + let text = composingBuffer.substring(with: markedRange) if markedRange.length < kMinMarkRangeLength { ctlInputMethod.tooltipController.setColor(state: .denialInsufficiency) return String( @@ -194,9 +194,8 @@ class InputState { ) } - let (exactBegin, _) = (composingBuffer as NSString).characterIndex( - from: markedRange.location) - let (exactEnd, _) = (composingBuffer as NSString).characterIndex( + let (exactBegin, _) = composingBuffer.utf16CharIndex(from: markedRange.location) + let (exactEnd, _) = composingBuffer.utf16CharIndex( from: markedRange.location + markedRange.length) let selectedReadings = readings[exactBegin.. 0 { - index = UInt((state.composingBuffer as NSString).previousUtf16Position(for: Int(index))) + index = UInt(state.composingBuffer.utf16PreviousPosition(for: Int(index))) let marking = InputState.Marking( composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, @@ -226,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 = UInt(state.composingBuffer.utf16NextPosition(for: Int(index))) let marking = InputState.Marking( composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, @@ -565,8 +563,8 @@ extension KeyHandler { if input.isShiftHold { // Shift + Right - if currentState.cursorIndex < (currentState.composingBuffer as NSString).length { - let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position( + if currentState.cursorIndex < currentState.composingBuffer.utf16.count { + let nextPosition = currentState.composingBuffer.utf16NextPosition( for: Int(currentState.cursorIndex)) let marking: InputState.Marking! = InputState.Marking( composingBuffer: currentState.composingBuffer, @@ -615,7 +613,7 @@ extension KeyHandler { if input.isShiftHold { // Shift + left if currentState.cursorIndex > 0 { - let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position( + let previousPosition = currentState.composingBuffer.utf16PreviousPosition( for: Int(currentState.cursorIndex)) let marking: InputState.Marking! = InputState.Marking( composingBuffer: currentState.composingBuffer, diff --git a/Source/Modules/ControllerModules/NSStringUtils.swift b/Source/Modules/ControllerModules/StringUtils.swift similarity index 79% rename from Source/Modules/ControllerModules/NSStringUtils.swift rename to Source/Modules/ControllerModules/StringUtils.swift index f90b0710..4beae553 100644 --- a/Source/Modules/ControllerModules/NSStringUtils.swift +++ b/Source/Modules/ControllerModules/StringUtils.swift @@ -26,8 +26,8 @@ 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. +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 /// the length of an NSString is only the sum of the UTF-16 code points. It @@ -35,8 +35,8 @@ extension NSString { /// 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) + public func utf16CharIndex(from utf16Index: Int) -> (Int, String) { + let string = self var length = 0 for (i, character) in string.enumerated() { length += character.utf16.count @@ -47,29 +47,27 @@ extension NSString { return (string.count, string) } - public func nextUtf16Position(for index: Int) -> Int { - var (fixedIndex, string) = characterIndex(from: index) + public func utf16NextPosition(for index: Int) -> Int { + var (fixedIndex, string) = utf16CharIndex(from: index) if fixedIndex < string.count { fixedIndex += 1 } return string[.. Int { - var (fixedIndex, string) = characterIndex(from: index) + public func utf16PreviousPosition(for index: Int) -> Int { + var (fixedIndex, string) = utf16CharIndex(from: index) if fixedIndex > 0 { fixedIndex -= 1 } return string[.. [NSString] { - Array(self as String).map { - NSString(string: String($0)) - } + public func substring(with nsRange: NSRange) -> String { + (self as NSString).substring(with: nsRange) } } diff --git a/Source/Modules/LangModelRelated/mgrLangModel.swift b/Source/Modules/LangModelRelated/mgrLangModel.swift index 2360ff47..770b4182 100644 --- a/Source/Modules/LangModelRelated/mgrLangModel.swift +++ b/Source/Modules/LangModelRelated/mgrLangModel.swift @@ -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() diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index b5d162ad..92f54571 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -28,7 +28,7 @@ 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 */; }; @@ -202,7 +202,7 @@ 5B62A32827AE77D100A19448 /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = FSEventStreamHelper.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33127AE792F00A19448 /* InputSourceHelper.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputSourceHelper.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; - 5B62A33727AE79CD00A19448 /* NSStringUtils.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = NSStringUtils.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; + 5B62A33727AE79CD00A19448 /* StringUtils.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = StringUtils.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidateHorizontal.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; @@ -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 */, ); @@ -1074,7 +1074,7 @@ 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 */, From 376a97ea30e89509b888f2d8eaace73174baade5 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 01:05:54 +0800 Subject: [PATCH 10/42] ctlNonModelAlertWindow // Guard-let the window in show(). --- .../ctlNonModalAlertWindow.swift | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Source/WindowControllers/ctlNonModalAlertWindow.swift b/Source/WindowControllers/ctlNonModalAlertWindow.swift index f8e28ddc..89d2ab36 100644 --- a/Source/WindowControllers/ctlNonModalAlertWindow.swift +++ b/Source/WindowControllers/ctlNonModalAlertWindow.swift @@ -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) } From 758642e0cf19be43667c934007d76b8cdbce4484 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 01:06:02 +0800 Subject: [PATCH 11/42] Repo // Remove useless "== true". --- Source/Modules/AppDelegate.swift | 2 +- Source/Modules/ControllerModules/InputState.swift | 1 - Source/Modules/IMEModules/ctlInputMethod.swift | 4 +--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index 1beee07c..93702611 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -74,7 +74,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega mgrPrefs.setMissingDefaults() // 只要使用者沒有勾選檢查更新、沒有主動做出要檢查更新的操作,就不要檢查更新。 - if (UserDefaults.standard.object(forKey: VersionUpdateApi.kCheckUpdateAutomatically) != nil) == true { + if UserDefaults.standard.object(forKey: VersionUpdateApi.kCheckUpdateAutomatically) != nil { checkForUpdate() } } diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index c322ab20..5931723e 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -300,7 +300,6 @@ class InputState { return mgrLangModel.checkIfUserPhraseExist( userPhrase: text, mode: ctlInputMethod.currentKeyHandler.inputMode, key: joined ) - == true } var userPhrase: String { diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index 5022f49f..dd89e5b5 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -472,9 +472,7 @@ extension ctlInputMethod { useVerticalMode = state.useVerticalMode candidates = state.candidates } - if useVerticalMode == true { - return true - } + if useVerticalMode { return true } candidates.sort { $0.count > $1.count } From e5d8e8fe980be99812b4692794cf0d098ccc5d2c Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 01:08:04 +0800 Subject: [PATCH 12/42] AppDelegate // Use mgrPrefs.checkUpdateAutomatically. --- Source/Modules/AppDelegate.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Modules/AppDelegate.swift b/Source/Modules/AppDelegate.swift index 93702611..40cbc575 100644 --- a/Source/Modules/AppDelegate.swift +++ b/Source/Modules/AppDelegate.swift @@ -74,7 +74,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega mgrPrefs.setMissingDefaults() // 只要使用者沒有勾選檢查更新、沒有主動做出要檢查更新的操作,就不要檢查更新。 - if UserDefaults.standard.object(forKey: VersionUpdateApi.kCheckUpdateAutomatically) != nil { + 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() From db555640eb03e002e21921cc3f3a7581b766744c Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 10:55:59 +0800 Subject: [PATCH 13/42] PreferencesExtension // Clang-Format. --- .../SindreSorhus/Preferences/Container.swift | 22 ++++----- .../Preferences/Localization.swift | 8 ++-- .../SindreSorhus/Preferences/Pane.swift | 18 +++---- .../PreferencesWindowController.swift | 18 +++---- .../SindreSorhus/Preferences/Section.swift | 48 +++++++++---------- .../SindreSorhus/Preferences/Utilities.swift | 4 +- 6 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Source/3rdParty/SindreSorhus/Preferences/Container.swift b/Source/3rdParty/SindreSorhus/Preferences/Container.swift index 115f7e58..ff7993d9 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Container.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Container.swift @@ -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, diff --git a/Source/3rdParty/SindreSorhus/Preferences/Localization.swift b/Source/3rdParty/SindreSorhus/Preferences/Localization.swift index de0c60cc..4f0808dd 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Localization.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Localization.swift @@ -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]! diff --git a/Source/3rdParty/SindreSorhus/Preferences/Pane.swift b/Source/3rdParty/SindreSorhus/Preferences/Pane.swift index 21b83af3..02262cee 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Pane.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Pane.swift @@ -25,18 +25,18 @@ import SwiftUI /// Acts as type-eraser for `Preferences.Pane`. 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: 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: NSHostingController, 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. diff --git a/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift b/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift index 0480271c..71fdfb32 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/PreferencesWindowController.swift @@ -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, diff --git a/Source/3rdParty/SindreSorhus/Preferences/Section.swift b/Source/3rdParty/SindreSorhus/Preferences/Section.swift index 86c7a637..2279bfe9 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Section.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Section.swift @@ -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( 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( title: String, bottomDivider: Bool = false, diff --git a/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift b/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift index f2c27a15..865d6670 100755 --- a/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift +++ b/Source/3rdParty/SindreSorhus/Preferences/Utilities.swift @@ -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) } From f083538f317b1a43c90837026bac7e2084645924 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 10:58:57 +0800 Subject: [PATCH 14/42] LMCoreNS // Clang-Format. --- Source/Modules/LangModelRelated/SubLMs/lmCoreNS.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Modules/LangModelRelated/SubLMs/lmCoreNS.swift b/Source/Modules/LangModelRelated/SubLMs/lmCoreNS.swift index ac0ab9db..7db56652 100644 --- a/Source/Modules/LangModelRelated/SubLMs/lmCoreNS.swift +++ b/Source/Modules/LangModelRelated/SubLMs/lmCoreNS.swift @@ -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 { From 9977ef484629de2dee84d37655e87fe9197992f5 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 14:25:27 +0800 Subject: [PATCH 15/42] Repo // UInt -> Int. - This should avoid a hell lot of unnecessary type conversions. --- .../ControllerModules/InputSignal.swift | 7 +++- .../ControllerModules/InputState.swift | 22 +++++----- .../KeyHandler_HandleCandidate.swift | 18 ++++---- .../ControllerModules/KeyHandler_States.swift | 14 +++---- .../ControllerModules/StringUtils.swift | 4 +- .../Modules/IMEModules/ctlInputMethod.swift | 36 ++++++++-------- Source/UI/CandidateUI/ctlCandidate.swift | 12 +++--- .../CandidateUI/ctlCandidateHorizontal.swift | 42 ++++++++++--------- .../UI/CandidateUI/ctlCandidateVertical.swift | 42 ++++++++++--------- 9 files changed, 104 insertions(+), 93 deletions(-) diff --git a/Source/Modules/ControllerModules/InputSignal.swift b/Source/Modules/ControllerModules/InputSignal.swift index 4bc1acbb..c972f704 100644 --- a/Source/Modules/ControllerModules/InputSignal.swift +++ b/Source/Modules/ControllerModules/InputSignal.swift @@ -110,8 +110,11 @@ 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. diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 5931723e..989564fe 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -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) } @@ -156,7 +156,7 @@ class InputState { /// Represents that the user is marking a range in the composing buffer. class Marking: NotEmpty { - private(set) var markerIndex: UInt + private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } } private(set) var markedRange: NSRange private var deleteTargetExists = false var tooltip: String { @@ -176,7 +176,7 @@ class InputState { return "" } - let text = composingBuffer.substring(with: markedRange) + let text = composingBuffer.utf16SubString(with: markedRange) if markedRange.length < kMinMarkRangeLength { ctlInputMethod.tooltipController.setColor(state: .denialInsufficiency) return String( @@ -221,11 +221,11 @@ 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 = NSRange(location: begin, length: end - begin) self.readings = readings super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex) } @@ -291,7 +291,7 @@ class InputState { } var chkIfUserPhraseExists: Bool { - let text = composingBuffer.substring(with: markedRange) + let text = composingBuffer.utf16SubString(with: markedRange) let (exactBegin, _) = composingBuffer.utf16CharIndex(from: markedRange.location) let (exactEnd, _) = composingBuffer.utf16CharIndex( from: markedRange.location + markedRange.length) @@ -303,7 +303,7 @@ class InputState { } var userPhrase: String { - let text = composingBuffer.substring(with: markedRange) + let text = composingBuffer.utf16SubString(with: markedRange) let (exactBegin, _) = composingBuffer.utf16CharIndex(from: markedRange.location) let (exactEnd, _) = composingBuffer.utf16CharIndex( from: markedRange.location + markedRange.length) @@ -314,7 +314,7 @@ class InputState { var userPhraseConverted: String { let text = - OpenCCBridge.crossConvert(composingBuffer.substring(with: markedRange)) ?? "" + OpenCCBridge.crossConvert(composingBuffer.utf16SubString(with: markedRange)) ?? "" let (exactBegin, _) = composingBuffer.utf16CharIndex(from: markedRange.location) let (exactEnd, _) = composingBuffer.utf16CharIndex( from: markedRange.location + markedRange.length) @@ -332,7 +332,7 @@ class InputState { private(set) var candidates: [String] private(set) var useVerticalMode: Bool - init(composingBuffer: String, cursorIndex: UInt, candidates: [String], useVerticalMode: Bool) { + init(composingBuffer: String, cursorIndex: Int, candidates: [String], useVerticalMode: Bool) { self.candidates = candidates self.useVerticalMode = useVerticalMode super.init(composingBuffer: composingBuffer, cursorIndex: cursorIndex) diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index 7c631905..8b9e6eae 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -71,7 +71,7 @@ extension KeyHandler { } delegate!.keyHandler( self, - didSelectCandidateAt: Int(ctlCandidateCurrent.selectedCandidateIndex), + didSelectCandidateAt: ctlCandidateCurrent.selectedCandidateIndex, ctlCandidate: ctlCandidateCurrent ) return true @@ -260,11 +260,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 +294,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 +342,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() diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index e4b963a8..ff5b2fb5 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -114,7 +114,7 @@ extension KeyHandler { let composedText = head + reading + tail let cursorIndex = composedStringCursorIndex + reading.utf16.count - let stateResult = InputState.Inputting(composingBuffer: composedText, cursorIndex: UInt(cursorIndex)) + let stateResult = InputState.Inputting(composingBuffer: composedText, cursorIndex: cursorIndex) // Now we start weaving the contents of the tooltip. if tooltipParameterRef[0].isEmpty, tooltipParameterRef[1].isEmpty { @@ -206,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.utf16PreviousPosition(for: Int(index))) + index = state.composingBuffer.utf16PreviousPosition(for: index) let marking = InputState.Marking( composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, @@ -227,7 +227,7 @@ extension KeyHandler { if input.isCursorForward || input.emacsKey == vChewingEmacsKey.forward, input.isShiftHold { var index = state.markerIndex if index < (state.composingBuffer.utf16.count) { - index = UInt(state.composingBuffer.utf16NextPosition(for: Int(index))) + index = state.composingBuffer.utf16NextPosition(for: index) let marking = InputState.Marking( composingBuffer: state.composingBuffer, cursorIndex: state.cursorIndex, @@ -565,11 +565,11 @@ extension KeyHandler { // Shift + Right if currentState.cursorIndex < currentState.composingBuffer.utf16.count { let nextPosition = currentState.composingBuffer.utf16NextPosition( - for: Int(currentState.cursorIndex)) + 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 @@ -614,11 +614,11 @@ extension KeyHandler { // Shift + left if currentState.cursorIndex > 0 { let previousPosition = currentState.composingBuffer.utf16PreviousPosition( - for: Int(currentState.cursorIndex)) + 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 diff --git a/Source/Modules/ControllerModules/StringUtils.swift b/Source/Modules/ControllerModules/StringUtils.swift index 4beae553..135f56f5 100644 --- a/Source/Modules/ControllerModules/StringUtils.swift +++ b/Source/Modules/ControllerModules/StringUtils.swift @@ -67,7 +67,7 @@ extension String { (self as NSString).expandingTildeInPath } - public func substring(with nsRange: NSRange) -> String { - (self as NSString).substring(with: nsRange) + public func utf16SubString(with range: NSRange) -> String { + (self as NSString).substring(with: range) } } diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index dd89e5b5..15360103 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -373,7 +373,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 { @@ -395,7 +395,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) ) @@ -420,7 +420,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) ) show(candidateWindowWith: state, client: client) @@ -437,7 +437,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) ) show(candidateWindowWith: state, client: client) @@ -553,7 +553,7 @@ extension ctlInputMethod { 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 } @@ -581,9 +581,9 @@ extension ctlInputMethod { } } - 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 } @@ -615,7 +615,7 @@ extension ctlInputMethod: KeyHandlerDelegate { ) { _ = 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) } } @@ -651,34 +651,34 @@ 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( @@ -693,7 +693,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 @@ -718,7 +718,7 @@ 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( diff --git a/Source/UI/CandidateUI/ctlCandidate.swift b/Source/UI/CandidateUI/ctlCandidate.swift index f4333e9c..9fb076f5 100644 --- a/Source/UI/CandidateUI/ctlCandidate.swift +++ b/Source/UI/CandidateUI/ctlCandidate.swift @@ -38,11 +38,11 @@ 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 ) } @@ -53,7 +53,7 @@ public class ctlCandidate: NSWindowController { } } - public var selectedCandidateIndex: UInt = .max + public var selectedCandidateIndex: Int = .max public var visible: Bool = false { didSet { NSObject.cancelPreviousPerformRequests(withTarget: self) @@ -108,8 +108,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. diff --git a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift index 17245e60..2e7ab7a7 100644 --- a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift +++ b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift @@ -27,7 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa private class HorizontalCandidateView: NSView { - var highlightedIndex: UInt = 0 + var highlightedIndex: Int = 0 { didSet { highlightedIndex = max(highlightedIndex, 0) } } var action: Selector? weak var target: AnyObject? @@ -42,7 +42,9 @@ private class HorizontalCandidateView: NSView { private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:] private var elementWidths: [CGFloat] = [] - private var trackingHighlightedIndex: UInt = .max + private var trackingHighlightedIndex: Int = .max { + didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) } + } override var isFlipped: Bool { true @@ -196,26 +198,27 @@ private class HorizontalCandidateView: NSView { } } - private func findHitIndex(event: NSEvent) -> UInt? { + private func findHitIndex(event: NSEvent) -> Int { let location = convert(event.locationInWindow, to: nil) if !bounds.contains(location) { - return nil + return NSNotFound } 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) + return index } accuWidth += currentWidth + 1.0 } - return nil + return NSNotFound } override func mouseUp(with event: NSEvent) { trackingHighlightedIndex = highlightedIndex - guard let newIndex = findHitIndex(event: event) else { + let newIndex = findHitIndex(event: event) + guard newIndex != NSNotFound else { return } highlightedIndex = newIndex @@ -223,7 +226,8 @@ private class HorizontalCandidateView: NSView { } override func mouseDown(with event: NSEvent) { - guard let newIndex = findHitIndex(event: event) else { + let newIndex = findHitIndex(event: event) + guard newIndex != NSNotFound else { return } var triggerAction = false @@ -247,7 +251,7 @@ public class ctlCandidateHorizontal: ctlCandidate { private var candidateView: HorizontalCandidateView private var prevPageButton: NSButton private var nextPageButton: NSButton - private var currentPageIndex: UInt = 0 + private var currentPageIndex: Int = 0 public init() { var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) @@ -364,24 +368,24 @@ public class ctlCandidateHorizontal: ctlCandidate { return true } - override public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + override public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int { guard let delegate = delegate else { - return UInt.max + return Int.max } - let result = currentPageIndex * UInt(keyLabels.count) + index - return result < delegate.candidateCountForController(self) ? result : UInt.max + let result = currentPageIndex * keyLabels.count + index + return result < delegate.candidateCountForController(self) ? result : Int.max } - override public var selectedCandidateIndex: UInt { + override public var selectedCandidateIndex: Int { get { - currentPageIndex * UInt(keyLabels.count) + candidateView.highlightedIndex + currentPageIndex * keyLabels.count + candidateView.highlightedIndex } set { guard let delegate = delegate else { return } - let keyLabelCount = UInt(keyLabels.count) + let keyLabelCount = keyLabels.count if newValue < delegate.candidateCountForController(self) { currentPageIndex = newValue / keyLabelCount candidateView.highlightedIndex = newValue % keyLabelCount @@ -392,12 +396,12 @@ public class ctlCandidateHorizontal: ctlCandidate { } extension ctlCandidateHorizontal { - private var pageCount: UInt { + private var pageCount: Int { guard let delegate = delegate else { return 0 } let totalCount = delegate.candidateCountForController(self) - let keyLabelCount = UInt(keyLabels.count) + let keyLabelCount = keyLabels.count return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0) } @@ -409,7 +413,7 @@ extension ctlCandidateHorizontal { candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont) var candidates = [String]() let count = delegate.candidateCountForController(self) - let keyLabelCount = UInt(keyLabels.count) + let keyLabelCount = keyLabels.count let begin = currentPageIndex * keyLabelCount for index in begin.. UInt? { + private func findHitIndex(event: NSEvent) -> Int { let location = convert(event.locationInWindow, to: nil) if !bounds.contains(location) { - return nil + return NSNotFound } 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) + return index } accuHeight += currentHeight } - return nil + return NSNotFound } override func mouseUp(with event: NSEvent) { trackingHighlightedIndex = highlightedIndex - guard let newIndex = findHitIndex(event: event) else { + let newIndex = findHitIndex(event: event) + guard newIndex != NSNotFound else { return } highlightedIndex = newIndex @@ -228,7 +231,8 @@ private class VerticalCandidateView: NSView { } override func mouseDown(with event: NSEvent) { - guard let newIndex = findHitIndex(event: event) else { + let newIndex = findHitIndex(event: event) + guard newIndex != NSNotFound else { return } var triggerAction = false @@ -252,7 +256,7 @@ public class ctlCandidateVertical: ctlCandidate { private var candidateView: VerticalCandidateView private var prevPageButton: NSButton private var nextPageButton: NSButton - private var currentPageIndex: UInt = 0 + private var currentPageIndex: Int = 0 public init() { var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0) @@ -369,24 +373,24 @@ public class ctlCandidateVertical: ctlCandidate { return true } - override public func candidateIndexAtKeyLabelIndex(_ index: UInt) -> UInt { + override public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int { guard let delegate = delegate else { - return UInt.max + return Int.max } - let result = currentPageIndex * UInt(keyLabels.count) + index - return result < delegate.candidateCountForController(self) ? result : UInt.max + let result = currentPageIndex * keyLabels.count + index + return result < delegate.candidateCountForController(self) ? result : Int.max } - override public var selectedCandidateIndex: UInt { + override public var selectedCandidateIndex: Int { get { - currentPageIndex * UInt(keyLabels.count) + candidateView.highlightedIndex + currentPageIndex * keyLabels.count + candidateView.highlightedIndex } set { guard let delegate = delegate else { return } - let keyLabelCount = UInt(keyLabels.count) + let keyLabelCount = keyLabels.count if newValue < delegate.candidateCountForController(self) { currentPageIndex = newValue / keyLabelCount candidateView.highlightedIndex = newValue % keyLabelCount @@ -397,12 +401,12 @@ public class ctlCandidateVertical: ctlCandidate { } extension ctlCandidateVertical { - private var pageCount: UInt { + private var pageCount: Int { guard let delegate = delegate else { return 0 } let totalCount = delegate.candidateCountForController(self) - let keyLabelCount = UInt(keyLabels.count) + let keyLabelCount = keyLabels.count return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0) } @@ -414,7 +418,7 @@ extension ctlCandidateVertical { candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont) var candidates = [String]() let count = delegate.candidateCountForController(self) - let keyLabelCount = UInt(keyLabels.count) + let keyLabelCount = keyLabels.count let begin = currentPageIndex * keyLabelCount for index in begin.. Date: Thu, 2 Jun 2022 16:22:39 +0800 Subject: [PATCH 16/42] IME // Add expandingTildeInPath to String. - Also removes the same section from StringUtils. --- Source/Modules/ControllerModules/StringUtils.swift | 4 ---- Source/Modules/IMEModules/IME.swift | 11 +++++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Source/Modules/ControllerModules/StringUtils.swift b/Source/Modules/ControllerModules/StringUtils.swift index 135f56f5..dc997a42 100644 --- a/Source/Modules/ControllerModules/StringUtils.swift +++ b/Source/Modules/ControllerModules/StringUtils.swift @@ -63,10 +63,6 @@ extension String { return string[.. String { (self as NSString).substring(with: range) } diff --git a/Source/Modules/IMEModules/IME.swift b/Source/Modules/IMEModules/IME.swift index 4ae72006..e6648177 100644 --- a/Source/Modules/IMEModules/IME.swift +++ b/Source/Modules/IMEModules/IME.swift @@ -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 From af08a31efafdb7f518e46e8ece0fcc26bddc9a0a Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 16:23:19 +0800 Subject: [PATCH 17/42] StringUtils // Advising against attempts of deprecating .utf16 handling. --- Source/Modules/ControllerModules/StringUtils.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Source/Modules/ControllerModules/StringUtils.swift b/Source/Modules/ControllerModules/StringUtils.swift index dc997a42..b47300ae 100644 --- a/Source/Modules/ControllerModules/StringUtils.swift +++ b/Source/Modules/ControllerModules/StringUtils.swift @@ -26,15 +26,24 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import Cocoa +/// 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. + /// in an NSString (or .utf16). public func utf16CharIndex(from utf16Index: Int) -> (Int, String) { let string = self var length = 0 From aff3a2014e3ac80896a1e66c6aa55f858dd78761 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 22:12:00 +0800 Subject: [PATCH 18/42] Repo // Swap NSRange to Range when necessary. - Also let utf16SubString() retrieve Swift range parameters. --- .../ControllerModules/InputState.swift | 48 +++++++++---------- .../ControllerModules/KeyHandler_States.swift | 4 +- .../ControllerModules/StringUtils.swift | 28 +++++------ 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 989564fe..2034030a 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -157,7 +157,7 @@ class InputState { /// Represents that the user is marking a range in the composing buffer. class Marking: NotEmpty { private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } } - private(set) var markedRange: NSRange + private(set) var markedRange: Range private var deleteTargetExists = false var tooltip: String { if composingBuffer.count != readings.count { @@ -172,19 +172,19 @@ class InputState { "⚠︎ Phrase replacement mode enabled, interfering user phrase entry.", comment: "" ) } - if markedRange.length == 0 { + if markedRange.isEmpty { return "" } let text = composingBuffer.utf16SubString(with: markedRange) - if markedRange.length < kMinMarkRangeLength { + if markedRange.count < kMinMarkRangeLength { ctlInputMethod.tooltipController.setColor(state: .denialInsufficiency) return String( format: NSLocalizedString( "\"%@\" length must ≥ 2 for a user phrase.", comment: "" ), text ) - } else if markedRange.length > kMaxMarkRangeLength { + } else if markedRange.count > kMaxMarkRangeLength { ctlInputMethod.tooltipController.setColor(state: .denialOverflow) return String( format: NSLocalizedString( @@ -194,9 +194,8 @@ class InputState { ) } - let (exactBegin, _) = composingBuffer.utf16CharIndex(from: markedRange.location) - let (exactEnd, _) = composingBuffer.utf16CharIndex( - from: markedRange.location + markedRange.length) + let exactBegin = composingBuffer.utf16CharIndex(from: markedRange.lowerBound) + let exactEnd = composingBuffer.utf16CharIndex(from: markedRange.upperBound) let selectedReadings = readings[exactBegin.. kMaxMarkRangeLength { + if markedRange.count > kMaxMarkRangeLength { return false } if ctlInputMethod.areWeDeleting, !deleteTargetExists { return false } - return markedRange.length >= kMinMarkRangeLength - && markedRange.length <= kMaxMarkRangeLength + return markedRange.count >= kMinMarkRangeLength + && markedRange.count <= kMaxMarkRangeLength } var chkIfUserPhraseExists: Bool { let text = composingBuffer.utf16SubString(with: markedRange) - let (exactBegin, _) = composingBuffer.utf16CharIndex(from: markedRange.location) - let (exactEnd, _) = composingBuffer.utf16CharIndex( - from: markedRange.location + markedRange.length) + let exactBegin = composingBuffer.utf16CharIndex(from: markedRange.lowerBound) + let exactEnd = composingBuffer.utf16CharIndex(from: markedRange.upperBound) let selectedReadings = readings[exactBegin.. (Int, String) { - let string = self + public func utf16CharIndex(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 utf16NextPosition(for index: Int) -> Int { - var (fixedIndex, string) = utf16CharIndex(from: index) - if fixedIndex < string.count { - fixedIndex += 1 - } - return string[.. Int { - var (fixedIndex, string) = utf16CharIndex(from: index) - if fixedIndex > 0 { - fixedIndex -= 1 - } - return string[.. String { - (self as NSString).substring(with: range) + func utf16SubString(with r: Range) -> String { + let arr = Array(self.utf16)[r].map { $0 } + return String(utf16CodeUnits: arr, count: arr.count) } } From 75978da72f78bd2cc9d3c22760cf329cd1641cd3 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Fri, 3 Jun 2022 09:13:09 +0800 Subject: [PATCH 19/42] Repo // Name Fix: utf16CharIndex -> charIndexLiteral. --- .../Modules/ControllerModules/InputState.swift | 16 ++++++++-------- .../Modules/ControllerModules/StringUtils.swift | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 2034030a..a3d8ded7 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -194,8 +194,8 @@ class InputState { ) } - let exactBegin = composingBuffer.utf16CharIndex(from: markedRange.lowerBound) - let exactEnd = composingBuffer.utf16CharIndex(from: markedRange.upperBound) + let exactBegin = composingBuffer.charIndexLiteral(from: markedRange.lowerBound) + let exactEnd = composingBuffer.charIndexLiteral(from: markedRange.upperBound) let selectedReadings = readings[exactBegin.. Int { + public func charIndexLiteral(from utf16Index: Int) -> Int { var length = 0 for (i, character) in self.enumerated() { length += character.utf16.count @@ -56,12 +56,12 @@ extension String { } public func utf16NextPosition(for index: Int) -> Int { - let fixedIndex = min(utf16CharIndex(from: index) + 1, count) + let fixedIndex = min(charIndexLiteral(from: index) + 1, count) return self[.. Int { - let fixedIndex = max(utf16CharIndex(from: index) - 1, 0) + let fixedIndex = max(charIndexLiteral(from: index) - 1, 0) return self[.. Date: Fri, 3 Jun 2022 09:15:01 +0800 Subject: [PATCH 20/42] InputState // Exact Begin / End -> Literal Begin / End. --- .../ControllerModules/InputState.swift | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index a3d8ded7..eb5fcf6e 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -194,9 +194,9 @@ class InputState { ) } - let exactBegin = composingBuffer.charIndexLiteral(from: markedRange.lowerBound) - let exactEnd = composingBuffer.charIndexLiteral(from: markedRange.upperBound) - let selectedReadings = readings[exactBegin.. Date: Fri, 3 Jun 2022 09:16:37 +0800 Subject: [PATCH 21/42] PrefUI & PrefWindow // Use Swift String with expandingTildeInPath. --- Source/UI/PrefUI/suiPrefPaneDictionary.swift | 2 +- Source/WindowControllers/ctlPrefWindow.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UI/PrefUI/suiPrefPaneDictionary.swift b/Source/UI/PrefUI/suiPrefPaneDictionary.swift index e8376b3e..cb0b1bfd 100644 --- a/Source/UI/PrefUI/suiPrefPaneDictionary.swift +++ b/Source/UI/PrefUI/suiPrefPaneDictionary.swift @@ -65,7 +65,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 diff --git a/Source/WindowControllers/ctlPrefWindow.swift b/Source/WindowControllers/ctlPrefWindow.swift index fc8812da..b73f64ff 100644 --- a/Source/WindowControllers/ctlPrefWindow.swift +++ b/Source/WindowControllers/ctlPrefWindow.swift @@ -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 From d67a6fd28fabb4a232a6ec0d8016bff1af70b7b0 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Thu, 2 Jun 2022 23:21:55 +0800 Subject: [PATCH 22/42] Tekkon 1.1.5 // Fix how Hsu arrange handles "v" key by default. --- Source/Modules/ControllerModules/SyllableComposer.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Modules/ControllerModules/SyllableComposer.swift b/Source/Modules/ControllerModules/SyllableComposer.swift index 4e088921..13758b40 100644 --- a/Source/Modules/ControllerModules/SyllableComposer.swift +++ b/Source/Modules/ControllerModules/SyllableComposer.swift @@ -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": "ㄗ", " ": " ", ] From 5a40f24ff84087949ab3bed2e76ec08031a31d89 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 11:28:41 +0800 Subject: [PATCH 23/42] ctlIME // Determine whether vertical candidates shall be enforced. --- .../Modules/IMEModules/ctlInputMethod.swift | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index 15360103..353b8650 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -462,7 +462,7 @@ extension ctlInputMethod { extension ctlInputMethod { private func show(candidateWindowWith state: InputState, client: Any!) { - let useVerticalMode: Bool = { + var useVerticalMode: Bool { var useVerticalMode = false var candidates: [String] = [] if let state = state as? InputState.ChoosingCandidate { @@ -476,22 +476,13 @@ extension ctlInputMethod { 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.. Int(round(Double(maxCandidatesPerPage) * 1.8)) + // 上面這句如果是 true 的話,就會是縱排;反之則為橫排。 + } ctlCandidateCurrent?.delegate = nil From 49ab499b13159d0d54038f9302a9d72bb69a5927 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Fri, 3 Jun 2022 23:54:09 +0800 Subject: [PATCH 24/42] InputState // Simplify validToWrite() and allowedMarkRange(). --- .../ControllerModules/InputState.swift | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index eb5fcf6e..d6c81878 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -151,11 +151,9 @@ 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 var allowedMarkRange = 2...mgrPrefs.maxCandidateLength private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } } private(set) var markedRange: Range private var deleteTargetExists = false @@ -177,20 +175,20 @@ class InputState { } let text = composingBuffer.utf16SubString(with: markedRange) - if markedRange.count < kMinMarkRangeLength { + if markedRange.count < allowedMarkRange.lowerBound { ctlInputMethod.tooltipController.setColor(state: .denialInsufficiency) return String( format: NSLocalizedString( "\"%@\" length must ≥ 2 for a user phrase.", comment: "" ), text ) - } else if markedRange.count > kMaxMarkRangeLength { + } else if markedRange.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 ) } @@ -277,20 +275,12 @@ 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.count < kMinMarkRangeLength { - return false - } - if markedRange.count > kMaxMarkRangeLength { - return false - } - if ctlInputMethod.areWeDeleting, !deleteTargetExists { - return false - } - return markedRange.count >= kMinMarkRangeLength - && markedRange.count <= kMaxMarkRangeLength + /// 這裡的 deleteTargetExists 是防止使用者排除「詞庫內尚未存在的詞」, + /// 免得使用者誤操作之後靠北「我怎麼敲不了這個詞?」之類的。 + ((composingBuffer.count != readings.count) + || (ctlInputMethod.areWeDeleting && !deleteTargetExists)) + ? false + : allowedMarkRange.contains(markedRange.count) } var chkIfUserPhraseExists: Bool { From e39bba23f457667ce383e5adbdabadc510f56387 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 00:27:28 +0800 Subject: [PATCH 25/42] InputState // Fix an upstream bug of handling literal marked range. --- .../ControllerModules/InputState.swift | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index d6c81878..afdc0a46 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -156,6 +156,11 @@ class InputState { private var allowedMarkRange = 2...mgrPrefs.maxCandidateLength private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } } private(set) var markedRange: Range + private var literalMarkedRange: Range { + let lowerBoundLiteral = composingBuffer.charIndexLiteral(from: markedRange.lowerBound) + let upperBoundLiteral = composingBuffer.charIndexLiteral(from: markedRange.upperBound) + return lowerBoundLiteral.. allowedMarkRange.upperBound { + } else if literalMarkedRange.count > allowedMarkRange.upperBound { ctlInputMethod.tooltipController.setColor(state: .denialOverflow) return String( format: NSLocalizedString( @@ -192,9 +197,7 @@ class InputState { ) } - let literalBegin = composingBuffer.charIndexLiteral(from: markedRange.lowerBound) - let literalEnd = composingBuffer.charIndexLiteral(from: markedRange.upperBound) - let selectedReadings = readings[literalBegin.. Date: Sat, 4 Jun 2022 12:12:10 +0800 Subject: [PATCH 26/42] Repo // Add ctlCandidateUniversal. --- .../Modules/IMEModules/ctlInputMethod.swift | 4 +- Source/UI/CandidateUI/ctlCandidate.swift | 5 + .../CandidateUI/ctlCandidateUniversal.swift | 602 ++++++++++++++++++ vChewing.xcodeproj/project.pbxproj | 4 + 4 files changed, 613 insertions(+), 2 deletions(-) create mode 100644 Source/UI/CandidateUI/ctlCandidateUniversal.swift diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index 353b8650..e52e7e69 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -32,8 +32,8 @@ private let kMinKeyLabelSize: CGFloat = 10 private var ctlCandidateCurrent: ctlCandidate? extension ctlCandidate { - fileprivate static let horizontal = ctlCandidateHorizontal() - fileprivate static let vertical = ctlCandidateVertical() + static let horizontal = ctlCandidateUniversal(.horizontal) + static let vertical = ctlCandidateUniversal(.vertical) } @objc(ctlInputMethod) diff --git a/Source/UI/CandidateUI/ctlCandidate.swift b/Source/UI/CandidateUI/ctlCandidate.swift index 9fb076f5..1bd93c26 100644 --- a/Source/UI/CandidateUI/ctlCandidate.swift +++ b/Source/UI/CandidateUI/ctlCandidate.swift @@ -47,6 +47,11 @@ public protocol ctlCandidateDelegate: AnyObject { } public class ctlCandidate: NSWindowController { + public enum Layout { + case horizontal + case vertical + } + public var currentLayout: Layout = .horizontal public weak var delegate: ctlCandidateDelegate? { didSet { reloadData() diff --git a/Source/UI/CandidateUI/ctlCandidateUniversal.swift b/Source/UI/CandidateUI/ctlCandidateUniversal.swift new file mode 100644 index 00000000..a622265c --- /dev/null +++ b/Source/UI/CandidateUI/ctlCandidateUniversal.swift @@ -0,0 +1,602 @@ +// 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 + + 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.. 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 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) + + 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) + currentLayout = layout + + 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: 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) + } + + 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.. 1, mgrPrefs.showPageButtonsInCandidateWindow { + var buttonRect = nextPageButton.frame + let spacing: CGFloat = 0.0 + + if currentLayout == .horizontal { buttonRect.size.height = floor(newSize.height / 2) } + var buttonOriginY = newSize.height - (buttonRect.size.height * 2.0 + spacing) + if currentLayout == .horizontal { buttonOriginY /= 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) + } +} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 92f54571..af371279 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -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 */; }; @@ -191,6 +192,7 @@ 5B18BA7227C7BD8B0056EB19 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; 5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-JPN.txt"; sourceTree = ""; }; 5B18BA7427C7BD8C0056EB19 /* LICENSE-CHT.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "LICENSE-CHT.txt"; sourceTree = ""; }; + 5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ctlCandidateUniversal.swift; sourceTree = ""; }; 5B2DB17127AF8771006D874E /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Data/Makefile; sourceTree = ""; }; 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = vChewingKeyLayout.bundle; sourceTree = ""; }; 5B3133BE280B229700A4A505 /* KeyHandler_States.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = KeyHandler_States.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; @@ -527,6 +529,7 @@ children = ( 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */, 5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */, + 5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */, 5B62A34127AE7CD900A19448 /* ctlCandidateVertical.swift */, ); path = CandidateUI; @@ -1078,6 +1081,7 @@ 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 */, From 50657278329e77208571c3fee93cc10f696588f8 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 12:48:50 +0800 Subject: [PATCH 27/42] KeyHandler & ctlIME // Use ctlCandidateUniversal instead. --- .../ControllerModules/KeyHandler_Core.swift | 4 +- .../KeyHandler_HandleCandidate.swift | 110 ++++++++++-------- .../Modules/IMEModules/ctlInputMethod.swift | 65 +++++------ 3 files changed, 90 insertions(+), 89 deletions(-) diff --git a/Source/Modules/ControllerModules/KeyHandler_Core.swift b/Source/Modules/ControllerModules/KeyHandler_Core.swift index a12349a5..3374829c 100644 --- a/Source/Modules/ControllerModules/KeyHandler_Core.swift +++ b/Source/Modules/ControllerModules/KeyHandler_Core.swift @@ -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 diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift index 8b9e6eae..a770892c 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleCandidate.swift @@ -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 = @@ -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 } diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index e52e7e69..edd0a42e 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -29,12 +29,7 @@ import InputMethodKit private let kMinKeyLabelSize: CGFloat = 10 -private var ctlCandidateCurrent: ctlCandidate? - -extension ctlCandidate { - static let horizontal = ctlCandidateUniversal(.horizontal) - static let vertical = ctlCandidateUniversal(.vertical) -} +private var ctlCandidateCurrent = ctlCandidateUniversal.init(.horizontal) @objc(ctlInputMethod) class ctlInputMethod: IMKInputController { @@ -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 { @@ -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 @@ -413,7 +408,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 } @@ -430,7 +425,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 } @@ -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( @@ -484,14 +479,14 @@ extension ctlInputMethod { // 上面這句如果是 true 的話,就會是縱排;反之則為橫排。 } - ctlCandidateCurrent?.delegate = nil + ctlCandidateCurrent.delegate = nil if useVerticalMode { - ctlCandidateCurrent = .vertical + ctlCandidateCurrent.currentLayout = .vertical } else if mgrPrefs.useHorizontalCandidateList { - ctlCandidateCurrent = .horizontal + ctlCandidateCurrent.currentLayout = .horizontal } else { - ctlCandidateCurrent = .vertical + ctlCandidateCurrent.currentLayout = .vertical } // set the attributes for the candidate panel (which uses NSAttributedString) @@ -519,10 +514,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 ) @@ -530,15 +525,15 @@ 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 @@ -558,14 +553,14 @@ extension ctlInputMethod { } if useVerticalMode { - ctlCandidateCurrent?.set( + 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 ) @@ -595,19 +590,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: index) - } + ctlCandidate(controller, didSelectCandidateAtIndex: index) } func keyHandler(_ keyHandler: KeyHandler, didRequestWriteUserPhraseWith state: InputState) From ec1a331075ebb4753ac982159144f35e7379c1fb Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 13:40:24 +0800 Subject: [PATCH 28/42] Repo // Remove ctlCandidateHorizontal/Vertical files. --- .../CandidateUI/ctlCandidateHorizontal.swift | 477 ----------------- .../UI/CandidateUI/ctlCandidateVertical.swift | 482 ------------------ vChewing.xcodeproj/project.pbxproj | 8 - 3 files changed, 967 deletions(-) delete mode 100644 Source/UI/CandidateUI/ctlCandidateHorizontal.swift delete mode 100644 Source/UI/CandidateUI/ctlCandidateVertical.swift diff --git a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift b/Source/UI/CandidateUI/ctlCandidateHorizontal.swift deleted file mode 100644 index 2e7ab7a7..00000000 --- a/Source/UI/CandidateUI/ctlCandidateHorizontal.swift +++ /dev/null @@ -1,477 +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: Int = 0 { didSet { highlightedIndex = max(highlightedIndex, 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: Int = .max { - didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) } - } - - 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.. Int { - let location = convert(event.locationInWindow, to: nil) - if !bounds.contains(location) { - return NSNotFound - } - 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 ctlCandidateHorizontal: ctlCandidate { - private var candidateView: HorizontalCandidateView - private var prevPageButton: NSButton - private var nextPageButton: NSButton - private var currentPageIndex: Int = 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: 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 ctlCandidateHorizontal { - 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) - } - - 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.. 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) - } -} diff --git a/Source/UI/CandidateUI/ctlCandidateVertical.swift b/Source/UI/CandidateUI/ctlCandidateVertical.swift deleted file mode 100644 index de56c7c5..00000000 --- a/Source/UI/CandidateUI/ctlCandidateVertical.swift +++ /dev/null @@ -1,482 +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: Int = 0 { didSet { highlightedIndex = max(highlightedIndex, 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: Int = .max { - didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) } - } - - 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.. Int { - let location = convert(event.locationInWindow, to: nil) - if !bounds.contains(location) { - return NSNotFound - } - 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 - } - 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 ctlCandidateVertical: ctlCandidate { - private var candidateView: VerticalCandidateView - private var prevPageButton: NSButton - private var nextPageButton: NSButton - private var currentPageIndex: Int = 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: 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 ctlCandidateVertical { - 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) - } - - 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.. 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) - } -} diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index af371279..0b0e18c8 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -31,9 +31,7 @@ 5B62A33627AE795800A19448 /* mgrPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B62A33527AE795800A19448 /* mgrPrefs.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 */; }; @@ -206,9 +204,7 @@ 5B62A33527AE795800A19448 /* mgrPrefs.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrPrefs.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33727AE79CD00A19448 /* StringUtils.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = StringUtils.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A33C27AE7CC100A19448 /* ctlAboutWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlAboutWindow.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; - 5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidateHorizontal.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; - 5B62A34127AE7CD900A19448 /* ctlCandidateVertical.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidateVertical.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34327AE7CD900A19448 /* TooltipController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = TooltipController.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34527AE7CD900A19448 /* NotifierController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = NotifierController.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B707CE527D9F3A10099EF99 /* SwiftyOpenCC */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SwiftyOpenCC; path = Packages/SwiftyOpenCC; sourceTree = ""; }; @@ -528,9 +524,7 @@ isa = PBXGroup; children = ( 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */, - 5B62A33F27AE7CD900A19448 /* ctlCandidateHorizontal.swift */, 5B242402284B0D6500520FE4 /* ctlCandidateUniversal.swift */, - 5B62A34127AE7CD900A19448 /* ctlCandidateVertical.swift */, ); path = CandidateUI; sourceTree = ""; @@ -1091,7 +1085,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 */, @@ -1100,7 +1093,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 */, From 05fbc1bf23b1494d6419b81f7b438ed93675c22b Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 13:43:05 +0800 Subject: [PATCH 29/42] Repo // VerticalMode -> VerticalTyping. --- .../ControllerModules/InputSignal.swift | 30 +++++++++---------- .../ControllerModules/InputState.swift | 22 +++++++------- .../KeyHandler_HandleInput.swift | 18 +++++------ .../ControllerModules/KeyHandler_States.swift | 12 ++++---- .../Modules/IMEModules/ctlInputMethod.swift | 24 +++++++-------- 5 files changed, 53 insertions(+), 53 deletions(-) diff --git a/Source/Modules/ControllerModules/InputSignal.swift b/Source/Modules/ControllerModules/InputSignal.swift index c972f704..a6f6a423 100644 --- a/Source/Modules/ControllerModules/InputSignal.swift +++ b/Source/Modules/ControllerModules/InputSignal.swift @@ -121,7 +121,7 @@ enum CharCode: UInt16 { } 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 @@ -133,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( @@ -147,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( @@ -157,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 { @@ -182,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 { - "" + "" } // 除了 ANSI charCode 以外,其餘一律過濾掉,免得純 Swift 版 KeyHandler 被餵屎。 @@ -334,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 { diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index afdc0a46..65286924 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -317,11 +317,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: Int, 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) } @@ -337,7 +337,7 @@ class InputState { } override var description: String { - "" + "" } } @@ -347,27 +347,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 { - "" + "" } } 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 ) } @@ -388,7 +388,7 @@ class InputState { } override var description: String { - "" + "" } } } diff --git a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift index acb9633f..5e51dad9 100644 --- a/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift +++ b/Source/Modules/ControllerModules/KeyHandler_HandleInput.swift @@ -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 ) { diff --git a/Source/Modules/ControllerModules/KeyHandler_States.swift b/Source/Modules/ControllerModules/KeyHandler_States.swift index 2c4ea14a..6c516dbc 100644 --- a/Source/Modules/ControllerModules/KeyHandler_States.swift +++ b/Source/Modules/ControllerModules/KeyHandler_States.swift @@ -147,13 +147,13 @@ extension KeyHandler { 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 ) } @@ -168,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 ) } @@ -251,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 { @@ -269,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() diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index edd0a42e..d84cf7c2 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -168,7 +168,7 @@ class ctlInputMethod: IMKInputController { forCharacterIndex: 0, lineHeightRectangle: &textFrame ) - let useVerticalMode = + let isTypingVertical = (attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false if client.bundleIdentifier() @@ -179,7 +179,7 @@ class ctlInputMethod: IMKInputController { IME.areWeUsingOurOwnPhraseEditor = false } - let input = InputSignal(event: event, isVerticalMode: useVerticalMode) + let input = InputSignal(event: event, isVerticalTyping: isTypingVertical) // 無法列印的訊號輸入,一概不作處理。 // 這個過程不能放在 KeyHandler 內,否則不會起作用。 @@ -457,17 +457,17 @@ extension ctlInputMethod { extension ctlInputMethod { private func show(candidateWindowWith state: InputState, client: Any!) { - var useVerticalMode: Bool { - var useVerticalMode = false + var isTypingVertical: Bool { + var isTypingVertical = false var candidates: [String] = [] if let state = state as? InputState.ChoosingCandidate { - useVerticalMode = state.useVerticalMode + isTypingVertical = state.isTypingVertical candidates = state.candidates } else if let state = state as? InputState.AssociatedPhrases { - useVerticalMode = state.useVerticalMode + isTypingVertical = state.isTypingVertical candidates = state.candidates } - if useVerticalMode { return true } + if isTypingVertical { return true } candidates.sort { $0.count > $1.count } @@ -481,7 +481,7 @@ extension ctlInputMethod { ctlCandidateCurrent.delegate = nil - if useVerticalMode { + if isTypingVertical { ctlCandidateCurrent.currentLayout = .vertical } else if mgrPrefs.useHorizontalCandidateList { ctlCandidateCurrent.currentLayout = .horizontal @@ -552,7 +552,7 @@ extension ctlInputMethod { cursor -= 1 } - if useVerticalMode { + if isTypingVertical { ctlCandidateCurrent.set( windowTopLeftPoint: NSPoint( x: lineHeightRect.origin.x + lineHeightRect.size.width + 4.0, y: lineHeightRect.origin.y - 4.0 @@ -662,7 +662,7 @@ extension ctlInputMethod: ctlCandidateDelegate { { if let children = node.children, !children.isEmpty { handle( - state: .SymbolTable(node: node, useVerticalMode: state.useVerticalMode), + state: .SymbolTable(node: node, isTypingVertical: state.isTypingVertical), client: currentClient ) } else { @@ -684,7 +684,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) @@ -702,7 +702,7 @@ extension ctlInputMethod: ctlCandidateDelegate { 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) From 1c3eef64007f5278d8edadf5814ea15abba76c0a Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 14:03:36 +0800 Subject: [PATCH 30/42] ctlIME // Add ctlCandidateVertical pos for horizontal typing. --- Source/Modules/IMEModules/ctlInputMethod.swift | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index d84cf7c2..8b856e0c 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -458,16 +458,22 @@ extension ctlInputMethod { extension ctlInputMethod { private func show(candidateWindowWith state: InputState, client: Any!) { var isTypingVertical: Bool { - var isTypingVertical = false + 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 { - isTypingVertical = state.isTypingVertical candidates = state.candidates } else if let state = state as? InputState.AssociatedPhrases { - isTypingVertical = state.isTypingVertical candidates = state.candidates } if isTypingVertical { return true } + // 以上是通用情形。接下來決定橫排輸入時是否使用縱排選字窗。 candidates.sort { $0.count > $1.count } @@ -481,7 +487,7 @@ extension ctlInputMethod { ctlCandidateCurrent.delegate = nil - if isTypingVertical { + if isCandidateWindowVertical { // 縱排輸入時強制使用縱排選字窗 ctlCandidateCurrent.currentLayout = .vertical } else if mgrPrefs.useHorizontalCandidateList { ctlCandidateCurrent.currentLayout = .horizontal From cf0c99a06d56bbe15430cef8fea765244f51c559 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 21:24:33 +0800 Subject: [PATCH 31/42] PrefUI // Fix selShowPageButtonsInCandidateUI. --- Source/UI/PrefUI/suiPrefPaneGeneral.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/UI/PrefUI/suiPrefPaneGeneral.swift b/Source/UI/PrefUI/suiPrefPaneGeneral.swift index c77cf25c..1551f0e9 100644 --- a/Source/UI/PrefUI/suiPrefPaneGeneral.swift +++ b/Source/UI/PrefUI/suiPrefPaneGeneral.swift @@ -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( From ad5263c6e3d4978f9f5e38727c49a3fa04f7e036 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sat, 4 Jun 2022 18:07:31 +0800 Subject: [PATCH 32/42] ctlCandidate // Add pageCounter. --- .../Modules/IMEModules/ctlInputMethod.swift | 13 ++- .../CandidateUI/ctlCandidateUniversal.swift | 95 +++++++++++++++++-- 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/Source/Modules/IMEModules/ctlInputMethod.swift b/Source/Modules/IMEModules/ctlInputMethod.swift index 8b856e0c..a371cfb7 100644 --- a/Source/Modules/IMEModules/ctlInputMethod.swift +++ b/Source/Modules/IMEModules/ctlInputMethod.swift @@ -487,12 +487,18 @@ extension ctlInputMethod { ctlCandidateCurrent.delegate = nil + /// 下面這一段本可直接指定 currentLayout,但這樣的話翻頁按鈕位置無法精準地重新繪製。 + /// 所以只能重新初期化。壞處就是得在 ctlCandidate() 當中與 SymbolTable 控制有關的地方 + /// 新增一個空狀態請求、防止縱排與橫排選字窗同時出現。 + /// layoutCandidateView 在這裡無法起到糾正作用。 + /// 該問題徹底解決的價值並不大,直接等到 macOS 10.x 全線淘汰之後用 SwiftUI 重寫選字窗吧。 + if isCandidateWindowVertical { // 縱排輸入時強制使用縱排選字窗 - ctlCandidateCurrent.currentLayout = .vertical + ctlCandidateCurrent = .init(.vertical) } else if mgrPrefs.useHorizontalCandidateList { - ctlCandidateCurrent.currentLayout = .horizontal + ctlCandidateCurrent = .init(.horizontal) } else { - ctlCandidateCurrent.currentLayout = .vertical + ctlCandidateCurrent = .init(.vertical) } // set the attributes for the candidate panel (which uses NSAttributedString) @@ -667,6 +673,7 @@ extension ctlInputMethod: ctlCandidateDelegate { let node = state.node.children?[index] { if let children = node.children, !children.isEmpty { + handle(state: .Empty(), client: client) // 防止縱橫排選字窗同時出現 handle( state: .SymbolTable(node: node, isTypingVertical: state.isTypingVertical), client: currentClient diff --git a/Source/UI/CandidateUI/ctlCandidateUniversal.swift b/Source/UI/CandidateUI/ctlCandidateUniversal.swift index a622265c..7447cd16 100644 --- a/Source/UI/CandidateUI/ctlCandidateUniversal.swift +++ b/Source/UI/CandidateUI/ctlCandidateUniversal.swift @@ -33,6 +33,7 @@ private class vwrCandidateUniversal: NSView { var action: Selector? weak var target: AnyObject? var isVerticalLayout: Bool = false + var fractionFontSize: CGFloat = 12.0 private var keyLabels: [String] = [] private var displayedCandidates: [String] = [] @@ -135,6 +136,7 @@ private class vwrCandidateUniversal: NSView { 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) @@ -365,6 +367,7 @@ 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 } @@ -400,10 +403,12 @@ public class ctlCandidateUniversal: ctlCandidate { 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 = NSButton(frame: contentRect) + nextPageButton = .init(frame: contentRect) NSColor.controlBackgroundColor.setFill() NSBezierPath.fill(nextPageButton.bounds) nextPageButton.wantsLayer = true @@ -416,7 +421,7 @@ public class ctlCandidateUniversal: ctlCandidate { nextPageButton.attributedTitle = NSMutableAttributedString( string: " ", attributes: buttonAttribute ) // Next Page Arrow - prevPageButton = NSButton(frame: contentRect) + prevPageButton = .init(frame: contentRect) NSColor.controlBackgroundColor.setFill() NSBezierPath.fill(prevPageButton.bounds) prevPageButton.wantsLayer = true @@ -432,6 +437,24 @@ public class ctlCandidateUniversal: ctlCandidate { 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 @@ -443,6 +466,8 @@ public class ctlCandidateUniversal: ctlCandidate { prevPageButton.target = self prevPageButton.action = #selector(pageButtonAction(_:)) + + pageCounterLabel.font = pageCounterFont } @available(*, unavailable) @@ -529,6 +554,30 @@ extension ctlCandidateUniversal { 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 @@ -551,23 +600,25 @@ extension ctlCandidateUniversal { 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) } - var buttonOriginY = newSize.height - (buttonRect.size.height * 2.0 + spacing) - if currentLayout == .horizontal { buttonOriginY /= 2.0 } - + 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 @@ -576,6 +627,36 @@ extension ctlCandidateUniversal { 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) From 21ed3fed6b9007ff2b715385c0b73ed97bcaa77b Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 00:02:57 +0800 Subject: [PATCH 33/42] Xcode // Enable incremental compilation, etc. --- vChewing.xcodeproj/project.pbxproj | 5 ++++- vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme | 2 +- vChewing.xcodeproj/xcshareddata/xcschemes/vChewing.xcscheme | 2 +- .../xcshareddata/xcschemes/vChewingInstaller.xcscheme | 2 +- .../xcshareddata/xcschemes/vChewingPhraseEditor.xcscheme | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 0b0e18c8..ca14580d 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -893,7 +893,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1320; - LastUpgradeCheck = 1330; + LastUpgradeCheck = 1340; TargetAttributes = { 5BD05BB727B2A429004C4F1D = { CreatedOnToolsVersion = 13.2; @@ -1403,6 +1403,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; @@ -1445,6 +1446,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; @@ -1584,6 +1586,7 @@ 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; diff --git a/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme b/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme index 1c4da1d1..24486708 100644 --- a/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme +++ b/vChewing.xcodeproj/xcshareddata/xcschemes/Data.xcscheme @@ -1,6 +1,6 @@ Date: Sun, 5 Jun 2022 14:48:18 +0800 Subject: [PATCH 34/42] mgrPrefs // Set default max candidate length to 10. - We solved the bug related, hence no need to use the workaround here. --- Source/Modules/IMEModules/mgrPrefs.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Modules/IMEModules/mgrPrefs.swift b/Source/Modules/IMEModules/mgrPrefs.swift index d5cdd12b..c2bff46a 100644 --- a/Source/Modules/IMEModules/mgrPrefs.swift +++ b/Source/Modules/IMEModules/mgrPrefs.swift @@ -346,7 +346,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) From c55f70e464a69a39357b854f21ad4e251ad755c8 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 14:51:54 +0800 Subject: [PATCH 35/42] mgrPrefs // +(Bool)allowBoostingSingleKanjiAsUserPhrase. --- Source/Modules/IMEModules/mgrPrefs.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Source/Modules/IMEModules/mgrPrefs.swift b/Source/Modules/IMEModules/mgrPrefs.swift index c2bff46a..1105d627 100644 --- a/Source/Modules/IMEModules/mgrPrefs.swift +++ b/Source/Modules/IMEModules/mgrPrefs.swift @@ -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 From ca8f28406427ebbd7d50a06b3b73dab77bacd159 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 14:56:03 +0800 Subject: [PATCH 36/42] InputState // Bind allowBoostingSingleKanjiAsUserPhrase. --- Source/Modules/ControllerModules/InputState.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Modules/ControllerModules/InputState.swift b/Source/Modules/ControllerModules/InputState.swift index 65286924..248a81f2 100644 --- a/Source/Modules/ControllerModules/InputState.swift +++ b/Source/Modules/ControllerModules/InputState.swift @@ -153,7 +153,7 @@ class InputState { /// Represents that the user is marking a range in the composing buffer. class Marking: NotEmpty { - private var allowedMarkRange = 2...mgrPrefs.maxCandidateLength + private var allowedMarkRange: ClosedRange = mgrPrefs.minCandidateLength...mgrPrefs.maxCandidateLength private(set) var markerIndex: Int = 0 { didSet { markerIndex = max(markerIndex, 0) } } private(set) var markedRange: Range private var literalMarkedRange: Range { @@ -161,6 +161,7 @@ class InputState { let upperBoundLiteral = composingBuffer.charIndexLiteral(from: markedRange.upperBound) return lowerBoundLiteral.. Date: Sun, 5 Jun 2022 15:16:06 +0800 Subject: [PATCH 37/42] PrefWindow // Add chkAllowBoostingSingleKanjiAsUserPhrase. DDDD --- .../WindowNIBs/Base.lproj/frmPrefWindow.xib | 51 +++++--- .../WindowNIBs/en.lproj/frmPrefWindow.strings | 109 ++++++++--------- .../WindowNIBs/ja.lproj/frmPrefWindow.strings | 109 ++++++++--------- .../zh-Hans.lproj/frmPrefWindow.strings | 110 +++++++++--------- .../zh-Hant.lproj/frmPrefWindow.strings | 109 ++++++++--------- 5 files changed, 255 insertions(+), 233 deletions(-) diff --git a/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib b/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib index 967fa19f..20db6049 100644 --- a/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib +++ b/Source/WindowNIBs/Base.lproj/frmPrefWindow.xib @@ -1,7 +1,8 @@ - + - + + @@ -680,9 +681,9 @@ + - + + - + + + + + - - - + + - - - + + + - diff --git a/Source/WindowNIBs/en.lproj/frmPrefWindow.strings b/Source/WindowNIBs/en.lproj/frmPrefWindow.strings index 1bb6b7c8..0433aa98 100644 --- a/Source/WindowNIBs/en.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/en.lproj/frmPrefWindow.strings @@ -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)."; diff --git a/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings b/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings index 32a956f3..caf8894d 100644 --- a/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/ja.lproj/frmPrefWindow.strings @@ -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" = "アプリ表示用言語をご指定ください、そして入力アプリは自動的に再起動。"; diff --git a/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings b/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings index f0ce6027..7fb31c88 100644 --- a/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/zh-Hans.lproj/frmPrefWindow.strings @@ -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" = "变更使用者接口语言,会自动重新启动输入法。"; diff --git a/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings b/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings index dd156cee..37a832b6 100644 --- a/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings +++ b/Source/WindowNIBs/zh-Hant.lproj/frmPrefWindow.strings @@ -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" = "變更使用者介面語言,會自動重新啟動輸入法。"; From ac355768acc77a7091ba787aedd4c6beb2d06d2d Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 15:25:23 +0800 Subject: [PATCH 38/42] PrefUI // Add chkAllowBoostingSingleKanjiAsUserPhrase. DDD --- .../Resources/Base.lproj/Localizable.strings | 1 + Source/Resources/en.lproj/Localizable.strings | 1 + Source/Resources/ja.lproj/Localizable.strings | 1 + .../zh-Hans.lproj/Localizable.strings | 1 + .../zh-Hant.lproj/Localizable.strings | 1 + Source/UI/PrefUI/suiPrefPaneDictionary.swift | 22 ++++++++++++++----- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Source/Resources/Base.lproj/Localizable.strings b/Source/Resources/Base.lproj/Localizable.strings index 55469beb..9fc16468 100644 --- a/Source/Resources/Base.lproj/Localizable.strings +++ b/Source/Resources/Base.lproj/Localizable.strings @@ -82,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"; diff --git a/Source/Resources/en.lproj/Localizable.strings b/Source/Resources/en.lproj/Localizable.strings index 55469beb..9fc16468 100644 --- a/Source/Resources/en.lproj/Localizable.strings +++ b/Source/Resources/en.lproj/Localizable.strings @@ -82,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"; diff --git a/Source/Resources/ja.lproj/Localizable.strings b/Source/Resources/ja.lproj/Localizable.strings index 1d0f6f16..0a2fd83c 100644 --- a/Source/Resources/ja.lproj/Localizable.strings +++ b/Source/Resources/ja.lproj/Localizable.strings @@ -82,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 大千注音キーボード"; diff --git a/Source/Resources/zh-Hans.lproj/Localizable.strings b/Source/Resources/zh-Hans.lproj/Localizable.strings index 89b4c435..d514925c 100644 --- a/Source/Resources/zh-Hans.lproj/Localizable.strings +++ b/Source/Resources/zh-Hans.lproj/Localizable.strings @@ -82,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 大千注音键盘排列"; diff --git a/Source/Resources/zh-Hant.lproj/Localizable.strings b/Source/Resources/zh-Hant.lproj/Localizable.strings index 232da7f1..95f5f1d9 100644 --- a/Source/Resources/zh-Hant.lproj/Localizable.strings +++ b/Source/Resources/zh-Hant.lproj/Localizable.strings @@ -82,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 大千注音鍵盤佈局"; diff --git a/Source/UI/PrefUI/suiPrefPaneDictionary.swift b/Source/UI/PrefUI/suiPrefPaneDictionary.swift index cb0b1bfd..660b1221 100644 --- a/Source/UI/PrefUI/suiPrefPaneDictionary.swift +++ b/Source/UI/PrefUI/suiPrefPaneDictionary.swift @@ -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": @@ -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 + } } } } From dca8f383eb57d665f531ae498f8caa01dbddef9b Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 23:28:09 +0800 Subject: [PATCH 39/42] Repo // Manage README-CHT.md in Xcode. --- vChewing.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index ca14580d..07061f6f 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -207,6 +207,7 @@ 5B62A34027AE7CD900A19448 /* ctlCandidate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlCandidate.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34327AE7CD900A19448 /* TooltipController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = TooltipController.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 5B62A34527AE7CD900A19448 /* NotifierController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = NotifierController.swift; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; + 5B65B919284D0185007C558B /* README-CHT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "README-CHT.md"; sourceTree = ""; }; 5B707CE527D9F3A10099EF99 /* SwiftyOpenCC */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = SwiftyOpenCC; path = Packages/SwiftyOpenCC; sourceTree = ""; }; 5B707CE727D9F4590099EF99 /* OpenCCBridge.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = OpenCCBridge.swift; sourceTree = ""; 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; }; @@ -371,6 +372,7 @@ 5B18BA7327C7BD8C0056EB19 /* LICENSE-JPN.txt */, 5B18BA7227C7BD8B0056EB19 /* LICENSE.txt */, 5B18BA7127C7BD8B0056EB19 /* README.md */, + 5B65B919284D0185007C558B /* README-CHT.md */, ); name = MiscRootFiles; sourceTree = ""; From bc2335e245d19e59e4097c9e75d1714da717cff2 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 21:53:06 +0800 Subject: [PATCH 40/42] Repo // Update copyright notices. --- Installer/Installer-Info.plist | 2 +- .../Resources/en.lproj/InfoPlist.strings | 2 +- Installer/Resources/en.lproj/MainMenu.strings | 4 +-- .../Resources/ja.lproj/InfoPlist.strings | 2 +- Installer/Resources/ja.lproj/MainMenu.strings | 4 +-- .../Resources/zh-Hans.lproj/InfoPlist.strings | 2 +- .../Resources/zh-Hans.lproj/MainMenu.strings | 4 +-- .../Resources/zh-Hant.lproj/InfoPlist.strings | 2 +- .../Resources/zh-Hant.lproj/MainMenu.strings | 4 +-- LICENSE-CHS.txt | 5 +-- LICENSE-CHT.txt | 5 +-- LICENSE-JPN.txt | 4 +-- LICENSE.txt | 5 +-- README-CHT.md | 10 ++---- README.md | 32 ++++++++----------- Source/Resources/Base.lproj/InfoPlist.strings | 2 +- Source/Resources/IME-Info.plist | 2 +- Source/Resources/en.lproj/InfoPlist.strings | 2 +- Source/Resources/ja.lproj/InfoPlist.strings | 2 +- .../Resources/zh-Hans.lproj/InfoPlist.strings | 2 +- .../Resources/zh-Hant.lproj/InfoPlist.strings | 2 +- .../en.lproj/frmAboutWindow.strings | 8 ++--- .../ja.lproj/frmAboutWindow.strings | 8 ++--- .../zh-Hans.lproj/frmAboutWindow.strings | 8 ++--- .../zh-Hant.lproj/frmAboutWindow.strings | 8 ++--- 25 files changed, 54 insertions(+), 77 deletions(-) diff --git a/Installer/Installer-Info.plist b/Installer/Installer-Info.plist index 4f418f3e..011f90fa 100644 --- a/Installer/Installer-Info.plist +++ b/Installer/Installer-Info.plist @@ -29,7 +29,7 @@ LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright - © 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. + © 2021-2022 vChewing Project. NSMainNibFile MainMenu NSPrincipalClass diff --git a/Installer/Resources/en.lproj/InfoPlist.strings b/Installer/Resources/en.lproj/InfoPlist.strings index 400f8bfd..bd9197ae 100644 --- a/Installer/Resources/en.lproj/InfoPlist.strings +++ b/Installer/Resources/en.lproj/InfoPlist.strings @@ -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"; diff --git a/Installer/Resources/en.lproj/MainMenu.strings b/Installer/Resources/en.lproj/MainMenu.strings index 128b545d..cd923190 100644 --- a/Installer/Resources/en.lproj/MainMenu.strings +++ b/Installer/Resources/en.lproj/MainMenu.strings @@ -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."; diff --git a/Installer/Resources/ja.lproj/InfoPlist.strings b/Installer/Resources/ja.lproj/InfoPlist.strings index 1d9cb312..03db32e3 100644 --- a/Installer/Resources/ja.lproj/InfoPlist.strings +++ b/Installer/Resources/ja.lproj/InfoPlist.strings @@ -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作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。"; diff --git a/Installer/Resources/ja.lproj/MainMenu.strings b/Installer/Resources/ja.lproj/MainMenu.strings index bda4245d..579abd44 100644 --- a/Installer/Resources/ja.lproj/MainMenu.strings +++ b/Installer/Resources/ja.lproj/MainMenu.strings @@ -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 Suen(Lukhnos の 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."; diff --git a/Installer/Resources/zh-Hans.lproj/InfoPlist.strings b/Installer/Resources/zh-Hans.lproj/InfoPlist.strings index e869099b..a87e9113 100644 --- a/Installer/Resources/zh-Hans.lproj/InfoPlist.strings +++ b/Installer/Resources/zh-Hans.lproj/InfoPlist.strings @@ -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"; diff --git a/Installer/Resources/zh-Hans.lproj/MainMenu.strings b/Installer/Resources/zh-Hans.lproj/MainMenu.strings index 49bcceef..a1316c29 100644 --- a/Installer/Resources/zh-Hans.lproj/MainMenu.strings +++ b/Installer/Resources/zh-Hans.lproj/MainMenu.strings @@ -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."; diff --git a/Installer/Resources/zh-Hant.lproj/InfoPlist.strings b/Installer/Resources/zh-Hant.lproj/InfoPlist.strings index 006fab5a..68d9d28c 100644 --- a/Installer/Resources/zh-Hant.lproj/InfoPlist.strings +++ b/Installer/Resources/zh-Hant.lproj/InfoPlist.strings @@ -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"; diff --git a/Installer/Resources/zh-Hant.lproj/MainMenu.strings b/Installer/Resources/zh-Hant.lproj/MainMenu.strings index 1da9c6a1..a9c75479 100644 --- a/Installer/Resources/zh-Hant.lproj/MainMenu.strings +++ b/Installer/Resources/zh-Hant.lproj/MainMenu.strings @@ -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."; diff --git a/LICENSE-CHS.txt b/LICENSE-CHS.txt index a636a2f4..b76078c6 100644 --- a/LICENSE-CHS.txt +++ b/LICENSE-CHS.txt @@ -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 重写而得。 软件之著作权利人依此麻理授权条款,将其对于软件之著作权利授权释出,只须使用者践履以下二项麻理授权条款叙明之义务性规定,其即享有对此软件程式及其相关说明文档自由不受限制地进行利用之权利,范围包括「使用、重制、修改、合并、出版、散布、再授权、及贩售程式重制作品」等诸多方面之应用,而散布程式之人、更可将上述权利传递予其后收受程式之后手,倘若其后收受程式之人亦服膺以下二项麻理授权条款之义务性规定,则其对程式亦享有与前手运用范围相同之同一权利。 diff --git a/LICENSE-CHT.txt b/LICENSE-CHT.txt index 55e191ae..a392729f 100644 --- a/LICENSE-CHT.txt +++ b/LICENSE-CHT.txt @@ -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 重寫而得。 軟體之著作權利人依此麻理授權條款,將其對於軟體之著作權利授權釋出,只須使用者踐履以下二項麻理授權條款敘明之義務性規定,其即享有對此軟體程式及其相關說明文檔自由不受限制地進行利用之權利,範圍包括「使用、重製、修改、合併、出版、散布、再授權、及販售程式重製作品」等諸多方面之應用,而散布程式之人、更可將上述權利傳遞予其後收受程式之後手,倘若其後收受程式之人亦服膺以下二項麻理授權條款之義務性規定,則其對程式亦享有與前手運用範圍相同之同一權利。 diff --git a/LICENSE-JPN.txt b/LICENSE-JPN.txt index 490f836a..f1c5a835 100644 --- a/LICENSE-JPN.txt +++ b/LICENSE-JPN.txt @@ -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 Suen(Lukhnos の Gramambular C++ エンジンを Swift で再開発したものである)。 以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。 diff --git a/LICENSE.txt b/LICENSE.txt index 803369ca..b663cec9 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -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: diff --git a/README-CHT.md b/README-CHT.md index 69161357..efb29760 100644 --- a/README-CHT.md +++ b/README-CHT.md @@ -80,9 +80,7 @@ ## 應用授權 -小麥注音引擎程式版權(MIT 授權):© 2011-2021 OpenVanilla 專案團隊(Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等)。 - -威注音專案僅用到小麥注音的下述程式組件: +威注音專案僅用到小麥注音的下述程式組件(MIT License): - 狀態管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang)。 @@ -98,7 +96,7 @@ - 鐵恨注音並擊處理引擎:Shiki Suen (MIT-NTL License)。 -- 天權星語彙處理引擎:Shiki Suen (MIT-NTL License),針對「Lukhnos Liu 用 C++ 寫的 Gramambular」用 Swift 徹底重寫而成。 +- 天權星語彙處理引擎:Shiki Suen (MIT-NTL License)。 - 威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。 @@ -116,8 +114,4 @@ 濫用沉默權來浪費對方的時間與熱情,也是一種暴力。**當對方最最最開始就把你當敵人的時候,你連呼吸都是錯的**。 -其實我滿懷念上游專案還沒被 Lukhnos Liu 接管收入 OpenVanilla 的那個年代。MJHsieh 主導開發小麥注音的時候,且不討論他立場怎樣,但基礎的技術交流是完全沒問題的。LibChewing 那邊也是,正常交流完全沒問題。 - -有些事情,繼續爭論下去也沒用。本來我想著重寫 ctlInputMethod 撤掉 zonble 的狀態管理引擎的,畢竟有大陸同鄉寫的火山五筆輸入法的框架套上我的鐵恨注音並擊引擎可以直接用。但這樣賭氣對誰都沒好處。眼下,威注音 macOS 版還需要一些小維護。之後我就得開始考慮用 Windows 平台可用的除了 C++ 以外的語言重寫鐵恨注音並擊引擎與天權星語彙引擎、方便接下來威注音的 Windows 版本的研發。能將 Lukhnos 的 C++ 內容全部換掉、徹底砸碎套在威注音身上的名為 C++ 的枷鎖、讓威注音有一個自由的未來,我已經知足了。讓更多的人用上好用的輸入法,才是最重要的。**這個重要性,不是 zonble 用「私人需求」這種帽子扣過來、就可以泯滅了的**。 - $ EOF. diff --git a/README.md b/README.md index 80169e8f..04f8d364 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ >- 可以自动整理用户语汇文档格式、自订联想词。 >- …… -威注音分支项目及威注音词库由孙志贵(Shiki Suen)维护。小麦注音官方原始仓库内的词库的内容均与孙志贵无关。 +威注音分支专案及威注音词库由孙志贵(Shiki Suen)维护。小麦注音官方原始仓库内的词库的内容均与孙志贵无关。 ## 系统需求 @@ -60,45 +60,43 @@ ## 建置流程 -安装 Xcode 之后,请先配置 Xcode 允许其直接构建在项目所在的文档夹下的 build 文档夹内。步骤: +安装 Xcode 之后,请先配置 Xcode 允许其直接构建在专案所在的文档夹下的 build 文档夹内。步骤: ``` 「Xcode」->「Preferences...」->「Locations」; 「File」->「Project/WorkspaceSettings...」->「Advanced」; 选「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)。 - 半衰记忆模块,因故障暂时无法激活 (by Mengjuei Hsieh)。 -- 仅供研发人员调试方便而使用的 App 版安装进程 (by Zonble Yang)。 +- 仅供研发人员调试方便而使用的 App 版安装程序 (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),针对「Lukhnos Liu 用 C++ 写的 Gramambular」用 Swift 彻底重写而成。 +- 天权星语汇处理引擎:Shiki Suen (MIT-NTL License)。 - 威注音词库由 Shiki Suen 维护,以 3-Clause BSD License 授权发布。其中的词频数据[由 NAER 授权用于非商业用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。 @@ -106,7 +104,7 @@ ## 格式规范等与参与研发时需要注意的事项 -该项目对源码格式有规范,且 Swift 与其他 (Obj)C(++) 系语言持不同规范: +该专案对源码格式有规范,且 Swift 与其他 (Obj)C(++) 系语言持不同规范: 请查看该仓库内的「[CONTRIBUTING.md](./CONTRIBUTING.md)」文档。 @@ -116,8 +114,4 @@ 滥用沉默权来浪费对方的时间与热情,也是一种暴力。**当对方最最最开始就把你当敌人的时候,你连呼吸都是错的**。 -其实我满怀念上游项目还没被 Lukhnos Liu 接管收入 OpenVanilla 的那个年代。MJHsieh 主导开发小麦注音的时候,且不讨论他立场怎样,但基础的技术交流是完全没问题的。LibChewing 那边也是,正常交流完全没问题。 - -有些事情,继续争论下去也没用。本来我想着重写 ctlInputMethod 撤掉 zonble 的状态管理引擎的,毕竟有大陆同乡写的火山五笔输入法的框架套上我的铁恨注音并击引擎可以直接用。但这样赌气对谁都没好处。眼下,威注音 macOS 版还需要一些小维护。之后我就得开始考虑用 Windows 平台可用的除了 C++ 以外的语言重写铁恨注音并击引擎与天权星语汇引擎、方便接下来威注音的 Windows 版本的研发。能将 Lukhnos 的 C++ 内容全部换掉、彻底砸碎套在威注音身上的名为 C++ 的枷锁、让威注音有一个自由的未来,我已经知足了。让更多的人用上好用的输入法,才是最重要的。**这个重要性,不是 zonble 用「私人需求」这种帽子扣过来、就可以泯灭了的**。 - $ EOF. diff --git a/Source/Resources/Base.lproj/InfoPlist.strings b/Source/Resources/Base.lproj/InfoPlist.strings index 67d2769d..ac47159c 100644 --- a/Source/Resources/Base.lproj/InfoPlist.strings +++ b/Source/Resources/Base.lproj/InfoPlist.strings @@ -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"; diff --git a/Source/Resources/IME-Info.plist b/Source/Resources/IME-Info.plist index 220b7cd1..4ea76f83 100644 --- a/Source/Resources/IME-Info.plist +++ b/Source/Resources/IME-Info.plist @@ -106,7 +106,7 @@ LSUIElement NSHumanReadableCopyright - © 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project. + © 2021-2022 vChewing Project. NSMainNibFile MainMenu NSPrincipalClass diff --git a/Source/Resources/en.lproj/InfoPlist.strings b/Source/Resources/en.lproj/InfoPlist.strings index 67d2769d..ac47159c 100644 --- a/Source/Resources/en.lproj/InfoPlist.strings +++ b/Source/Resources/en.lproj/InfoPlist.strings @@ -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"; diff --git a/Source/Resources/ja.lproj/InfoPlist.strings b/Source/Resources/ja.lproj/InfoPlist.strings index aaae7526..7b58f468 100644 --- a/Source/Resources/ja.lproj/InfoPlist.strings +++ b/Source/Resources/ja.lproj/InfoPlist.strings @@ -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作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。"; diff --git a/Source/Resources/zh-Hans.lproj/InfoPlist.strings b/Source/Resources/zh-Hans.lproj/InfoPlist.strings index 5280246e..1be0d491 100644 --- a/Source/Resources/zh-Hans.lproj/InfoPlist.strings +++ b/Source/Resources/zh-Hans.lproj/InfoPlist.strings @@ -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"; diff --git a/Source/Resources/zh-Hant.lproj/InfoPlist.strings b/Source/Resources/zh-Hant.lproj/InfoPlist.strings index a9ce050b..91fb8f5c 100644 --- a/Source/Resources/zh-Hant.lproj/InfoPlist.strings +++ b/Source/Resources/zh-Hant.lproj/InfoPlist.strings @@ -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"; diff --git a/Source/WindowNIBs/en.lproj/frmAboutWindow.strings b/Source/WindowNIBs/en.lproj/frmAboutWindow.strings index a05b24a3..2bb44275 100644 --- a/Source/WindowNIBs/en.lproj/frmAboutWindow.strings +++ b/Source/WindowNIBs/en.lproj/frmAboutWindow.strings @@ -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."; diff --git a/Source/WindowNIBs/ja.lproj/frmAboutWindow.strings b/Source/WindowNIBs/ja.lproj/frmAboutWindow.strings index 4ae9cb84..2f25f6b2 100644 --- a/Source/WindowNIBs/ja.lproj/frmAboutWindow.strings +++ b/Source/WindowNIBs/ja.lproj/frmAboutWindow.strings @@ -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 Suen(Lukhnos の 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。"; diff --git a/Source/WindowNIBs/zh-Hans.lproj/frmAboutWindow.strings b/Source/WindowNIBs/zh-Hans.lproj/frmAboutWindow.strings index cc8903c3..234a4a42 100644 --- a/Source/WindowNIBs/zh-Hans.lproj/frmAboutWindow.strings +++ b/Source/WindowNIBs/zh-Hans.lproj/frmAboutWindow.strings @@ -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。"; diff --git a/Source/WindowNIBs/zh-Hant.lproj/frmAboutWindow.strings b/Source/WindowNIBs/zh-Hant.lproj/frmAboutWindow.strings index 58f38111..248929f1 100644 --- a/Source/WindowNIBs/zh-Hant.lproj/frmAboutWindow.strings +++ b/Source/WindowNIBs/zh-Hant.lproj/frmAboutWindow.strings @@ -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。"; From 2897da677e80cdc571fae2ffe322fd6b854233ac Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 17:48:10 +0800 Subject: [PATCH 41/42] Update Data - 20220605 --- Source/Data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Data b/Source/Data index 924c8f41..06d16d8a 160000 --- a/Source/Data +++ b/Source/Data @@ -1 +1 @@ -Subproject commit 924c8f4156edf2f034b45f5f06d488e5e81d351c +Subproject commit 06d16d8a468668278ad9f50cc8629983c490fa42 From 66d69ea5f5bedb3556ea68daf04596f74f3215b5 Mon Sep 17 00:00:00 2001 From: ShikiSuen Date: Sun, 5 Jun 2022 19:43:18 +0800 Subject: [PATCH 42/42] Bump version to 1.7.0 Build 1970. --- Update-Info.plist | 4 ++-- vChewing.pkgproj | 2 +- vChewing.xcodeproj/project.pbxproj | 24 ++++++++++++------------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Update-Info.plist b/Update-Info.plist index c7488b69..71c02ceb 100644 --- a/Update-Info.plist +++ b/Update-Info.plist @@ -3,9 +3,9 @@ CFBundleShortVersionString - 1.6.3 + 1.7.0 CFBundleVersion - 1963 + 1970 UpdateInfoEndpoint https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist UpdateInfoSite diff --git a/vChewing.pkgproj b/vChewing.pkgproj index 426823d0..c781ad21 100644 --- a/vChewing.pkgproj +++ b/vChewing.pkgproj @@ -726,7 +726,7 @@ USE_HFS+_COMPRESSION VERSION - 1.6.3 + 1.7.0 TYPE 0 diff --git a/vChewing.xcodeproj/project.pbxproj b/vChewing.xcodeproj/project.pbxproj index 07061f6f..8d97beb1 100644 --- a/vChewing.xcodeproj/project.pbxproj +++ b/vChewing.xcodeproj/project.pbxproj @@ -1294,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; @@ -1317,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; @@ -1350,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; @@ -1369,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; @@ -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,7 +1583,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.inputmethod.vChewing; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1667,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; @@ -1692,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)"; @@ -1719,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; @@ -1739,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 = "";