Pre Merge pull request !32 from ShikiSuen/upd/1.5.8
This commit is contained in:
commit
1b3e331c9d
|
@ -76,6 +76,8 @@
|
|||
|
||||
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang)。
|
||||
|
||||
- Voltaire MK2 選字窗、飄雲通知視窗、工具提示 (by Zonble Yang),有大幅度修改。
|
||||
|
||||
威注音輸入法 macOS 版以 MIT-NTL License 授權釋出 (與 MIT 相容):© 2021-2022 vChewing 專案。
|
||||
|
||||
- 威注音輸入法 macOS 版程式維護:Shiki Suen。特別感謝 Isaac Xen 與 Hiraku Wong 等人的技術協力。
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 5abc68212bba31114197bdfee08dd615d89878bd
|
||||
Subproject commit 383ad9af7dd6f9ffa58ad2560e186bf06ffea3ad
|
|
@ -84,7 +84,6 @@ class KeyHandler: NSObject {
|
|||
_walkedNodes.removeAll()
|
||||
}
|
||||
|
||||
// 這個函數得獨立出來給 ObjC 使用。
|
||||
func setInputMode(_ value: String) {
|
||||
// 下面這句的「isKindOfClass」是做類型檢查,
|
||||
// 為了應對出現輸入法 plist 被改壞掉這樣的極端情況。
|
||||
|
@ -122,7 +121,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(), balanced: true)
|
||||
let walked = walker.reverseWalk(at: _builder.grid().width(), nodesLimit: 3, balanced: true)
|
||||
|
||||
// then we use ".reversed()" to reverse the nodes so that we get the forward-walked nodes
|
||||
_walkedNodes.removeAll()
|
||||
|
@ -312,11 +311,11 @@ class KeyHandler: NSObject {
|
|||
}
|
||||
|
||||
func deleteBuilderReadingInFrontOfCursor() {
|
||||
_builder.deleteReadingBeforeCursor()
|
||||
_builder.deleteReadingAtTheRearOfCursor()
|
||||
}
|
||||
|
||||
func deleteBuilderReadingAfterCursor() {
|
||||
_builder.deleteReadingAfterCursor()
|
||||
func deleteBuilderReadingToTheFrontOfCursor() {
|
||||
_builder.deleteReadingToTheFrontOfCursor()
|
||||
}
|
||||
|
||||
func getKeyLengthAtIndexZero() -> Int {
|
||||
|
|
|
@ -37,12 +37,10 @@ extension KeyHandler {
|
|||
) -> Bool {
|
||||
let charCode: UniChar = input.charCode
|
||||
var state = state // Turn this incoming constant into variable.
|
||||
let inputText: String = input.inputText ?? ""
|
||||
|
||||
// Ignore the input if its inputText is empty.
|
||||
// Reason: such inputs may be functional key combinations.
|
||||
|
||||
if inputText.isEmpty {
|
||||
guard let inputText: String = input.inputText, !inputText.isEmpty else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -168,7 +166,7 @@ extension KeyHandler {
|
|||
// However, Swift does not support "|=".
|
||||
composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter))
|
||||
if composeReading {
|
||||
let reading = _composer.getRealComposition()
|
||||
let reading = _composer.realComposition
|
||||
|
||||
// See whether we have a unigram for this...
|
||||
if !ifLangModelHasUnigrams(forKey: reading) {
|
||||
|
@ -238,36 +236,34 @@ extension KeyHandler {
|
|||
|
||||
// MARK: Calling candidate window using Space or Down or PageUp / PageDn.
|
||||
|
||||
if let currentState = state as? InputState.NotEmpty {
|
||||
if _composer.isEmpty,
|
||||
input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace
|
||||
|| input.isPageDown || input.isPageUp || input.isTab
|
||||
|| (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey))
|
||||
{
|
||||
if input.isSpace {
|
||||
// If the Space key is NOT set to be a selection key
|
||||
if input.isShiftHold || !mgrPrefs.chooseCandidateUsingSpace {
|
||||
if getBuilderCursorIndex() >= getBuilderLength() {
|
||||
let composingBuffer = currentState.composingBuffer
|
||||
if (composingBuffer.count) != 0 {
|
||||
stateCallback(InputState.Committing(poppedText: composingBuffer))
|
||||
}
|
||||
clear()
|
||||
stateCallback(InputState.Committing(poppedText: " "))
|
||||
stateCallback(InputState.Empty())
|
||||
} else if ifLangModelHasUnigrams(forKey: " ") {
|
||||
insertReadingToBuilderAtCursor(reading: " ")
|
||||
let poppedText = popOverflowComposingTextAndWalk()
|
||||
let inputting = buildInputtingState()
|
||||
inputting.poppedText = poppedText
|
||||
stateCallback(inputting)
|
||||
if let currentState = state as? InputState.NotEmpty, _composer.isEmpty,
|
||||
input.isExtraChooseCandidateKey || input.isExtraChooseCandidateKeyReverse || input.isSpace
|
||||
|| input.isPageDown || input.isPageUp || input.isTab
|
||||
|| (input.useVerticalMode && (input.isVerticalModeOnlyChooseCandidateKey))
|
||||
{
|
||||
if input.isSpace {
|
||||
// If the Space key is NOT set to be a selection key
|
||||
if input.isShiftHold || !mgrPrefs.chooseCandidateUsingSpace {
|
||||
if getBuilderCursorIndex() >= getBuilderLength() {
|
||||
let composingBuffer = currentState.composingBuffer
|
||||
if !composingBuffer.isEmpty {
|
||||
stateCallback(InputState.Committing(poppedText: composingBuffer))
|
||||
}
|
||||
return true
|
||||
clear()
|
||||
stateCallback(InputState.Committing(poppedText: " "))
|
||||
stateCallback(InputState.Empty())
|
||||
} else if ifLangModelHasUnigrams(forKey: " ") {
|
||||
insertReadingToBuilderAtCursor(reading: " ")
|
||||
let poppedText = popOverflowComposingTextAndWalk()
|
||||
let inputting = buildInputtingState()
|
||||
inputting.poppedText = poppedText
|
||||
stateCallback(inputting)
|
||||
}
|
||||
return true
|
||||
}
|
||||
stateCallback(buildCandidate(state: currentState, useVerticalMode: input.useVerticalMode))
|
||||
return true
|
||||
}
|
||||
stateCallback(buildCandidate(state: currentState, useVerticalMode: input.useVerticalMode))
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
|
|
@ -51,4 +51,31 @@ extension KeyHandler {
|
|||
}
|
||||
return cursorIndex
|
||||
}
|
||||
|
||||
// 用於網頁 Ruby 的注音需要按照教科書印刷的方式來顯示輕聲,所以這裡處理一下。
|
||||
func cnvZhuyinKeyToTextbookReading(target: String, newSeparator: String = "-") -> String {
|
||||
var arrReturn: [String] = []
|
||||
for neta in target.split(separator: "-") {
|
||||
var newString = String(neta)
|
||||
if String(neta.reversed()[0]) == "˙" {
|
||||
newString = String(neta.dropLast())
|
||||
newString.insert("˙", at: newString.startIndex)
|
||||
}
|
||||
arrReturn.append(newString)
|
||||
}
|
||||
return arrReturn.joined(separator: newSeparator)
|
||||
}
|
||||
|
||||
// 用於網頁 Ruby 的拼音的陰平必須顯示,這裡處理一下。
|
||||
func restoreToneOneInZhuyinKey(target: String, newSeparator: String = "-") -> String {
|
||||
var arrReturn: [String] = []
|
||||
for neta in target.split(separator: "-") {
|
||||
var newNeta = String(neta)
|
||||
if !"ˊˇˋ˙".contains(String(neta.reversed()[0])), !neta.contains("_") {
|
||||
newNeta += "1"
|
||||
}
|
||||
arrReturn.append(newNeta)
|
||||
}
|
||||
return arrReturn.joined(separator: newSeparator)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,58 +37,60 @@ extension KeyHandler {
|
|||
var composingBuffer = ""
|
||||
var composedStringCursorIndex = 0
|
||||
|
||||
var readingCursorIndex: size_t = 0
|
||||
let builderCursorIndex: size_t = getBuilderCursorIndex()
|
||||
var readingCursorIndex = 0
|
||||
let builderCursorIndex = getBuilderCursorIndex()
|
||||
|
||||
// We must do some Unicode codepoint counting to find the actual cursor location for the client
|
||||
// i.e. we need to take UTF-16 into consideration, for which a surrogate pair takes 2 UniChars
|
||||
// locations. These processes are inherited from the ObjC++ version of this class and might be
|
||||
// unnecessary in Swift, but this deduction requires further experiments.
|
||||
for walkedNode in _walkedNodes {
|
||||
if let theNode = walkedNode.node {
|
||||
let strNodeValue = theNode.currentKeyValue().value
|
||||
composingBuffer += strNodeValue
|
||||
for theAnchor in _walkedNodes {
|
||||
guard let node = theAnchor.node else {
|
||||
continue
|
||||
}
|
||||
|
||||
let arrSplit: [NSString] = (strNodeValue as NSString).split()
|
||||
let codepointCount = arrSplit.count
|
||||
let valueString = node.currentKeyValue().value
|
||||
composingBuffer += valueString
|
||||
let codepointCount = valueString.count
|
||||
|
||||
// This re-aligns the cursor index in the composed string
|
||||
// (the actual cursor on the screen) with the builder's logical
|
||||
// cursor (reading) cursor; each built node has a "spanning length"
|
||||
// (e.g. two reading blocks has a spanning length of 2), and we
|
||||
// accumulate those lengths to calculate the displayed cursor
|
||||
// index.
|
||||
let spanningLength: Int = walkedNode.spanningLength
|
||||
if readingCursorIndex + spanningLength <= builderCursorIndex {
|
||||
composedStringCursorIndex += (strNodeValue as NSString).length
|
||||
readingCursorIndex += spanningLength
|
||||
} else {
|
||||
if codepointCount == spanningLength {
|
||||
var i = 0
|
||||
while i < codepointCount, readingCursorIndex < builderCursorIndex {
|
||||
composedStringCursorIndex += arrSplit[i].length
|
||||
readingCursorIndex += 1
|
||||
i += 1
|
||||
}
|
||||
} else {
|
||||
let spanningLength = theAnchor.spanningLength
|
||||
if readingCursorIndex + spanningLength <= builderCursorIndex {
|
||||
composedStringCursorIndex += valueString.count
|
||||
readingCursorIndex += spanningLength
|
||||
} else {
|
||||
if codepointCount == spanningLength {
|
||||
for _ in 0..<codepointCount {
|
||||
if readingCursorIndex < builderCursorIndex {
|
||||
composedStringCursorIndex += (strNodeValue as NSString).length
|
||||
readingCursorIndex += spanningLength
|
||||
if readingCursorIndex > builderCursorIndex {
|
||||
readingCursorIndex = builderCursorIndex
|
||||
}
|
||||
composedStringCursorIndex += 1
|
||||
readingCursorIndex += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if readingCursorIndex < builderCursorIndex {
|
||||
composedStringCursorIndex += valueString.count
|
||||
readingCursorIndex += spanningLength
|
||||
if readingCursorIndex > builderCursorIndex {
|
||||
readingCursorIndex = builderCursorIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, we gather all the intel, separate the composing buffer to two parts (head and tail),
|
||||
// and insert the reading text (the Mandarin syllable) in between them.
|
||||
// The reading text is what the user is typing.
|
||||
|
||||
let head = String((composingBuffer as NSString).substring(to: composedStringCursorIndex))
|
||||
let reading = _composer.getDisplayedComposition()
|
||||
let tail = String((composingBuffer as NSString).substring(from: composedStringCursorIndex))
|
||||
var rawHead = ""
|
||||
var rawEnd = ""
|
||||
|
||||
for (i, n) in composingBuffer.enumerated() {
|
||||
if i < composedStringCursorIndex {
|
||||
rawHead += String(n)
|
||||
} else {
|
||||
rawEnd += String(n)
|
||||
}
|
||||
}
|
||||
|
||||
let head = rawHead
|
||||
let reading = _composer.getComposition(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
|
||||
let tail = rawEnd
|
||||
let composedText = head + reading + tail
|
||||
let cursorIndex = composedStringCursorIndex + reading.count
|
||||
|
||||
|
@ -279,11 +281,15 @@ extension KeyHandler {
|
|||
return false
|
||||
}
|
||||
|
||||
let readings: [String] = currentReadings()
|
||||
let composingBuffer =
|
||||
(IME.areWeUsingOurOwnPhraseEditor)
|
||||
? readings.joined(separator: "-")
|
||||
: readings.joined(separator: " ")
|
||||
var composingBuffer = currentReadings().joined(separator: "-")
|
||||
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
|
||||
composingBuffer = restoreToneOneInZhuyinKey(target: composingBuffer) // 恢復陰平標記
|
||||
composingBuffer = Tekkon.cnvPhonaToHanyuPinyin(target: composingBuffer) // 注音轉拼音
|
||||
}
|
||||
|
||||
if !IME.areWeUsingOurOwnPhraseEditor {
|
||||
composingBuffer = composingBuffer.replacingOccurrences(of: "-", with: " ")
|
||||
}
|
||||
|
||||
clear()
|
||||
|
||||
|
@ -307,7 +313,16 @@ extension KeyHandler {
|
|||
|
||||
for theAnchor in _walkedNodes {
|
||||
if let node = theAnchor.node {
|
||||
let key = node.currentKeyValue().key.replacingOccurrences(of: "-", with: " ")
|
||||
var key = node.currentKeyValue().key
|
||||
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
|
||||
key = restoreToneOneInZhuyinKey(target: key) // 恢復陰平標記
|
||||
key = Tekkon.cnvPhonaToHanyuPinyin(target: key) // 注音轉拼音
|
||||
key = Tekkon.cnvHanyuPinyinToTextbookStyle(target: key) // 轉教科書式標調
|
||||
key = key.replacingOccurrences(of: "-", with: " ")
|
||||
} else {
|
||||
key = cnvZhuyinKeyToTextbookReading(target: key, newSeparator: " ")
|
||||
}
|
||||
|
||||
let value = node.currentKeyValue().value
|
||||
if key.contains("_") { // 不要給標點符號等特殊元素加注音
|
||||
composed += value
|
||||
|
@ -372,11 +387,11 @@ extension KeyHandler {
|
|||
|
||||
if _composer.isEmpty {
|
||||
if getBuilderCursorIndex() != getBuilderLength() {
|
||||
deleteBuilderReadingAfterCursor()
|
||||
deleteBuilderReadingToTheFrontOfCursor()
|
||||
walk()
|
||||
let inputting = buildInputtingState()
|
||||
// 這裡不用「count > 0」,因為該整數變數只要「!isEmpty」那就必定滿足這個條件。
|
||||
if !inputting.composingBuffer.isEmpty {
|
||||
if inputting.composingBuffer.isEmpty {
|
||||
stateCallback(InputState.EmptyIgnoringPreviousState())
|
||||
} else {
|
||||
stateCallback(inputting)
|
||||
|
|
|
@ -28,14 +28,16 @@ import Foundation
|
|||
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 semivowel = 2 // 介
|
||||
case vowel = 3 // 韻
|
||||
case intonation = 4 // 調
|
||||
}
|
||||
|
||||
/// 定義注音排列的類型
|
||||
public enum MandarinParser: Int {
|
||||
case ofDachen = 0
|
||||
case ofEten = 1
|
||||
|
@ -45,7 +47,7 @@ public struct Tekkon {
|
|||
case ofMiTAC = 5
|
||||
case ofFakeSeigyou = 6
|
||||
case ofSeigyou = 7
|
||||
case ofHanyuPinyin = 10
|
||||
case ofHanyuPinyin = 10 // 目前暫時沒有漢語拼音支援
|
||||
|
||||
var name: String {
|
||||
switch self {
|
||||
|
@ -71,52 +73,75 @@ public struct Tekkon {
|
|||
}
|
||||
}
|
||||
|
||||
/// 引擎僅接受這些記號作為聲母
|
||||
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
|
||||
|
||||
/// 注音符號型別。本身與字串差不多,但卻只能被設定成一個注音符號字符。
|
||||
/// 然後會根據自身的 value 的內容值自動計算自身的 PhoneType 類型(聲介韻調假)。
|
||||
/// 如果遇到被設為多個字符、或者字符不對的情況的話,value 會被清空、PhoneType 會變成 null。
|
||||
/// 賦值時最好直接重新 init 且一直用 let 來初期化 Phonabet。
|
||||
/// 其實 value 對外只讀,對內的話另有 valueStorage 代為存儲內容。這樣比較安全一些。
|
||||
@frozen public struct Phonabet: Equatable, Hashable, ExpressibleByStringLiteral {
|
||||
public var type: PhoneType = .null
|
||||
public var value: String = ""
|
||||
private var valueStorage = ""
|
||||
public var value: String { valueStorage }
|
||||
public var isEmpty: Bool {
|
||||
value.isEmpty
|
||||
}
|
||||
|
||||
/// 初期化,會根據傳入的 input 字串參數來自動判定自身的 PhoneType 類型屬性值。
|
||||
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 }
|
||||
valueStorage = String(input.reversed()[0])
|
||||
if Tekkon.allowedConsonants.contains(value) {
|
||||
type = .consonant
|
||||
} else if Tekkon.allowedsemivowels.contains(value) {
|
||||
type = .semivowel
|
||||
} else if Tekkon.allowedVowels.contains(value) {
|
||||
type = .vowel
|
||||
} else if Tekkon.allowedIntonations.contains(value) {
|
||||
type = .intonation
|
||||
} else {
|
||||
type = .null
|
||||
valueStorage = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 自我清空內容。
|
||||
public mutating func clear() {
|
||||
value = ""
|
||||
valueStorage = ""
|
||||
}
|
||||
|
||||
// MARK: - Misc Definitions
|
||||
|
||||
/// 這些內容用來滿足 "Equatable, Hashable, ExpressibleByStringLiteral" 需求。
|
||||
|
||||
public static func == (lhs: Phonabet, rhs: Phonabet) -> Bool {
|
||||
lhs.value == rhs.value
|
||||
}
|
||||
|
@ -141,25 +166,76 @@ public struct Tekkon {
|
|||
|
||||
// MARK: - Syllable Composer
|
||||
|
||||
/// 注音並擊處理的對外介面以注拼槽(Syllable Composer)的形式存在。
|
||||
/// 使用時需要單獨初期化為一個副本變數(因為是 Struct 所以必須得是變數)。
|
||||
/// 注拼槽只有四格:聲、介、韻、調。
|
||||
/// @--DISCUSSION--@
|
||||
/// 因為是 String Literal,所以初期化時可以藉由 @input 參數指定初期已經傳入的按鍵訊號。
|
||||
/// 還可以在初期化時藉由 @arrange 參數來指定注音排列(預設為「.ofDachen」大千佈局)。
|
||||
@frozen public struct Composer: Equatable, Hashable, ExpressibleByStringLiteral {
|
||||
/// 聲母。
|
||||
public var consonant: Phonabet = ""
|
||||
|
||||
/// 介母。
|
||||
public var semivowel: Phonabet = ""
|
||||
|
||||
/// 韻母。
|
||||
public var vowel: Phonabet = ""
|
||||
|
||||
/// 聲調。
|
||||
public var intonation: Phonabet = ""
|
||||
|
||||
/// 注音排列種類。預設情況下是大千排列(Windows / macOS 預設注音排列)。
|
||||
public var parser: MandarinParser = .ofDachen
|
||||
|
||||
/// 內容值,會直接按照正確的順序拼裝自己的聲介韻調內容、再回傳。
|
||||
/// 注意:直接取這個參數的內容的話,陰平聲調會成為一個空格。
|
||||
/// 如果是要取不帶空格的注音的話,請使用「.realComposition」而非「.value」。
|
||||
public var value: String {
|
||||
consonant.value + semivowel.value + vowel.value + intonation.value.replacingOccurrences(of: " ", with: "")
|
||||
consonant.value + semivowel.value + vowel.value + intonation.value
|
||||
}
|
||||
|
||||
/// 這是專門用來「生成用以進行詞庫檢索的 Key」的函數。
|
||||
public var realComposition: String {
|
||||
value.replacingOccurrences(of: " ", with: "")
|
||||
}
|
||||
|
||||
/// 與 value 類似。這個函數就是用來決定輸入法組字區內顯示的注音/拼音內容。
|
||||
/// 但可以指定是否輸出教科書格式(拼音的調號在字母上方、注音的輕聲寫在左側)。
|
||||
public func getComposition(isHanyuPinyin: Bool = false, isTextBookStyle: Bool = false) -> String {
|
||||
switch isHanyuPinyin {
|
||||
case false:
|
||||
var valReturnZhuyin = value.replacingOccurrences(of: " ", with: "")
|
||||
if isTextBookStyle, valReturnZhuyin.contains("˙") {
|
||||
valReturnZhuyin = String(valReturnZhuyin.dropLast())
|
||||
valReturnZhuyin.insert("˙", at: valReturnZhuyin.startIndex)
|
||||
}
|
||||
return valReturnZhuyin
|
||||
case true:
|
||||
var valReturnPinyin = Tekkon.cnvPhonaToHanyuPinyin(target: value)
|
||||
if isTextBookStyle {
|
||||
valReturnPinyin = Tekkon.cnvHanyuPinyinToTextbookStyle(target: valReturnPinyin)
|
||||
}
|
||||
return valReturnPinyin
|
||||
}
|
||||
}
|
||||
|
||||
/// 注拼槽內容是否為空。
|
||||
public var isEmpty: Bool {
|
||||
intonation.isEmpty && vowel.isEmpty && semivowel.isEmpty && consonant.isEmpty
|
||||
}
|
||||
|
||||
// MARK: 注拼槽對外處理函數
|
||||
|
||||
/// 初期化一個新的注拼槽。可以藉由 @input 參數指定初期已經傳入的按鍵訊號。
|
||||
/// 還可以在初期化時藉由 @arrange 參數來指定注音排列(預設為「.ofDachen」大千佈局)。
|
||||
public init(_ input: String = "", arrange parser: MandarinParser = .ofDachen) {
|
||||
receiveKey(fromString: input)
|
||||
ensureParser(arrange: parser)
|
||||
receiveKey(fromString: input)
|
||||
}
|
||||
|
||||
/// 清除自身的內容,就是將聲介韻調全部清空。
|
||||
/// 嚴格而言,「注音排列」這個屬性沒有需要清空的概念,只能用 ensureParser 參數變更之。
|
||||
public mutating func clear() {
|
||||
consonant.clear()
|
||||
semivowel.clear()
|
||||
|
@ -170,9 +246,10 @@ public struct Tekkon {
|
|||
// MARK: - Public Functions
|
||||
|
||||
/// 用於檢測「某個輸入字符訊號的合規性」的函數。
|
||||
/// Phonabet 是一個特殊的 String 類 Struct,
|
||||
/// 只會接受正確的注音符號資料、且根據其類型自動回報其類型。
|
||||
/// 類型只有「聲、韻、介、調」這四類。
|
||||
/// @--DISCUSSION--@
|
||||
/// 注意:回傳結果會受到當前注音排列 parser 屬性的影響。
|
||||
/// - Parameters:
|
||||
/// - key: 傳入的 UniChar 內容。
|
||||
public func inputValidityCheck(key inputKey: UniChar = 0) -> Bool {
|
||||
if let scalar = UnicodeScalar(inputKey) {
|
||||
let input = String(scalar)
|
||||
|
@ -200,6 +277,12 @@ public struct Tekkon {
|
|||
return false
|
||||
}
|
||||
|
||||
/// 接受傳入的按鍵訊號時的處理,處理對象為 String。
|
||||
/// 另有同名函數可處理 UniChar 訊號。
|
||||
/// @--DISCUSSION--@
|
||||
/// 如果是諸如複合型注音排列的話,翻譯結果有可能為空,但翻譯過程已經處理好聲介韻調分配了。
|
||||
/// - Parameters:
|
||||
/// - fromString: 傳入的 String 內容。
|
||||
public mutating func receiveKey(fromString input: String = "") {
|
||||
let translatedInput = translate(key: String(input))
|
||||
let thePhone: Phonabet = .init(translatedInput)
|
||||
|
@ -212,32 +295,22 @@ public struct Tekkon {
|
|||
}
|
||||
}
|
||||
|
||||
/// 接受傳入的按鍵訊號時的處理,處理對象為 UniChar。
|
||||
/// 其實也就是先將 UniChar 轉為 String 再交給某個同名異參的函數來處理而已。
|
||||
/// @--DISCUSSION--@
|
||||
/// 如果是諸如複合型注音排列的話,翻譯結果有可能為空,但翻譯過程已經處理好聲介韻調分配了。
|
||||
/// - Parameters:
|
||||
/// - fromCharCode: 傳入的 UniChar 內容。
|
||||
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
|
||||
}
|
||||
receiveKey(fromString: String(scalar))
|
||||
}
|
||||
}
|
||||
|
||||
/// 本來這個函數是不需要的,但將來在做漢語拼音功能時、這裡得回傳別的東西。
|
||||
/// 也就是說,這個函數就是用來決定輸入法組字區內顯示的注音/拼音內容。
|
||||
public func getDisplayedComposition() -> String {
|
||||
value
|
||||
}
|
||||
|
||||
/// 這是專門用來「生成用以進行詞庫檢索的 Key」的函數。
|
||||
public func getRealComposition() -> String {
|
||||
value
|
||||
}
|
||||
|
||||
/// 專門用來響應使用者摁下 BackSpace 按鍵時的行為。
|
||||
/// 刪除順序:調、韻、介、聲。
|
||||
/// @--DISCUSSION--@
|
||||
/// 基本上就是按順序從游標前方開始往後刪。
|
||||
public mutating func doBackSpace() {
|
||||
if !intonation.isEmpty {
|
||||
intonation.clear()
|
||||
|
@ -250,7 +323,9 @@ public struct Tekkon {
|
|||
}
|
||||
}
|
||||
|
||||
/// 用來檢測是否有調號
|
||||
/// 用來檢測是否有調號的函數,預設情況下不判定聲調以外的內容的存無。
|
||||
/// - Parameters:
|
||||
/// - withNothingElse: 追加判定「槽內是否僅有調號」。
|
||||
public func hasToneMarker(withNothingElse: Bool = false) -> Bool {
|
||||
if !withNothingElse {
|
||||
return !intonation.isEmpty
|
||||
|
@ -258,23 +333,22 @@ public struct Tekkon {
|
|||
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 處於何種鍵盤排列分析模式
|
||||
// 設定該 Composer 處於何種鍵盤排列分析模式。
|
||||
/// - Parameters:
|
||||
/// - arrange: 給該注拼槽指定注音排列。
|
||||
public mutating func ensureParser(arrange: MandarinParser = .ofDachen) {
|
||||
parser = arrange
|
||||
}
|
||||
|
||||
// MARK: - Parser Processings
|
||||
|
||||
// 注拼槽對內處理用函數都在這一小節。
|
||||
|
||||
/// 根據目前的注音排列設定來翻譯傳入的 String 訊號。
|
||||
/// @--DISCUSSION--@
|
||||
/// 倚天或許氏鍵盤的處理函數會將分配過程代為處理過,此時回傳結果為空字串。
|
||||
/// - Parameters:
|
||||
/// - key: 傳入的 String 訊號。
|
||||
mutating func translate(key: String = "") -> String {
|
||||
switch parser {
|
||||
case .ofDachen:
|
||||
|
@ -299,6 +373,10 @@ public struct Tekkon {
|
|||
}
|
||||
|
||||
/// 倚天忘形注音排列比較麻煩,需要單獨處理。
|
||||
/// @--DISCUSSION--@
|
||||
/// 回傳結果是空字串的話,不要緊,因為該函數內部已經處理過分配過程了。
|
||||
/// - Parameters:
|
||||
/// - key: 傳入的 String 訊號。
|
||||
mutating func handleEten26(key: String = "") -> String {
|
||||
var strReturn = ""
|
||||
strReturn = Tekkon.mapEten26StaticKeys[key] ?? ""
|
||||
|
@ -348,34 +426,54 @@ public struct Tekkon {
|
|||
}
|
||||
}
|
||||
|
||||
// 這些按鍵在上文處理過了,就不要再回傳了。
|
||||
if "dfhjklmnpqtw".contains(key) { strReturn = "" }
|
||||
|
||||
// 回傳結果是空字串的話,不要緊,因為上文已經代處理過分配過程了。
|
||||
return strReturn
|
||||
}
|
||||
|
||||
/// 許氏鍵盤與倚天忘形一樣同樣也比較麻煩,需要單獨處理。
|
||||
/// @--DISCUSSION--@
|
||||
/// 回傳結果是空的話,不要緊,因為該函數內部已經處理過分配過程了。
|
||||
/// - Parameters:
|
||||
/// - key: 傳入的 String 訊號。
|
||||
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 "d": if consonant.isEmpty { consonant = "ㄉ" } else { intonation = "ˊ" }
|
||||
case "e": if semivowel.isEmpty { semivowel = "ㄧ" } else { vowel = "ㄝ" }
|
||||
case "f": if consonant.isEmpty { consonant = "ㄈ" } else { intonation = "ˇ" }
|
||||
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 "l":
|
||||
if value.isEmpty, !consonant.isEmpty, !semivowel.isEmpty {
|
||||
vowel = "ㄦ"
|
||||
} else 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 "ㄍ": // 許氏鍵盤應該也需要這個自動糾正
|
||||
switch incomingPhonabet {
|
||||
case "ㄧ": consonant = "ㄑ" // ㄑㄧ
|
||||
case "ㄨ": consonant = "ㄍ" // ㄍㄨ
|
||||
case "ㄩ": consonant = "ㄑ" // ㄑㄩ
|
||||
default: break
|
||||
}
|
||||
case "ㄓ":
|
||||
if intonation.isEmpty {
|
||||
switch incomingPhonabet {
|
||||
|
@ -396,11 +494,21 @@ public struct Tekkon {
|
|||
}
|
||||
}
|
||||
|
||||
if key == "j" { // 對該按鍵作為調號的處理得放在最後
|
||||
if !consonant.isEmpty { intonation = "ˋ" }
|
||||
}
|
||||
|
||||
// 這些按鍵在上文處理過了,就不要再回傳了。
|
||||
if "adefghklmns".contains(key) { strReturn = "" }
|
||||
|
||||
// 回傳結果是空的話,不要緊,因為上文已經代處理過分配過程了。
|
||||
return strReturn
|
||||
}
|
||||
|
||||
// MARK: - Misc Definitions
|
||||
|
||||
/// 這些內容用來滿足 "Equatable, Hashable, ExpressibleByStringLiteral" 需求。
|
||||
|
||||
public static func == (lhs: Composer, rhs: Composer) -> Bool {
|
||||
lhs.value == rhs.value
|
||||
}
|
||||
|
@ -427,6 +535,7 @@ public struct Tekkon {
|
|||
|
||||
// MARK: - Phonabets (Enum)
|
||||
|
||||
/// 該 Enum 羅列了所有合理的注音符號,將來做漢語拼音功能支援時可能會用到。
|
||||
enum Phonabets: Phonabet {
|
||||
case ofBO = "ㄅ"
|
||||
case ofPO = "ㄆ"
|
||||
|
@ -471,12 +580,129 @@ public struct Tekkon {
|
|||
case ofT5 = "˙"
|
||||
}
|
||||
|
||||
// MARK: - Phonabet to Hanyu-Pinyin Conversion Processing
|
||||
|
||||
/// 注音轉拼音,要求陰平必須是空格。
|
||||
/// - Parameters:
|
||||
/// - target: 傳入的 String 對象物件。
|
||||
static func cnvPhonaToHanyuPinyin(target: String) -> String {
|
||||
var targetConverted = target
|
||||
for pair in arrPhonaToHanyuPinyin {
|
||||
targetConverted = targetConverted.replacingOccurrences(of: pair[0], with: pair[1])
|
||||
}
|
||||
return targetConverted
|
||||
}
|
||||
|
||||
static func cnvHanyuPinyinToTextbookStyle(target: String) -> String {
|
||||
var targetConverted = target
|
||||
for pair in arrHanyuPinyinTextbookStyleConversionTable {
|
||||
targetConverted = targetConverted.replacingOccurrences(of: pair[0], with: pair[1])
|
||||
}
|
||||
return targetConverted
|
||||
}
|
||||
|
||||
/// 原始轉換對照表資料貯存專用佇列(數字標調格式)
|
||||
static let arrPhonaToHanyuPinyin = [ // 排序很重要。先處理最長的,再處理短的。不然會出亂子。
|
||||
[" ", "1"], ["ˊ", "2"], ["ˇ", "3"], ["ˋ", "4"], ["˙", "5"], ["ㄔㄨㄤ", "chuang"], ["ㄕㄨㄤ", "shuang"],
|
||||
["ㄓㄨㄤ", "zhuang"], ["ㄔㄨㄥ", "chong"], ["ㄔㄨㄞ", "chuai"], ["ㄔㄨㄢ", "chuan"], ["ㄍㄨㄤ", "guang"], ["ㄏㄨㄤ", "huang"],
|
||||
["ㄐㄧㄤ", "jiang"], ["ㄐㄩㄥ", "jiong"], ["ㄎㄨㄤ", "kuang"], ["ㄌㄧㄤ", "liang"], ["ㄋㄧㄤ", "niang"], ["ㄑㄧㄤ", "qiang"],
|
||||
["ㄑㄩㄥ", "qiong"], ["ㄕㄨㄞ", "shuai"], ["ㄕㄨㄢ", "shuan"], ["ㄒㄧㄤ", "xiang"], ["ㄒㄩㄥ", "xiong"], ["ㄓㄨㄥ", "zhong"],
|
||||
["ㄓㄨㄞ", "zhuai"], ["ㄓㄨㄢ", "zhuan"], ["ㄅㄧㄢ", "bian"], ["ㄅㄧㄠ", "biao"], ["ㄅㄧㄥ", "bing"], ["ㄔㄨㄚ", "chua"],
|
||||
["ㄔㄨㄟ", "chui"], ["ㄔㄨㄣ", "chun"], ["ㄔㄨㄛ", "chuo"], ["ㄘㄨㄥ", "cong"], ["ㄘㄨㄢ", "cuan"], ["ㄉㄧㄢ", "dian"],
|
||||
["ㄉㄧㄠ", "diao"], ["ㄉㄧㄥ", "ding"], ["ㄉㄨㄥ", "dong"], ["ㄉㄨㄢ", "duan"], ["ㄈㄧㄠ", "fiao"], ["ㄍㄧㄠ", "giao"],
|
||||
["ㄍㄧㄣ", "gin"], ["ㄍㄨㄥ", "gong"], ["ㄍㄨㄞ", "guai"], ["ㄍㄨㄢ", "guan"], ["ㄏㄨㄥ", "hong"], ["ㄏㄨㄞ", "huai"],
|
||||
["ㄏㄨㄢ", "huan"], ["ㄐㄧㄢ", "jian"], ["ㄐㄧㄠ", "jiao"], ["ㄐㄧㄥ", "jing"], ["ㄐㄩㄢ", "juan"], ["ㄎㄧㄡ", "kiu"],
|
||||
["ㄎㄨㄥ", "kong"], ["ㄎㄨㄞ", "kuai"], ["ㄎㄨㄢ", "kuan"], ["ㄌㄧㄢ", "lian"], ["ㄌㄧㄠ", "liao"], ["ㄌㄧㄥ", "ling"],
|
||||
["ㄌㄨㄥ", "long"], ["ㄌㄨㄢ", "luan"], ["ㄌㄩㄢ", "lvan"], ["ㄇㄧㄢ", "mian"], ["ㄇㄧㄠ", "miao"], ["ㄇㄧㄥ", "ming"],
|
||||
["ㄋㄧㄢ", "nian"], ["ㄋㄧㄠ", "niao"], ["ㄋㄧㄥ", "ning"], ["ㄋㄨㄥ", "nong"], ["ㄋㄨㄢ", "nuan"], ["ㄆㄧㄢ", "pian"],
|
||||
["ㄆㄧㄠ", "piao"], ["ㄆㄧㄥ", "ping"], ["ㄑㄧㄢ", "qian"], ["ㄑㄧㄠ", "qiao"], ["ㄑㄧㄥ", "qing"], ["ㄑㄩㄢ", "quan"],
|
||||
["ㄖㄨㄥ", "rong"], ["ㄖㄨㄢ", "ruan"], ["ㄕㄨㄚ", "shua"], ["ㄕㄨㄟ", "shui"], ["ㄕㄨㄣ", "shun"], ["ㄕㄨㄛ", "shuo"],
|
||||
["ㄙㄨㄥ", "song"], ["ㄙㄨㄢ", "suan"], ["ㄊㄧㄢ", "tian"], ["ㄊㄧㄠ", "tiao"], ["ㄊㄧㄥ", "ting"], ["ㄊㄨㄥ", "tong"],
|
||||
["ㄊㄨㄢ", "tuan"], ["ㄒㄧㄢ", "xian"], ["ㄒㄧㄠ", "xiao"], ["ㄒㄧㄥ", "xing"], ["ㄒㄩㄢ", "xuan"], ["ㄓㄨㄚ", "zhua"],
|
||||
["ㄓㄨㄟ", "zhui"], ["ㄓㄨㄣ", "zhun"], ["ㄓㄨㄛ", "zhuo"], ["ㄗㄨㄥ", "zong"], ["ㄗㄨㄢ", "zuan"], ["ㄈㄨㄥ", "fong"],
|
||||
["ㄐㄩㄣ", "jun"], ["ㄅㄧㄝ", "bie"], ["ㄅㄧㄣ", "bin"], ["ㄘㄨㄟ", "cui"], ["ㄘㄨㄣ", "cun"], ["ㄘㄨㄛ", "cuo"], ["ㄉㄧㄚ", "dia"],
|
||||
["ㄉㄧㄝ", "die"], ["ㄉㄧㄡ", "diu"], ["ㄉㄨㄟ", "dui"], ["ㄉㄨㄣ", "dun"], ["ㄉㄨㄛ", "duo"], ["ㄍㄨㄚ", "gua"], ["ㄍㄨㄜ", "gue"],
|
||||
["ㄍㄨㄟ", "gui"], ["ㄍㄨㄣ", "gun"], ["ㄍㄨㄛ", "guo"], ["ㄏㄨㄚ", "hua"], ["ㄏㄨㄟ", "hui"], ["ㄏㄨㄣ", "hun"], ["ㄏㄨㄛ", "huo"],
|
||||
["ㄐㄧㄚ", "jia"], ["ㄐㄧㄝ", "jie"], ["ㄐㄧㄣ", "jin"], ["ㄐㄧㄡ", "jiu"], ["ㄐㄩㄝ", "jue"], ["ㄎㄨㄚ", "kua"], ["ㄎㄨㄟ", "kui"],
|
||||
["ㄎㄨㄣ", "kun"], ["ㄎㄨㄛ", "kuo"], ["ㄌㄧㄚ", "lia"], ["ㄌㄧㄝ", "lie"], ["ㄌㄧㄣ", "lin"], ["ㄌㄧㄡ", "liu"], ["ㄌㄨㄣ", "lun"],
|
||||
["ㄌㄨㄛ", "luo"], ["ㄌㄩㄝ", "lve"], ["ㄇㄧㄝ", "mie"], ["ㄇㄧㄣ", "min"], ["ㄇㄧㄡ", "miu"], ["ㄋㄧㄝ", "nie"], ["ㄋㄧㄣ", "nin"],
|
||||
["ㄋㄧㄡ", "niu"], ["ㄋㄨㄟ", "nui"], ["ㄋㄨㄣ", "nun"], ["ㄋㄨㄛ", "nuo"], ["ㄋㄩㄝ", "nve"], ["ㄆㄧㄚ", "pia"], ["ㄆㄧㄝ", "pie"],
|
||||
["ㄆㄧㄣ", "pin"], ["ㄑㄧㄚ", "qia"], ["ㄑㄧㄝ", "qie"], ["ㄑㄧㄣ", "qin"], ["ㄑㄧㄡ", "qiu"], ["ㄑㄩㄝ", "que"], ["ㄑㄩㄣ", "qun"],
|
||||
["ㄖㄨㄟ", "rui"], ["ㄖㄨㄣ", "run"], ["ㄖㄨㄛ", "ruo"], ["ㄙㄨㄟ", "sui"], ["ㄙㄨㄣ", "sun"], ["ㄙㄨㄛ", "suo"], ["ㄊㄧㄝ", "tie"],
|
||||
["ㄊㄨㄟ", "tui"], ["ㄊㄨㄣ", "tun"], ["ㄊㄨㄛ", "tuo"], ["ㄒㄧㄚ", "xia"], ["ㄒㄧㄝ", "xie"], ["ㄒㄧㄣ", "xin"], ["ㄒㄧㄡ", "xiu"],
|
||||
["ㄒㄩㄝ", "xue"], ["ㄒㄩㄣ", "xun"], ["ㄗㄨㄟ", "zui"], ["ㄗㄨㄣ", "zun"], ["ㄗㄨㄛ", "zuo"], ["ㄘㄟ", "cei"], ["ㄔㄤ", "chang"],
|
||||
["ㄔㄥ", "cheng"], ["ㄕㄤ", "shang"], ["ㄕㄥ", "sheng"], ["ㄓㄤ", "zhang"], ["ㄓㄥ", "zheng"], ["ㄅㄤ", "bang"],
|
||||
["ㄅㄥ", "beng"], ["ㄘㄤ", "cang"], ["ㄘㄥ", "ceng"], ["ㄔㄞ", "chai"], ["ㄔㄢ", "chan"], ["ㄔㄠ", "chao"], ["ㄔㄣ", "chen"],
|
||||
["ㄔㄡ", "chou"], ["ㄉㄤ", "dang"], ["ㄉㄥ", "deng"], ["ㄈㄤ", "fang"], ["ㄈㄥ", "feng"], ["ㄍㄤ", "gang"], ["ㄍㄥ", "geng"],
|
||||
["ㄏㄤ", "hang"], ["ㄏㄥ", "heng"], ["ㄎㄤ", "kang"], ["ㄎㄥ", "keng"], ["ㄌㄤ", "lang"], ["ㄌㄥ", "leng"], ["ㄇㄤ", "mang"],
|
||||
["ㄇㄥ", "meng"], ["ㄋㄤ", "nang"], ["ㄋㄥ", "neng"], ["ㄆㄤ", "pang"], ["ㄆㄥ", "peng"], ["ㄖㄤ", "rang"], ["ㄖㄥ", "reng"],
|
||||
["ㄙㄤ", "sang"], ["ㄙㄥ", "seng"], ["ㄕㄞ", "shai"], ["ㄕㄢ", "shan"], ["ㄕㄠ", "shao"], ["ㄕㄟ", "shei"], ["ㄕㄣ", "shen"],
|
||||
["ㄕㄡ", "shou"], ["ㄊㄤ", "tang"], ["ㄊㄥ", "teng"], ["ㄨㄤ", "wang"], ["ㄨㄥ", "weng"], ["ㄧㄤ", "yang"], ["ㄧㄥ", "ying"],
|
||||
["ㄩㄥ", "yong"], ["ㄩㄢ", "yuan"], ["ㄗㄤ", "zang"], ["ㄗㄥ", "zeng"], ["ㄓㄞ", "zhai"], ["ㄓㄢ", "zhan"], ["ㄓㄠ", "zhao"],
|
||||
["ㄓㄟ", "zhei"], ["ㄓㄣ", "zhen"], ["ㄓㄡ", "zhou"], ["ㄅㄞ", "bai"], ["ㄅㄢ", "ban"], ["ㄅㄠ", "bao"], ["ㄅㄟ", "bei"],
|
||||
["ㄅㄣ", "ben"], ["ㄘㄞ", "cai"], ["ㄘㄢ", "can"], ["ㄘㄠ", "cao"], ["ㄘㄣ", "cen"], ["ㄔㄚ", "cha"], ["ㄔㄜ", "che"],
|
||||
["ㄔㄨ", "chu"], ["ㄘㄡ", "cou"], ["ㄉㄞ", "dai"], ["ㄉㄢ", "dan"], ["ㄉㄠ", "dao"], ["ㄉㄟ", "dei"], ["ㄉㄣ", "den"],
|
||||
["ㄉㄡ", "dou"], ["ㄈㄢ", "fan"], ["ㄈㄟ", "fei"], ["ㄈㄣ", "fen"], ["ㄈㄡ", "fou"], ["ㄍㄞ", "gai"], ["ㄍㄢ", "gan"],
|
||||
["ㄍㄠ", "gao"], ["ㄍㄟ", "gei"], ["ㄍㄣ", "gen"], ["ㄍㄡ", "gou"], ["ㄏㄞ", "hai"], ["ㄏㄢ", "han"], ["ㄏㄠ", "hao"],
|
||||
["ㄏㄟ", "hei"], ["ㄏㄣ", "hen"], ["ㄏㄡ", "hou"], ["ㄎㄞ", "kai"], ["ㄎㄢ", "kan"], ["ㄎㄠ", "kao"], ["ㄎㄣ", "ken"],
|
||||
["ㄎㄡ", "kou"], ["ㄌㄞ", "lai"], ["ㄌㄢ", "lan"], ["ㄌㄠ", "lao"], ["ㄌㄟ", "lei"], ["ㄌㄡ", "lou"], ["ㄇㄞ", "mai"],
|
||||
["ㄇㄢ", "man"], ["ㄇㄠ", "mao"], ["ㄇㄟ", "mei"], ["ㄇㄣ", "men"], ["ㄇㄡ", "mou"], ["ㄋㄞ", "nai"], ["ㄋㄢ", "nan"],
|
||||
["ㄋㄠ", "nao"], ["ㄋㄟ", "nei"], ["ㄋㄣ", "nen"], ["ㄋㄡ", "nou"], ["ㄆㄞ", "pai"], ["ㄆㄢ", "pan"], ["ㄆㄠ", "pao"],
|
||||
["ㄆㄟ", "pei"], ["ㄆㄣ", "pen"], ["ㄆㄡ", "pou"], ["ㄖㄢ", "ran"], ["ㄖㄠ", "rao"], ["ㄖㄣ", "ren"], ["ㄖㄡ", "rou"],
|
||||
["ㄙㄞ", "sai"], ["ㄙㄢ", "san"], ["ㄙㄠ", "sao"], ["ㄙㄟ", "sei"], ["ㄙㄣ", "sen"], ["ㄕㄚ", "sha"], ["ㄕㄜ", "she"],
|
||||
["ㄕㄨ", "shu"], ["ㄙㄡ", "sou"], ["ㄊㄞ", "tai"], ["ㄊㄢ", "tan"], ["ㄊㄠ", "tao"], ["ㄊㄡ", "tou"], ["ㄨㄞ", "wai"],
|
||||
["ㄨㄢ", "wan"], ["ㄨㄟ", "wei"], ["ㄨㄣ", "wen"], ["ㄧㄞ", "yai"], ["ㄧㄢ", "yan"], ["ㄧㄠ", "yao"], ["ㄧㄣ", "yin"],
|
||||
["ㄧㄡ", "you"], ["ㄩㄝ", "yue"], ["ㄩㄣ", "yun"], ["ㄗㄞ", "zai"], ["ㄗㄢ", "zan"], ["ㄗㄠ", "zao"], ["ㄗㄟ", "zei"],
|
||||
["ㄗㄣ", "zen"], ["ㄓㄚ", "zha"], ["ㄓㄜ", "zhe"], ["ㄓㄨ", "zhu"], ["ㄗㄡ", "zou"], ["ㄅㄚ", "ba"], ["ㄅㄧ", "bi"],
|
||||
["ㄅㄛ", "bo"], ["ㄅㄨ", "bu"], ["ㄘㄚ", "ca"], ["ㄘㄜ", "ce"], ["ㄘㄨ", "cu"], ["ㄉㄚ", "da"], ["ㄉㄜ", "de"], ["ㄉㄧ", "di"],
|
||||
["ㄉㄨ", "du"], ["ㄈㄚ", "fa"], ["ㄈㄛ", "fo"], ["ㄈㄨ", "fu"], ["ㄍㄚ", "ga"], ["ㄍㄜ", "ge"], ["ㄍㄧ", "gi"], ["ㄍㄨ", "gu"],
|
||||
["ㄏㄚ", "ha"], ["ㄏㄜ", "he"], ["ㄏㄨ", "hu"], ["ㄐㄧ", "ji"], ["ㄐㄩ", "ju"], ["ㄎㄚ", "ka"], ["ㄎㄜ", "ke"], ["ㄎㄨ", "ku"],
|
||||
["ㄌㄚ", "la"], ["ㄌㄜ", "le"], ["ㄌㄧ", "li"], ["ㄌㄛ", "lo"], ["ㄌㄨ", "lu"], ["ㄌㄩ", "lv"], ["ㄇㄚ", "ma"], ["ㄇㄜ", "me"],
|
||||
["ㄇㄧ", "mi"], ["ㄇㄛ", "mo"], ["ㄇㄨ", "mu"], ["ㄋㄚ", "na"], ["ㄋㄜ", "ne"], ["ㄋㄧ", "ni"], ["ㄋㄨ", "nu"], ["ㄋㄩ", "nv"],
|
||||
["ㄆㄚ", "pa"], ["ㄆㄧ", "pi"], ["ㄆㄛ", "po"], ["ㄆㄨ", "pu"], ["ㄑㄧ", "qi"], ["ㄑㄩ", "qu"], ["ㄖㄜ", "re"], ["ㄖㄨ", "ru"],
|
||||
["ㄙㄚ", "sa"], ["ㄙㄜ", "se"], ["ㄙㄨ", "su"], ["ㄊㄚ", "ta"], ["ㄊㄜ", "te"], ["ㄊㄧ", "ti"], ["ㄊㄨ", "tu"], ["ㄨㄚ", "wa"],
|
||||
["ㄨㄛ", "wo"], ["ㄒㄧ", "xi"], ["ㄒㄩ", "xu"], ["ㄧㄚ", "ya"], ["ㄧㄝ", "ye"], ["ㄧㄛ", "yo"], ["ㄗㄚ", "za"], ["ㄗㄜ", "ze"],
|
||||
["ㄗㄨ", "zu"], ["ㄅ", "b"], ["ㄆ", "p"], ["ㄇ", "m"], ["ㄈ", "f"], ["ㄉ", "d"], ["ㄊ", "t"], ["ㄋ", "n"],
|
||||
["ㄌ", "l"], ["ㄍ", "g"], ["ㄎ", "k"], ["ㄏ", "h"], ["ㄐ", "j"], ["ㄑ", "q"], ["ㄒ", "x"], ["ㄓ", "zhi"],
|
||||
["ㄔ", "chi"], ["ㄕ", "shi"], ["ㄖ", "ri"], ["ㄗ", "zi"], ["ㄘ", "ci"], ["ㄙ", "si"], ["ㄚ", "a"], ["ㄛ", "o"], ["ㄜ", "e"],
|
||||
["ㄝ", "eh"], ["ㄞ", "ai"], ["ㄟ", "ei"], ["ㄠ", "ao"], ["ㄡ", "ou"], ["ㄢ", "an"], ["ㄣ", "en"], ["ㄤ", "ang"],
|
||||
["ㄥ", "eng"], ["ㄦ", "er"], ["ㄧ", "yi"], ["ㄨ", "wu"], ["ㄩ", "yu"],
|
||||
]
|
||||
|
||||
/// 漢語拼音韻母轉換對照表資料貯存專用佇列
|
||||
static let arrHanyuPinyinTextbookStyleConversionTable = [ // 排序很重要。先處理最長的,再處理短的。不然會出亂子。
|
||||
["iang1", "iāng"], ["iang2", "iáng"], ["iang3", "iǎng"], ["iang4", "iàng"], ["iong1", "iōng"], ["iong2", "ióng"],
|
||||
["iong3", "iǒng"], ["iong4", "iòng"], ["uang1", "uāng"], ["uang2", "uáng"], ["uang3", "uǎng"], ["uang4", "uàng"],
|
||||
["uang5", "uang"], ["ang1", "āng"], ["ang2", "áng"], ["ang3", "ǎng"], ["ang4", "àng"], ["ang5", "ang"],
|
||||
["eng1", "ēng"], ["eng2", "éng"], ["eng3", "ěng"], ["eng4", "èng"], ["ian1", "iān"], ["ian2", "ián"],
|
||||
["ian3", "iǎn"], ["ian4", "iàn"], ["iao1", "iāo"], ["iao2", "iáo"], ["iao3", "iǎo"], ["iao4", "iào"],
|
||||
["ing1", "īng"], ["ing2", "íng"], ["ing3", "ǐng"], ["ing4", "ìng"], ["ong1", "ōng"], ["ong2", "óng"],
|
||||
["ong3", "ǒng"], ["ong4", "òng"], ["uai1", "uāi"], ["uai2", "uái"], ["uai3", "uǎi"], ["uai4", "uài"],
|
||||
["uan1", "uān"], ["uan2", "uán"], ["uan3", "uǎn"], ["uan4", "uàn"], ["van2", "üán"], ["van3", "üǎn"],
|
||||
["ai1", "āi"], ["ai2", "ái"], ["ai3", "ǎi"], ["ai4", "ài"], ["ai5", "ai"], ["an1", "ān"], ["an2", "án"],
|
||||
["an3", "ǎn"], ["an4", "àn"], ["ao1", "āo"], ["ao2", "áo"], ["ao3", "ǎo"], ["ao4", "ào"], ["ao5", "ao"],
|
||||
["eh2", "ế"], ["eh3", "êˇ"], ["eh4", "ề"], ["eh5", "ê"], ["ei1", "ēi"], ["ei2", "éi"], ["ei3", "ěi"],
|
||||
["ei4", "èi"], ["ei5", "ei"], ["en1", "ēn"], ["en2", "én"], ["en3", "ěn"], ["en4", "èn"], ["en5", "en"],
|
||||
["er1", "ēr"], ["er2", "ér"], ["er3", "ěr"], ["er4", "èr"], ["er5", "er"], ["ia1", "iā"], ["ia2", "iá"],
|
||||
["ia3", "iǎ"], ["ia4", "ià"], ["ie1", "iē"], ["ie2", "ié"], ["ie3", "iě"], ["ie4", "iè"], ["ie5", "ie"],
|
||||
["in1", "īn"], ["in2", "ín"], ["in3", "ǐn"], ["in4", "ìn"], ["iu1", "iū"], ["iu2", "iú"], ["iu3", "iǔ"],
|
||||
["iu4", "iù"], ["ou1", "ōu"], ["ou2", "óu"], ["ou3", "ǒu"], ["ou4", "òu"], ["ou5", "ou"], ["ua1", "uā"],
|
||||
["ua2", "uá"], ["ua3", "uǎ"], ["ua4", "uà"], ["ue1", "uē"], ["ue2", "ué"], ["ue3", "uě"], ["ue4", "uè"],
|
||||
["ui1", "uī"], ["ui2", "uí"], ["ui3", "uǐ"], ["ui4", "uì"], ["un1", "ūn"], ["un2", "ún"], ["un3", "ǔn"],
|
||||
["un4", "ùn"], ["uo1", "uō"], ["uo2", "uó"], ["uo3", "uǒ"], ["uo4", "uò"], ["uo5", "uo"], ["ve1", "üē"],
|
||||
["ve3", "üě"], ["ve4", "üè"], ["a1", "ā"], ["a2", "á"], ["a3", "ǎ"], ["a4", "à"], ["a5", "a"], ["e1", "ē"],
|
||||
["e2", "é"], ["e3", "ě"], ["e4", "è"], ["e5", "e"], ["i1", "ī"], ["i2", "í"], ["i3", "ǐ"], ["i4", "ì"],
|
||||
["i5", "i"], ["o1", "ō"], ["o2", "ó"], ["o3", "ǒ"], ["o4", "ò"], ["o5", "o"], ["u1", "ū"], ["u2", "ú"],
|
||||
["u3", "ǔ"], ["u4", "ù"], ["v1", "ǖ"], ["v2", "ǘ"], ["v3", "ǚ"], ["v4", "ǜ"],
|
||||
]
|
||||
|
||||
// MARK: - Maps for Keyboard-to-Phonabet parsers
|
||||
|
||||
// 任何形式的拼音排列都會用到的陣列,用 Strings 反而省事一些。
|
||||
/// 任何形式的拼音排列都會用到的陣列,用 Strings 反而省事一些。
|
||||
static let mapArayuruPinyin: String = "abcdefghijklmnopqrstuvwxyz12345 "
|
||||
|
||||
/// 標準大千排列專用處理陣列。
|
||||
/// @--DISCUSSION--@
|
||||
/// 威注音輸入法 macOS 版使用了 Ukelele 佈局來完成對諸如倚天傳統等其它注音鍵盤排列的支援。
|
||||
/// 如果要將鐵恨模組拿給別的平台的輸入法使用的話,恐怕需要針對這些注音鍵盤排列各自新增專用陣列才可以。
|
||||
static let mapQwertyDachen: [String: String] = [
|
||||
|
@ -487,6 +713,7 @@ public struct Tekkon {
|
|||
]
|
||||
|
||||
/// 許氏排列專用處理陣列,但未包含全部的映射內容。
|
||||
/// @--DISCUSSION--@
|
||||
/// 在這裡將二十六個字母寫全,也只是為了方便做 validity check。
|
||||
/// 這裡提前對複音按鍵做處理,然後再用程式判斷介母類型、據此判斷是否需要做複音切換。
|
||||
static let mapHsuStaticKeys: [String: String] = [
|
||||
|
@ -496,6 +723,7 @@ public struct Tekkon {
|
|||
]
|
||||
|
||||
/// 倚天忘形排列預處理專用陣列,但未包含全部的映射內容。
|
||||
/// @--DISCUSSION--@
|
||||
/// 在這裡將二十六個字母寫全,也只是為了方便做 validity check。
|
||||
/// 這裡提前對ㄓ/ㄍ/ㄕ做處理,然後再用程式判斷介母類型、據此判斷是否需要換成ㄒ/ㄑ/ㄐ。
|
||||
static let mapEten26StaticKeys: [String: String] = [
|
||||
|
|
|
@ -53,6 +53,8 @@ struct UserDef {
|
|||
static let kUseSCPCTypingMode = "UseSCPCTypingMode"
|
||||
static let kMaxCandidateLength = "MaxCandidateLength"
|
||||
static let kShouldNotFartInLieuOfBeep = "ShouldNotFartInLieuOfBeep"
|
||||
static let kShowHanyuPinyinInCompositionBuffer = "ShowHanyuPinyinInCompositionBuffer"
|
||||
static let kInlineDumpPinyinInLieuOfZhuyin = "InlineDumpPinyinInLieuOfZhuyin"
|
||||
|
||||
static let kCandidateTextFontName = "CandidateTextFontName"
|
||||
static let kCandidateKeyLabelFontName = "CandidateKeyLabelFontName"
|
||||
|
@ -230,6 +232,8 @@ public class mgrPrefs: NSObject {
|
|||
UserDef.kUseSCPCTypingMode,
|
||||
UserDef.kMaxCandidateLength,
|
||||
UserDef.kShouldNotFartInLieuOfBeep,
|
||||
UserDef.kShowHanyuPinyinInCompositionBuffer,
|
||||
UserDef.kInlineDumpPinyinInLieuOfZhuyin,
|
||||
UserDef.kAssociatedPhrasesEnabled,
|
||||
]
|
||||
}
|
||||
|
@ -273,6 +277,10 @@ public class mgrPrefs: NSObject {
|
|||
)
|
||||
UserDefaults.standard.setDefault(mgrPrefs.phraseReplacementEnabled, forKey: UserDef.kPhraseReplacementEnabled)
|
||||
UserDefaults.standard.setDefault(mgrPrefs.shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep)
|
||||
UserDefaults.standard.setDefault(
|
||||
mgrPrefs.showHanyuPinyinInCompositionBuffer, forKey: UserDef.kShowHanyuPinyinInCompositionBuffer)
|
||||
UserDefaults.standard.setDefault(
|
||||
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin)
|
||||
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
@ -352,6 +360,12 @@ public class mgrPrefs: NSObject {
|
|||
@UserDefault(key: UserDef.kShouldNotFartInLieuOfBeep, defaultValue: true)
|
||||
static var shouldNotFartInLieuOfBeep: Bool
|
||||
|
||||
@UserDefault(key: UserDef.kShowHanyuPinyinInCompositionBuffer, defaultValue: false)
|
||||
static var showHanyuPinyinInCompositionBuffer: Bool
|
||||
|
||||
@UserDefault(key: UserDef.kInlineDumpPinyinInLieuOfZhuyin, defaultValue: false)
|
||||
static var inlineDumpPinyinInLieuOfZhuyin: Bool
|
||||
|
||||
static func toggleShouldNotFartInLieuOfBeep() -> Bool {
|
||||
shouldNotFartInLieuOfBeep = !shouldNotFartInLieuOfBeep
|
||||
UserDefaults.standard.set(shouldNotFartInLieuOfBeep, forKey: UserDef.kShouldNotFartInLieuOfBeep)
|
||||
|
|
|
@ -215,9 +215,6 @@ extension vChewing {
|
|||
// 這樣一來就可以在就地新增語彙時徹底複寫優先權。
|
||||
// 將兩句差分也是為了讓 rawUserUnigrams 的類型不受可能的影響。
|
||||
rawAllUnigrams += lmUserPhrases.unigramsFor(key: key).reversed()
|
||||
if lmUserPhrases.unigramsFor(key: key).isEmpty {
|
||||
IME.prtDebugIntel("Not found in UserPhrasesUnigram(\(lmUserPhrases.count)): \(key)")
|
||||
}
|
||||
|
||||
// LMMisc 與 LMCore 的 score 在 (-10.0, 0.0) 這個區間內。
|
||||
rawAllUnigrams += lmMisc.unigramsFor(key: key)
|
||||
|
@ -229,10 +226,6 @@ extension vChewing {
|
|||
|
||||
if isSymbolEnabled {
|
||||
rawAllUnigrams += lmUserSymbols.unigramsFor(key: key)
|
||||
if lmUserSymbols.unigramsFor(key: key).isEmpty {
|
||||
IME.prtDebugIntel("Not found in UserSymbolUnigram(\(lmUserSymbols.count)): \(key)")
|
||||
}
|
||||
|
||||
rawAllUnigrams += lmSymbols.unigramsFor(key: key)
|
||||
}
|
||||
|
||||
|
|
|
@ -25,15 +25,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
extension Megrez {
|
||||
public class BlockReadingBuilder {
|
||||
let kMaximumBuildSpanLength = 10 // 規定最多可以組成的詞的字數上限為 10
|
||||
var mutMaximumBuildSpanLength = 10
|
||||
var mutCursorIndex: Int = 0
|
||||
var mutReadings: [String] = []
|
||||
var mutGrid: Grid = .init()
|
||||
var mutLM: LanguageModel
|
||||
var mutJoinSeparator: String = ""
|
||||
|
||||
public init(lm: LanguageModel) {
|
||||
public init(lm: LanguageModel, length: Int = 10) {
|
||||
mutLM = lm
|
||||
mutMaximumBuildSpanLength = length
|
||||
}
|
||||
|
||||
public func clear() {
|
||||
|
@ -59,7 +60,7 @@ extension Megrez {
|
|||
|
||||
public func readings() -> [String] { mutReadings }
|
||||
|
||||
@discardableResult public func deleteReadingBeforeCursor() -> Bool {
|
||||
@discardableResult public func deleteReadingAtTheRearOfCursor() -> Bool {
|
||||
if mutCursorIndex == 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -71,7 +72,7 @@ extension Megrez {
|
|||
return true
|
||||
}
|
||||
|
||||
@discardableResult public func deleteReadingAfterCursor() -> Bool {
|
||||
@discardableResult public func deleteReadingToTheFrontOfCursor() -> Bool {
|
||||
if mutCursorIndex == mutReadings.count {
|
||||
return false
|
||||
}
|
||||
|
@ -87,15 +88,13 @@ extension Megrez {
|
|||
return false
|
||||
}
|
||||
|
||||
var i = 0
|
||||
while i < count {
|
||||
if mutCursorIndex != 0 {
|
||||
for _ in 0..<count {
|
||||
if mutCursorIndex > 0 {
|
||||
mutCursorIndex -= 1
|
||||
}
|
||||
mutReadings.removeFirst()
|
||||
mutGrid.shrinkGridByOneAt(location: 0)
|
||||
build()
|
||||
i += 1
|
||||
}
|
||||
|
||||
return true
|
||||
|
@ -113,15 +112,17 @@ extension Megrez {
|
|||
// if (mutLM == nil) { return } // 這個出不了 nil,所以註釋掉。
|
||||
|
||||
let itrBegin: Int =
|
||||
(mutCursorIndex < kMaximumBuildSpanLength) ? 0 : mutCursorIndex - kMaximumBuildSpanLength
|
||||
let itrEnd: Int = min(mutCursorIndex + kMaximumBuildSpanLength, mutReadings.count)
|
||||
(mutCursorIndex < mutMaximumBuildSpanLength) ? 0 : mutCursorIndex - mutMaximumBuildSpanLength
|
||||
let itrEnd: Int = min(mutCursorIndex + mutMaximumBuildSpanLength, mutReadings.count)
|
||||
|
||||
var p = itrBegin
|
||||
while p < itrEnd {
|
||||
var q = 1
|
||||
while q <= kMaximumBuildSpanLength, p + q <= itrEnd {
|
||||
for p in itrBegin..<itrEnd {
|
||||
for q in 1..<mutMaximumBuildSpanLength {
|
||||
if p + q > itrEnd {
|
||||
break
|
||||
}
|
||||
let strSlice = mutReadings[p..<(p + q)]
|
||||
let combinedReading: String = join(slice: strSlice, separator: mutJoinSeparator)
|
||||
|
||||
if !mutGrid.hasMatchedNode(location: p, spanningLength: q, key: combinedReading) {
|
||||
let unigrams: [Unigram] = mutLM.unigramsFor(key: combinedReading)
|
||||
if !unigrams.isEmpty {
|
||||
|
@ -129,9 +130,7 @@ extension Megrez {
|
|||
mutGrid.insertNode(node: n, location: p, spanningLength: q)
|
||||
}
|
||||
}
|
||||
q += 1
|
||||
}
|
||||
p += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,24 +46,24 @@ extension Megrez {
|
|||
|
||||
if balanced {
|
||||
nodes.sort {
|
||||
$0.balancedScore > $1.balancedScore // 排序規則已經在 NodeAnchor 內定義了。
|
||||
$0.balancedScore > $1.balancedScore
|
||||
}
|
||||
}
|
||||
|
||||
// 只檢查前 X 個 NodeAnchor 是否有 node。
|
||||
// 這裡有 abs 是為了防止有白癡填負數。
|
||||
var border: Int = nodes.count
|
||||
if nodesLimit > 0 {
|
||||
border = min(nodes.count, abs(nodesLimit))
|
||||
}
|
||||
for (i, n) in nodes.enumerated() {
|
||||
// 只檢查前 X 個 NodeAnchor 是否有 node。
|
||||
// 這裡有 abs 是為了防止有白癡填負數。
|
||||
if abs(nodesLimit) > 0, i == abs(nodesLimit) - 1 {
|
||||
break
|
||||
}
|
||||
|
||||
for n in nodes[0..<border] {
|
||||
var n = n
|
||||
guard let nNode = n.node else {
|
||||
continue
|
||||
}
|
||||
|
||||
n.accumulatedScore = accumulatedScore + nNode.score()
|
||||
|
||||
// 利用 Spanning Length 來決定權重。
|
||||
// 這樣一來,例:「再見」比「在」與「見」的權重更高。
|
||||
if balanced {
|
||||
|
@ -75,6 +75,7 @@ extension Megrez {
|
|||
at: location - n.spanningLength,
|
||||
score: n.accumulatedScore
|
||||
)
|
||||
|
||||
path.insert(n, at: 0)
|
||||
|
||||
paths.append(path)
|
||||
|
|
|
@ -38,10 +38,8 @@ extension Megrez {
|
|||
public func insertNode(node: Node, location: Int, spanningLength: Int) {
|
||||
if location >= mutSpans.count {
|
||||
let diff = location - mutSpans.count + 1
|
||||
var i = 0
|
||||
while i < diff {
|
||||
for _ in 0..<diff {
|
||||
mutSpans.append(Span())
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
mutSpans[location].insert(node: node, length: spanningLength)
|
||||
|
@ -57,13 +55,12 @@ extension Megrez {
|
|||
}
|
||||
|
||||
public func expandGridByOneAt(location: Int) {
|
||||
mutSpans.append(Span())
|
||||
if location > 0, location < mutSpans.count {
|
||||
var i = 0
|
||||
while i < location {
|
||||
// 這裡加入 abs 完全是一個防呆設計
|
||||
mutSpans.insert(Span(), at: abs(location))
|
||||
if location != 0, abs(location) != mutSpans.count {
|
||||
for i in 0..<abs(location) {
|
||||
// zaps overlapping spans
|
||||
mutSpans[i].removeNodeOfLengthGreaterThan(location - i)
|
||||
i += 1
|
||||
mutSpans[i].removeNodeOfLengthGreaterThan(abs(location) - i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,11 +71,9 @@ extension Megrez {
|
|||
}
|
||||
|
||||
mutSpans.remove(at: location)
|
||||
var i = 0
|
||||
while i < location {
|
||||
for i in 0..<location {
|
||||
// zaps overlapping spans
|
||||
mutSpans[i].removeNodeOfLengthGreaterThan(location - i)
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,8 +82,7 @@ extension Megrez {
|
|||
public func nodesEndingAt(location: Int) -> [NodeAnchor] {
|
||||
var results: [NodeAnchor] = []
|
||||
if !mutSpans.isEmpty, location <= mutSpans.count {
|
||||
var i = 0
|
||||
while i < location {
|
||||
for i in 0..<location {
|
||||
let span = mutSpans[i]
|
||||
if i + span.maximumLength >= location {
|
||||
if let np = span.node(length: location - i) {
|
||||
|
@ -101,7 +95,6 @@ extension Megrez {
|
|||
)
|
||||
}
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
return results
|
||||
|
@ -110,14 +103,11 @@ extension Megrez {
|
|||
public func nodesCrossingOrEndingAt(location: Int) -> [NodeAnchor] {
|
||||
var results: [NodeAnchor] = []
|
||||
if !mutSpans.isEmpty, location <= mutSpans.count {
|
||||
var i = 0
|
||||
while i < location {
|
||||
for i in 0..<location {
|
||||
let span = mutSpans[i]
|
||||
if i + span.maximumLength >= location {
|
||||
var j = 1
|
||||
while j <= span.maximumLength {
|
||||
for j in 1...span.maximumLength {
|
||||
if i + j < location {
|
||||
j += 1
|
||||
continue
|
||||
}
|
||||
if let np = span.node(length: j) {
|
||||
|
@ -129,10 +119,8 @@ extension Megrez {
|
|||
)
|
||||
)
|
||||
}
|
||||
j += 1
|
||||
}
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
return results
|
||||
|
|
|
@ -128,10 +128,12 @@
|
|||
"Misc Settings:" = "Misc Settings:";
|
||||
"MiTAC" = "MiTAC";
|
||||
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only.";
|
||||
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
|
||||
"Output Settings:" = "Output Settings:";
|
||||
"Phonetic Parser:" = "Phonetic Parser:";
|
||||
"Push the cursor in front of the phrase after selection" = "Push the cursor in front of the phrase after selection";
|
||||
"Selection Keys:" = "Selection Keys:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "Show Hanyu-Pinyin in the inline composition buffer";
|
||||
"Show page buttons in candidate window" = "Show page buttons in candidate window";
|
||||
"Simplified Chinese" = "Simplified Chinese";
|
||||
"Space & ESC Key:" = "Space & ESC Key:";
|
||||
|
|
|
@ -128,10 +128,12 @@
|
|||
"Misc Settings:" = "Misc Settings:";
|
||||
"MiTAC" = "MiTAC";
|
||||
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only.";
|
||||
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
|
||||
"Output Settings:" = "Output Settings:";
|
||||
"Phonetic Parser:" = "Phonetic Parser:";
|
||||
"Push the cursor in front of the phrase after selection" = "Push the cursor in front of the phrase after selection";
|
||||
"Selection Keys:" = "Selection Keys:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "Show Hanyu-Pinyin in the inline composition buffer";
|
||||
"Show page buttons in candidate window" = "Show page buttons in candidate window";
|
||||
"Simplified Chinese" = "Simplified Chinese";
|
||||
"Space & ESC Key:" = "Space & ESC Key:";
|
||||
|
|
|
@ -128,10 +128,12 @@
|
|||
"Misc Settings:" = "他の設定:";
|
||||
"MiTAC" = "神通配列";
|
||||
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外の英数キーボードは漢語弁音以外の配列に不適用。";
|
||||
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Ctrl(+Alt)+CMD+Enter で出すのを漢語弁音と変換";
|
||||
"Output Settings:" = "出力設定:";
|
||||
"Phonetic Parser:" = "注音配列:";
|
||||
"Push the cursor in front of the phrase after selection" = "候補選択の直後、すぐカーソルを単語の向こうに推し進める";
|
||||
"Selection Keys:" = "言選り用キー:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "弁音合併入力(入力緩衝列で代わりに漢語弁音の音読み)";
|
||||
"Show page buttons in candidate window" = "入力候補陳列の側にページボタンを表示";
|
||||
"Simplified Chinese" = "簡体中国語";
|
||||
"Space & ESC Key:" = "ESC と Space:";
|
||||
|
|
|
@ -128,10 +128,12 @@
|
|||
"Misc Settings:" = "杂项:";
|
||||
"MiTAC" = "神通排列";
|
||||
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英数布局是为了汉语拼音排列使用者而准备的。";
|
||||
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Ctrl(+Alt)+CMD+Enter 输出汉语拼音而非注音";
|
||||
"Output Settings:" = "输出设定:";
|
||||
"Phonetic Parser:" = "注音排列:";
|
||||
"Push the cursor in front of the phrase after selection" = "在选字后将游标置于该字词的前方";
|
||||
"Selection Keys:" = "选字键:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音并击模式(组字区内看到的是汉语拼音)";
|
||||
"Show page buttons in candidate window" = "在选字窗内显示翻页按钮";
|
||||
"Simplified Chinese" = "简体中文";
|
||||
"Space & ESC Key:" = "ESC 与空格键:";
|
||||
|
|
|
@ -128,10 +128,12 @@
|
|||
"Misc Settings:" = "雜項:";
|
||||
"MiTAC" = "神通排列";
|
||||
"Non-QWERTY alphanumeral keyboard layouts are for Hanyu Pinyin parser only." = "QWERTY 以外的英數佈局是為了漢語拼音排列使用者而準備的。";
|
||||
"Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" = "Ctrl(+Alt)+CMD+Enter 輸出漢語拼音而非注音";
|
||||
"Output Settings:" = "輸出設定:";
|
||||
"Phonetic Parser:" = "注音排列:";
|
||||
"Push the cursor in front of the phrase after selection" = "在選字後將游標置於該字詞的前方";
|
||||
"Selection Keys:" = "選字鍵:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音並擊模式(組字區內看到的是漢語拼音)";
|
||||
"Show page buttons in candidate window" = "在選字窗內顯示翻頁按鈕";
|
||||
"Simplified Chinese" = "簡體中文";
|
||||
"Space & ESC Key:" = "ESC 與空格鍵:";
|
||||
|
|
|
@ -43,6 +43,10 @@ struct suiPrefPaneGeneral: View {
|
|||
forKey: UserDef.kChineseConversionEnabled)
|
||||
@State private var selEnableKanjiConvToJIS = UserDefaults.standard.bool(
|
||||
forKey: UserDef.kShiftJISShinjitaiOutputEnabled)
|
||||
@State private var selShowHanyuPinyinInCompositionBuffer = UserDefaults.standard.bool(
|
||||
forKey: UserDef.kShowHanyuPinyinInCompositionBuffer)
|
||||
@State private var selInlineDumpPinyinInLieuOfZhuyin = UserDefaults.standard.bool(
|
||||
forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin)
|
||||
@State private var selEnableFartSuppressor = UserDefaults.standard.bool(forKey: UserDef.kShouldNotFartInLieuOfBeep)
|
||||
@State private var selEnableAutoUpdateCheck = UserDefaults.standard.bool(forKey: UserDef.kCheckUpdateAutomatically)
|
||||
@State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled)
|
||||
|
@ -147,6 +151,20 @@ struct suiPrefPaneGeneral: View {
|
|||
selEnableKanjiConvToKangXi = !value
|
||||
}
|
||||
}
|
||||
Toggle(
|
||||
LocalizedStringKey("Show Hanyu-Pinyin in the inline composition buffer"),
|
||||
isOn: $selShowHanyuPinyinInCompositionBuffer
|
||||
).onChange(of: selShowHanyuPinyinInCompositionBuffer) { value in
|
||||
mgrPrefs.showHanyuPinyinInCompositionBuffer = value
|
||||
selShowHanyuPinyinInCompositionBuffer = value
|
||||
}
|
||||
Toggle(
|
||||
LocalizedStringKey("Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"),
|
||||
isOn: $selInlineDumpPinyinInLieuOfZhuyin
|
||||
).onChange(of: selInlineDumpPinyinInLieuOfZhuyin) { value in
|
||||
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin = value
|
||||
selInlineDumpPinyinInLieuOfZhuyin = value
|
||||
}
|
||||
Toggle(
|
||||
LocalizedStringKey("Stop farting (when typed phonetic combination is invalid, etc.)"),
|
||||
isOn: $selEnableFartSuppressor
|
||||
|
|
|
@ -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">
|
||||
<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>
|
||||
|
@ -162,7 +163,7 @@
|
|||
</connections>
|
||||
</matrix>
|
||||
<button verticalHuggingPriority="750" id="233">
|
||||
<rect key="frame" x="169" y="26.5" width="245" height="17"/>
|
||||
<rect key="frame" x="169" y="27.5" width="245" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" title="Show page buttons in candidate list" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="shc-Nu-UsM">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
|
@ -234,7 +235,7 @@
|
|||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5IL-zZ-CL9" userLabel="chkTrad2KangXi">
|
||||
<rect key="frame" x="19" y="99.5" width="406" height="16"/>
|
||||
<rect key="frame" x="19" y="105.5" width="406" height="16"/>
|
||||
<buttonCell key="cell" type="check" title="Auto-convert traditional Chinese glyphs to KangXi characters" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="BSK-bH-Gct">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
|
@ -245,7 +246,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="h4r-Sp-LBI" userLabel="chkTrad2JISShinjitai">
|
||||
<rect key="frame" x="19" y="78.5" width="406" height="16"/>
|
||||
<rect key="frame" x="19" y="84.5" width="406" height="16"/>
|
||||
<buttonCell key="cell" type="check" title="Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="eia-1F-Do0">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
|
@ -256,7 +257,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pYB-E5-4Nv">
|
||||
<rect key="frame" x="19" y="57.5" width="406" height="16"/>
|
||||
<rect key="frame" x="19" y="63.5" width="406" height="16"/>
|
||||
<buttonCell key="cell" type="check" title="Stop farting (when typed phonetic combination is invalid, etc.)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="62u-jY-BRh">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
|
@ -266,17 +267,45 @@
|
|||
<binding destination="32" name="value" keyPath="values.ShouldNotFartInLieuOfBeep" id="EOH-Pc-8Hk"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="vwf-Kq-s8M" userLabel="chkShowHanyuPinyinInCompositionBuffer">
|
||||
<rect key="frame" x="19" y="42.5" width="406" height="16"/>
|
||||
<buttonCell key="cell" type="check" title="Show Hanyu-Pinyin in the inline composition buffer" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="wFR-zX-M8H">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="toggleTrad2KangXiAction:" target="-2" id="Bko-rV-Ygf"/>
|
||||
<binding destination="32" name="value" keyPath="values.ShowHanyuPinyinInCompositionBuffer" id="uDq-eC-wan"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gZ0-OK-r7a" userLabel="InlineDumpPinyinInLieuOfZhuyin">
|
||||
<rect key="frame" x="19" y="21.5" width="406" height="16"/>
|
||||
<buttonCell key="cell" type="check" title="Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="iWy-Nw-QKB">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="toggleTrad2KangXiAction:" target="-2" id="ACW-LL-i6G"/>
|
||||
<binding destination="32" name="value" keyPath="values.InlineDumpPinyinInLieuOfZhuyin" id="MtZ-L5-uvv"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="h4r-Sp-LBI" firstAttribute="top" secondItem="5IL-zZ-CL9" secondAttribute="bottom" constant="6" symbolic="YES" id="8Pq-i7-vK8"/>
|
||||
<constraint firstItem="pYB-E5-4Nv" firstAttribute="trailing" secondItem="h4r-Sp-LBI" secondAttribute="trailing" id="IWM-hB-AeP"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="top" secondItem="brd-6J-saN" secondAttribute="top" constant="19.5" id="i7s-ez-iKF"/>
|
||||
<constraint firstItem="pYB-E5-4Nv" firstAttribute="leading" secondItem="h4r-Sp-LBI" secondAttribute="leading" id="jsE-BB-mo7"/>
|
||||
<constraint firstAttribute="trailing" secondItem="5IL-zZ-CL9" secondAttribute="trailing" constant="20" symbolic="YES" id="kZf-wi-ijB"/>
|
||||
<constraint firstItem="pYB-E5-4Nv" firstAttribute="top" secondItem="h4r-Sp-LBI" secondAttribute="bottom" constant="6" symbolic="YES" id="unl-l5-LUF"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="leading" secondItem="h4r-Sp-LBI" secondAttribute="leading" id="v0c-Cb-FH7"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="leading" secondItem="brd-6J-saN" secondAttribute="leading" constant="20" symbolic="YES" id="xAB-f3-f0e"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="trailing" secondItem="h4r-Sp-LBI" secondAttribute="trailing" id="z2C-jk-sNa"/>
|
||||
<constraint firstItem="pYB-E5-4Nv" firstAttribute="leading" secondItem="vwf-Kq-s8M" secondAttribute="leading" id="1rZ-f3-1zX"/>
|
||||
<constraint firstItem="vwf-Kq-s8M" firstAttribute="trailing" secondItem="gZ0-OK-r7a" secondAttribute="trailing" id="5cy-8X-7Au"/>
|
||||
<constraint firstItem="h4r-Sp-LBI" firstAttribute="leading" secondItem="pYB-E5-4Nv" secondAttribute="leading" id="7hd-5d-da4"/>
|
||||
<constraint firstItem="pYB-E5-4Nv" firstAttribute="top" secondItem="h4r-Sp-LBI" secondAttribute="bottom" constant="6" symbolic="YES" id="9wj-ZN-icr"/>
|
||||
<constraint firstItem="pYB-E5-4Nv" firstAttribute="trailing" secondItem="vwf-Kq-s8M" secondAttribute="trailing" id="CIn-2X-pob"/>
|
||||
<constraint firstAttribute="trailing" secondItem="5IL-zZ-CL9" secondAttribute="trailing" constant="20" symbolic="YES" id="LS4-To-vob"/>
|
||||
<constraint firstItem="gZ0-OK-r7a" firstAttribute="top" secondItem="vwf-Kq-s8M" secondAttribute="bottom" constant="6" symbolic="YES" id="Rsh-wh-py3"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="leading" secondItem="brd-6J-saN" secondAttribute="leading" constant="20" symbolic="YES" id="TZx-QY-h2O"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="trailing" secondItem="h4r-Sp-LBI" secondAttribute="trailing" id="WW0-Yz-JzI"/>
|
||||
<constraint firstItem="vwf-Kq-s8M" firstAttribute="leading" secondItem="gZ0-OK-r7a" secondAttribute="leading" id="Yig-Jx-L3P"/>
|
||||
<constraint firstItem="vwf-Kq-s8M" firstAttribute="top" secondItem="pYB-E5-4Nv" secondAttribute="bottom" constant="6" symbolic="YES" id="cbL-Tb-hUr"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="top" secondItem="brd-6J-saN" secondAttribute="top" constant="13" id="hsK-pj-HMJ"/>
|
||||
<constraint firstItem="h4r-Sp-LBI" firstAttribute="trailing" secondItem="pYB-E5-4Nv" secondAttribute="trailing" id="hsW-zt-ozX"/>
|
||||
<constraint firstItem="h4r-Sp-LBI" firstAttribute="top" secondItem="5IL-zZ-CL9" secondAttribute="bottom" constant="6" symbolic="YES" id="qhu-6f-Ncy"/>
|
||||
<constraint firstItem="5IL-zZ-CL9" firstAttribute="leading" secondItem="h4r-Sp-LBI" secondAttribute="leading" id="sPQ-GZ-39w"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</box>
|
||||
|
|
|
@ -226,3 +226,9 @@
|
|||
|
||||
/* Class = "NSTextFieldCell"; title = "Choose your desired user data folder path. Will be omitted if invalid."; ObjectID = "wN3-k3-b2a"; */
|
||||
"wN3-k3-b2a.title" = "Choose your desired user data folder path. Will be omitted if invalid.";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Show Hanyu-Pinyin in the inline composition buffer"; ObjectID = "wFR-zX-M8H"; */
|
||||
"wFR-zX-M8H.title" = "Show Hanyu-Pinyin in the inline composition buffer";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
|
||||
"iWy-Nw-QKB.title" = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter";
|
||||
|
|
|
@ -226,3 +226,9 @@
|
|||
|
||||
/* Class = "NSTextFieldCell"; title = "Choose your desired user data folder path. Will be omitted if invalid."; ObjectID = "wN3-k3-b2a"; */
|
||||
"wN3-k3-b2a.title" = "欲しがるユーザー辞書保存先をご指定ください。無効の保存先設定は効かぬ。";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Show Hanyu-Pinyin in the inline composition buffer"; ObjectID = "wFR-zX-M8H"; */
|
||||
"wFR-zX-M8H.title" = "弁音合併入力(入力緩衝列で代わりに漢語弁音の音読み)";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
|
||||
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter で出すのを漢語弁音と変換";
|
||||
|
|
|
@ -226,3 +226,9 @@
|
|||
|
||||
/* Class = "NSTextFieldCell"; title = "Choose your desired user data folder path. Will be omitted if invalid."; ObjectID = "wN3-k3-b2a"; */
|
||||
"wN3-k3-b2a.title" = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Show Hanyu-Pinyin in the inline composition buffer"; ObjectID = "wFR-zX-M8H"; */
|
||||
"wFR-zX-M8H.title" = "拼音并击模式(组字区内看到的是汉语拼音)";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
|
||||
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 输出汉语拼音而非注音";
|
||||
|
|
|
@ -226,3 +226,9 @@
|
|||
|
||||
/* Class = "NSTextFieldCell"; title = "Choose your desired user data folder path. Will be omitted if invalid."; ObjectID = "wN3-k3-b2a"; */
|
||||
"wN3-k3-b2a.title" = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Show Hanyu-Pinyin in the inline composition buffer"; ObjectID = "wFR-zX-M8H"; */
|
||||
"wFR-zX-M8H.title" = "拼音並擊模式(組字區內看到的是漢語拼音)";
|
||||
|
||||
/* Class = "NSButtonCell"; title = "Output Hanyu-Pinyin in lieu of Zhuyin when Ctrl(+Alt)+CMD+Enter"; ObjectID = "iWy-Nw-QKB"; */
|
||||
"iWy-Nw-QKB.title" = "Ctrl(+Alt)+CMD+Enter 輸出漢語拼音而非注音";
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.5.7</string>
|
||||
<string>1.5.8</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1957</string>
|
||||
<string>1958</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.7</string>
|
||||
<string>1.5.8</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
|
|
|
@ -1308,7 +1308,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1331,7 +1331,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1364,7 +1364,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
@ -1383,7 +1383,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1498,7 +1498,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
|
@ -1533,7 +1533,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1565,7 +1565,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1595,7 +1595,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1678,7 +1678,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1703,7 +1703,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1730,7 +1730,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1957;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
|
@ -1750,7 +1750,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.7;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
Loading…
Reference in New Issue