1.5.9 SP1 // Pinyin Input, etc. Merge Gitee PR!34 from upd/1.5.9
This commit is contained in:
commit
9a71d52e85
24
AUTHORS
24
AUTHORS
|
@ -1,14 +1,30 @@
|
|||
$ Main contributors and volunteers of this repository (vChewing for macOS):
|
||||
|
||||
- Shiki Suen // Main developer of vChewing for macOS.
|
||||
- Shiki Suen // Main developer of vChewing for macOS, Megrez language engine, and Tekkon syllable composer engine.
|
||||
- Hiraku Wang // Technical reinforcement in Cocoa during the Object-Cpp dev period of this project.
|
||||
- Isaac Xen // Technical reinforcement in Swift: SFX Module and StringView Ranges Extension.
|
||||
|
||||
$ Contributors and volunteeres of the upstream repo, having no responsibility in discussing anything in the current repo:
|
||||
|
||||
- Mengjuei Hsieh // McBopomofo for macOS 1.x main developer and architect.
|
||||
- Zonble Yang // McBopomofo for macOS 2.x architect, especially state-based IME behavior management.
|
||||
- Lukhnos D Liu // Developer of the Mandarin syllable input processor.
|
||||
- Zonble Yang:
|
||||
- McBopomofo for macOS 2.x architect, especially state-based IME behavior management.
|
||||
- Voltaire candidate window MK2 (massively modified in vChewing by Shiki Suen).
|
||||
- InputHandler.
|
||||
- Notifier window and Tooltip UI.
|
||||
- NSStringUtils and FSEventStreamHelper.
|
||||
- App-style installer (only preserved for developer purposes).
|
||||
- Mengjuei Hsieh
|
||||
- McBopomofo for macOS 1.x main developer and architect.
|
||||
- User Override Module (not enabled at this moment).
|
||||
- Shiki Suen is trying to rewrite this module in Swift but it is not working yet.
|
||||
|
||||
Although there is no Lukhnos's codes left in the current repository, we still credit him for his previous work:
|
||||
|
||||
- Lukhnos Liu:
|
||||
- Developer of Gramambular language engine (removed since vChewing 1.5.4).
|
||||
- Shiki Suen's Megrez engine is basically a Swift-rewritten version of Gramambular.
|
||||
- Developer of Mandarin syllable composer (removed since vChewing 1.5.7).
|
||||
- Shiki Suen's Tekkon engine is made from scratch and has no relationship to Mandarin syllable composer.
|
||||
|
||||
$ Special thanks to:
|
||||
|
||||
|
|
10
Makefile
10
Makefile
|
@ -24,21 +24,19 @@ VC_APP_ROOT = $(DSTROOT)/vChewing.app
|
|||
|
||||
format: batchfix clang-format lint
|
||||
|
||||
clang-format: clang-format-swift clang-format-cpp
|
||||
|
||||
clang-format-swift:
|
||||
clang-format:
|
||||
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format format --in-place --configuration ./.clang-format-swift.json --parallel
|
||||
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
|
||||
|
||||
clang-format-cpp:
|
||||
@git ls-files --exclude-standard | grep -E '\.(cpp|hpp|c|cc|cxx|hxx|ixx|h|m|mm|hh)$$' | xargs clang-format -i
|
||||
|
||||
lint:
|
||||
@git ls-files --exclude-standard | grep -E '\.swift$$' | xargs swift-format lint --configuration ./.clang-format-swift.json --parallel
|
||||
|
||||
batchfix:
|
||||
@git ls-files --exclude-standard | grep -E '\.swift$$' | swiftlint --fix --autocorrect
|
||||
|
||||
advanced-lint:
|
||||
@swiftformat --swiftversion 5.5 --indent 2 ./
|
||||
|
||||
.PHONY: permission-check install-debug install-release
|
||||
|
||||
permission-check:
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 383ad9af7dd6f9ffa58ad2560e186bf06ffea3ad
|
||||
Subproject commit 4e5f1dc11a9b477b7907f5e59594e636a8830ce8
|
|
@ -64,7 +64,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, ctlNonModalAlertWindowDelega
|
|||
}
|
||||
|
||||
func applicationDidFinishLaunching(_: Notification) {
|
||||
IME.initLangModels(userOnly: false)
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()) {
|
||||
IME.initLangModels(userOnly: false)
|
||||
}
|
||||
|
||||
fsStreamHelper.delegate = self
|
||||
_ = fsStreamHelper.start()
|
||||
|
||||
|
|
|
@ -57,10 +57,10 @@ import Cocoa
|
|||
/// create a new user phrase.
|
||||
/// - Choosing Candidate: The candidate window is open to let the user to choose
|
||||
/// one among the candidates.
|
||||
class InputState: NSObject {
|
||||
class InputState {
|
||||
/// Represents that the input controller is deactivated.
|
||||
class Deactivated: InputState {
|
||||
override var description: String {
|
||||
var description: String {
|
||||
"<InputState.Deactivated>"
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class InputState: NSObject {
|
|||
""
|
||||
}
|
||||
|
||||
override var description: String {
|
||||
var description: String {
|
||||
"<InputState.Empty>"
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class InputState: NSObject {
|
|||
""
|
||||
}
|
||||
|
||||
override var description: String {
|
||||
var description: String {
|
||||
"<InputState.EmptyIgnoringPreviousState>"
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ class InputState: NSObject {
|
|||
self.poppedText = poppedText
|
||||
}
|
||||
|
||||
override var description: String {
|
||||
var description: String {
|
||||
"<InputState.Committing poppedText:\(poppedText)>"
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ class InputState: NSObject {
|
|||
self.cursorIndex = cursorIndex
|
||||
}
|
||||
|
||||
override var description: String {
|
||||
var description: String {
|
||||
"<InputState.NotEmpty, composingBuffer:\(composingBuffer), cursorIndex:\(cursorIndex)>"
|
||||
}
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ class InputState: NSObject {
|
|||
super.init()
|
||||
}
|
||||
|
||||
override var description: String {
|
||||
var description: String {
|
||||
"<InputState.AssociatedPhrases, candidates:\(candidates), useVerticalMode:\(useVerticalMode)>"
|
||||
}
|
||||
}
|
||||
|
@ -421,20 +421,18 @@ class InputState: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
class SymbolNode: NSObject {
|
||||
class SymbolNode {
|
||||
var title: String
|
||||
var children: [SymbolNode]?
|
||||
|
||||
init(_ title: String, _ children: [SymbolNode]? = nil) {
|
||||
self.title = title
|
||||
self.children = children
|
||||
super.init()
|
||||
}
|
||||
|
||||
init(_ title: String, symbols: String) {
|
||||
self.title = title
|
||||
children = Array(symbols).map { SymbolNode(String($0), nil) }
|
||||
super.init()
|
||||
}
|
||||
|
||||
static let catCommonSymbols = String(
|
||||
|
|
|
@ -34,7 +34,7 @@ public enum InputMode: String {
|
|||
|
||||
// MARK: - Delegate.
|
||||
|
||||
protocol KeyHandlerDelegate: NSObjectProtocol {
|
||||
protocol KeyHandlerDelegate {
|
||||
func ctlCandidate(for _: KeyHandler) -> Any
|
||||
func keyHandler(
|
||||
_: KeyHandler, didSelectCandidateAt index: Int,
|
||||
|
@ -46,7 +46,7 @@ protocol KeyHandlerDelegate: NSObjectProtocol {
|
|||
|
||||
// MARK: - Kernel.
|
||||
|
||||
class KeyHandler: NSObject {
|
||||
class KeyHandler {
|
||||
let kEpsilon: Double = 0.000001
|
||||
var _composer: Tekkon.Composer = .init()
|
||||
var _inputMode: String = ""
|
||||
|
@ -55,7 +55,7 @@ class KeyHandler: NSObject {
|
|||
var _builder: Megrez.BlockReadingBuilder
|
||||
var _walkedNodes: [Megrez.NodeAnchor] = []
|
||||
|
||||
weak var delegate: KeyHandlerDelegate?
|
||||
var delegate: KeyHandlerDelegate?
|
||||
|
||||
var inputMode: InputMode {
|
||||
get {
|
||||
|
@ -71,9 +71,8 @@ class KeyHandler: NSObject {
|
|||
set { setInputMode(newValue.rawValue) }
|
||||
}
|
||||
|
||||
override init() {
|
||||
public init() {
|
||||
_builder = Megrez.BlockReadingBuilder(lm: _languageModel)
|
||||
super.init()
|
||||
ensureParser()
|
||||
setInputMode(ctlInputMethod.currentInputMode)
|
||||
}
|
||||
|
@ -117,15 +116,11 @@ class KeyHandler: NSObject {
|
|||
func walk() {
|
||||
// Retrieve the most likely grid, i.e. a Maximum Likelihood Estimation
|
||||
// of the best possible Mandarin characters given the input syllables,
|
||||
// using the Viterbi algorithm implemented in the Megrez library
|
||||
let walker = Megrez.Walker(grid: _builder.grid())
|
||||
|
||||
// the reverse walk traces the grid from the end
|
||||
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()
|
||||
_walkedNodes.append(contentsOf: walked.reversed())
|
||||
// using the Viterbi algorithm implemented in the Megrez library.
|
||||
// The walk() traces the grid to the end, hence no need to use .reversed() here.
|
||||
_walkedNodes = Megrez.Walker(
|
||||
grid: _builder.grid()
|
||||
).walk(at: _builder.grid().width(), nodesLimit: 3, balanced: true)
|
||||
}
|
||||
|
||||
func popOverflowComposingTextAndWalk() -> String {
|
||||
|
@ -171,17 +166,20 @@ class KeyHandler: NSObject {
|
|||
// in the user override model.
|
||||
var addToUserOverrideModel = true
|
||||
if selectedNode.spanningLength != value.count {
|
||||
IME.prtDebugIntel("UOM: SpanningLength != value.count, dismissing.")
|
||||
addToUserOverrideModel = false
|
||||
}
|
||||
if addToUserOverrideModel {
|
||||
if let theNode = selectedNode.node {
|
||||
// 威注音的 SymbolLM 的 Score 是 -12。
|
||||
if theNode.scoreFor(candidate: value) <= -12 {
|
||||
IME.prtDebugIntel("UOM: Score <= -12, dismissing.")
|
||||
addToUserOverrideModel = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if addToUserOverrideModel {
|
||||
IME.prtDebugIntel("UOM: Start Observation.")
|
||||
_userOverrideModel.observe(
|
||||
walkedNodes: _walkedNodes, cursorIndex: cursorIndex, candidate: value,
|
||||
timestamp: NSDate().timeIntervalSince1970
|
||||
|
@ -237,11 +235,15 @@ class KeyHandler: NSObject {
|
|||
)
|
||||
|
||||
if !overrideValue.isEmpty {
|
||||
IME.prtDebugIntel(
|
||||
"UOM: Suggestion retrieved, overriding the node score of the selected candidate.")
|
||||
_builder.grid().overrideNodeScoreForSelectedCandidate(
|
||||
location: getActualCandidateCursorIndex(),
|
||||
value: overrideValue,
|
||||
overridingScore: findHighestScore(nodes: getRawNodes(), epsilon: kEpsilon)
|
||||
)
|
||||
} else {
|
||||
IME.prtDebugIntel("UOM: Blank suggestion retrieved, dismissing.")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,6 +330,8 @@ class KeyHandler: NSObject {
|
|||
switch mgrPrefs.mandarinParser {
|
||||
case MandarinParser.ofStandard.rawValue:
|
||||
_composer.ensureParser(arrange: .ofDachen)
|
||||
case MandarinParser.ofDachen26.rawValue:
|
||||
_composer.ensureParser(arrange: .ofDachen26)
|
||||
case MandarinParser.ofEten.rawValue:
|
||||
_composer.ensureParser(arrange: .ofEten)
|
||||
case MandarinParser.ofHsu.rawValue:
|
||||
|
@ -340,11 +344,20 @@ class KeyHandler: NSObject {
|
|||
_composer.ensureParser(arrange: .ofMiTAC)
|
||||
case MandarinParser.ofFakeSeigyou.rawValue:
|
||||
_composer.ensureParser(arrange: .ofFakeSeigyou)
|
||||
case MandarinParser.ofHanyuPinyin.rawValue:
|
||||
_composer.ensureParser(arrange: .ofHanyuPinyin)
|
||||
case MandarinParser.ofSecondaryPinyin.rawValue:
|
||||
_composer.ensureParser(arrange: .ofSecondaryPinyin)
|
||||
case MandarinParser.ofYalePinyin.rawValue:
|
||||
_composer.ensureParser(arrange: .ofYalePinyin)
|
||||
case MandarinParser.ofHualuoPinyin.rawValue:
|
||||
_composer.ensureParser(arrange: .ofHualuoPinyin)
|
||||
case MandarinParser.ofUniversalPinyin.rawValue:
|
||||
_composer.ensureParser(arrange: .ofUniversalPinyin)
|
||||
default:
|
||||
_composer.ensureParser(arrange: .ofDachen)
|
||||
mgrPrefs.mandarinParser = MandarinParser.ofStandard.rawValue
|
||||
}
|
||||
_composer.clear()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -166,7 +166,10 @@ extension KeyHandler {
|
|||
// However, Swift does not support "|=".
|
||||
composeReading = composeReading || (!_composer.isEmpty && (input.isSpace || input.isEnter))
|
||||
if composeReading {
|
||||
let reading = _composer.realComposition
|
||||
if input.isSpace && !_composer.hasToneMarker() {
|
||||
_composer.receiveKey(fromString: " ") // 補上空格。
|
||||
}
|
||||
let reading = _composer.getComposition()
|
||||
|
||||
// See whether we have a unigram for this...
|
||||
if !ifLangModelHasUnigrams(forKey: reading) {
|
||||
|
|
|
@ -89,7 +89,7 @@ extension KeyHandler {
|
|||
}
|
||||
|
||||
let head = rawHead
|
||||
let reading = _composer.getComposition(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
|
||||
let reading = _composer.getInlineCompositionForIMK(isHanyuPinyin: mgrPrefs.showHanyuPinyinInCompositionBuffer)
|
||||
let tail = rawEnd
|
||||
let composedText = head + reading + tail
|
||||
let cursorIndex = composedStringCursorIndex + reading.count
|
||||
|
@ -256,16 +256,10 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback _: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard let currentState = state as? InputState.Inputting else { return false }
|
||||
|
||||
clear()
|
||||
|
||||
if let current = state as? InputState.Inputting {
|
||||
stateCallback(InputState.Committing(poppedText: current.composingBuffer))
|
||||
}
|
||||
|
||||
stateCallback(InputState.Committing(poppedText: currentState.composingBuffer))
|
||||
stateCallback(InputState.Empty())
|
||||
return true
|
||||
}
|
||||
|
@ -277,9 +271,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback _: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
var composingBuffer = currentReadings().joined(separator: "-")
|
||||
if mgrPrefs.inlineDumpPinyinInLieuOfZhuyin {
|
||||
|
@ -305,9 +297,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback _: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
var composed = ""
|
||||
|
||||
|
@ -346,9 +336,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
if _composer.hasToneMarker(withNothingElse: true) {
|
||||
_composer.clear()
|
||||
|
@ -381,9 +369,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
if _composer.isEmpty {
|
||||
if getBuilderCursorIndex() != getBuilderLength() {
|
||||
|
@ -417,9 +403,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("9B6F908D")
|
||||
errorCallback()
|
||||
|
@ -435,9 +419,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("ABC44080")
|
||||
|
@ -465,9 +447,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) {
|
||||
return false
|
||||
}
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("9B69908D")
|
||||
|
@ -495,7 +475,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback _: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) { return false }
|
||||
guard state is InputState.Inputting else { return false }
|
||||
|
||||
let escToClearInputBufferEnabled: Bool = mgrPrefs.escToCleanInputBuffer
|
||||
|
||||
|
@ -528,7 +508,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) { return false }
|
||||
guard let currentState = state as? InputState.Inputting else { return false }
|
||||
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("B3BA5257")
|
||||
|
@ -537,34 +517,32 @@ extension KeyHandler {
|
|||
return true
|
||||
}
|
||||
|
||||
if let currentState = state as? InputState.Inputting {
|
||||
if input.isShiftHold {
|
||||
// Shift + Right
|
||||
if currentState.cursorIndex < (currentState.composingBuffer as NSString).length {
|
||||
let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position(
|
||||
for: Int(currentState.cursorIndex))
|
||||
let marking: InputState.Marking! = InputState.Marking(
|
||||
composingBuffer: currentState.composingBuffer,
|
||||
cursorIndex: currentState.cursorIndex,
|
||||
markerIndex: UInt(nextPosition),
|
||||
readings: currentReadings()
|
||||
)
|
||||
marking.tooltipForInputting = currentState.tooltip
|
||||
stateCallback(marking)
|
||||
} else {
|
||||
IME.prtDebugIntel("BB7F6DB9")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
if input.isShiftHold {
|
||||
// Shift + Right
|
||||
if currentState.cursorIndex < (currentState.composingBuffer as NSString).length {
|
||||
let nextPosition = (currentState.composingBuffer as NSString).nextUtf16Position(
|
||||
for: Int(currentState.cursorIndex))
|
||||
let marking: InputState.Marking! = InputState.Marking(
|
||||
composingBuffer: currentState.composingBuffer,
|
||||
cursorIndex: currentState.cursorIndex,
|
||||
markerIndex: UInt(nextPosition),
|
||||
readings: currentReadings()
|
||||
)
|
||||
marking.tooltipForInputting = currentState.tooltip
|
||||
stateCallback(marking)
|
||||
} else {
|
||||
if getBuilderCursorIndex() < getBuilderLength() {
|
||||
setBuilderCursorIndex(value: getBuilderCursorIndex() + 1)
|
||||
stateCallback(buildInputtingState())
|
||||
} else {
|
||||
IME.prtDebugIntel("A96AAD58")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
IME.prtDebugIntel("BB7F6DB9")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
} else {
|
||||
if getBuilderCursorIndex() < getBuilderLength() {
|
||||
setBuilderCursorIndex(value: getBuilderCursorIndex() + 1)
|
||||
stateCallback(buildInputtingState())
|
||||
} else {
|
||||
IME.prtDebugIntel("A96AAD58")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -579,7 +557,7 @@ extension KeyHandler {
|
|||
stateCallback: @escaping (InputState) -> Void,
|
||||
errorCallback: @escaping () -> Void
|
||||
) -> Bool {
|
||||
if !(state is InputState.Inputting) { return false }
|
||||
guard let currentState = state as? InputState.Inputting else { return false }
|
||||
|
||||
if !_composer.isEmpty {
|
||||
IME.prtDebugIntel("6ED95318")
|
||||
|
@ -588,34 +566,32 @@ extension KeyHandler {
|
|||
return true
|
||||
}
|
||||
|
||||
if let currentState = state as? InputState.Inputting {
|
||||
if input.isShiftHold {
|
||||
// Shift + left
|
||||
if currentState.cursorIndex > 0 {
|
||||
let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position(
|
||||
for: Int(currentState.cursorIndex))
|
||||
let marking: InputState.Marking! = InputState.Marking(
|
||||
composingBuffer: currentState.composingBuffer,
|
||||
cursorIndex: currentState.cursorIndex,
|
||||
markerIndex: UInt(previousPosition),
|
||||
readings: currentReadings()
|
||||
)
|
||||
marking.tooltipForInputting = currentState.tooltip
|
||||
stateCallback(marking)
|
||||
} else {
|
||||
IME.prtDebugIntel("D326DEA3")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
if input.isShiftHold {
|
||||
// Shift + left
|
||||
if currentState.cursorIndex > 0 {
|
||||
let previousPosition = (currentState.composingBuffer as NSString).previousUtf16Position(
|
||||
for: Int(currentState.cursorIndex))
|
||||
let marking: InputState.Marking! = InputState.Marking(
|
||||
composingBuffer: currentState.composingBuffer,
|
||||
cursorIndex: currentState.cursorIndex,
|
||||
markerIndex: UInt(previousPosition),
|
||||
readings: currentReadings()
|
||||
)
|
||||
marking.tooltipForInputting = currentState.tooltip
|
||||
stateCallback(marking)
|
||||
} else {
|
||||
if getBuilderCursorIndex() > 0 {
|
||||
setBuilderCursorIndex(value: getBuilderCursorIndex() - 1)
|
||||
stateCallback(buildInputtingState())
|
||||
} else {
|
||||
IME.prtDebugIntel("7045E6F3")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
IME.prtDebugIntel("D326DEA3")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
} else {
|
||||
if getBuilderCursorIndex() > 0 {
|
||||
setBuilderCursorIndex(value: getBuilderCursorIndex() - 1)
|
||||
stateCallback(buildInputtingState())
|
||||
} else {
|
||||
IME.prtDebugIntel("7045E6F3")
|
||||
errorCallback()
|
||||
stateCallback(state)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -30,7 +30,7 @@ extension String {
|
|||
}
|
||||
}
|
||||
|
||||
class vChewingKanjiConverter: NSObject {
|
||||
class vChewingKanjiConverter {
|
||||
class func cnvTradToKangXi(_ strObj: String) -> String {
|
||||
var strObj = strObj
|
||||
strObj.selfReplace("偽", "僞")
|
||||
|
|
|
@ -30,7 +30,7 @@ public protocol FSEventStreamHelperDelegate: AnyObject {
|
|||
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event])
|
||||
}
|
||||
|
||||
public class FSEventStreamHelper: NSObject {
|
||||
public class FSEventStreamHelper {
|
||||
public struct Event {
|
||||
var path: String
|
||||
var flags: FSEventStreamEventFlags
|
||||
|
@ -41,7 +41,7 @@ public class FSEventStreamHelper: NSObject {
|
|||
public let dispatchQueue: DispatchQueue
|
||||
public weak var delegate: FSEventStreamHelperDelegate?
|
||||
|
||||
@objc public init(path: String, queue: DispatchQueue) {
|
||||
public init(path: String, queue: DispatchQueue) {
|
||||
self.path = path
|
||||
dispatchQueue = queue
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import Cocoa
|
|||
// The namespace of this input method.
|
||||
public enum vChewing {}
|
||||
|
||||
public class IME: NSObject {
|
||||
public enum IME {
|
||||
static let arrSupportedLocales = ["en", "zh-Hant", "zh-Hans", "ja"]
|
||||
static let dlgOpenPath = NSOpenPanel()
|
||||
|
||||
|
@ -364,7 +364,7 @@ extension String: LocalizedError {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Ensuring trailing slash of a string:
|
||||
// MARK: - Ensuring trailing slash of a string
|
||||
|
||||
extension String {
|
||||
mutating func ensureTrailingSlash() {
|
||||
|
@ -373,3 +373,16 @@ extension String {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CharCode printability check
|
||||
|
||||
// Ref: https://forums.swift.org/t/57085/5
|
||||
extension UniChar {
|
||||
public func isPrintable() -> Bool {
|
||||
guard Unicode.Scalar(UInt32(self)) != nil else {
|
||||
struct NotAWholeScalar: Error {}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ class ctlInputMethod: IMKInputController {
|
|||
return Int(events.rawValue)
|
||||
}
|
||||
|
||||
override func handle(_ event: NSEvent!, client: Any!) -> Bool {
|
||||
@objc(handleEvent:client:) override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
|
||||
// 這裡仍舊需要判斷 flags。之前使輸入法狀態卡住無法敲漢字的問題已在 KeyHandler 內修復。
|
||||
// 這裡不判斷 flags 的話,用方向鍵前後定位光標之後,再次試圖觸發組字區時、反而會在首次按鍵時失敗。
|
||||
// 同時注意:必須在 event.type == .flagsChanged 結尾插入 return false,
|
||||
|
@ -161,13 +161,18 @@ class ctlInputMethod: IMKInputController {
|
|||
ctlInputMethod.areWeDeleting = event.modifierFlags.contains([.shift, .command])
|
||||
|
||||
var textFrame = NSRect.zero
|
||||
let attributes: [AnyHashable: Any]? = (client as? IMKTextInput)?.attributes(
|
||||
guard let client = sender as? IMKTextInput else {
|
||||
return false
|
||||
}
|
||||
|
||||
let attributes: [AnyHashable: Any]? = client.attributes(
|
||||
forCharacterIndex: 0, lineHeightRectangle: &textFrame
|
||||
)
|
||||
|
||||
let useVerticalMode =
|
||||
(attributes?["IMKTextOrientation"] as? NSNumber)?.intValue == 0 || false
|
||||
|
||||
if (client as? IMKTextInput)?.bundleIdentifier()
|
||||
if client.bundleIdentifier()
|
||||
== "org.atelierInmu.vChewing.vChewingPhraseEditor"
|
||||
{
|
||||
IME.areWeUsingOurOwnPhraseEditor = true
|
||||
|
@ -177,6 +182,12 @@ class ctlInputMethod: IMKInputController {
|
|||
|
||||
let input = InputHandler(event: event, isVerticalMode: useVerticalMode)
|
||||
|
||||
// 無法列印的訊號輸入,一概不作處理。
|
||||
// 這個過程不能放在 KeyHandler 內,否則不會起作用。
|
||||
if !input.charCode.isPrintable() {
|
||||
return false
|
||||
}
|
||||
|
||||
let result = keyHandler.handle(input: input, state: state) { newState in
|
||||
self.handle(state: newState, client: client)
|
||||
} errorCallback: {
|
||||
|
|
|
@ -166,7 +166,7 @@ struct ComposingBufferSize {
|
|||
|
||||
// MARK: -
|
||||
|
||||
@objc enum MandarinParser: Int {
|
||||
enum MandarinParser: Int {
|
||||
case ofStandard = 0
|
||||
case ofEten = 1
|
||||
case ofHsu = 2
|
||||
|
@ -174,7 +174,12 @@ struct ComposingBufferSize {
|
|||
case ofIBM = 4
|
||||
case ofMiTAC = 5
|
||||
case ofFakeSeigyou = 6
|
||||
case ofDachen26 = 7
|
||||
case ofHanyuPinyin = 10
|
||||
case ofSecondaryPinyin = 11
|
||||
case ofYalePinyin = 12
|
||||
case ofHualuoPinyin = 13
|
||||
case ofUniversalPinyin = 14
|
||||
|
||||
var name: String {
|
||||
switch self {
|
||||
|
@ -192,15 +197,25 @@ struct ComposingBufferSize {
|
|||
return "MiTAC"
|
||||
case .ofFakeSeigyou:
|
||||
return "FakeSeigyou"
|
||||
case .ofDachen26:
|
||||
return "Dachen26"
|
||||
case .ofHanyuPinyin:
|
||||
return "HanyuPinyin"
|
||||
case .ofSecondaryPinyin:
|
||||
return "SecondaryPinyin"
|
||||
case .ofYalePinyin:
|
||||
return "YalePinyin"
|
||||
case .ofHualuoPinyin:
|
||||
return "HualuoPinyin"
|
||||
case .ofUniversalPinyin:
|
||||
return "UniversalPinyin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public class mgrPrefs: NSObject {
|
||||
public enum mgrPrefs {
|
||||
static var allKeys: [String] {
|
||||
[
|
||||
UserDef.kIsDebugModeEnabled,
|
||||
|
@ -278,9 +293,11 @@ 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)
|
||||
mgrPrefs.showHanyuPinyinInCompositionBuffer, forKey: UserDef.kShowHanyuPinyinInCompositionBuffer
|
||||
)
|
||||
UserDefaults.standard.setDefault(
|
||||
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin)
|
||||
mgrPrefs.inlineDumpPinyinInLieuOfZhuyin, forKey: UserDef.kInlineDumpPinyinInLieuOfZhuyin
|
||||
)
|
||||
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
@ -310,7 +327,7 @@ public class mgrPrefs: NSObject {
|
|||
static var appleLanguages: [String]
|
||||
|
||||
@UserDefault(key: UserDef.kMandarinParser, defaultValue: 0)
|
||||
@objc static var mandarinParser: Int
|
||||
static var mandarinParser: Int
|
||||
|
||||
static var mandarinParserName: String {
|
||||
(MandarinParser(rawValue: mandarinParser) ?? MandarinParser.ofStandard).name
|
||||
|
|
|
@ -270,6 +270,7 @@ extension vChewing {
|
|||
filter filteredPairs: Set<Megrez.KeyValuePair>
|
||||
) -> [Megrez.Unigram] {
|
||||
var results: [Megrez.Unigram] = []
|
||||
var insertedPairs: Set<Megrez.KeyValuePair> = []
|
||||
|
||||
for unigram in unigrams {
|
||||
var pair: Megrez.KeyValuePair = unigram.keyValue
|
||||
|
@ -284,12 +285,13 @@ extension vChewing {
|
|||
pair.value = replacement
|
||||
}
|
||||
}
|
||||
results.append(Megrez.Unigram(keyValue: pair, score: unigram.score))
|
||||
}
|
||||
// Swift 不見得非得用 Swift-Collections 才可以用 OrderedSet,還有 NSOrderedSet 可用來去重複。
|
||||
let resultsDeduplicated = Array(NSOrderedSet(array: results).array as! [Megrez.Unigram])
|
||||
|
||||
return resultsDeduplicated
|
||||
if !insertedPairs.contains(pair) {
|
||||
results.append(Megrez.Unigram(keyValue: pair, score: unigram.score))
|
||||
insertedPairs.insert(pair)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,220 +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 "UserOverrideModel.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
namespace vChewing
|
||||
{
|
||||
|
||||
// About 20 generations.
|
||||
static const double DecayThreshold = 1.0 / 1048576.0;
|
||||
|
||||
static double Score(size_t eventCount, size_t totalCount, double eventTimestamp, double timestamp, double lambda);
|
||||
static bool IsEndingPunctuation(const std::string &value);
|
||||
static std::string WalkedNodesToKey(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex);
|
||||
|
||||
UserOverrideModel::UserOverrideModel(size_t capacity, double decayConstant) : m_capacity(capacity)
|
||||
{
|
||||
assert(m_capacity > 0);
|
||||
m_decayExponent = log(0.5) / decayConstant;
|
||||
}
|
||||
|
||||
void UserOverrideModel::observe(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex,
|
||||
const std::string &candidate, double timestamp)
|
||||
{
|
||||
std::string key = WalkedNodesToKey(walkedNodes, cursorIndex);
|
||||
auto mapIter = m_lruMap.find(key);
|
||||
if (mapIter == m_lruMap.end())
|
||||
{
|
||||
auto keyValuePair = KeyObservationPair(key, Observation());
|
||||
Observation &observation = keyValuePair.second;
|
||||
observation.update(candidate, timestamp);
|
||||
|
||||
m_lruList.push_front(keyValuePair);
|
||||
auto listIter = m_lruList.begin();
|
||||
auto lruKeyValue = std::pair<std::string, std::list<KeyObservationPair>::iterator>(key, listIter);
|
||||
m_lruMap.insert(lruKeyValue);
|
||||
|
||||
if (m_lruList.size() > m_capacity)
|
||||
{
|
||||
auto lastKeyValuePair = m_lruList.end();
|
||||
--lastKeyValuePair;
|
||||
m_lruMap.erase(lastKeyValuePair->first);
|
||||
m_lruList.pop_back();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto listIter = mapIter->second;
|
||||
m_lruList.splice(m_lruList.begin(), m_lruList, listIter);
|
||||
|
||||
auto &keyValuePair = *listIter;
|
||||
Observation &observation = keyValuePair.second;
|
||||
observation.update(candidate, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
std::string UserOverrideModel::suggest(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex,
|
||||
double timestamp)
|
||||
{
|
||||
std::string key = WalkedNodesToKey(walkedNodes, cursorIndex);
|
||||
auto mapIter = m_lruMap.find(key);
|
||||
if (mapIter == m_lruMap.end())
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
auto listIter = mapIter->second;
|
||||
auto &keyValuePair = *listIter;
|
||||
const Observation &observation = keyValuePair.second;
|
||||
|
||||
std::string candidate;
|
||||
double score = 0.0;
|
||||
for (auto i = observation.overrides.begin(); i != observation.overrides.end(); ++i)
|
||||
{
|
||||
const Override &o = i->second;
|
||||
double overrideScore = Score(o.count, observation.count, o.timestamp, timestamp, m_decayExponent);
|
||||
if (overrideScore == 0.0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overrideScore > score)
|
||||
{
|
||||
candidate = i->first;
|
||||
score = overrideScore;
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
void UserOverrideModel::Observation::update(const std::string &candidate, double timestamp)
|
||||
{
|
||||
count++;
|
||||
auto &o = overrides[candidate];
|
||||
o.timestamp = timestamp;
|
||||
o.count++;
|
||||
}
|
||||
|
||||
static double Score(size_t eventCount, size_t totalCount, double eventTimestamp, double timestamp, double lambda)
|
||||
{
|
||||
double decay = exp((timestamp - eventTimestamp) * lambda);
|
||||
if (decay < DecayThreshold)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double prob = (double)eventCount / (double)totalCount;
|
||||
return prob * decay;
|
||||
}
|
||||
|
||||
static bool IsEndingPunctuation(const std::string &value)
|
||||
{
|
||||
return value == "," || value == "。" || value == "!" || value == "?" || value == "」" || value == "』" ||
|
||||
value == "”" || value == "’";
|
||||
}
|
||||
static std::string WalkedNodesToKey(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex)
|
||||
{
|
||||
std::stringstream s;
|
||||
std::vector<Gramambular::NodeAnchor> n;
|
||||
size_t ll = 0;
|
||||
for (std::vector<Gramambular::NodeAnchor>::const_iterator i = walkedNodes.begin(); i != walkedNodes.end(); ++i)
|
||||
{
|
||||
const auto &nn = *i;
|
||||
n.push_back(nn);
|
||||
ll += nn.spanningLength;
|
||||
if (ll >= cursorIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Gramambular::NodeAnchor>::const_reverse_iterator r = n.rbegin();
|
||||
|
||||
if (r == n.rend())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string current = (*r).node->currentKeyValue().key;
|
||||
++r;
|
||||
|
||||
s.clear();
|
||||
s.str(std::string());
|
||||
if (r != n.rend())
|
||||
{
|
||||
std::string value = (*r).node->currentKeyValue().value;
|
||||
if (IsEndingPunctuation(value))
|
||||
{
|
||||
s << "()";
|
||||
r = n.rend();
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "(" << (*r).node->currentKeyValue().key << "," << value << ")";
|
||||
++r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "()";
|
||||
}
|
||||
std::string prev = s.str();
|
||||
|
||||
s.clear();
|
||||
s.str(std::string());
|
||||
if (r != n.rend())
|
||||
{
|
||||
std::string value = (*r).node->currentKeyValue().value;
|
||||
if (IsEndingPunctuation(value))
|
||||
{
|
||||
s << "()";
|
||||
r = n.rend();
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "(" << (*r).node->currentKeyValue().key << "," << value << ")";
|
||||
++r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "()";
|
||||
}
|
||||
std::string anterior = s.str();
|
||||
|
||||
s.clear();
|
||||
s.str(std::string());
|
||||
s << "(" << anterior << "," << prev << "," << current << ")";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
} // namespace vChewing
|
|
@ -1,82 +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 USEROVERRIDEMODEL_H
|
||||
#define USEROVERRIDEMODEL_H
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "Gramambular.h"
|
||||
|
||||
namespace vChewing
|
||||
{
|
||||
|
||||
using namespace Gramambular;
|
||||
|
||||
class UserOverrideModel
|
||||
{
|
||||
public:
|
||||
UserOverrideModel(size_t capacity, double decayConstant);
|
||||
|
||||
void observe(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex,
|
||||
const std::string &candidate, double timestamp);
|
||||
|
||||
std::string suggest(const std::vector<Gramambular::NodeAnchor> &walkedNodes, size_t cursorIndex, double timestamp);
|
||||
|
||||
private:
|
||||
struct Override
|
||||
{
|
||||
size_t count;
|
||||
double timestamp;
|
||||
|
||||
Override() : count(0), timestamp(0.0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Observation
|
||||
{
|
||||
size_t count;
|
||||
std::map<std::string, Override> overrides;
|
||||
|
||||
Observation() : count(0)
|
||||
{
|
||||
}
|
||||
void update(const std::string &candidate, double timestamp);
|
||||
};
|
||||
|
||||
typedef std::pair<std::string, Observation> KeyObservationPair;
|
||||
|
||||
size_t m_capacity;
|
||||
double m_decayExponent;
|
||||
std::list<KeyObservationPair> m_lruList;
|
||||
std::map<std::string, std::list<KeyObservationPair>::iterator> m_lruMap;
|
||||
};
|
||||
|
||||
}; // namespace vChewing
|
||||
|
||||
#endif
|
|
@ -95,7 +95,7 @@ extension vChewing {
|
|||
if let arrRangeRecords: [Range<String.Index>] = rangeMap[key] {
|
||||
for netaRange in arrRangeRecords {
|
||||
let neta = strData[netaRange].split(separator: " ")
|
||||
let theValue: String = String(neta[1])
|
||||
let theValue: String = .init(neta[1])
|
||||
pairs.append(theValue)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
// Refactored from the ObjCpp-version of this class by:
|
||||
// (c) 2011 and onwards The OpenVanilla Project (MIT License).
|
||||
// Refactored from the ObjCpp-version of this class by Mengjuei Hsieh (MIT 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
|
||||
|
@ -68,7 +67,7 @@ extension vChewing {
|
|||
|
||||
var mutCapacity: Int
|
||||
var mutDecayExponent: Double
|
||||
var mutLRUList = [KeyObservationPair]()
|
||||
var mutLRUList: [KeyObservationPair] = []
|
||||
var mutLRUMap: [String: KeyObservationPair] = [:]
|
||||
let kDecayThreshold: Double = 1.0 / 1_048_576.0
|
||||
|
||||
|
@ -86,27 +85,27 @@ extension vChewing {
|
|||
candidate: String,
|
||||
timestamp: Double
|
||||
) {
|
||||
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
||||
guard !key.isEmpty
|
||||
else {
|
||||
return
|
||||
}
|
||||
let key = convertKeyFrom(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
||||
|
||||
guard mutLRUMap[key] != nil else {
|
||||
var observation: Observation = .init()
|
||||
observation.update(candidate: candidate, timestamp: timestamp)
|
||||
mutLRUMap[key] = KeyObservationPair(key: key, observation: observation)
|
||||
mutLRUList.insert(KeyObservationPair(key: key, observation: observation), at: 0)
|
||||
let koPair = KeyObservationPair(key: key, observation: observation)
|
||||
mutLRUMap[key] = koPair
|
||||
mutLRUList.insert(koPair, at: 0)
|
||||
|
||||
if mutLRUList.count > mutCapacity {
|
||||
mutLRUMap[mutLRUList.reversed()[0].key] = nil
|
||||
mutLRUMap[mutLRUList[mutLRUList.endIndex].key] = nil
|
||||
mutLRUList.removeLast()
|
||||
}
|
||||
IME.prtDebugIntel("UOM: Observation finished with new observation: \(key)")
|
||||
return
|
||||
}
|
||||
mutLRUList.insert(contentsOf: mutLRUMap.values, at: 0)
|
||||
|
||||
if mutLRUMap[key] != nil {
|
||||
mutLRUMap[key]?.observation.update(candidate: candidate, timestamp: timestamp)
|
||||
if var theNeta = mutLRUMap[key] {
|
||||
theNeta.observation.update(candidate: candidate, timestamp: timestamp)
|
||||
mutLRUList.insert(theNeta, at: 0)
|
||||
mutLRUMap[key] = theNeta
|
||||
IME.prtDebugIntel("UOM: Observation finished with existing observation: \(key)")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,25 +114,22 @@ extension vChewing {
|
|||
cursorIndex: Int,
|
||||
timestamp: Double
|
||||
) -> String {
|
||||
let key = getWalkedNodesToKey(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
||||
guard let keyValuePair = mutLRUMap[key],
|
||||
!key.isEmpty
|
||||
else {
|
||||
let key = convertKeyFrom(walkedNodes: walkedNodes, cursorIndex: cursorIndex)
|
||||
guard let koPair = mutLRUMap[key] else {
|
||||
IME.prtDebugIntel("UOM: mutLRUMap[key] is nil, throwing blank suggestion for key: \(key).")
|
||||
return ""
|
||||
}
|
||||
|
||||
IME.prtDebugIntel("Suggest - A: \(key)")
|
||||
IME.prtDebugIntel("Suggest - B: \(keyValuePair.key)")
|
||||
|
||||
let observation = keyValuePair.observation
|
||||
let observation = koPair.observation
|
||||
|
||||
var candidate = ""
|
||||
var score = 0.0
|
||||
for overrideNeta in Array(observation.overrides) {
|
||||
let overrideScore = getScore(
|
||||
eventCount: overrideNeta.value.count,
|
||||
let override: Override = overrideNeta.value
|
||||
let overrideScore: Double = getScore(
|
||||
eventCount: override.count,
|
||||
totalCount: observation.count,
|
||||
eventTimestamp: overrideNeta.value.timestamp,
|
||||
eventTimestamp: override.timestamp,
|
||||
timestamp: timestamp,
|
||||
lambda: mutDecayExponent
|
||||
)
|
||||
|
@ -147,13 +143,12 @@ extension vChewing {
|
|||
score = overrideScore
|
||||
}
|
||||
}
|
||||
if candidate.isEmpty {
|
||||
IME.prtDebugIntel("UOM: No usable suggestions in the result for key: \(key).")
|
||||
}
|
||||
return candidate
|
||||
}
|
||||
|
||||
func isEndingPunctuation(value: String) -> Bool {
|
||||
[",", "。", "!", "?", "」", "』", "”", "’"].contains(value)
|
||||
}
|
||||
|
||||
public func getScore(
|
||||
eventCount: Int,
|
||||
totalCount: Int,
|
||||
|
@ -170,58 +165,51 @@ extension vChewing {
|
|||
return prob * decay
|
||||
}
|
||||
|
||||
func getWalkedNodesToKey(
|
||||
func convertKeyFrom(
|
||||
walkedNodes: [Megrez.NodeAnchor], cursorIndex: Int
|
||||
) -> String {
|
||||
var strOutput = ""
|
||||
var arrNodes: [Megrez.NodeAnchor] = []
|
||||
let arrEndingPunctuation = [",", "。", "!", "?", "」", "』", "”", "’"]
|
||||
var arrNodesReversed: [Megrez.NodeAnchor] = []
|
||||
var intLength = 0
|
||||
for nodeNeta in walkedNodes {
|
||||
arrNodes.append(nodeNeta)
|
||||
intLength += nodeNeta.spanningLength
|
||||
for theNodeAnchor in walkedNodes {
|
||||
// 這裡直接生成一個反向排序的陣列,之後就不用再「.reverse()」了。
|
||||
arrNodesReversed = [theNodeAnchor] + arrNodesReversed
|
||||
intLength += theNodeAnchor.spanningLength
|
||||
if intLength >= cursorIndex {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 一個被 .reversed 過的陣列不能直接使用,因為不是正常的 Swift 陣列。
|
||||
// 那就新開一個正常的陣列、然後將內容拓印過去。
|
||||
var arrNodesReversed: [Megrez.NodeAnchor] = []
|
||||
arrNodesReversed.append(contentsOf: arrNodes.reversed())
|
||||
if arrNodesReversed.isEmpty { return "" }
|
||||
|
||||
if arrNodesReversed.isEmpty {
|
||||
var strCurrent = "()"
|
||||
var strPrevious = "()"
|
||||
var strAnterior = "()"
|
||||
|
||||
guard let kvCurrent = arrNodesReversed[0].node?.currentKeyValue(),
|
||||
!arrEndingPunctuation.contains(kvCurrent.value)
|
||||
else {
|
||||
return ""
|
||||
}
|
||||
|
||||
var strCurrent = "()"
|
||||
var strPrev = "()"
|
||||
var strAnterior = "()"
|
||||
// 前置單元只記錄讀音,在其後的單元則同時記錄讀音與字詞
|
||||
strCurrent = kvCurrent.key
|
||||
|
||||
for (theIndex, theAnchor) in arrNodesReversed.enumerated() {
|
||||
if strCurrent != "()", let nodeCurrent = theAnchor.node {
|
||||
let keyCurrent = nodeCurrent.currentKeyValue().key
|
||||
let valCurrent = nodeCurrent.currentKeyValue().value
|
||||
strCurrent = "(\(keyCurrent), \(valCurrent))"
|
||||
if let nodePrev = arrNodesReversed[theIndex + 1].node {
|
||||
let keyPrev = nodePrev.currentKeyValue().key
|
||||
let valPrev = nodePrev.currentKeyValue().value
|
||||
strPrev = "(\(keyPrev), \(valPrev))"
|
||||
}
|
||||
if let nodeAnterior = arrNodesReversed[theIndex + 2].node {
|
||||
let keyAnterior = nodeAnterior.currentKeyValue().key
|
||||
let valAnterior = nodeAnterior.currentKeyValue().value
|
||||
strAnterior = "(\(keyAnterior), \(valAnterior))"
|
||||
}
|
||||
break // 我們只取第一個有效結果。
|
||||
}
|
||||
if arrNodesReversed.count >= 2,
|
||||
let kvPrevious = arrNodesReversed[1].node?.currentKeyValue(),
|
||||
!arrEndingPunctuation.contains(kvPrevious.value)
|
||||
{
|
||||
strPrevious = "(\(kvPrevious.key),\(kvPrevious.value))"
|
||||
}
|
||||
|
||||
strOutput = "(\(strAnterior),\(strPrev),\(strCurrent))"
|
||||
if strOutput == "((),(),())" {
|
||||
strOutput = ""
|
||||
if arrNodesReversed.count >= 3,
|
||||
let kvAnterior = arrNodesReversed[2].node?.currentKeyValue(),
|
||||
!arrEndingPunctuation.contains(kvAnterior.value)
|
||||
{
|
||||
strAnterior = "(\(kvAnterior.key),\(kvAnterior.value))"
|
||||
}
|
||||
|
||||
return strOutput
|
||||
return "(\(strAnterior),\(strPrevious),\(strCurrent))"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ private var gLangModelCHT = vChewing.LMInstantiator()
|
|||
private var gUserOverrideModelCHS = vChewing.LMUserOverride()
|
||||
private var gUserOverrideModelCHT = vChewing.LMUserOverride()
|
||||
|
||||
class mgrLangModel: NSObject {
|
||||
enum mgrLangModel {
|
||||
/// 寫幾個回傳函數、供其餘控制模組來讀取那些被設為 fileprivate 的器外變數。
|
||||
public static var lmCHS: vChewing.LMInstantiator { gLangModelCHS }
|
||||
public static var lmCHT: vChewing.LMInstantiator { gLangModelCHT }
|
||||
|
|
|
@ -31,6 +31,25 @@ extension Megrez {
|
|||
mutGrid = grid
|
||||
}
|
||||
|
||||
public func walk(
|
||||
at location: Int,
|
||||
score accumulatedScore: Double = 0.0,
|
||||
nodesLimit: Int = 0,
|
||||
balanced: Bool = false
|
||||
) -> [NodeAnchor] {
|
||||
var arrReturn: [NodeAnchor] = []
|
||||
let arrReversedSource = reverseWalk(
|
||||
at: location, score: accumulatedScore,
|
||||
nodesLimit: nodesLimit, balanced: balanced
|
||||
).reversed()
|
||||
|
||||
for neta in arrReversedSource {
|
||||
arrReturn.append(neta)
|
||||
}
|
||||
|
||||
return arrReturn
|
||||
}
|
||||
|
||||
public func reverseWalk(
|
||||
at location: Int,
|
||||
score accumulatedScore: Double = 0.0,
|
||||
|
|
|
@ -128,15 +128,17 @@ extension Megrez {
|
|||
|
||||
public func fixNodeSelectedCandidate(location: Int, value: String) -> NodeAnchor {
|
||||
var node = NodeAnchor()
|
||||
for (index, nodeAnchor) in nodesCrossingOrEndingAt(location: location).enumerated() {
|
||||
for nodeAnchor in nodesCrossingOrEndingAt(location: location) {
|
||||
guard let theNode = nodeAnchor.node else {
|
||||
continue
|
||||
}
|
||||
let candidates = theNode.candidates()
|
||||
// Reset the candidate-fixed state of every node at the location.
|
||||
let candidates = nodeAnchor.node?.candidates() ?? []
|
||||
nodesCrossingOrEndingAt(location: location)[index].node?.resetCandidate()
|
||||
|
||||
theNode.resetCandidate()
|
||||
for (i, candidate) in candidates.enumerated() {
|
||||
if candidate.value == value {
|
||||
nodesCrossingOrEndingAt(location: location)[index].node?.selectCandidateAt(index: i)
|
||||
node = nodesCrossingOrEndingAt(location: location)[index]
|
||||
theNode.selectCandidateAt(index: i)
|
||||
node = nodeAnchor
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -145,19 +147,17 @@ extension Megrez {
|
|||
}
|
||||
|
||||
public func overrideNodeScoreForSelectedCandidate(location: Int, value: String, overridingScore: Double) {
|
||||
for (index, nodeAnchor) in nodesCrossingOrEndingAt(location: location).enumerated() {
|
||||
if let theNode = nodeAnchor.node {
|
||||
let candidates = theNode.candidates()
|
||||
// Reset the candidate-fixed state of every node at the location.
|
||||
nodesCrossingOrEndingAt(location: location)[index].node?.resetCandidate()
|
||||
|
||||
for (i, candidate) in candidates.enumerated() {
|
||||
if candidate.value == value {
|
||||
nodesCrossingOrEndingAt(location: location)[index].node?.selectFloatingCandidateAt(
|
||||
index: i, score: overridingScore
|
||||
)
|
||||
break
|
||||
}
|
||||
for nodeAnchor in nodesCrossingOrEndingAt(location: location) {
|
||||
guard let theNode = nodeAnchor.node else {
|
||||
continue
|
||||
}
|
||||
let candidates = theNode.candidates()
|
||||
// Reset the candidate-fixed state of every node at the location.
|
||||
theNode.resetCandidate()
|
||||
for (i, candidate) in candidates.enumerated() {
|
||||
if candidate.value == value {
|
||||
theNode.selectFloatingCandidateAt(index: i, score: overridingScore)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"Apple Chewing - Dachen" = "Apple Chewing - Dachen";
|
||||
"Apple Chewing - Eten Traditional" = "Apple Chewing - Eten Traditional";
|
||||
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
|
||||
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters";
|
||||
"Auto-convert traditional Chinese glyphs to KangXi characters" = "Auto-convert traditional Chinese glyphs to KangXi characters";
|
||||
"Automatically reload user data files if changes detected" = "Automatically reload user data files if changes detected";
|
||||
|
@ -104,6 +105,7 @@
|
|||
"Choose your preferred layout of the candidate window." = "Choose your preferred layout of the candidate window.";
|
||||
"Cursor Selection:" = "Cursor Selection:";
|
||||
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "Dachen (Microsoft Standard / Wang / 01, etc.)";
|
||||
"Dachen 26 (libChewing)" = "Dachen 26 (libChewing)";
|
||||
"Debug Mode" = "Debug Mode";
|
||||
"Dictionary" = "Dictionary";
|
||||
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
|
||||
|
@ -122,7 +124,9 @@
|
|||
"Hanyu Pinyin with Numeral Intonation" = "Hanyu Pinyin with Numeral Intonation";
|
||||
"Horizontal" = "Horizontal";
|
||||
"Hsu" = "Hsu";
|
||||
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
|
||||
"IBM" = "IBM";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
|
||||
"Japanese" = "Japanese";
|
||||
"Keyboard" = "Keyboard";
|
||||
"Misc Settings:" = "Misc Settings:";
|
||||
|
@ -132,6 +136,7 @@
|
|||
"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";
|
||||
"Secondary Pinyin with Numeral Intonation" = "Secondary Pinyin with Numeral Intonation";
|
||||
"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";
|
||||
|
@ -140,10 +145,10 @@
|
|||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates";
|
||||
"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
|
||||
"Traditional Chinese" = "Traditional Chinese";
|
||||
"Typing Style:" = "Typing Style:";
|
||||
"UI Language:" = "UI Language:";
|
||||
"Universal Pinyin with Numeral Intonation" = "Universal Pinyin with Numeral Intonation";
|
||||
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
|
||||
"Vertical" = "Vertical";
|
||||
"Yale Pinyin with Numeral Intonation" = "Yale Pinyin with Numeral Intonation";
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"Apple Chewing - Dachen" = "Apple Chewing - Dachen";
|
||||
"Apple Chewing - Eten Traditional" = "Apple Chewing - Eten Traditional";
|
||||
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
|
||||
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "Auto-convert traditional Chinese glyphs to JIS Shinjitai characters";
|
||||
"Auto-convert traditional Chinese glyphs to KangXi characters" = "Auto-convert traditional Chinese glyphs to KangXi characters";
|
||||
"Automatically reload user data files if changes detected" = "Automatically reload user data files if changes detected";
|
||||
|
@ -104,6 +105,7 @@
|
|||
"Choose your preferred layout of the candidate window." = "Choose your preferred layout of the candidate window.";
|
||||
"Cursor Selection:" = "Cursor Selection:";
|
||||
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "Dachen (Microsoft Standard / Wang / 01, etc.)";
|
||||
"Dachen 26 (libChewing)" = "Dachen 26 (libChewing)";
|
||||
"Debug Mode" = "Debug Mode";
|
||||
"Dictionary" = "Dictionary";
|
||||
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
|
||||
|
@ -122,7 +124,9 @@
|
|||
"Hanyu Pinyin with Numeral Intonation" = "Hanyu Pinyin with Numeral Intonation";
|
||||
"Horizontal" = "Horizontal";
|
||||
"Hsu" = "Hsu";
|
||||
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
|
||||
"IBM" = "IBM";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
|
||||
"Japanese" = "Japanese";
|
||||
"Keyboard" = "Keyboard";
|
||||
"Misc Settings:" = "Misc Settings:";
|
||||
|
@ -132,6 +136,7 @@
|
|||
"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";
|
||||
"Secondary Pinyin with Numeral Intonation" = "Secondary Pinyin with Numeral Intonation";
|
||||
"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";
|
||||
|
@ -140,10 +145,10 @@
|
|||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Space to +cycle candidates, Shift+Space to +cycle pages";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space to +cycle pages, Shift+Space to +cycle candidates";
|
||||
"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "at anyplace else (like Windows Yahoo KeyKey)";
|
||||
"Traditional Chinese" = "Traditional Chinese";
|
||||
"Typing Style:" = "Typing Style:";
|
||||
"UI Language:" = "UI Language:";
|
||||
"Universal Pinyin with Numeral Intonation" = "Universal Pinyin with Numeral Intonation";
|
||||
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
|
||||
"Vertical" = "Vertical";
|
||||
"Yale Pinyin with Numeral Intonation" = "Yale Pinyin with Numeral Intonation";
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"Apple Chewing - Dachen" = "Apple 大千注音キーボード";
|
||||
"Apple Chewing - Eten Traditional" = "Apple 倚天傳統キーボード";
|
||||
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の配列を大千と設定すべきである。";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "単語の中・後で // Windows Yahoo KeyKey のやり方";
|
||||
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "入力した繁体字を日文 JIS 新字体と自動変換";
|
||||
"Auto-convert traditional Chinese glyphs to KangXi characters" = "入力した繁体字を康熙字体と自動変換";
|
||||
"Automatically reload user data files if changes detected" = "ユーザー辞書データの変更を自動検出し、自動的に再読込";
|
||||
|
@ -104,6 +105,7 @@
|
|||
"Choose your preferred layout of the candidate window." = "入力候補陳列の仕様をご指定ください。";
|
||||
"Cursor Selection:" = "カーソル候補呼出:";
|
||||
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千配列 (Microsoft 標準・王安・零壹など)";
|
||||
"Dachen 26 (libChewing)" = "酷音大千 26 キー配列";
|
||||
"Debug Mode" = "欠陥辿着モード";
|
||||
"Dictionary" = "辞書設定";
|
||||
"Emulating select-candidate-per-character mode" = "漢字1つづつ全候補選択入力モード";
|
||||
|
@ -122,7 +124,9 @@
|
|||
"Hanyu Pinyin with Numeral Intonation" = "漢語弁音 (ローマ字+数字音調)";
|
||||
"Horizontal" = "横型陳列";
|
||||
"Hsu" = "許氏国音自然配列";
|
||||
"Hualuo Pinyin with Numeral Intonation" = "中華ローマ弁音 (ローマ字+数字音調)";
|
||||
"IBM" = "IBM 配列";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "単語の前で // macOS 内蔵注音入力のやり方";
|
||||
"Japanese" = "和語";
|
||||
"Keyboard" = "配列設定";
|
||||
"Misc Settings:" = "他の設定:";
|
||||
|
@ -132,6 +136,7 @@
|
|||
"Output Settings:" = "出力設定:";
|
||||
"Phonetic Parser:" = "注音配列:";
|
||||
"Push the cursor in front of the phrase after selection" = "候補選択の直後、すぐカーソルを単語の向こうに推し進める";
|
||||
"Secondary Pinyin with Numeral Intonation" = "国音二式 (ローマ字+数字音調)";
|
||||
"Selection Keys:" = "言選り用キー:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "弁音合併入力(入力緩衝列で代わりに漢語弁音の音読み)";
|
||||
"Show page buttons in candidate window" = "入力候補陳列の側にページボタンを表示";
|
||||
|
@ -140,10 +145,10 @@
|
|||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+Space で次のページ、Space で次の候補文字を";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "Space で次のページ、Shift+Space で次の候補文字を";
|
||||
"Stop farting (when typed phonetic combination is invalid, etc.)" = "マナーモード // 外すと入力間違った時に変な声が出る";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "単語の前で // macOS 内蔵注音入力のやり方";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "単語の中・後で // Windows Yahoo KeyKey のやり方";
|
||||
"Traditional Chinese" = "繁体中国語";
|
||||
"Typing Style:" = "入力習慣:";
|
||||
"UI Language:" = "表示用言語:";
|
||||
"Universal Pinyin with Numeral Intonation" = "汎用弁音 (ローマ字+数字音調)";
|
||||
"Use ESC key to clear the entire input buffer" = "ESC キーで入力緩衝列を消す";
|
||||
"Vertical" = "縦型陳列";
|
||||
"Yale Pinyin with Numeral Intonation" = "イェール弁音 (ローマ字+数字音調)";
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"Apple Chewing - Dachen" = "Apple 大千注音键盘排列";
|
||||
"Apple Chewing - Eten Traditional" = "Apple 倚天传统键盘排列";
|
||||
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器得配置为大千排列。";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "将游标置于词语中后方 // Windows 奇摩注音风格";
|
||||
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自动将繁体中文字转为日文 JIS 新字体";
|
||||
"Auto-convert traditional Chinese glyphs to KangXi characters" = "自动将繁体中文字转为康熙正体字";
|
||||
"Automatically reload user data files if changes detected" = "自动检测并载入使用者语汇档案变更";
|
||||
|
@ -104,6 +105,7 @@
|
|||
"Choose your preferred layout of the candidate window." = "选择您所偏好的候选字窗布局。";
|
||||
"Cursor Selection:" = "选字游标:";
|
||||
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微软标准/王安/零壹/仲鼎/国乔)";
|
||||
"Dachen 26 (libChewing)" = "酷音大千二十六键";
|
||||
"Debug Mode" = "侦错模式";
|
||||
"Dictionary" = "辞典";
|
||||
"Emulating select-candidate-per-character mode" = "模拟 90 年代前期注音逐字选字输入风格";
|
||||
|
@ -122,7 +124,10 @@
|
|||
"Hanyu Pinyin with Numeral Intonation" = "汉语拼音+数字标调";
|
||||
"Horizontal" = "横向布局";
|
||||
"Hsu" = "许氏国音自然排列";
|
||||
"Hualuo Pinyin with Numeral Intonation" = "华罗拼音+数字标调";
|
||||
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+数字标调";
|
||||
"IBM" = "IBM 排列";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "将游标置于词语前方 // macOS 内建注音风格";
|
||||
"Japanese" = "和语";
|
||||
"Keyboard" = "键盘";
|
||||
"Misc Settings:" = "杂项:";
|
||||
|
@ -132,6 +137,7 @@
|
|||
"Output Settings:" = "输出设定:";
|
||||
"Phonetic Parser:" = "注音排列:";
|
||||
"Push the cursor in front of the phrase after selection" = "在选字后将游标置于该字词的前方";
|
||||
"Secondary Pinyin with Numeral Intonation" = "国音二式+数字标调";
|
||||
"Selection Keys:" = "选字键:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音并击模式(组字区内看到的是汉语拼音)";
|
||||
"Show page buttons in candidate window" = "在选字窗内显示翻页按钮";
|
||||
|
@ -140,10 +146,11 @@
|
|||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格键 换下一页,空格键 换选下一个后选字";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格键 换下一页,Shift+空格键 换选下一个后选字";
|
||||
"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉耻模式 // 取消勾选的话,敲错字时会有异音";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "将游标置于词语前方 // macOS 内建注音风格";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "将游标置于词语中后方 // Windows 奇摩注音风格";
|
||||
"Traditional Chinese" = "繁体中文";
|
||||
"Typing Style:" = "输入风格:";
|
||||
"UI Language:" = "介面语言:";
|
||||
"Universal Pinyin with Numeral Intonation" = "通用拼音+数字标调";
|
||||
"Universal Pinyin with Numeral Intonation" = "通用拼音+数字标调";
|
||||
"Use ESC key to clear the entire input buffer" = "敲 ESC 键以清空整个组字缓冲区";
|
||||
"Vertical" = "纵向布局";
|
||||
"Yale Pinyin with Numeral Intonation" = "耶鲁拼音+数字标调";
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"Apple Chewing - Dachen" = "Apple 大千注音鍵盤佈局";
|
||||
"Apple Chewing - Eten Traditional" = "Apple 倚天傳統鍵盤佈局";
|
||||
"Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional." = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器得配置為大千排列。";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "將游標置於詞語中後方 // Windows 奇摩注音風格";
|
||||
"Auto-convert traditional Chinese glyphs to JIS Shinjitai characters" = "自動將繁體中文字轉為日文 JIS 新字體";
|
||||
"Auto-convert traditional Chinese glyphs to KangXi characters" = "自動將繁體中文字轉為康熙正體字";
|
||||
"Automatically reload user data files if changes detected" = "自動檢測並載入使用者語彙檔案變更";
|
||||
|
@ -104,6 +105,7 @@
|
|||
"Choose your preferred layout of the candidate window." = "選擇您所偏好的候選字窗佈局。";
|
||||
"Cursor Selection:" = "選字游標:";
|
||||
"Dachen (Microsoft Standard / Wang / 01, etc.)" = "大千排列 (微軟標準/王安/零壹/仲鼎/國喬)";
|
||||
"Dachen 26 (libChewing)" = "酷音大千二十六鍵";
|
||||
"Debug Mode" = "偵錯模式";
|
||||
"Dictionary" = "辭典";
|
||||
"Emulating select-candidate-per-character mode" = "模擬 90 年代前期注音逐字選字輸入風格";
|
||||
|
@ -122,7 +124,9 @@
|
|||
"Hanyu Pinyin with Numeral Intonation" = "漢語拼音+數字標調";
|
||||
"Horizontal" = "橫向佈局";
|
||||
"Hsu" = "許氏國音自然排列";
|
||||
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+數字標調";
|
||||
"IBM" = "IBM 排列";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "將游標置於詞語前方 // macOS 內建注音風格";
|
||||
"Japanese" = "和語";
|
||||
"Keyboard" = "鍵盤";
|
||||
"Misc Settings:" = "雜項:";
|
||||
|
@ -132,6 +136,7 @@
|
|||
"Output Settings:" = "輸出設定:";
|
||||
"Phonetic Parser:" = "注音排列:";
|
||||
"Push the cursor in front of the phrase after selection" = "在選字後將游標置於該字詞的前方";
|
||||
"Secondary Pinyin with Numeral Intonation" = "國音二式+數字標調";
|
||||
"Selection Keys:" = "選字鍵:";
|
||||
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音並擊模式(組字區內看到的是漢語拼音)";
|
||||
"Show page buttons in candidate window" = "在選字窗內顯示翻頁按鈕";
|
||||
|
@ -140,10 +145,10 @@
|
|||
"Space to +cycle candidates, Shift+Space to +cycle pages" = "Shift+空格鍵 換下一頁,空格鍵 換選下一個後選字";
|
||||
"Space to +cycle pages, Shift+Space to +cycle candidates" = "空格鍵 換下一頁,Shift+空格鍵 換選下一個後選字";
|
||||
"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音";
|
||||
"in front of the phrase (like macOS built-in Zhuyin IME)" = "將游標置於詞語前方 // macOS 內建注音風格";
|
||||
"at anyplace else (like Windows Yahoo KeyKey)" = "將游標置於詞語中後方 // Windows 奇摩注音風格";
|
||||
"Traditional Chinese" = "繁體中文";
|
||||
"Typing Style:" = "輸入風格:";
|
||||
"UI Language:" = "介面語言:";
|
||||
"Universal Pinyin with Numeral Intonation" = "通用拼音+數字標調";
|
||||
"Use ESC key to clear the entire input buffer" = "敲 ESC 鍵以清空整個組字緩衝區";
|
||||
"Vertical" = "縱向佈局";
|
||||
"Yale Pinyin with Numeral Intonation" = "耶魯拼音+數字標調";
|
||||
|
|
|
@ -45,20 +45,60 @@ struct suiPrefPaneKeyboard: View {
|
|||
var body: some View {
|
||||
Preferences.Container(contentWidth: contentWidth) {
|
||||
Preferences.Section(label: { Text(LocalizedStringKey("Phonetic Parser:")) }) {
|
||||
Picker("", selection: $selMandarinParser) {
|
||||
Text(LocalizedStringKey("Dachen (Microsoft Standard / Wang / 01, etc.)")).tag(0)
|
||||
Text(LocalizedStringKey("Eten Traditional")).tag(1)
|
||||
Text(LocalizedStringKey("Eten 26")).tag(3)
|
||||
Text(LocalizedStringKey("IBM")).tag(4)
|
||||
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)
|
||||
}.onChange(of: selMandarinParser) { value in
|
||||
mgrPrefs.mandarinParser = value
|
||||
HStack {
|
||||
Picker("", selection: $selMandarinParser) {
|
||||
Group {
|
||||
Text(LocalizedStringKey("Dachen (Microsoft Standard / Wang / 01, etc.)")).tag(0)
|
||||
Text(LocalizedStringKey("Dachen 26 (libChewing)")).tag(7)
|
||||
Text(LocalizedStringKey("Eten Traditional")).tag(1)
|
||||
Text(LocalizedStringKey("Eten 26")).tag(3)
|
||||
Text(LocalizedStringKey("IBM")).tag(4)
|
||||
Text(LocalizedStringKey("Hsu")).tag(2)
|
||||
Text(LocalizedStringKey("MiTAC")).tag(5)
|
||||
Text(LocalizedStringKey("Fake Seigyou")).tag(6)
|
||||
}
|
||||
Divider()
|
||||
Group {
|
||||
Text(LocalizedStringKey("Hanyu Pinyin with Numeral Intonation")).tag(10)
|
||||
Text(LocalizedStringKey("Secondary Pinyin with Numeral Intonation")).tag(11)
|
||||
Text(LocalizedStringKey("Yale Pinyin with Numeral Intonation")).tag(12)
|
||||
Text(LocalizedStringKey("Hualuo Pinyin with Numeral Intonation")).tag(13)
|
||||
Text(LocalizedStringKey("Universal Pinyin with Numeral Intonation")).tag(14)
|
||||
}
|
||||
}.onChange(of: selMandarinParser) { value in
|
||||
mgrPrefs.mandarinParser = value
|
||||
switch value {
|
||||
case 0:
|
||||
if !AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
|
||||
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
|
||||
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
|
||||
}
|
||||
default:
|
||||
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(mgrPrefs.basicKeyboardLayout) {
|
||||
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
|
||||
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
|
||||
}
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
Button {
|
||||
mgrPrefs.mandarinParser = 0
|
||||
selMandarinParser = mgrPrefs.mandarinParser
|
||||
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ZhuyinBopomofo"
|
||||
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
|
||||
} label: {
|
||||
Text("↻ㄅ")
|
||||
}
|
||||
Button {
|
||||
mgrPrefs.mandarinParser = 10
|
||||
selMandarinParser = mgrPrefs.mandarinParser
|
||||
mgrPrefs.basicKeyboardLayout = "com.apple.keylayout.ABC"
|
||||
selBasicKeyboardLayout = mgrPrefs.basicKeyboardLayout
|
||||
} label: {
|
||||
Text("↻A")
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
.frame(width: 320.0)
|
||||
.frame(width: 380.0)
|
||||
Text(LocalizedStringKey("Choose the phonetic layout for Mandarin parser."))
|
||||
.preferenceDescription()
|
||||
}
|
||||
|
@ -71,6 +111,10 @@ struct suiPrefPaneKeyboard: View {
|
|||
}.id(UUID())
|
||||
}.onChange(of: selBasicKeyboardLayout) { value in
|
||||
mgrPrefs.basicKeyboardLayout = value
|
||||
if AppleKeyboardConverter.arrDynamicBasicKeyLayout.contains(value) {
|
||||
mgrPrefs.mandarinParser = 0
|
||||
selMandarinParser = mgrPrefs.mandarinParser
|
||||
}
|
||||
}
|
||||
.labelsHidden()
|
||||
.frame(width: 240.0)
|
||||
|
|
|
@ -782,12 +782,18 @@
|
|||
<menu key="menu" title="OtherViews" id="5">
|
||||
<items>
|
||||
<menuItem title="Standard" state="on" id="6"/>
|
||||
<menuItem title="Dachen 26" tag="7" id="xjP-r7-GaK"/>
|
||||
<menuItem title="ETen" tag="1" id="7"/>
|
||||
<menuItem title="ETen26" tag="3" id="9"/>
|
||||
<menuItem title="IBM" tag="4" id="137"/>
|
||||
<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"/>
|
||||
<menuItem title="Secondary Pinyin" tag="11" id="Parser11"/>
|
||||
<menuItem title="Yale Pinyin" tag="12" id="Parser12"/>
|
||||
<menuItem title="Hualuo Pinyin" tag="13" id="Parser13"/>
|
||||
<menuItem title="Universal Pinyin" tag="14" id="Parser14"/>
|
||||
</items>
|
||||
</menu>
|
||||
<connections>
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
|
||||
"9.title" = "ETen26";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
|
||||
"10.title" = "Hanyu Pinyin";
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
|
||||
"10.title" = "Hanyu Pinyin with Numeral Intonation";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
|
||||
"12.title" = "BPMF Parser:";
|
||||
|
@ -232,3 +232,18 @@
|
|||
|
||||
/* 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";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
|
||||
"xjP-r7-GaK.title" = "Dachen 26 (libChewing)";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
|
||||
"Parser11.title" = "Secondary Pinyin with Numeral Intonation";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
|
||||
"Parser12.title" = "Yale Pinyin with Numeral Intonation";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
|
||||
"Parser13.title" = "Hualuo Pinyin with Numeral Intonation";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
|
||||
"Parser14.title" = "Universal Pinyin with Numeral Intonation";
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
|
||||
"9.title" = "倚天形忘れ配列 (26キー)";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
|
||||
"10.title" = "漢語弁音(ローマ字+数字音調)";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
|
||||
|
@ -232,3 +232,18 @@
|
|||
|
||||
/* 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 で出すのを漢語弁音と変換";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
|
||||
"xjP-r7-GaK.title" = "酷音大千 26 キー配列";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
|
||||
"Parser11.title" = "国音二式 (ローマ字+数字音調)";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
|
||||
"Parser12.title" = "イェール弁音 (ローマ字+数字音調)";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
|
||||
"Parser13.title" = "中華ローマ弁音 (ローマ字+数字音調)";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
|
||||
"Parser14.title" = "汎用弁音 (ローマ字+数字音調)";
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
|
||||
"9.title" = "倚天二十六键";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
|
||||
"10.title" = "汉语拼音二式(字母拼音+数字标调)";
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
|
||||
"10.title" = "汉语拼音+数字标调";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
|
||||
"12.title" = "基础键盘布局:";
|
||||
|
@ -232,3 +232,18 @@
|
|||
|
||||
/* 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 输出汉语拼音而非注音";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
|
||||
"xjP-r7-GaK.title" = "酷音大千二十六键";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
|
||||
"Parser11.title" = "国音二式+数字标调";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
|
||||
"Parser12.title" = "耶鲁拼音+数字标调";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
|
||||
"Parser13.title" = "华罗拼音+数字标调";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
|
||||
"Parser14.title" = "通用拼音+数字标调";
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
/* Class = "NSMenuItem"; title = "ETen26"; ObjectID = "9"; */
|
||||
"9.title" = "倚天二十六鍵";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin"; ObjectID = "10"; */
|
||||
"10.title" = "漢語拼音二式(字母拼音+數字標調)";
|
||||
/* Class = "NSMenuItem"; title = "Hanyu Pinyin with Numeral Intonation"; ObjectID = "10"; */
|
||||
"10.title" = "漢語拼音+數字標調";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "BPMF Parser:"; ObjectID = "12"; */
|
||||
"12.title" = "注音排列:";
|
||||
|
@ -232,3 +232,18 @@
|
|||
|
||||
/* 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 輸出漢語拼音而非注音";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Dachen 26 (libChewing)"; ObjectID = "xjP-r7-GaK"; */
|
||||
"xjP-r7-GaK.title" = "酷音大千二十六鍵";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Secondary Pinyin with Numeral Intonation"; ObjectID = "Parser11"; */
|
||||
"Parser11.title" = "國音二式+數字標調";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Yale Pinyin with Numeral Intonation"; ObjectID = "Parser12"; */
|
||||
"Parser12.title" = "耶魯拼音+數字標調";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Hualuo Pinyin with Numeral Intonation"; ObjectID = "Parser13"; */
|
||||
"Parser13.title" = "華羅拼音+數字標調";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Universal Pinyin with Numeral Intonation"; ObjectID = "Parser14"; */
|
||||
"Parser14.title" = "通用拼音+數字標調";
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.5.8</string>
|
||||
<string>1.5.9</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1958</string>
|
||||
<string>1959</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.8</string>
|
||||
<string>1.5.9</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
|
|
|
@ -318,8 +318,6 @@
|
|||
D47B92BF27972AC800458394 /* main.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = main.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D47F7DCD278BFB57002F9DD7 /* ctlPrefWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlPrefWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D47F7DCF278C0897002F9DD7 /* ctlNonModalAlertWindow.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlNonModalAlertWindow.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = UserOverrideModel.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = UserOverrideModel.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
|
||||
D4A13D5927A59D5C003BE359 /* ctlInputMethod.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = ctlInputMethod.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
|
||||
D4E33D8927A838CF006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
D4E33D8E27A838F0006DB1CF /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
|
@ -470,7 +468,6 @@
|
|||
5B62A32427AE757300A19448 /* LangModelRelated */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B62A32527AE758000A19448 /* OldFileReferences */,
|
||||
5B407308281672610023DFFF /* SubLMs */,
|
||||
5B949BDA2816DDBC00D87B5D /* LMConsolidator.swift */,
|
||||
5BD0113A28180D6100609769 /* LMInstantiator.swift */,
|
||||
|
@ -479,15 +476,6 @@
|
|||
path = LangModelRelated;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B62A32527AE758000A19448 /* OldFileReferences */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */,
|
||||
D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */,
|
||||
);
|
||||
path = OldFileReferences;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B62A33027AE78E500A19448 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1308,7 +1296,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
CURRENT_PROJECT_VERSION = 1959;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1331,7 +1319,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1364,7 +1352,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
CURRENT_PROJECT_VERSION = 1959;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
@ -1383,7 +1371,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1498,7 +1486,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
CURRENT_PROJECT_VERSION = 1959;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
|
@ -1533,7 +1521,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1565,7 +1553,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
CURRENT_PROJECT_VERSION = 1959;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1595,7 +1583,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1678,7 +1666,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
CURRENT_PROJECT_VERSION = 1959;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
|
@ -1703,7 +1691,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1730,7 +1718,7 @@
|
|||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1958;
|
||||
CURRENT_PROJECT_VERSION = 1959;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
|
@ -1750,7 +1738,7 @@
|
|||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11.5;
|
||||
MARKETING_VERSION = 1.5.8;
|
||||
MARKETING_VERSION = 1.5.9;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.atelierInmu.vChewing.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
Loading…
Reference in New Issue