Pre Merge pull request !31 from ShikiSuen/upd/1.5.7
This commit is contained in:
commit
d0c39805e0
|
@ -6,13 +6,8 @@
|
|||
|
||||
為了不讓參與者們浪費各自的熱情,特設此文以說明該專案目前最需要協助的地方。
|
||||
|
||||
1. 有人能用 Swift 將該專案內的這個源自 LibFormosa 的組件套件重寫:
|
||||
- Mandarin 組件,用以分析普通話音韻數據、創建且控制 Syllable Composer 注音拼識組件。
|
||||
- 一堆記憶體指針操作,實在看不懂這個組件的處理邏輯是什麼,無能為力。
|
||||
2. 讓 Alt+波浪鍵選單能夠在諸如 MS Word 以及終端機內正常工作(可以用方向鍵控制高亮候選內容,等)。
|
||||
1. 讓 Alt+波浪鍵選單能夠在諸如 MS Word 以及終端機內正常工作(可以用方向鍵控制高亮候選內容,等)。
|
||||
- 原理上而言恐怕得欺騙當前正在接受輸入的應用、使其誤以為當前有組字區。這只是推測。
|
||||
3. SQLite 實現。
|
||||
|
||||
|
||||
除了上述各項以外的貢獻,除非特邀、或者有足夠的說服理由與吸引力(比如語法錯誤或更好的重構方法等),否則敝專案可能會無視或者拒絕。
|
||||
|
||||
|
|
|
@ -132,17 +132,17 @@
|
|||
</connections>
|
||||
</button>
|
||||
<scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" findBarPosition="belowContent" translatesAutoresizingMaskIntoConstraints="NO" id="YCR-wo-M5a">
|
||||
<rect key="frame" x="91" y="166" width="427" height="160"/>
|
||||
<rect key="frame" x="91" y="166" width="427" height="190"/>
|
||||
<clipView key="contentView" drawsBackground="NO" id="NrY-FL-PVu" userLabel="appEULAContentClip">
|
||||
<rect key="frame" x="1" y="1" width="425" height="158"/>
|
||||
<rect key="frame" x="1" y="1" width="425" height="188"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" findStyle="bar" smartInsertDelete="YES" id="47J-tO-8TZ" userLabel="appEULAContent">
|
||||
<rect key="frame" x="0.0" y="-2" width="425" height="158"/>
|
||||
<rect key="frame" x="0.0" y="-2" width="425" height="188"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="minSize" width="425" height="158"/>
|
||||
<size key="minSize" width="425" height="188"/>
|
||||
<size key="maxSize" width="427" height="10000000"/>
|
||||
<attributedString key="textStorage">
|
||||
<fragment content="Placeholder for EULA Texts.">
|
||||
|
@ -162,7 +162,7 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="NO" id="E5B-3B-faV">
|
||||
<rect key="frame" x="412" y="1" width="14" height="158"/>
|
||||
<rect key="frame" x="412" y="1" width="14" height="188"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
|
@ -194,11 +194,9 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XLb-mv-73s">
|
||||
<rect key="frame" x="89" y="357" width="431" height="45"/>
|
||||
<textFieldCell key="cell" selectable="YES" id="VW8-s5-Wpn">
|
||||
<rect key="frame" x="89" y="387" width="431" height="15"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="Placeholder for detailed credits." id="VW8-s5-Wpn">
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
<string key="title">McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.
|
||||
vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
vChewing Phrase Database Maintained by Shiki Suen.</string>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -207,7 +205,7 @@ vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
vChewing
|
|||
<rect key="frame" x="15" y="137" width="503" height="5"/>
|
||||
</box>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="k5O-zZ-gQY">
|
||||
<rect key="frame" x="89" y="334" width="431" height="15"/>
|
||||
<rect key="frame" x="89" y="364" width="431" height="15"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="MIT-NTL License:" id="AVS-ih-FXM">
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
|
|
|
@ -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 = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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" = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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 = "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 = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
|
||||
// "eo3-TK-0rB.title" = "Placeholder for showing copyright information.";
|
||||
|
|
|
@ -56,8 +56,8 @@
|
|||
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
|
||||
"QYf-Nf-hoi.title" = "OpenVanilla 小麦注音プロジェクトから派生。";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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" = "ボポモフォエンジン開発:Lukhnos Liu。\n入力状態管理システム開発:Zonble Yang。\nmacOS 版威注音の開発:Shiki Suen, Isaac Xen, Hiraku Wang, など。\n威注音語彙データの維持:Shiki Suen。\nMegrez 辞書処理エンジン:Shiki Suen(Lukhnos の Gramambular C++ エンジンを Swift で再開発したものである)。";
|
||||
/* 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 = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
|
||||
"eo3-TK-0rB.title" = "Placeholder for showing copyright information.";
|
||||
|
|
|
@ -56,9 +56,8 @@
|
|||
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
|
||||
"QYf-Nf-hoi.title" = "该专案由 OpenVanilla 小麦注音专案衍生而来。";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
|
||||
vChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */
|
||||
"VW8-s5-Wpn.title" = "注音拼音输入处理引擎研发:Lukhnos Liu。\n输入法状态管理引擎研发:Zonble Yang。\n威注音 macOS 程式研发:Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护:Shiki Suen。\n天权星语汇引擎:Shiki Suen,用 Swift 将 Lukhnos 的 C++ Gramambular 重写而得。";
|
||||
/* 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 = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
|
||||
// "eo3-TK-0rB.title" = "Placeholder for showing copyright information.";
|
||||
|
|
|
@ -56,9 +56,8 @@
|
|||
/* Class = "NSTextFieldCell"; title = "Derived from OpenVanilla McBopopmofo Project."; ObjectID = "QYf-Nf-hoi"; */
|
||||
"QYf-Nf-hoi.title" = "該專案由 OpenVanilla 小麥注音專案衍生而來。";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.\nvChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
|
||||
vChewing Phrase Database Maintained by Shiki Suen."; ObjectID = "VW8-s5-Wpn"; */
|
||||
"VW8-s5-Wpn.title" = "注音拼音輸入處理引擎研發:Lukhnos Liu。\n輸入法狀態管理引擎研發:Zonble Yang。\n威注音 macOS 程式研發:Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音詞庫維護:Shiki Suen。\n天權星語彙引擎:Shiki Suen,用 Swift 將 Lukhnos 的 C++ Gramambular 重寫而得。";
|
||||
/* 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 = "Placeholder for showing copyright information."; ObjectID = "eo3-TK-0rB"; */
|
||||
// "eo3-TK-0rB.title" = "Placeholder for showing copyright information.";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.1" encoding="UTF-8"?>
|
||||
<!DOCTYPE keyboard SYSTEM "file://localhost/System/Library/DTDs/KeyboardLayout.dtd">
|
||||
<!--Last edited by Ukelele version 351 on 2022-03-08 at 13:26 (GMT+8)-->
|
||||
<keyboard group="126" id="-17519" name="vChewing FakeSeigyou" maxout="1">
|
||||
<!--Last edited by Ukelele version 351 on 2022-05-12 at 11:52 (GMT+8)-->
|
||||
<keyboard group="126" id="-30406" name="vChewing FakeSeigyou" maxout="1">
|
||||
<layouts>
|
||||
<layout first="0" last="17" mapSet="16c" modifiers="f4"/>
|
||||
<layout first="18" last="18" mapSet="a88" modifiers="f4"/>
|
||||
|
@ -84,7 +84,7 @@
|
|||
<key code="36" output="
"/>
|
||||
<key code="37" output="ㄠ"/>
|
||||
<key code="38" output="ㄘ"/>
|
||||
<key code="39" output="ㄩ"/>
|
||||
<key code="39" output="'"/>
|
||||
<key code="40" output="ㄜ"/>
|
||||
<key code="41" output="ㄤ"/>
|
||||
<key code="42" output="、"/>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
vChewing macOS: MIT-NTL License 麻理(去商标)授权合约
|
||||
|
||||
© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.
|
||||
注音拼音输入处理引擎研发:Lukhnos Liu。
|
||||
铁恨注音并击输入处理引擎研发:Shiki Suen。
|
||||
输入法状态管理引擎研发:Zonble Yang。
|
||||
威注音 macOS 程式研发:Shiki Suen, Isaac Xen, Hiraku Wang, 等。
|
||||
威注音词库维护:Shiki Suen。
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
vChewing macOS: MIT-NTL License 麻理(去商標)授權合約
|
||||
|
||||
© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.
|
||||
注音拼音輸入處理引擎研發:Lukhnos Liu。
|
||||
鐵恨注音並擊輸入處理引擎研發:Shiki Suen。
|
||||
輸入法狀態管理引擎研發:Zonble Yang。
|
||||
威注音 macOS 程式研發:Shiki Suen, Isaac Xen, Hiraku Wang, 等。
|
||||
威注音詞庫維護:Shiki Suen。
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
vChewing macOS: MIT商標不許可ライセンス (MIT-NTL License)
|
||||
|
||||
ボポモフォエンジン開発:Lukhnos Liu。
|
||||
鉄恨ボポモフォエンジン開発:Shiki Suen。
|
||||
入力状態管理システム開発:Zonble Yang。
|
||||
macOS 版威注音の開発:Shiki Suen, Isaac Xen, Hiraku Wang, など。
|
||||
威注音語彙データの維持:Shiki Suen。
|
||||
|
|
|
@ -3,7 +3,7 @@ DISCLAIMER: The vChewing project, having no relationship of cooperation or affil
|
|||
vChewing macOS: MIT-NTL License
|
||||
|
||||
© 2011-2022 OpenVanilla Project & © 2021-2022 vChewing Project.
|
||||
Mandarin Syllable Composer Engine by Lukhnos Liu.
|
||||
Tekkon Syllable Composition Engine by Shiki Suen.
|
||||
Input State Management Architecture by Zonble Yang.
|
||||
vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
|
||||
vChewing Phrase Database Maintained by Shiki Suen.
|
||||
|
|
16
README.md
16
README.md
|
@ -68,11 +68,23 @@
|
|||
|
||||
小麥注音引擎程式版權(MIT 授權):© 2011-2021 OpenVanilla 專案團隊(Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, 等)。
|
||||
|
||||
威注音專案僅用到小麥注音的下述程式組件:
|
||||
|
||||
- 狀態管理引擎 & NSStringUtils & FSEventStreamHelper (by Zonble Yang)。
|
||||
|
||||
- 半衰記憶模組,因故障暫時無法啟用 (by Mengjuei Hsieh)。
|
||||
|
||||
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang)。
|
||||
|
||||
威注音輸入法 macOS 版以 MIT-NTL License 授權釋出 (與 MIT 相容):© 2021-2022 vChewing 專案。
|
||||
|
||||
威注音輸入法 macOS 版程式維護:Shiki Suen。特別感謝 Hiraku Wong 等人的技術協力。
|
||||
- 威注音輸入法 macOS 版程式維護:Shiki Suen。特別感謝 Isaac Xen 與 Hiraku Wong 等人的技術協力。
|
||||
|
||||
威注音詞庫由 Shiki Suen 維護,以 3-Clause BSD License 授權釋出。其中的詞頻數據[由 NAER 授權用於非商業用途](https://twitter.com/ShikiSuen/status/1479329302713831424)。
|
||||
- 鐵恨注音並擊處理引擎: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)。
|
||||
|
||||
使用者可自由使用、散播本軟體,惟散播時必須完整保留版權聲明及軟體授權、且一旦經過修改便不可以再繼續使用威注音的產品名稱。
|
||||
|
||||
|
|
|
@ -1,44 +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 <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface Composer : NSObject
|
||||
+ (BOOL)chkKeyValidity:(UniChar)charCode;
|
||||
+ (BOOL)isBufferEmpty;
|
||||
+ (void)clearBuffer;
|
||||
+ (void)combineReadingKey:(UniChar)charCode;
|
||||
+ (BOOL)hasToneMarker;
|
||||
+ (BOOL)hasToneMarkerOnly;
|
||||
+ (NSString *)getSyllableComposition;
|
||||
+ (void)doBackSpaceToBuffer;
|
||||
+ (NSString *)getComposition;
|
||||
+ (void)ensureParser;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,122 +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 "Composer.hh"
|
||||
#import "Mandarin.h"
|
||||
#import "vChewing-Swift.h"
|
||||
|
||||
static Mandarin::BopomofoReadingBuffer *PhoneticBuffer;
|
||||
|
||||
@implementation Composer
|
||||
|
||||
+ (BOOL)chkKeyValidity:(UniChar)charCode
|
||||
{
|
||||
return PhoneticBuffer->isValidKey((char)charCode);
|
||||
}
|
||||
|
||||
+ (BOOL)isBufferEmpty
|
||||
{
|
||||
return PhoneticBuffer->isEmpty();
|
||||
}
|
||||
|
||||
+ (void)clearBuffer
|
||||
{
|
||||
PhoneticBuffer->clear();
|
||||
}
|
||||
|
||||
+ (void)combineReadingKey:(UniChar)charCode
|
||||
{
|
||||
PhoneticBuffer->combineKey((char)charCode);
|
||||
}
|
||||
|
||||
+ (BOOL)hasToneMarker
|
||||
{
|
||||
return PhoneticBuffer->hasToneMarker();
|
||||
}
|
||||
|
||||
+ (BOOL)hasToneMarkerOnly
|
||||
{
|
||||
return PhoneticBuffer->hasToneMarkerOnly();
|
||||
}
|
||||
|
||||
+ (NSString *)getSyllableComposition
|
||||
{
|
||||
return [NSString stringWithUTF8String:PhoneticBuffer->syllable().composedString().c_str()];
|
||||
}
|
||||
|
||||
+ (void)doBackSpaceToBuffer
|
||||
{
|
||||
PhoneticBuffer->backspace();
|
||||
}
|
||||
|
||||
+ (NSString *)getComposition
|
||||
{
|
||||
return [NSString stringWithUTF8String:PhoneticBuffer->composedString().c_str()];
|
||||
}
|
||||
|
||||
+ (void)ensureParser
|
||||
{
|
||||
if (PhoneticBuffer)
|
||||
{
|
||||
switch (mgrPrefs.mandarinParser)
|
||||
{
|
||||
case MandarinParserOfStandard:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::StandardLayout());
|
||||
break;
|
||||
case MandarinParserOfEten:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::ETenLayout());
|
||||
break;
|
||||
case MandarinParserOfHsu:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::HsuLayout());
|
||||
break;
|
||||
case MandarinParserOfEen26:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::ETen26Layout());
|
||||
break;
|
||||
case MandarinParserOfIBM:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::IBMLayout());
|
||||
break;
|
||||
case MandarinParserOfMiTAC:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::MiTACLayout());
|
||||
break;
|
||||
case MandarinParserOfFakeSeigyou:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::FakeSeigyouLayout());
|
||||
break;
|
||||
case MandarinParserOfHanyuPinyin:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::HanyuPinyinLayout());
|
||||
break;
|
||||
default:
|
||||
PhoneticBuffer->setKeyboardLayout(Mandarin::BopomofoKeyboardLayout::StandardLayout());
|
||||
mgrPrefs.mandarinParser = MandarinParserOfStandard;
|
||||
}
|
||||
PhoneticBuffer->clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
PhoneticBuffer = new Mandarin::BopomofoReadingBuffer(Mandarin::BopomofoKeyboardLayout::StandardLayout());
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
File diff suppressed because it is too large
Load Diff
|
@ -1,587 +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.
|
||||
*/
|
||||
|
||||
#ifndef MANDARIN_H_
|
||||
#define MANDARIN_H_
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Mandarin
|
||||
{
|
||||
|
||||
class BopomofoSyllable
|
||||
{
|
||||
public:
|
||||
typedef uint16_t Component;
|
||||
|
||||
explicit BopomofoSyllable(Component syllable = 0) : syllable_(syllable)
|
||||
{
|
||||
}
|
||||
|
||||
BopomofoSyllable(const BopomofoSyllable &) = default;
|
||||
BopomofoSyllable(BopomofoSyllable &&another) = default;
|
||||
BopomofoSyllable &operator=(const BopomofoSyllable &) = default;
|
||||
BopomofoSyllable &operator=(BopomofoSyllable &&) = default;
|
||||
|
||||
// takes the ASCII-form, "v"-tolerant, TW-style Hanyu Pinyin (fong, pong, bong
|
||||
// acceptable)
|
||||
static const BopomofoSyllable FromHanyuPinyin(const std::string &str);
|
||||
|
||||
// TO DO: Support accented vowels
|
||||
const std::string HanyuPinyinString(bool includesTone, bool useVForUUmlaut) const;
|
||||
|
||||
static const BopomofoSyllable FromComposedString(const std::string &str);
|
||||
const std::string composedString() const;
|
||||
|
||||
void clear()
|
||||
{
|
||||
syllable_ = 0;
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return !syllable_;
|
||||
}
|
||||
|
||||
bool hasConsonant() const
|
||||
{
|
||||
return !!(syllable_ & ConsonantMask);
|
||||
}
|
||||
|
||||
bool hasMiddleVowel() const
|
||||
{
|
||||
return !!(syllable_ & MiddleVowelMask);
|
||||
}
|
||||
bool hasVowel() const
|
||||
{
|
||||
return !!(syllable_ & VowelMask);
|
||||
}
|
||||
|
||||
bool hasToneMarker() const
|
||||
{
|
||||
return !!(syllable_ & ToneMarkerMask);
|
||||
}
|
||||
|
||||
Component consonantComponent() const
|
||||
{
|
||||
return syllable_ & ConsonantMask;
|
||||
}
|
||||
|
||||
Component middleVowelComponent() const
|
||||
{
|
||||
return syllable_ & MiddleVowelMask;
|
||||
}
|
||||
|
||||
Component vowelComponent() const
|
||||
{
|
||||
return syllable_ & VowelMask;
|
||||
}
|
||||
|
||||
Component toneMarkerComponent() const
|
||||
{
|
||||
return syllable_ & ToneMarkerMask;
|
||||
}
|
||||
|
||||
bool operator==(const BopomofoSyllable &another) const
|
||||
{
|
||||
return syllable_ == another.syllable_;
|
||||
}
|
||||
|
||||
bool operator!=(const BopomofoSyllable &another) const
|
||||
{
|
||||
return syllable_ != another.syllable_;
|
||||
}
|
||||
|
||||
bool isOverlappingWith(const BopomofoSyllable &another) const
|
||||
{
|
||||
#define IOW_SAND(mask) ((syllable_ & mask) && (another.syllable_ & mask))
|
||||
return IOW_SAND(ConsonantMask) || IOW_SAND(MiddleVowelMask) || IOW_SAND(VowelMask) || IOW_SAND(ToneMarkerMask);
|
||||
#undef IOW_SAND
|
||||
}
|
||||
|
||||
// consonants J, Q, X all require the existence of vowel I or UE
|
||||
bool belongsToJQXClass() const
|
||||
{
|
||||
Component consonant = syllable_ & ConsonantMask;
|
||||
return (consonant == J || consonant == Q || consonant == X);
|
||||
}
|
||||
|
||||
// zi, ci, si, chi, chi, shi, ri
|
||||
bool belongsToZCSRClass() const
|
||||
{
|
||||
Component consonant = syllable_ & ConsonantMask;
|
||||
return (consonant >= ZH && consonant <= S);
|
||||
}
|
||||
|
||||
Component maskType() const
|
||||
{
|
||||
Component mask = 0;
|
||||
mask |= (syllable_ & ConsonantMask) ? ConsonantMask : 0;
|
||||
mask |= (syllable_ & MiddleVowelMask) ? MiddleVowelMask : 0;
|
||||
mask |= (syllable_ & VowelMask) ? VowelMask : 0;
|
||||
mask |= (syllable_ & ToneMarkerMask) ? ToneMarkerMask : 0;
|
||||
return mask;
|
||||
}
|
||||
|
||||
const BopomofoSyllable operator+(const BopomofoSyllable &another) const
|
||||
{
|
||||
Component newSyllable = syllable_;
|
||||
#define OP_SOVER(mask) \
|
||||
if (another.syllable_ & mask) \
|
||||
{ \
|
||||
newSyllable = (newSyllable & ~mask) | (another.syllable_ & mask); \
|
||||
}
|
||||
OP_SOVER(ConsonantMask);
|
||||
OP_SOVER(MiddleVowelMask);
|
||||
OP_SOVER(VowelMask);
|
||||
OP_SOVER(ToneMarkerMask);
|
||||
#undef OP_SOVER
|
||||
return BopomofoSyllable(newSyllable);
|
||||
}
|
||||
|
||||
BopomofoSyllable &operator+=(const BopomofoSyllable &another)
|
||||
{
|
||||
#define OPE_SOVER(mask) \
|
||||
if (another.syllable_ & mask) \
|
||||
{ \
|
||||
syllable_ = (syllable_ & ~mask) | (another.syllable_ & mask); \
|
||||
}
|
||||
OPE_SOVER(ConsonantMask);
|
||||
OPE_SOVER(MiddleVowelMask);
|
||||
OPE_SOVER(VowelMask);
|
||||
OPE_SOVER(ToneMarkerMask);
|
||||
#undef OPE_SOVER
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream, const BopomofoSyllable &syllable);
|
||||
|
||||
static constexpr Component ConsonantMask = 0x001f, // 0000 0000 0001 1111, 21 consonants
|
||||
MiddleVowelMask = 0x0060, // 0000 0000 0110 0000, 3 middle vowels
|
||||
VowelMask = 0x0780, // 0000 0111 1000 0000, 13 vowels
|
||||
ToneMarkerMask = 0x3800, // 0011 1000 0000 0000, 5 tones (tone1 = 0x00)
|
||||
B = 0x0001, P = 0x0002, M = 0x0003, F = 0x0004, D = 0x0005, T = 0x0006, N = 0x0007, L = 0x0008, G = 0x0009,
|
||||
K = 0x000a, H = 0x000b, J = 0x000c, Q = 0x000d, X = 0x000e, ZH = 0x000f, CH = 0x0010,
|
||||
SH = 0x0011, R = 0x0012, Z = 0x0013, C = 0x0014, S = 0x0015, I = 0x0020, U = 0x0040,
|
||||
UE = 0x0060, // ue = u umlaut (we use the German convention here as an
|
||||
// ersatz to the /ju:/ sound)
|
||||
A = 0x0080, O = 0x0100, ER = 0x0180, E = 0x0200, AI = 0x0280, EI = 0x0300, AO = 0x0380, OU = 0x0400,
|
||||
AN = 0x0480, EN = 0x0500, ANG = 0x0580, ENG = 0x0600, ERR = 0x0680, Tone1 = 0x0000,
|
||||
Tone2 = 0x0800, Tone3 = 0x1000, Tone4 = 0x1800, Tone5 = 0x2000;
|
||||
|
||||
protected:
|
||||
Component syllable_;
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &stream, const BopomofoSyllable &syllable)
|
||||
{
|
||||
stream << syllable.composedString();
|
||||
return stream;
|
||||
}
|
||||
|
||||
typedef BopomofoSyllable BPMF;
|
||||
|
||||
typedef std::map<char, std::vector<BPMF::Component>> BopomofoKeyToComponentMap;
|
||||
typedef std::map<BPMF::Component, char> BopomofoComponentToKeyMap;
|
||||
|
||||
extern "C" class BopomofoKeyboardLayout
|
||||
{
|
||||
public:
|
||||
static const BopomofoKeyboardLayout *StandardLayout();
|
||||
static const BopomofoKeyboardLayout *ETenLayout();
|
||||
static const BopomofoKeyboardLayout *HsuLayout();
|
||||
static const BopomofoKeyboardLayout *ETen26Layout();
|
||||
static const BopomofoKeyboardLayout *IBMLayout();
|
||||
static const BopomofoKeyboardLayout *MiTACLayout();
|
||||
static const BopomofoKeyboardLayout *FakeSeigyouLayout();
|
||||
static const BopomofoKeyboardLayout *HanyuPinyinLayout();
|
||||
|
||||
BopomofoKeyboardLayout(const BopomofoKeyToComponentMap &ktcm, const std::string &name)
|
||||
: m_keyToComponent(ktcm), m_name(name)
|
||||
{
|
||||
for (BopomofoKeyToComponentMap::const_iterator miter = m_keyToComponent.begin();
|
||||
miter != m_keyToComponent.end(); ++miter)
|
||||
for (std::vector<BPMF::Component>::const_iterator viter = (*miter).second.begin();
|
||||
viter != (*miter).second.end(); ++viter)
|
||||
m_componentToKey[*viter] = (*miter).first;
|
||||
}
|
||||
|
||||
const std::string name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
char componentToKey(BPMF::Component component) const
|
||||
{
|
||||
BopomofoComponentToKeyMap::const_iterator iter = m_componentToKey.find(component);
|
||||
return (iter == m_componentToKey.end()) ? 0 : (*iter).second;
|
||||
}
|
||||
|
||||
const std::vector<BPMF::Component> keyToComponents(char key) const
|
||||
{
|
||||
BopomofoKeyToComponentMap::const_iterator iter = m_keyToComponent.find(key);
|
||||
return (iter == m_keyToComponent.end()) ? std::vector<BPMF::Component>() : (*iter).second;
|
||||
}
|
||||
|
||||
const std::string keySequenceFromSyllable(BPMF syllable) const
|
||||
{
|
||||
std::string sequence;
|
||||
|
||||
BPMF::Component c;
|
||||
char k;
|
||||
#define STKS_COMBINE(component) \
|
||||
if ((c = component)) \
|
||||
{ \
|
||||
if ((k = componentToKey(c))) \
|
||||
sequence += std::string(1, k); \
|
||||
}
|
||||
STKS_COMBINE(syllable.consonantComponent());
|
||||
STKS_COMBINE(syllable.middleVowelComponent());
|
||||
STKS_COMBINE(syllable.vowelComponent());
|
||||
STKS_COMBINE(syllable.toneMarkerComponent());
|
||||
#undef STKS_COMBINE
|
||||
return sequence;
|
||||
}
|
||||
|
||||
const BPMF syllableFromKeySequence(const std::string &sequence) const
|
||||
{
|
||||
BPMF syllable;
|
||||
|
||||
for (std::string::const_iterator iter = sequence.begin(); iter != sequence.end(); ++iter)
|
||||
{
|
||||
bool beforeSeqHasIorUE = sequenceContainsIorUE(sequence.begin(), iter);
|
||||
bool aheadSeqHasIorUE = sequenceContainsIorUE(iter + 1, sequence.end());
|
||||
|
||||
std::vector<BPMF::Component> components = keyToComponents(*iter);
|
||||
|
||||
if (!components.size())
|
||||
continue;
|
||||
|
||||
if (components.size() == 1)
|
||||
{
|
||||
syllable += BPMF(components[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
BPMF head = BPMF(components[0]);
|
||||
BPMF follow = BPMF(components[1]);
|
||||
BPMF ending = components.size() > 2 ? BPMF(components[2]) : follow;
|
||||
|
||||
// apply the I/UE + E rule
|
||||
if (head.vowelComponent() == BPMF::E && follow.vowelComponent() != BPMF::E)
|
||||
{
|
||||
syllable += beforeSeqHasIorUE ? head : follow;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (head.vowelComponent() != BPMF::E && follow.vowelComponent() == BPMF::E)
|
||||
{
|
||||
syllable += beforeSeqHasIorUE ? follow : head;
|
||||
continue;
|
||||
}
|
||||
|
||||
// apply the J/Q/X + I/UE rule, only two components are allowed in the
|
||||
// components vector here
|
||||
if (head.belongsToJQXClass() && !follow.belongsToJQXClass())
|
||||
{
|
||||
if (!syllable.isEmpty())
|
||||
{
|
||||
if (ending != follow)
|
||||
syllable += ending;
|
||||
}
|
||||
else
|
||||
{
|
||||
syllable += aheadSeqHasIorUE ? head : follow;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!head.belongsToJQXClass() && follow.belongsToJQXClass())
|
||||
{
|
||||
if (!syllable.isEmpty())
|
||||
{
|
||||
if (ending != follow)
|
||||
syllable += ending;
|
||||
}
|
||||
else
|
||||
{
|
||||
syllable += aheadSeqHasIorUE ? follow : head;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// the nasty issue of only one char in the buffer
|
||||
if (iter == sequence.begin() && iter + 1 == sequence.end())
|
||||
{
|
||||
if (head.hasVowel() || follow.hasToneMarker() || head.belongsToZCSRClass())
|
||||
{
|
||||
syllable += head;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (follow.hasVowel() || ending.hasToneMarker())
|
||||
{
|
||||
syllable += follow;
|
||||
}
|
||||
else
|
||||
{
|
||||
syllable += ending;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(syllable.maskType() & head.maskType()) && !endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end()))
|
||||
{
|
||||
syllable += head;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (endAheadOrAheadHasToneMarkKey(iter + 1, sequence.end()) && head.belongsToZCSRClass() &&
|
||||
syllable.isEmpty())
|
||||
{
|
||||
syllable += head;
|
||||
}
|
||||
else if (syllable.maskType() < follow.maskType())
|
||||
{
|
||||
syllable += follow;
|
||||
}
|
||||
else
|
||||
{
|
||||
syllable += ending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// heuristics for Hsu keyboard layout
|
||||
if (this == HsuLayout())
|
||||
{
|
||||
// fix the left out L to ERR when it has sound, and GI, GUE -> JI, JUE
|
||||
if (syllable.vowelComponent() == BPMF::ENG && !syllable.hasConsonant() && !syllable.hasMiddleVowel())
|
||||
{
|
||||
syllable += BPMF(BPMF::ERR);
|
||||
}
|
||||
else if (syllable.consonantComponent() == BPMF::G &&
|
||||
(syllable.middleVowelComponent() == BPMF::I || syllable.middleVowelComponent() == BPMF::UE))
|
||||
{
|
||||
syllable += BPMF(BPMF::J);
|
||||
}
|
||||
}
|
||||
|
||||
return syllable;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool endAheadOrAheadHasToneMarkKey(std::string::const_iterator ahead, std::string::const_iterator end) const
|
||||
{
|
||||
if (ahead == end)
|
||||
return true;
|
||||
|
||||
char tone1 = componentToKey(BPMF::Tone1);
|
||||
char tone2 = componentToKey(BPMF::Tone2);
|
||||
char tone3 = componentToKey(BPMF::Tone3);
|
||||
char tone4 = componentToKey(BPMF::Tone4);
|
||||
char tone5 = componentToKey(BPMF::Tone5);
|
||||
|
||||
if (tone1)
|
||||
if (*ahead == tone1)
|
||||
return true;
|
||||
|
||||
if (*ahead == tone2 || *ahead == tone3 || *ahead == tone4 || *ahead == tone5)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sequenceContainsIorUE(std::string::const_iterator start, std::string::const_iterator end) const
|
||||
{
|
||||
char iChar = componentToKey(BPMF::I);
|
||||
char ueChar = componentToKey(BPMF::UE);
|
||||
|
||||
for (; start != end; ++start)
|
||||
if (*start == iChar || *start == ueChar)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string m_name;
|
||||
BopomofoKeyToComponentMap m_keyToComponent;
|
||||
BopomofoComponentToKeyMap m_componentToKey;
|
||||
};
|
||||
|
||||
extern "C" class BopomofoReadingBuffer
|
||||
{
|
||||
public:
|
||||
explicit BopomofoReadingBuffer(const BopomofoKeyboardLayout *layout) : layout_(layout), pinyin_mode_(false)
|
||||
{
|
||||
if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout())
|
||||
{
|
||||
pinyin_mode_ = true;
|
||||
pinyin_sequence_ = "";
|
||||
}
|
||||
}
|
||||
|
||||
void setKeyboardLayout(const BopomofoKeyboardLayout *layout)
|
||||
{
|
||||
layout_ = layout;
|
||||
|
||||
if (layout == BopomofoKeyboardLayout::HanyuPinyinLayout())
|
||||
{
|
||||
pinyin_mode_ = true;
|
||||
pinyin_sequence_ = "";
|
||||
}
|
||||
}
|
||||
|
||||
bool isValidKey(char k) const
|
||||
{
|
||||
if (!pinyin_mode_)
|
||||
{
|
||||
return layout_ ? (layout_->keyToComponents(k)).size() > 0 : false;
|
||||
}
|
||||
|
||||
char lk = tolower(k);
|
||||
if (lk >= 'a' && lk <= 'z')
|
||||
{
|
||||
// if a tone marker is already in place
|
||||
if (pinyin_sequence_.length())
|
||||
{
|
||||
char lastc = pinyin_sequence_[pinyin_sequence_.length() - 1];
|
||||
if (lastc >= '2' && lastc <= '5')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pinyin_sequence_.length() && (lk >= '2' && lk <= '5'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool combineKey(char k)
|
||||
{
|
||||
if (!isValidKey(k))
|
||||
return false;
|
||||
|
||||
if (pinyin_mode_)
|
||||
{
|
||||
pinyin_sequence_ += std::string(1, tolower(k));
|
||||
syllable_ = BPMF::FromHanyuPinyin(pinyin_sequence_);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string sequence = layout_->keySequenceFromSyllable(syllable_) + std::string(1, k);
|
||||
syllable_ = layout_->syllableFromKeySequence(sequence);
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
pinyin_sequence_.clear();
|
||||
syllable_.clear();
|
||||
}
|
||||
|
||||
void backspace()
|
||||
{
|
||||
if (!layout_)
|
||||
return;
|
||||
|
||||
if (pinyin_mode_)
|
||||
{
|
||||
if (pinyin_sequence_.length())
|
||||
{
|
||||
pinyin_sequence_ = pinyin_sequence_.substr(0, pinyin_sequence_.length() - 1);
|
||||
}
|
||||
|
||||
syllable_ = BPMF::FromHanyuPinyin(pinyin_sequence_);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string sequence = layout_->keySequenceFromSyllable(syllable_);
|
||||
if (sequence.length())
|
||||
{
|
||||
sequence = sequence.substr(0, sequence.length() - 1);
|
||||
syllable_ = layout_->syllableFromKeySequence(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return syllable_.isEmpty();
|
||||
}
|
||||
|
||||
const std::string composedString() const
|
||||
{
|
||||
if (pinyin_mode_)
|
||||
{
|
||||
return pinyin_sequence_;
|
||||
}
|
||||
|
||||
return syllable_.composedString();
|
||||
}
|
||||
|
||||
const BPMF syllable() const
|
||||
{
|
||||
return syllable_;
|
||||
}
|
||||
|
||||
const std::string standardLayoutQueryString() const
|
||||
{
|
||||
return BopomofoKeyboardLayout::StandardLayout()->keySequenceFromSyllable(syllable_);
|
||||
}
|
||||
|
||||
bool hasToneMarker() const
|
||||
{
|
||||
return syllable_.hasToneMarker();
|
||||
}
|
||||
|
||||
bool hasToneMarkerOnly() const
|
||||
{
|
||||
return syllable_.hasToneMarker() &&
|
||||
!(syllable_.hasConsonant() || syllable_.hasMiddleVowel() || syllable_.hasVowel());
|
||||
}
|
||||
|
||||
protected:
|
||||
const BopomofoKeyboardLayout *layout_;
|
||||
BPMF syllable_;
|
||||
|
||||
bool pinyin_mode_;
|
||||
std::string pinyin_sequence_;
|
||||
};
|
||||
} // namespace Mandarin
|
||||
|
||||
#endif // MANDARIN_H_
|
|
@ -1 +1 @@
|
|||
Subproject commit f49547bff120f4a800d1930384a428890cf13f9d
|
||||
Subproject commit 5abc68212bba31114197bdfee08dd615d89878bd
|
|
@ -31,4 +31,3 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
@import Foundation;
|
||||
|
||||
#import "CTools.h"
|
||||
#import "Composer.hh"
|
||||
|
|
|
@ -48,6 +48,7 @@ protocol KeyHandlerDelegate: NSObjectProtocol {
|
|||
|
||||
class KeyHandler: NSObject {
|
||||
let kEpsilon: Double = 0.000001
|
||||
var _composer: Tekkon.Composer = .init()
|
||||
var _inputMode: String = ""
|
||||
var _languageModel: vChewing.LMInstantiator = .init()
|
||||
var _userOverrideModel: vChewing.LMUserOverride = .init()
|
||||
|
@ -73,12 +74,12 @@ class KeyHandler: NSObject {
|
|||
override init() {
|
||||
_builder = Megrez.BlockReadingBuilder(lm: _languageModel)
|
||||
super.init()
|
||||
Composer.ensureParser()
|
||||
ensureParser()
|
||||
setInputMode(ctlInputMethod.currentInputMode)
|
||||
}
|
||||
|
||||
func clear() {
|
||||
Composer.clearBuffer()
|
||||
_composer.clear()
|
||||
_builder.clear()
|
||||
_walkedNodes.removeAll()
|
||||
}
|
||||
|
@ -104,8 +105,8 @@ class KeyHandler: NSObject {
|
|||
// Create new grid builder.
|
||||
createNewBuilder()
|
||||
|
||||
if !Composer.isBufferEmpty() {
|
||||
Composer.clearBuffer()
|
||||
if !_composer.isEmpty {
|
||||
_composer.clear()
|
||||
}
|
||||
}
|
||||
// 直接寫到衛星模組內,省得類型轉換
|
||||
|
@ -121,7 +122,7 @@ class KeyHandler: NSObject {
|
|||
let walker = Megrez.Walker(grid: _builder.grid())
|
||||
|
||||
// the reverse walk traces the grid from the end
|
||||
let walked: [Megrez.NodeAnchor] = walker.reverseWalk(at: _builder.grid().width(), nodesLimit: 10)
|
||||
let walked: [Megrez.NodeAnchor] = walker.reverseWalk(at: _builder.grid().width(), balanced: true)
|
||||
|
||||
// then we use ".reversed()" to reverse the nodes so that we get the forward-walked nodes
|
||||
_walkedNodes.removeAll()
|
||||
|
@ -258,7 +259,7 @@ class KeyHandler: NSObject {
|
|||
return highestScore + epsilon
|
||||
}
|
||||
|
||||
// MARK: - Extracted methods and functions.
|
||||
// MARK: - Extracted methods and functions (Megrez).
|
||||
|
||||
func isBuilderEmpty() -> Bool { _builder.grid().width() == 0 }
|
||||
|
||||
|
@ -321,4 +322,30 @@ class KeyHandler: NSObject {
|
|||
func getKeyLengthAtIndexZero() -> Int {
|
||||
_walkedNodes[0].node?.currentKeyValue().value.count ?? 0
|
||||
}
|
||||
|
||||
// MARK: - Extracted methods and functions (Tekkon).
|
||||
|
||||
func ensureParser() {
|
||||
switch mgrPrefs.mandarinParser {
|
||||
case MandarinParser.ofStandard.rawValue:
|
||||
_composer.ensureParser(arrange: .ofDachen)
|
||||
case MandarinParser.ofEten.rawValue:
|
||||
_composer.ensureParser(arrange: .ofEten)
|
||||
case MandarinParser.ofHsu.rawValue:
|
||||
_composer.ensureParser(arrange: .ofHsu)
|
||||
case MandarinParser.ofEten26.rawValue:
|
||||
_composer.ensureParser(arrange: .ofEten26)
|
||||
case MandarinParser.ofIBM.rawValue:
|
||||
_composer.ensureParser(arrange: .ofIBM)
|
||||
case MandarinParser.ofMiTAC.rawValue:
|
||||
_composer.ensureParser(arrange: .ofMiTAC)
|
||||
case MandarinParser.ofFakeSeigyou.rawValue:
|
||||
_composer.ensureParser(arrange: .ofFakeSeigyou)
|
||||
default:
|
||||
_composer.ensureParser(arrange: .ofDachen)
|
||||
mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue
|
||||
}
|
||||
_composer.clear()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -331,7 +331,7 @@ extension KeyHandler {
|
|||
let punctuation: String = arrPunctuations.joined(separator: "")
|
||||
|
||||
var shouldAutoSelectCandidate: Bool =
|
||||
Composer.chkKeyValidity(charCode) || ifLangModelHasUnigrams(forKey: customPunctuation)
|
||||
_composer.inputValidityCheck(key: charCode) || ifLangModelHasUnigrams(forKey: customPunctuation)
|
||||
|| ifLangModelHasUnigrams(forKey: punctuation)
|
||||
|
||||
if !shouldAutoSelectCandidate, input.isUpperCaseASCIILetterKey {
|
||||
|
|
|
@ -147,34 +147,34 @@ extension KeyHandler {
|
|||
let skipPhoneticHandling = input.isReservedKey || input.isControlHold || input.isOptionHold
|
||||
|
||||
// See if Phonetic reading is valid.
|
||||
if !skipPhoneticHandling && Composer.chkKeyValidity(charCode) {
|
||||
Composer.combineReadingKey(charCode)
|
||||
if !skipPhoneticHandling && _composer.inputValidityCheck(key: charCode) {
|
||||
_composer.receiveKey(fromCharCode: charCode)
|
||||
keyConsumedByReading = true
|
||||
|
||||
// If we have a tone marker, we have to insert the reading to the
|
||||
// builder in other words, if we don't have a tone marker, we just
|
||||
// update the composing buffer.
|
||||
let composeReading = Composer.hasToneMarker()
|
||||
let composeReading = _composer.hasToneMarker()
|
||||
if !composeReading {
|
||||
stateCallback(buildInputtingState())
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var composeReading = Composer.hasToneMarker() || Composer.hasToneMarkerOnly()
|
||||
var composeReading = _composer.hasToneMarker() // 這裡不需要做排他性判斷。
|
||||
|
||||
// See if we have composition if Enter/Space is hit and buffer is not empty.
|
||||
// We use "|=" conditioning so that the tone marker key is also taken into account.
|
||||
// However, Swift does not support "|=".
|
||||
composeReading = composeReading || (!Composer.isBufferEmpty() && (input.isSpace || input.isEnter))
|
||||
composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter))
|
||||
if composeReading {
|
||||
let reading = Composer.getSyllableComposition()
|
||||
let reading = _composer.getRealComposition()
|
||||
|
||||
// See whether we have a unigram for this...
|
||||
if !ifLangModelHasUnigrams(forKey: reading) {
|
||||
IME.prtDebugIntel("B49C0979:語彙庫內無「\(reading)」的匹配記錄。")
|
||||
errorCallback()
|
||||
Composer.clearBuffer()
|
||||
_composer.clear()
|
||||
stateCallback((getBuilderLength() == 0) ? InputState.EmptyIgnoringPreviousState() : buildInputtingState())
|
||||
return true
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ extension KeyHandler {
|
|||
dealWithOverrideModelSuggestions()
|
||||
|
||||
// ... then update the text.
|
||||
Composer.clearBuffer()
|
||||
_composer.clear()
|
||||
|
||||
let inputting = buildInputtingState()
|
||||
inputting.poppedText = poppedText
|
||||
|
@ -239,7 +239,7 @@ extension KeyHandler {
|
|||
// MARK: Calling candidate window using Space or Down or PageUp / PageDn.
|
||||
|
||||
if let currentState = state as? InputState.NotEmpty {
|
||||
if Composer.isBufferEmpty(),
|
||||
if _composer.isEmpty,
|
||||
input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace
|
||||
|| input.isPageDown || input.isPageUp || input.isTab
|
||||
|| (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey))
|
||||
|
@ -354,7 +354,7 @@ extension KeyHandler {
|
|||
if input.isSymbolMenuPhysicalKey && !input.isShiftHold {
|
||||
if !input.isOptionHold {
|
||||
if ifLangModelHasUnigrams(forKey: "_punctuation_list") {
|
||||
if Composer.isBufferEmpty() {
|
||||
if _composer.isEmpty {
|
||||
insertReadingToBuilderAtCursor(reading: "_punctuation_list")
|
||||
let poppedText: String! = popOverflowComposingTextAndWalk()
|
||||
let inputting = buildInputtingState()
|
||||
|
@ -443,7 +443,7 @@ extension KeyHandler {
|
|||
// "thinking" that the key is not actually consumed.
|
||||
// 砍掉這一段會導致「F1-F12 按鍵干擾組字區」的問題。
|
||||
// 暫時只能先恢復這段,且補上偵錯彙報機制,方便今後排查故障。
|
||||
if (state is InputState.NotEmpty) || !Composer.isBufferEmpty() {
|
||||
if (state is InputState.NotEmpty) || !_composer.isEmpty {
|
||||
IME.prtDebugIntel(
|
||||
"Blocked data: charCode: \(charCode), keyCode: \(input.keyCode)")
|
||||
IME.prtDebugIntel("A9BFF20E")
|
||||
|
|
|
@ -87,7 +87,7 @@ extension KeyHandler {
|
|||
// The reading text is what the user is typing.
|
||||
|
||||
let head = String((composingBuffer as NSString).substring(to: composedStringCursorIndex))
|
||||
let reading = Composer.getComposition()
|
||||
let reading = _composer.getDisplayedComposition()
|
||||
let tail = String((composingBuffer as NSString).substring(from: composedStringCursorIndex))
|
||||
let composedText = head + reading + tail
|
||||
let cursorIndex = composedStringCursorIndex + reading.count
|
||||
|
@ -213,14 +213,14 @@ extension KeyHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
if Composer.isBufferEmpty() {
|
||||
if _composer.isEmpty {
|
||||
insertReadingToBuilderAtCursor(reading: customPunctuation)
|
||||
let poppedText = popOverflowComposingTextAndWalk()
|
||||
let inputting = buildInputtingState()
|
||||
inputting.poppedText = poppedText
|
||||
stateCallback(inputting)
|
||||
|
||||
if mgrPrefs.useSCPCTypingMode, Composer.isBufferEmpty() {
|
||||
if mgrPrefs.useSCPCTypingMode, _composer.isEmpty {
|
||||
let candidateState = buildCandidate(
|
||||
state: inputting,
|
||||
useVerticalMode: useVerticalMode
|
||||
|
@ -335,9 +335,9 @@ extension KeyHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
if Composer.hasToneMarkerOnly() {
|
||||
Composer.clearBuffer()
|
||||
} else if Composer.isBufferEmpty() {
|
||||
if _composer.hasToneMarker(withNothingElse: true) {
|
||||
_composer.clear()
|
||||
} else if _composer.isEmpty {
|
||||
if getBuilderCursorIndex() >= 0 {
|
||||
deleteBuilderReadingInFrontOfCursor()
|
||||
walk()
|
||||
|
@ -348,10 +348,10 @@ extension KeyHandler {
|
|||
return true
|
||||
}
|
||||
} else {
|
||||
Composer.doBackSpaceToBuffer()
|
||||
_composer.doBackSpace()
|
||||
}
|
||||
|
||||
if Composer.isBufferEmpty(), getBuilderLength() == 0 {
|
||||
if _composer.isEmpty, getBuilderLength() == 0 {
|
||||
stateCallback(InputState.EmptyIgnoringPreviousState())
|
||||
} else {
|
||||
stateCallback(buildInputtingState())
|
||||
|
@ -370,7 +370,7 @@ extension KeyHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
if Composer.isBufferEmpty() {
|
||||
if _composer.isEmpty {
|
||||
if getBuilderCursorIndex() != getBuilderLength() {
|
||||
deleteBuilderReadingAfterCursor()
|
||||
walk()
|
||||
|
@ -405,7 +405,7 @@ extension KeyHandler {
|
|||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
if !Composer.isBufferEmpty() {
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("9B6F908D")
|
||||
errorCallback()
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ extension KeyHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
if !Composer.isBufferEmpty() {
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("ABC44080")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
|
@ -454,7 +454,7 @@ extension KeyHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
if !Composer.isBufferEmpty() {
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("9B69908D")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
|
@ -493,8 +493,8 @@ extension KeyHandler {
|
|||
stateCallback(InputState.EmptyIgnoringPreviousState())
|
||||
} else {
|
||||
// If reading is not empty, we cancel the reading.
|
||||
if !Composer.isBufferEmpty() {
|
||||
Composer.clearBuffer()
|
||||
if !_composer.isEmpty {
|
||||
_composer.clear()
|
||||
if getBuilderLength() == 0 {
|
||||
stateCallback(InputState.EmptyIgnoringPreviousState())
|
||||
} else {
|
||||
|
@ -515,7 +515,7 @@ extension KeyHandler {
|
|||
) -> Bool {
|
||||
if !(state is InputState.Inputting) { return false }
|
||||
|
||||
if !Composer.isBufferEmpty() {
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("B3BA5257")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
|
@ -566,7 +566,7 @@ extension KeyHandler {
|
|||
) -> Bool {
|
||||
if !(state is InputState.Inputting) { return false }
|
||||
|
||||
if !Composer.isBufferEmpty() {
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("6ED95318")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
|
|
|
@ -0,0 +1,546 @@
|
|||
// (c) 2022 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 Foundation
|
||||
|
||||
/// The namespace for this package.
|
||||
public struct Tekkon {
|
||||
// MARK: - Static Constants and Basic Enums
|
||||
|
||||
public enum PhoneType: Int {
|
||||
case null = 0 // 假
|
||||
case consonant = 1 // 聲
|
||||
case semivowel = 2 // 韻
|
||||
case vowel = 3 // 介
|
||||
case intonation = 4 // 調
|
||||
}
|
||||
|
||||
public enum MandarinParser: Int {
|
||||
case ofDachen = 0
|
||||
case ofEten = 1
|
||||
case ofHsu = 2
|
||||
case ofEten26 = 3
|
||||
case ofIBM = 4
|
||||
case ofMiTAC = 5
|
||||
case ofFakeSeigyou = 6
|
||||
case ofSeigyou = 7
|
||||
case ofHanyuPinyin = 10
|
||||
|
||||
var name: String {
|
||||
switch self {
|
||||
case .ofDachen:
|
||||
return "Dachen"
|
||||
case .ofEten:
|
||||
return "ETen"
|
||||
case .ofHsu:
|
||||
return "Hsu"
|
||||
case .ofEten26:
|
||||
return "ETen26"
|
||||
case .ofIBM:
|
||||
return "IBM"
|
||||
case .ofMiTAC:
|
||||
return "MiTAC"
|
||||
case .ofFakeSeigyou:
|
||||
return "FakeSeigyou"
|
||||
case .ofSeigyou:
|
||||
return "Seigyou"
|
||||
case .ofHanyuPinyin:
|
||||
return "HanyuPinyin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static let allowedConsonants = [
|
||||
"ㄅ", "ㄆ", "ㄇ", "ㄈ", "ㄉ", "ㄊ", "ㄋ", "ㄌ",
|
||||
"ㄍ", "ㄎ", "ㄏ", "ㄐ", "ㄑ", "ㄒ",
|
||||
"ㄓ", "ㄔ", "ㄕ", "ㄖ", "ㄗ", "ㄘ", "ㄙ",
|
||||
]
|
||||
|
||||
public static let allowedsemivowels = ["ㄧ", "ㄨ", "ㄩ"]
|
||||
|
||||
public static let allowedVowels = [
|
||||
"ㄚ", "ㄛ", "ㄜ", "ㄝ", "ㄞ", "ㄟ",
|
||||
"ㄠ", "ㄡ", "ㄢ", "ㄣ", "ㄤ", "ㄥ", "ㄦ",
|
||||
]
|
||||
|
||||
public static let allowedIntonations = [" ", "ˊ", "ˇ", "ˋ", "˙"]
|
||||
|
||||
public static var allowedPhonabets: [String] {
|
||||
allowedConsonants + allowedsemivowels + allowedVowels + allowedIntonations
|
||||
}
|
||||
|
||||
// MARK: - Phonabet Structure
|
||||
|
||||
@frozen public struct Phonabet: Equatable, Hashable, ExpressibleByStringLiteral {
|
||||
public var type: PhoneType = .null
|
||||
public var value: String = ""
|
||||
public var isEmpty: Bool {
|
||||
value.isEmpty
|
||||
}
|
||||
|
||||
public init(_ input: String = "") {
|
||||
if !input.isEmpty {
|
||||
if allowedPhonabets.contains(String(input.reversed()[0])) {
|
||||
value = String(input.reversed()[0])
|
||||
if Tekkon.allowedConsonants.contains(value) { type = .consonant }
|
||||
if Tekkon.allowedsemivowels.contains(value) { type = .semivowel }
|
||||
if Tekkon.allowedVowels.contains(value) { type = .vowel }
|
||||
if Tekkon.allowedIntonations.contains(value) { type = .intonation }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func clear() {
|
||||
value = ""
|
||||
}
|
||||
|
||||
// MARK: - Misc Definitions
|
||||
|
||||
public static func == (lhs: Phonabet, rhs: Phonabet) -> Bool {
|
||||
lhs.value == rhs.value
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(value)
|
||||
hasher.combine(type)
|
||||
}
|
||||
|
||||
public init(stringLiteral value: String) {
|
||||
self.init(value)
|
||||
}
|
||||
|
||||
public init(unicodeScalarLiteral value: String) {
|
||||
self.init(stringLiteral: value)
|
||||
}
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: String) {
|
||||
self.init(stringLiteral: value)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Syllable Composer
|
||||
|
||||
@frozen public struct Composer: Equatable, Hashable, ExpressibleByStringLiteral {
|
||||
public var consonant: Phonabet = ""
|
||||
public var semivowel: Phonabet = ""
|
||||
public var vowel: Phonabet = ""
|
||||
public var intonation: Phonabet = ""
|
||||
public var parser: MandarinParser = .ofDachen
|
||||
public var value: String {
|
||||
consonant.value + semivowel.value + vowel.value + intonation.value.replacingOccurrences(of: " ", with: "")
|
||||
}
|
||||
|
||||
public var isEmpty: Bool {
|
||||
intonation.isEmpty && vowel.isEmpty && semivowel.isEmpty && consonant.isEmpty
|
||||
}
|
||||
|
||||
public init(_ input: String = "", arrange parser: MandarinParser = .ofDachen) {
|
||||
receiveKey(fromString: input)
|
||||
ensureParser(arrange: parser)
|
||||
}
|
||||
|
||||
public mutating func clear() {
|
||||
consonant.clear()
|
||||
semivowel.clear()
|
||||
vowel.clear()
|
||||
intonation.clear()
|
||||
}
|
||||
|
||||
// MARK: - Public Functions
|
||||
|
||||
/// 用於檢測「某個輸入字符訊號的合規性」的函數。
|
||||
/// Phonabet 是一個特殊的 String 類 Struct,
|
||||
/// 只會接受正確的注音符號資料、且根據其類型自動回報其類型。
|
||||
/// 類型只有「聲、韻、介、調」這四類。
|
||||
public func inputValidityCheck(key inputKey: UniChar = 0) -> Bool {
|
||||
if let scalar = UnicodeScalar(inputKey) {
|
||||
let input = String(scalar)
|
||||
switch parser {
|
||||
case .ofDachen:
|
||||
return Tekkon.mapQwertyDachen[input] != nil
|
||||
case .ofEten:
|
||||
return Tekkon.mapQwertyEtenTraditional[input] != nil
|
||||
case .ofHsu:
|
||||
return Tekkon.mapHsuStaticKeys[input] != nil
|
||||
case .ofEten26:
|
||||
return Tekkon.mapEten26StaticKeys[input] != nil
|
||||
case .ofIBM:
|
||||
return Tekkon.mapQwertyIBM[input] != nil
|
||||
case .ofMiTAC:
|
||||
return Tekkon.mapQwertyMiTAC[input] != nil
|
||||
case .ofSeigyou:
|
||||
return Tekkon.mapSeigyou[input] != nil
|
||||
case .ofFakeSeigyou:
|
||||
return Tekkon.mapFakeSeigyou[input] != nil
|
||||
case .ofHanyuPinyin:
|
||||
return Tekkon.mapArayuruPinyin.contains(input)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public mutating func receiveKey(fromString input: String = "") {
|
||||
let translatedInput = translate(key: String(input))
|
||||
let thePhone: Phonabet = .init(translatedInput)
|
||||
switch thePhone.type {
|
||||
case .consonant: consonant = thePhone
|
||||
case .semivowel: semivowel = thePhone
|
||||
case .vowel: vowel = thePhone
|
||||
case .intonation: intonation = thePhone
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func receiveKey(fromCharCode inputCharCode: UniChar = 0) {
|
||||
if let scalar = UnicodeScalar(inputCharCode) {
|
||||
let translatedInput = translate(key: String(scalar))
|
||||
let thePhone: Phonabet = .init(translatedInput)
|
||||
switch thePhone.type {
|
||||
case .consonant: consonant = thePhone
|
||||
case .semivowel: semivowel = thePhone
|
||||
case .vowel: vowel = thePhone
|
||||
case .intonation: intonation = thePhone
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 本來這個函數是不需要的,但將來在做漢語拼音功能時、這裡得回傳別的東西。
|
||||
/// 也就是說,這個函數就是用來決定輸入法組字區內顯示的注音/拼音內容。
|
||||
public func getDisplayedComposition() -> String {
|
||||
value
|
||||
}
|
||||
|
||||
/// 這是專門用來「生成用以進行詞庫檢索的 Key」的函數。
|
||||
public func getRealComposition() -> String {
|
||||
value
|
||||
}
|
||||
|
||||
/// 專門用來響應使用者摁下 BackSpace 按鍵時的行為。
|
||||
public mutating func doBackSpace() {
|
||||
if !intonation.isEmpty {
|
||||
intonation.clear()
|
||||
} else if !vowel.isEmpty {
|
||||
vowel.clear()
|
||||
} else if !semivowel.isEmpty {
|
||||
semivowel.clear()
|
||||
} else if !consonant.isEmpty {
|
||||
consonant.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/// 用來檢測是否有調號
|
||||
public func hasToneMarker(withNothingElse: Bool = false) -> Bool {
|
||||
if !withNothingElse {
|
||||
return !intonation.isEmpty
|
||||
}
|
||||
return !intonation.isEmpty && vowel.isEmpty && semivowel.isEmpty && consonant.isEmpty
|
||||
}
|
||||
|
||||
/// 當接收按鍵輸入時的處理。本來 Phonabet 就會自動使輸入的無效數值被忽略掉。
|
||||
/// 然後再根據 Phonabet 初期化後自身的 type 屬性來決定「聲、韻、介、調」到底哪個該更新。
|
||||
public mutating func receiveCharCode(_ inputKey: UniChar = 0) {
|
||||
// TODO: 在這裡補上鍵盤轉換工序
|
||||
if let scalar = UnicodeScalar(inputKey) {
|
||||
let input = String(scalar)
|
||||
receiveKey(fromString: input)
|
||||
}
|
||||
}
|
||||
|
||||
// 設定該 Composer 處於何種鍵盤排列分析模式
|
||||
public mutating func ensureParser(arrange: MandarinParser = .ofDachen) {
|
||||
parser = arrange
|
||||
}
|
||||
|
||||
// MARK: - Parser Processings
|
||||
|
||||
mutating func translate(key: String = "") -> String {
|
||||
switch parser {
|
||||
case .ofDachen:
|
||||
return Tekkon.mapQwertyDachen[key] ?? ""
|
||||
case .ofEten:
|
||||
return Tekkon.mapQwertyEtenTraditional[key] ?? ""
|
||||
case .ofHsu:
|
||||
return handleHsu(key: key)
|
||||
case .ofEten26:
|
||||
return handleEten26(key: key)
|
||||
case .ofIBM:
|
||||
return Tekkon.mapQwertyIBM[key] ?? ""
|
||||
case .ofMiTAC:
|
||||
return Tekkon.mapQwertyMiTAC[key] ?? ""
|
||||
case .ofSeigyou:
|
||||
return Tekkon.mapSeigyou[key] ?? ""
|
||||
case .ofFakeSeigyou:
|
||||
return Tekkon.mapFakeSeigyou[key] ?? ""
|
||||
case .ofHanyuPinyin: break // TODO: 待辦
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
/// 倚天忘形注音排列比較麻煩,需要單獨處理。
|
||||
mutating func handleEten26(key: String = "") -> String {
|
||||
var strReturn = ""
|
||||
strReturn = Tekkon.mapEten26StaticKeys[key] ?? ""
|
||||
let incomingPhonabet = Phonabet(strReturn)
|
||||
|
||||
switch key {
|
||||
case "d": if consonant.isEmpty { consonant = "ㄉ" } else { intonation = "˙" }
|
||||
case "f": if consonant.isEmpty { consonant = "ㄈ" } else { intonation = "ˊ" }
|
||||
case "h": if consonant.isEmpty { consonant = "ㄏ" } else { vowel = "ㄦ" }
|
||||
case "j": if consonant.isEmpty { consonant = "ㄖ" } else { intonation = "ˇ" }
|
||||
case "k": if consonant.isEmpty { consonant = "ㄎ" } else { intonation = "ˋ" }
|
||||
case "l": if consonant.isEmpty { consonant = "ㄌ" } else { vowel = "ㄥ" }
|
||||
case "m": if consonant.isEmpty { consonant = "ㄇ" } else { vowel = "ㄢ" }
|
||||
case "n": if consonant.isEmpty { consonant = "ㄋ" } else { vowel = "ㄣ" }
|
||||
case "p": if consonant.isEmpty { consonant = "ㄆ" } else { vowel = "ㄡ" }
|
||||
case "q": if consonant.isEmpty { consonant = "ㄗ" } else { vowel = "ㄟ" }
|
||||
case "t": if consonant.isEmpty { consonant = "ㄊ" } else { vowel = "ㄤ" }
|
||||
case "w": if consonant.isEmpty { consonant = "ㄘ" } else { vowel = "ㄝ" }
|
||||
default: break
|
||||
}
|
||||
|
||||
// 處理「一個按鍵對應兩個聲母」的情形。
|
||||
if !consonant.isEmpty, incomingPhonabet.type == .semivowel {
|
||||
switch consonant {
|
||||
case "ㄍ":
|
||||
switch incomingPhonabet {
|
||||
case "ㄧ": consonant = "ㄑ" // ㄑㄧ
|
||||
case "ㄨ": consonant = "ㄍ" // ㄍㄨ
|
||||
case "ㄩ": consonant = "ㄑ" // ㄑㄩ
|
||||
default: break
|
||||
}
|
||||
case "ㄓ":
|
||||
switch incomingPhonabet {
|
||||
case "ㄧ": consonant = "ㄐ" // ㄐㄧ
|
||||
case "ㄨ": consonant = "ㄓ" // ㄓㄨ
|
||||
case "ㄩ": consonant = "ㄐ" // ㄐㄩ
|
||||
default: break
|
||||
}
|
||||
case "ㄕ":
|
||||
switch incomingPhonabet {
|
||||
case "ㄧ": consonant = "ㄒ" // ㄒㄧ
|
||||
case "ㄨ": consonant = "ㄕ" // ㄕㄨ
|
||||
case "ㄩ": consonant = "ㄒ" // ㄒㄩ
|
||||
default: break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
return strReturn
|
||||
}
|
||||
|
||||
/// 許氏鍵盤與倚天忘形一樣同樣也比較麻煩,需要單獨處理。
|
||||
mutating func handleHsu(key: String = "") -> String {
|
||||
var strReturn = ""
|
||||
strReturn = Tekkon.mapHsuStaticKeys[key] ?? ""
|
||||
let incomingPhonabet = Phonabet(strReturn)
|
||||
|
||||
switch key {
|
||||
case "e": if semivowel.isEmpty { semivowel = "ㄧ" } else { vowel = "ㄝ" }
|
||||
case "a": if consonant.isEmpty { consonant = "ㄘ" } else { vowel = "ㄟ" }
|
||||
case "g": if consonant.isEmpty { consonant = "ㄍ" } else { vowel = "ㄜ" }
|
||||
case "h": if consonant.isEmpty { consonant = "ㄏ" } else { vowel = "ㄛ" }
|
||||
case "k": if consonant.isEmpty { consonant = "ㄎ" } else { vowel = "ㄤ" }
|
||||
case "m": if consonant.isEmpty { consonant = "ㄇ" } else { vowel = "ㄢ" }
|
||||
case "n": if consonant.isEmpty { consonant = "ㄋ" } else { vowel = "ㄣ" }
|
||||
case "s": if consonant.isEmpty { consonant = "ㄙ" } else { intonation = "˙" }
|
||||
case "d": if consonant.isEmpty { consonant = "ㄉ" } else { intonation = "ˊ" }
|
||||
case "f": if consonant.isEmpty { consonant = "ㄈ" } else { intonation = "ˇ" }
|
||||
case "l": if value.isEmpty { vowel = "ㄦ" } else if consonant.isEmpty { consonant = "ㄌ" } else { vowel = "ㄥ" }
|
||||
case "j": if !consonant.isEmpty { intonation = "ˋ" }
|
||||
default: break
|
||||
}
|
||||
|
||||
// 處理「一個按鍵對應兩個聲母」的情形。
|
||||
if !consonant.isEmpty, incomingPhonabet.type == .semivowel {
|
||||
switch consonant {
|
||||
case "ㄓ":
|
||||
if intonation.isEmpty {
|
||||
switch incomingPhonabet {
|
||||
case "ㄧ": consonant = "ㄐ" // ㄐㄧ
|
||||
case "ㄨ": consonant = "ㄓ" // ㄓㄨ
|
||||
case "ㄩ": consonant = "ㄐ" // ㄐㄩ
|
||||
default: break
|
||||
}
|
||||
}
|
||||
case "ㄕ":
|
||||
switch incomingPhonabet {
|
||||
case "ㄧ": consonant = "ㄒ" // ㄒㄧ
|
||||
case "ㄨ": consonant = "ㄕ" // ㄕㄨ
|
||||
case "ㄩ": consonant = "ㄒ" // ㄒㄩ
|
||||
default: break
|
||||
}
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
return strReturn
|
||||
}
|
||||
|
||||
// MARK: - Misc Definitions
|
||||
|
||||
public static func == (lhs: Composer, rhs: Composer) -> Bool {
|
||||
lhs.value == rhs.value
|
||||
}
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(consonant)
|
||||
hasher.combine(semivowel)
|
||||
hasher.combine(vowel)
|
||||
hasher.combine(intonation)
|
||||
}
|
||||
|
||||
public init(stringLiteral value: String) {
|
||||
self.init(value)
|
||||
}
|
||||
|
||||
public init(unicodeScalarLiteral value: String) {
|
||||
self.init(stringLiteral: value)
|
||||
}
|
||||
|
||||
public init(extendedGraphemeClusterLiteral value: String) {
|
||||
self.init(stringLiteral: value)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Phonabets (Enum)
|
||||
|
||||
enum Phonabets: Phonabet {
|
||||
case ofBO = "ㄅ"
|
||||
case ofPO = "ㄆ"
|
||||
case ofMO = "ㄇ"
|
||||
case ofFO = "ㄈ"
|
||||
case ofDE = "ㄉ"
|
||||
case ofTE = "ㄊ"
|
||||
case ofNE = "ㄋ"
|
||||
case ofLE = "ㄌ"
|
||||
case ofGE = "ㄍ"
|
||||
case ofKE = "ㄎ"
|
||||
case ofHE = "ㄏ"
|
||||
case ofJI = "ㄐ"
|
||||
case ofQI = "ㄑ"
|
||||
case ofXI = "ㄒ"
|
||||
case ofZH = "ㄓ"
|
||||
case ofCH = "ㄔ"
|
||||
case ofSH = "ㄕ"
|
||||
case ofRI = "ㄖ"
|
||||
case ofZI = "ㄗ"
|
||||
case ofCI = "ㄘ"
|
||||
case ofSI = "ㄙ"
|
||||
case ofYI = "ㄧ"
|
||||
case ofWU = "ㄨ"
|
||||
case ofYU = "ㄩ"
|
||||
case ofAA = "ㄚ"
|
||||
case ofOO = "ㄛ"
|
||||
case ofEE = "ㄜ"
|
||||
case ofEA = "ㄝ"
|
||||
case ofAI = "ㄞ"
|
||||
case ofEI = "ㄟ"
|
||||
case ofAO = "ㄠ"
|
||||
case ofOU = "ㄡ"
|
||||
case ofAN = "ㄢ"
|
||||
case ofEN = "ㄣ"
|
||||
case ofAG = "ㄤ"
|
||||
case ofOG = "ㄥ"
|
||||
case ofT1 = " "
|
||||
case ofT2 = "ˊ"
|
||||
case ofT3 = "ˇ"
|
||||
case ofT4 = "ˋ"
|
||||
case ofT5 = "˙"
|
||||
}
|
||||
|
||||
// MARK: - Maps for Keyboard-to-Phonabet parsers
|
||||
|
||||
// 任何形式的拼音排列都會用到的陣列,用 Strings 反而省事一些。
|
||||
static let mapArayuruPinyin: String = "abcdefghijklmnopqrstuvwxyz12345 "
|
||||
|
||||
/// 標準大千排列專用處理陣列。
|
||||
/// 威注音輸入法 macOS 版使用了 Ukelele 佈局來完成對諸如倚天傳統等其它注音鍵盤排列的支援。
|
||||
/// 如果要將鐵恨模組拿給別的平台的輸入法使用的話,恐怕需要針對這些注音鍵盤排列各自新增專用陣列才可以。
|
||||
static let mapQwertyDachen: [String: String] = [
|
||||
"0": "ㄢ", "1": "ㄅ", "2": "ㄉ", "3": "ˇ", "4": "ˋ", "5": "ㄓ", "6": "ˊ", "7": "˙", "8": "ㄚ", "9": "ㄞ", "-": "ㄦ",
|
||||
",": "ㄝ", ".": "ㄡ", "/": "ㄥ", ";": "ㄤ", "a": "ㄇ", "b": "ㄖ", "c": "ㄏ", "d": "ㄎ", "e": "ㄍ", "f": "ㄑ", "g": "ㄕ",
|
||||
"h": "ㄘ", "i": "ㄛ", "j": "ㄨ", "k": "ㄜ", "l": "ㄠ", "m": "ㄩ", "n": "ㄙ", "o": "ㄟ", "p": "ㄣ", "q": "ㄆ", "r": "ㄐ",
|
||||
"s": "ㄋ", "t": "ㄔ", "u": "ㄧ", "v": "ㄒ", "w": "ㄊ", "x": "ㄌ", "y": "ㄗ", "z": "ㄈ", " ": " ",
|
||||
]
|
||||
|
||||
/// 許氏排列專用處理陣列,但未包含全部的映射內容。
|
||||
/// 在這裡將二十六個字母寫全,也只是為了方便做 validity check。
|
||||
/// 這裡提前對複音按鍵做處理,然後再用程式判斷介母類型、據此判斷是否需要做複音切換。
|
||||
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": "ㄠ",
|
||||
"x": "ㄨ", "y": "ㄚ", "z": "ㄗ", " ": " ",
|
||||
]
|
||||
|
||||
/// 倚天忘形排列預處理專用陣列,但未包含全部的映射內容。
|
||||
/// 在這裡將二十六個字母寫全,也只是為了方便做 validity check。
|
||||
/// 這裡提前對ㄓ/ㄍ/ㄕ做處理,然後再用程式判斷介母類型、據此判斷是否需要換成ㄒ/ㄑ/ㄐ。
|
||||
static let mapEten26StaticKeys: [String: String] = [
|
||||
"a": "ㄚ", "b": "ㄅ", "c": "ㄕ", "d": "ㄉ", "e": "ㄧ", "f": "ㄈ", "g": "ㄓ", "h": "ㄏ", "i": "ㄞ", "j": "ㄖ", "k": "ㄎ",
|
||||
"l": "ㄌ", "m": "ㄇ", "n": "ㄋ", "o": "ㄛ", "p": "ㄆ", "q": "ㄗ", "r": "ㄜ", "s": "ㄙ", "t": "ㄊ", "u": "ㄩ", "v": "ㄍ",
|
||||
"w": "ㄘ", "x": "ㄨ", "y": "ㄔ", "z": "ㄠ", " ": " ",
|
||||
]
|
||||
|
||||
/// 倚天傳統排列專用處理陣列。
|
||||
static let mapQwertyEtenTraditional: [String: String] = [
|
||||
"'": "ㄘ", ",": "ㄓ", "-": "ㄥ", ".": "ㄔ", "/": "ㄕ", "0": "ㄤ", "1": "˙", "2": "ˊ", "3": "ˇ", "4": "ˋ", "7": "ㄑ",
|
||||
"8": "ㄢ", "9": "ㄣ", ";": "ㄗ", "=": "ㄦ", "a": "ㄚ", "b": "ㄅ", "c": "ㄒ", "d": "ㄉ", "e": "ㄧ", "f": "ㄈ", "g": "ㄐ",
|
||||
"h": "ㄏ", "i": "ㄞ", "j": "ㄖ", "k": "ㄎ", "l": "ㄌ", "m": "ㄇ", "n": "ㄋ", "o": "ㄛ", "p": "ㄆ", "q": "ㄟ", "r": "ㄜ",
|
||||
"s": "ㄙ", "t": "ㄊ", "u": "ㄩ", "v": "ㄍ", "w": "ㄝ", "x": "ㄨ", "y": "ㄡ", "z": "ㄠ", " ": " ",
|
||||
]
|
||||
|
||||
/// IBM排列專用處理陣列。
|
||||
static let mapQwertyIBM: [String: String] = [
|
||||
",": "ˇ", "-": "ㄏ", ".": "ˋ", "/": "˙", "0": "ㄎ", "1": "ㄅ", "2": "ㄆ", "3": "ㄇ", "4": "ㄈ", "5": "ㄉ", "6": "ㄊ",
|
||||
"7": "ㄋ", "8": "ㄌ", "9": "ㄍ", ";": "ㄠ", "a": "ㄧ", "b": "ㄥ", "c": "ㄣ", "d": "ㄩ", "e": "ㄒ", "f": "ㄚ", "g": "ㄛ",
|
||||
"h": "ㄜ", "i": "ㄗ", "j": "ㄝ", "k": "ㄞ", "l": "ㄟ", "m": "ˊ", "n": "ㄦ", "o": "ㄘ", "p": "ㄙ", "q": "ㄐ", "r": "ㄓ",
|
||||
"s": "ㄨ", "t": "ㄔ", "u": "ㄖ", "v": "ㄤ", "w": "ㄑ", "x": "ㄢ", "y": "ㄕ", "z": "ㄡ", " ": " ",
|
||||
]
|
||||
|
||||
/// 精業排列專用處理陣列。
|
||||
static let mapSeigyou: [String: String] = [
|
||||
"a": "ˇ", "b": "ㄒ", "c": "ㄌ", "d": "ㄋ", "e": "ㄊ", "f": "ㄎ", "g": "ㄑ", "h": "ㄕ", "i": "ㄛ", "j": "ㄘ", "k": "ㄜ",
|
||||
"l": "ㄠ", "m": "ㄙ", "n": "ㄖ", "o": "ㄟ", "p": "ㄣ", "q": "ˊ", "r": "ㄍ", "s": "ㄇ", "t": "ㄐ", "u": "ㄗ", "v": "ㄏ",
|
||||
"w": "ㄆ", "x": "ㄈ", "y": "ㄔ", "z": "ˋ", "1": "˙", "2": "ㄅ", "3": "ㄉ", "6": "ㄓ", "8": "ㄚ", "9": "ㄞ", "0": "ㄢ",
|
||||
"-": "ㄧ", ";": "ㄤ", ",": "ㄝ", ".": "ㄡ", "/": "ㄥ", "'": "ㄩ", "[": "ㄨ", "=": "ㄦ", " ": " ",
|
||||
]
|
||||
|
||||
/// 偽精業排列專用處理陣列。
|
||||
static let mapFakeSeigyou: [String: String] = [
|
||||
"a": "ˇ", "b": "ㄒ", "c": "ㄌ", "d": "ㄋ", "e": "ㄊ", "f": "ㄎ", "g": "ㄑ", "h": "ㄕ", "i": "ㄛ", "j": "ㄘ", "k": "ㄜ",
|
||||
"l": "ㄠ", "m": "ㄙ", "n": "ㄖ", "o": "ㄟ", "p": "ㄣ", "q": "ˊ", "r": "ㄍ", "s": "ㄇ", "t": "ㄐ", "u": "ㄗ", "v": "ㄏ",
|
||||
"w": "ㄆ", "x": "ㄈ", "y": "ㄔ", "z": "ˋ", "1": "˙", "2": "ㄅ", "3": "ㄉ", "6": "ㄓ", "8": "ㄚ", "9": "ㄞ", "0": "ㄢ",
|
||||
"4": "ㄧ", ";": "ㄤ", ",": "ㄝ", ".": "ㄡ", "/": "ㄥ", "7": "ㄩ", "5": "ㄨ", "-": "ㄦ", " ": " ",
|
||||
]
|
||||
|
||||
/// 神通排列專用處理陣列。
|
||||
static let mapQwertyMiTAC: [String: String] = [
|
||||
",": "ㄓ", "-": "ㄦ", ".": "ㄔ", "/": "ㄕ", "0": "ㄥ", "1": "˙", "2": "ˊ", "3": "ˇ", "4": "ˋ", "5": "ㄞ", "6": "ㄠ",
|
||||
"7": "ㄢ", "8": "ㄣ", "9": "ㄤ", ";": "ㄝ", "a": "ㄚ", "b": "ㄅ", "c": "ㄘ", "d": "ㄉ", "e": "ㄜ", "f": "ㄈ", "g": "ㄍ",
|
||||
"h": "ㄏ", "i": "ㄟ", "j": "ㄐ", "k": "ㄎ", "l": "ㄌ", "m": "ㄇ", "n": "ㄋ", "o": "ㄛ", "p": "ㄆ", "q": "ㄑ", "r": "ㄖ",
|
||||
"s": "ㄙ", "t": "ㄊ", "u": "ㄡ", "v": "ㄩ", "w": "ㄨ", "x": "ㄒ", "y": "ㄧ", "z": "ㄗ", " ": " ",
|
||||
]
|
||||
}
|
|
@ -93,7 +93,8 @@ class ctlInputMethod: IMKInputController {
|
|||
currentClient = client
|
||||
|
||||
keyHandler.clear()
|
||||
Composer.ensureParser()
|
||||
keyHandler.ensureParser()
|
||||
|
||||
if let bundleCheckID = (client as? IMKTextInput)?.bundleIdentifier() {
|
||||
if bundleCheckID != Bundle.main.bundleIdentifier {
|
||||
// Override the keyboard layout to the basic one.
|
||||
|
|
|
@ -168,7 +168,7 @@ struct ComposingBufferSize {
|
|||
case ofStandard = 0
|
||||
case ofEten = 1
|
||||
case ofHsu = 2
|
||||
case ofEen26 = 3
|
||||
case ofEten26 = 3
|
||||
case ofIBM = 4
|
||||
case ofMiTAC = 5
|
||||
case ofFakeSeigyou = 6
|
||||
|
@ -182,7 +182,7 @@ struct ComposingBufferSize {
|
|||
return "ETen"
|
||||
case .ofHsu:
|
||||
return "Hsu"
|
||||
case .ofEen26:
|
||||
case .ofEten26:
|
||||
return "ETen26"
|
||||
case .ofIBM:
|
||||
return "IBM"
|
||||
|
|
|
@ -1,168 +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.
|
||||
*/
|
||||
|
||||
#include "ParselessLM.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
vChewing::ParselessLM::~ParselessLM()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool vChewing::ParselessLM::isLoaded()
|
||||
{
|
||||
if (data_)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vChewing::ParselessLM::open(const std::string_view &path)
|
||||
{
|
||||
if (data_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fd_ = ::open(path.data(), O_RDONLY);
|
||||
if (fd_ == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
if (fstat(fd_, &sb) == -1)
|
||||
{
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
length_ = static_cast<size_t>(sb.st_size);
|
||||
|
||||
data_ = mmap(NULL, length_, PROT_READ, MAP_SHARED, fd_, 0);
|
||||
if (data_ == nullptr)
|
||||
{
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
length_ = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
db_ = std::unique_ptr<ParselessPhraseDB>(new ParselessPhraseDB(static_cast<char *>(data_), length_));
|
||||
return true;
|
||||
}
|
||||
|
||||
void vChewing::ParselessLM::close()
|
||||
{
|
||||
if (data_ != nullptr)
|
||||
{
|
||||
munmap(data_, length_);
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
length_ = 0;
|
||||
data_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Gramambular::Bigram> vChewing::ParselessLM::bigramsForKeys(const std::string &preceedingKey,
|
||||
const std::string &key)
|
||||
{
|
||||
return std::vector<Gramambular::Bigram>();
|
||||
}
|
||||
|
||||
const std::vector<Gramambular::Unigram> vChewing::ParselessLM::unigramsForKey(const std::string &key)
|
||||
{
|
||||
if (db_ == nullptr)
|
||||
{
|
||||
return std::vector<Gramambular::Unigram>();
|
||||
}
|
||||
|
||||
std::vector<Gramambular::Unigram> results;
|
||||
for (const auto &row : db_->findRows(key + " "))
|
||||
{
|
||||
Gramambular::Unigram unigram;
|
||||
|
||||
// Move ahead until we encounter the first space. This is the key.
|
||||
auto it = row.begin();
|
||||
while (it != row.end() && *it != ' ')
|
||||
{
|
||||
++it;
|
||||
}
|
||||
|
||||
unigram.keyValue.key = std::string(row.begin(), it);
|
||||
|
||||
// Read past the space.
|
||||
if (it != row.end())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != row.end())
|
||||
{
|
||||
// Now it is the start of the value portion.
|
||||
auto value_begin = it;
|
||||
|
||||
// Move ahead until we encounter the second space. This is the
|
||||
// value.
|
||||
while (it != row.end() && *it != ' ')
|
||||
{
|
||||
++it;
|
||||
}
|
||||
unigram.keyValue.value = std::string(value_begin, it);
|
||||
}
|
||||
|
||||
// Read past the space. The remainder, if it exists, is the score.
|
||||
if (it != row.end())
|
||||
{
|
||||
++it;
|
||||
}
|
||||
|
||||
if (it != row.end())
|
||||
{
|
||||
unigram.score = std::stod(std::string(it, row.end()));
|
||||
}
|
||||
results.push_back(unigram);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
bool vChewing::ParselessLM::hasUnigramsForKey(const std::string &key)
|
||||
{
|
||||
if (db_ == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return db_->findFirstMatchingLine(key + " ") != nullptr;
|
||||
}
|
|
@ -1,63 +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.
|
||||
*/
|
||||
|
||||
#ifndef SOURCE_ENGINE_PARSELESSLM_H_
|
||||
#define SOURCE_ENGINE_PARSELESSLM_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "LanguageModel.h"
|
||||
#include "ParselessPhraseDB.h"
|
||||
|
||||
namespace vChewing
|
||||
{
|
||||
|
||||
class ParselessLM : public Gramambular::LanguageModel
|
||||
{
|
||||
public:
|
||||
~ParselessLM() override;
|
||||
|
||||
bool isLoaded();
|
||||
bool open(const std::string_view &path);
|
||||
void close();
|
||||
|
||||
const std::vector<Gramambular::Bigram> bigramsForKeys(const std::string &preceedingKey,
|
||||
const std::string &key) override;
|
||||
const std::vector<Gramambular::Unigram> unigramsForKey(const std::string &key) override;
|
||||
bool hasUnigramsForKey(const std::string &key) override;
|
||||
|
||||
private:
|
||||
int fd_ = -1;
|
||||
void *data_ = nullptr;
|
||||
size_t length_ = 0;
|
||||
std::unique_ptr<ParselessPhraseDB> db_;
|
||||
};
|
||||
|
||||
}; // namespace vChewing
|
||||
|
||||
#endif // SOURCE_ENGINE_PARSELESSLM_H_
|
|
@ -1,163 +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.
|
||||
*/
|
||||
|
||||
#include "ParselessPhraseDB.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace vChewing
|
||||
{
|
||||
|
||||
ParselessPhraseDB::ParselessPhraseDB(const char *buf, size_t length) : begin_(buf), end_(buf + length)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<std::string_view> ParselessPhraseDB::findRows(const std::string_view &key)
|
||||
{
|
||||
std::vector<std::string_view> rows;
|
||||
|
||||
const char *ptr = findFirstMatchingLine(key);
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
while (ptr + key.length() <= end_ && memcmp(ptr, key.data(), key.length()) == 0)
|
||||
{
|
||||
const char *eol = ptr;
|
||||
|
||||
while (eol != end_ && *eol != '\n')
|
||||
{
|
||||
++eol;
|
||||
}
|
||||
|
||||
rows.emplace_back(ptr, eol - ptr);
|
||||
if (eol == end_)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = ++eol;
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
// Implements a binary search that returns the pointer to the first matching
|
||||
// row. In its core it's just a standard binary search, but we use backtracking
|
||||
// to locate the line start. We also check the previous line to see if the
|
||||
// current line is actually the first matching line: if the previous line is
|
||||
// less to the key and the current line starts exactly with the key, then
|
||||
// the current line is the first matching line.
|
||||
const char *ParselessPhraseDB::findFirstMatchingLine(const std::string_view &key)
|
||||
{
|
||||
if (key.empty())
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
|
||||
const char *top = begin_;
|
||||
const char *bottom = end_;
|
||||
|
||||
while (top < bottom)
|
||||
{
|
||||
const char *mid = top + (bottom - top) / 2;
|
||||
const char *ptr = mid;
|
||||
|
||||
if (ptr != begin_)
|
||||
{
|
||||
--ptr;
|
||||
}
|
||||
|
||||
while (ptr != begin_ && *ptr != '\n')
|
||||
{
|
||||
--ptr;
|
||||
}
|
||||
|
||||
const char *prev = nullptr;
|
||||
if (*ptr == '\n')
|
||||
{
|
||||
prev = ptr;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
// ptr is now in the "current" line we're interested in.
|
||||
if (ptr + key.length() > end_)
|
||||
{
|
||||
// not enough data to compare at this point, bail.
|
||||
break;
|
||||
}
|
||||
|
||||
int current_cmp = memcmp(ptr, key.data(), key.length());
|
||||
|
||||
if (current_cmp > 0)
|
||||
{
|
||||
bottom = mid - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_cmp < 0)
|
||||
{
|
||||
top = mid + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!prev)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Move the prev so that it reaches the previous line.
|
||||
if (prev != begin_)
|
||||
{
|
||||
--prev;
|
||||
}
|
||||
while (prev != begin_ && *prev != '\n')
|
||||
{
|
||||
--prev;
|
||||
}
|
||||
if (*prev == '\n')
|
||||
{
|
||||
++prev;
|
||||
}
|
||||
|
||||
int prev_cmp = memcmp(prev, key.data(), key.length());
|
||||
|
||||
// This is the first occurrence.
|
||||
if (prev_cmp < 0 && current_cmp == 0)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// This is not, which means ptr is "larger" than the keyData.
|
||||
bottom = mid - 1;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}; // namespace vChewing
|
|
@ -1,61 +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.
|
||||
*/
|
||||
|
||||
#ifndef SOURCE_ENGINE_PARSELESSPHRASEDB_H_
|
||||
#define SOURCE_ENGINE_PARSELESSPHRASEDB_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vChewing
|
||||
{
|
||||
|
||||
// Defines phrase database that consists of (key, value, score) rows that are
|
||||
// pre-sorted by the byte value of the keys. It is way faster than FastLM
|
||||
// because it does not need to parse anything. Instead, it relies on the fact
|
||||
// that the database is already sorted, and binary search is used to find the
|
||||
// rows.
|
||||
class ParselessPhraseDB
|
||||
{
|
||||
public:
|
||||
ParselessPhraseDB(const char *buf, size_t length);
|
||||
|
||||
// Find the rows that match the key. Note that prefix match is used. If you
|
||||
// need exact match, the key will need to have a delimiter (usually a space)
|
||||
// at the end.
|
||||
std::vector<std::string_view> findRows(const std::string_view &key);
|
||||
|
||||
const char *findFirstMatchingLine(const std::string_view &key);
|
||||
|
||||
private:
|
||||
const char *begin_;
|
||||
const char *end_;
|
||||
};
|
||||
|
||||
}; // namespace vChewing
|
||||
|
||||
#endif // SOURCE_ENGINE_PARSELESSPHRASEDB_H_
|
|
@ -31,9 +31,12 @@ extension Megrez {
|
|||
mutGrid = grid
|
||||
}
|
||||
|
||||
public func reverseWalk(at location: Int, score accumulatedScore: Double = 0.0, nodesLimit: Int = 0)
|
||||
-> [NodeAnchor]
|
||||
{
|
||||
public func reverseWalk(
|
||||
at location: Int,
|
||||
score accumulatedScore: Double = 0.0,
|
||||
nodesLimit: Int = 0,
|
||||
balanced: Bool = false
|
||||
) -> [NodeAnchor] {
|
||||
if location == 0 || location > mutGrid.width() {
|
||||
return [] as [NodeAnchor]
|
||||
}
|
||||
|
@ -41,8 +44,10 @@ extension Megrez {
|
|||
var paths: [[NodeAnchor]] = []
|
||||
var nodes: [NodeAnchor] = mutGrid.nodesEndingAt(location: location)
|
||||
|
||||
nodes.sort {
|
||||
$0.balancedScore > $1.balancedScore // 排序規則已經在 NodeAnchor 內定義了。
|
||||
if balanced {
|
||||
nodes.sort {
|
||||
$0.balancedScore > $1.balancedScore // 排序規則已經在 NodeAnchor 內定義了。
|
||||
}
|
||||
}
|
||||
|
||||
// 只檢查前 X 個 NodeAnchor 是否有 node。
|
||||
|
@ -58,10 +63,13 @@ extension Megrez {
|
|||
continue
|
||||
}
|
||||
|
||||
n.accumulatedScore = accumulatedScore + nNode.score()
|
||||
// 利用 Spanning Length 來決定權重。
|
||||
// 這樣一來,例:「再見」比「在」與「見」的權重更高。
|
||||
let weightedScore: Double = (Double(n.spanningLength) - 1) * 2
|
||||
n.accumulatedScore = accumulatedScore + nNode.score() + weightedScore
|
||||
if balanced {
|
||||
let weightedScore: Double = (Double(n.spanningLength) - 1) * 2
|
||||
n.accumulatedScore += weightedScore
|
||||
}
|
||||
|
||||
var path: [NodeAnchor] = reverseWalk(
|
||||
at: location - n.spanningLength,
|
||||
|
@ -72,7 +80,7 @@ extension Megrez {
|
|||
paths.append(path)
|
||||
|
||||
// 始終使用固定的候選字
|
||||
if nNode.score() >= 0 {
|
||||
if balanced, nNode.score() >= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ struct suiPrefPaneKeyboard: View {
|
|||
Text(LocalizedStringKey("Hsu")).tag(2)
|
||||
Text(LocalizedStringKey("MiTAC")).tag(5)
|
||||
Text(LocalizedStringKey("Fake Seigyou")).tag(6)
|
||||
Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10)
|
||||
// Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10)
|
||||
}.onChange(of: selMandarinParser) { value in
|
||||
mgrPrefs.mandarinParser = value
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19529" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19529"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -53,12 +54,9 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" setsMaxLayoutWidthAtFirstLayout="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8M8-3C-BZO">
|
||||
<rect key="frame" x="89" y="357" width="431" height="45"/>
|
||||
<textFieldCell key="cell" selectable="YES" id="lblCredits">
|
||||
<rect key="frame" x="89" y="387" width="431" height="15"/>
|
||||
<textFieldCell key="cell" selectable="YES" title="Placeholder for detailed credits." id="lblCredits">
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
<string key="title">McBopomofo Engine by Mengjuei Hsieh, Lukhnos Liu, Zonble Yang, et al.
|
||||
vChewing macOS Development: Shiki Suen, Isaac Xen, Hiraku Wang, etc.
|
||||
vChewing Phrase Database Maintained by Shiki Suen.</string>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
|
@ -67,7 +65,7 @@ vChewing Phrase Database Maintained by Shiki Suen.</string>
|
|||
<rect key="frame" x="15" y="132" width="503" height="5"/>
|
||||
</box>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="eYM-F7-drf">
|
||||
<rect key="frame" x="89" y="334" width="431" height="15"/>
|
||||
<rect key="frame" x="89" y="364" width="431" height="15"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="MIT-NTL License:" id="lblLicense">
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -121,17 +119,17 @@ DQ
|
|||
</connections>
|
||||
</button>
|
||||
<scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JkD-J1-Yeu">
|
||||
<rect key="frame" x="91" y="143" width="427" height="183"/>
|
||||
<rect key="frame" x="91" y="143" width="427" height="213"/>
|
||||
<clipView key="contentView" drawsBackground="NO" id="35U-hd-B9v">
|
||||
<rect key="frame" x="1" y="1" width="425" height="181"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<rect key="frame" x="1" y="1" width="425" height="211"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" smartInsertDelete="YES" id="cEu-uC-XnV" userLabel="appEULAContent">
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="181"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="425" height="211"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="minSize" width="425" height="181"/>
|
||||
<size key="minSize" width="425" height="211"/>
|
||||
<size key="maxSize" width="436" height="10000000"/>
|
||||
<attributedString key="textStorage">
|
||||
<fragment content="Placeholder for EULA Texts.">
|
||||
|
@ -151,7 +149,7 @@ DQ
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="qxC-Vo-FVi">
|
||||
<rect key="frame" x="410" y="1" width="16" height="181"/>
|
||||
<rect key="frame" x="410" y="1" width="16" height="211"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
|
|
|
@ -759,7 +759,6 @@
|
|||
<menuItem title="Hsu" tag="2" id="8"/>
|
||||
<menuItem title="MiTAC" tag="5" id="7fV-x8-WHQ"/>
|
||||
<menuItem title="Fake Seigyou" tag="6" id="27F-8T-FkQ"/>
|
||||
<menuItem title="Hanyu Pinyin" tag="10" id="10"/>
|
||||
</items>
|
||||
</menu>
|
||||
<connections>
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
/* 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 = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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" = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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 = "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.";
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
/* 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 = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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" = "ボポモフォエンジン開発:Lukhnos Liu。\n入力状態管理システム開発:Zonble Yang。\nmacOS 版威注音の開発:Shiki Suen, Isaac Xen, Hiraku Wang, など。\n威注音語彙データの維持:Shiki Suen。\nMegrez 辞書処理エンジン:Shiki Suen(Lukhnos の Gramambular C++ エンジンを Swift で再開発したものである)。";
|
||||
/* 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 で再開発したものである)。";
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
/* 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 = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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" = "注音拼音输入处理引擎研发:Lukhnos Liu。\n输入法状态管理引擎研发:Zonble Yang。\n威注音 macOS 程式研发:Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音词库维护:Shiki Suen。\n天权星语汇引擎:Shiki Suen,用 Swift 将 Lukhnos 的 C++ Gramambular 重写而得。";
|
||||
/* 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 重写而得。";
|
||||
|
|
|
@ -23,5 +23,5 @@
|
|||
/* 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 = "Mandarin Syllable Composer Engine by Lukhnos Liu.\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" = "注音拼音輸入處理引擎研發:Lukhnos Liu。\n輸入法狀態管理引擎研發:Zonble Yang。\n威注音 macOS 程式研發:Shiki Suen, Isaac Xen, Hiraku Wang, 等。\n威注音詞庫維護:Shiki Suen。\n天權星語彙引擎:Shiki Suen,用 Swift 將 Lukhnos 的 C++ Gramambular 重寫而得。";
|
||||
/* 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 重寫而得。";
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.5.6</string>
|
||||
<string>1.5.7</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1956</string>
|
||||
<string>1957</string>
|
||||
<key>UpdateInfoEndpoint</key>
|
||||
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
|
||||
<key>UpdateInfoSite</key>
|
||||
|
|
|
@ -726,7 +726,7 @@
|
|||
<key>USE_HFS+_COMPRESSION</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.5.6</string>
|
||||
<string>1.5.7</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
5B38F5A2281E2E49007D5F5D /* 0_Megrez.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1615FC0EB100ABF4B3 /* 0_Megrez.swift */; };
|
||||
5B38F5A3281E2E49007D5F5D /* 3_Span.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1C15FC0EB100ABF4B3 /* 3_Span.swift */; };
|
||||
5B38F5A4281E2E49007D5F5D /* 5_LanguageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F1915FC0EB100ABF4B3 /* 5_LanguageModel.swift */; };
|
||||
5B407153281F94E6009C24CB /* Composer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B407152281F94E6009C24CB /* Composer.mm */; };
|
||||
5B40730C281672610023DFFF /* lmAssociates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B407309281672610023DFFF /* lmAssociates.swift */; };
|
||||
5B40730D281672610023DFFF /* lmReplacements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B40730A281672610023DFFF /* lmReplacements.swift */; };
|
||||
5B5E535227EF261400C6AA1E /* IME.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B5E535127EF261400C6AA1E /* IME.swift */; };
|
||||
|
@ -70,6 +69,7 @@
|
|||
5BA9FD4927FEF3C9002DE248 /* Section.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3C27FEF3C8002DE248 /* Section.swift */; };
|
||||
5BA9FD4A27FEF3C9002DE248 /* PreferencesTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD3D27FEF3C8002DE248 /* PreferencesTabViewController.swift */; };
|
||||
5BA9FD8B28006B41002DE248 /* VDKComboBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD8A28006B41002DE248 /* VDKComboBox.swift */; };
|
||||
5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAA8FBD282CAF380066C406 /* SyllableComposer.swift */; };
|
||||
5BAD0CD527D701F6003D127F /* vChewingKeyLayout.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */; };
|
||||
5BAEFAD028012565001F42C9 /* mgrLangModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAEFACF28012565001F42C9 /* mgrLangModel.swift */; };
|
||||
5BB802DA27FABA8300CF1C19 /* ctlInputMethod_Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */; };
|
||||
|
@ -98,7 +98,6 @@
|
|||
5BE78BD927B3775B005EA1BE /* ctlAboutWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BE78BD827B37750005EA1BE /* ctlAboutWindow.swift */; };
|
||||
5BE78BDD27B3776D005EA1BE /* frmAboutWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5BE78BDA27B37764005EA1BE /* frmAboutWindow.xib */; };
|
||||
5BF8423127BAA942008E7E4C /* vChewingKanjiConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BF8423027BAA942008E7E4C /* vChewingKanjiConverter.swift */; };
|
||||
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */; };
|
||||
6A187E2616004C5900466B2E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6A187E2816004C5900466B2E /* MainMenu.xib */; };
|
||||
6A225A1F23679F2600F685C6 /* NotarizedArchives in Resources */ = {isa = PBXBuildFile; fileRef = 6A225A1E23679F2600F685C6 /* NotarizedArchives */; };
|
||||
6A2E40F6253A69DA00D1AE1D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A2E40F5253A69DA00D1AE1D /* Images.xcassets */; };
|
||||
|
@ -199,8 +198,6 @@
|
|||
5B2DB17127AF8771006D874E /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; name = Makefile; path = Data/Makefile; sourceTree = "<group>"; };
|
||||
5B30F11227BA568800484E24 /* vChewingKeyLayout.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = vChewingKeyLayout.bundle; sourceTree = "<group>"; };
|
||||
5B3133BE280B229700A4A505 /* KeyHandler_States.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = KeyHandler_States.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5B407151281F94E6009C24CB /* Composer.hh */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Composer.hh; sourceTree = "<group>"; };
|
||||
5B407152281F94E6009C24CB /* Composer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Composer.mm; sourceTree = "<group>"; };
|
||||
5B407309281672610023DFFF /* lmAssociates.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; lineEnding = 0; path = lmAssociates.swift; sourceTree = "<group>"; usesTabs = 0; };
|
||||
5B40730A281672610023DFFF /* lmReplacements.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; lineEnding = 0; path = lmReplacements.swift; sourceTree = "<group>"; usesTabs = 0; };
|
||||
5B5E535127EF261400C6AA1E /* IME.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = IME.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
|
@ -246,6 +243,7 @@
|
|||
5BA9FD3C27FEF3C8002DE248 /* Section.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = Section.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5BA9FD3D27FEF3C8002DE248 /* PreferencesTabViewController.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = PreferencesTabViewController.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5BA9FD8A28006B41002DE248 /* VDKComboBox.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = VDKComboBox.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5BAA8FBD282CAF380066C406 /* SyllableComposer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyllableComposer.swift; sourceTree = "<group>"; };
|
||||
5BAEFACF28012565001F42C9 /* mgrLangModel.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = mgrLangModel.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5BB802D927FABA8300CF1C19 /* ctlInputMethod_Menu.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlInputMethod_Menu.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
5BBBB75D27AED54C0023B93A /* Beep.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Beep.m4a; sourceTree = "<group>"; };
|
||||
|
@ -303,8 +301,6 @@
|
|||
6A0D4F1C15FC0EB100ABF4B3 /* 3_Span.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 3_Span.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
6A0D4F1D15FC0EB100ABF4B3 /* 6_Unigram.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 6_Unigram.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
6A0D4F1E15FC0EB100ABF4B3 /* 1_Walker.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = 1_Walker.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Mandarin.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
6A0D4F2115FC0EB100ABF4B3 /* Mandarin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Mandarin.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
6A15B32421A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
6A15B32521A51F2300B92CD3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
6A225A1E23679F2600F685C6 /* NotarizedArchives */ = {isa = PBXFileReference; lastKnownFileType = folder; path = NotarizedArchives; sourceTree = "<group>"; };
|
||||
|
@ -315,10 +311,6 @@
|
|||
6ACA41EF15FC1D9000935EF6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
6ACA41F215FC1D9000935EF6 /* Installer-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Installer-Info.plist"; path = "Installer/Installer-Info.plist"; sourceTree = SOURCE_ROOT; };
|
||||
6ACA41F315FC1D9000935EF6 /* Installer-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Installer-Prefix.pch"; path = "Installer/Installer-Prefix.pch"; sourceTree = SOURCE_ROOT; };
|
||||
6ACC3D402793701600F1B140 /* ParselessPhraseDB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = ParselessPhraseDB.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
6ACC3D412793701600F1B140 /* ParselessPhraseDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ParselessPhraseDB.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
6ACC3D422793701600F1B140 /* ParselessLM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = ParselessLM.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
6ACC3D432793701600F1B140 /* ParselessLM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ParselessLM.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
D427A9BF25ED28CC005D43E0 /* vChewing-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "vChewing-Bridging-Header.h"; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
D427F76B278CA1BA004A2160 /* AppDelegate.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = AppDelegate.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D456576D279E4F7B00DF6BC9 /* InputHandler.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = InputHandler.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
|
@ -403,24 +395,12 @@
|
|||
children = (
|
||||
5B949BD72816DC4400D87B5D /* LineReader */,
|
||||
5B707CE627D9F43E0099EF99 /* OpenCCBridge */,
|
||||
5B62A30227AE733500A19448 /* OVMandarin */,
|
||||
5BA9FCEA27FED652002DE248 /* SindreSorhus */,
|
||||
5BA9FD8C28006BA7002DE248 /* VDKComboBox */,
|
||||
);
|
||||
path = 3rdParty;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B62A30227AE733500A19448 /* OVMandarin */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6A0D4F2015FC0EB100ABF4B3 /* Mandarin.cpp */,
|
||||
6A0D4F2115FC0EB100ABF4B3 /* Mandarin.h */,
|
||||
5B407151281F94E6009C24CB /* Composer.hh */,
|
||||
5B407152281F94E6009C24CB /* Composer.mm */,
|
||||
);
|
||||
path = OVMandarin;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B62A31E27AE74E400A19448 /* SFX */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -443,6 +423,7 @@
|
|||
5B61B0C9280BEFD4002E3CFA /* KeyHandler_Misc.swift */,
|
||||
5B3133BE280B229700A4A505 /* KeyHandler_States.swift */,
|
||||
5B62A33727AE79CD00A19448 /* NSStringUtils.swift */,
|
||||
5BAA8FBD282CAF380066C406 /* SyllableComposer.swift */,
|
||||
5BF8423027BAA942008E7E4C /* vChewingKanjiConverter.swift */,
|
||||
);
|
||||
path = ControllerModules;
|
||||
|
@ -501,10 +482,6 @@
|
|||
5B62A32527AE758000A19448 /* OldFileReferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6ACC3D422793701600F1B140 /* ParselessLM.cpp */,
|
||||
6ACC3D432793701600F1B140 /* ParselessLM.h */,
|
||||
6ACC3D402793701600F1B140 /* ParselessPhraseDB.cpp */,
|
||||
6ACC3D412793701600F1B140 /* ParselessPhraseDB.h */,
|
||||
D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */,
|
||||
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */,
|
||||
);
|
||||
|
@ -1111,7 +1088,6 @@
|
|||
5B62A33827AE79CD00A19448 /* NSStringUtils.swift in Sources */,
|
||||
5BA9FD0F27FEDB6B002DE248 /* suiPrefPaneGeneral.swift in Sources */,
|
||||
5BA9FD4927FEF3C9002DE248 /* Section.swift in Sources */,
|
||||
5B407153281F94E6009C24CB /* Composer.mm in Sources */,
|
||||
5BA9FD3E27FEF3C8002DE248 /* Utilities.swift in Sources */,
|
||||
5BA9FD1127FEDB6B002DE248 /* ctlPrefUI.swift in Sources */,
|
||||
5B38F59C281E2E49007D5F5D /* 2_Grid.swift in Sources */,
|
||||
|
@ -1120,12 +1096,12 @@
|
|||
5B62A33227AE792F00A19448 /* InputSourceHelper.swift in Sources */,
|
||||
5B5E535227EF261400C6AA1E /* IME.swift in Sources */,
|
||||
5B62A34927AE7CD900A19448 /* TooltipController.swift in Sources */,
|
||||
6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */,
|
||||
5B61B0CA280BEFD4002E3CFA /* KeyHandler_Misc.swift in Sources */,
|
||||
5B38F59A281E2E49007D5F5D /* 6_Unigram.swift in Sources */,
|
||||
5B38F5A0281E2E49007D5F5D /* 1_Walker.swift in Sources */,
|
||||
5B62A34827AE7CD900A19448 /* ctlCandidateVertical.swift in Sources */,
|
||||
5BA9FD4027FEF3C8002DE248 /* Localization.swift in Sources */,
|
||||
5BAA8FBE282CAF380066C406 /* SyllableComposer.swift in Sources */,
|
||||
5BA9FD1327FEDB6B002DE248 /* suiPrefPaneDictionary.swift in Sources */,
|
||||
5BBBB77A27AEDC690023B93A /* clsSFX.swift in Sources */,
|
||||
5BA9FD4727FEF3C9002DE248 /* PreferencesStyleController.swift in Sources */,
|
||||
|
@ -1332,7 +1308,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1956;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1355,7 +1331,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.6;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1388,7 +1364,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1956;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
@ -1407,7 +1383,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.6;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1522,7 +1498,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1956;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
|
@ -1557,7 +1533,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.6;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1589,7 +1565,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1956;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1619,7 +1595,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.6;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1702,7 +1678,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1956;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1727,7 +1703,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.6;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1754,7 +1730,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1956;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
|
@ -1774,7 +1750,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.6;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
Loading…
Reference in New Issue