Repo // Implementing reverse-lookup, requiring macOS 10.15 and later.

- Prefs & PrefUI // Add reverse-lookup toggle.
This commit is contained in:
ShikiSuen 2022-10-22 10:41:02 +08:00
parent 6e67a5edc8
commit f94ecf5fda
20 changed files with 115 additions and 30 deletions

View File

@ -14,6 +14,7 @@ open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
open var currentLayout: NSUserInterfaceLayoutOrientation = .horizontal
open var locale: String = ""
open var useLangIdentifier: Bool = false
open var reverseLookupResult: String = ""
open func highlightedColor() -> NSColor {
var result = NSColor.alternateSelectedControlColor

View File

@ -19,20 +19,32 @@ public class CtlCandidateTDK: CtlCandidate {
@available(macOS 12, *)
public var theViewHorizontal: VwrCandidateHorizontal {
.init(controller: self, thePool: thePoolHorizontal, tooltip: tooltip)
.init(
controller: self, thePool: thePoolHorizontal,
tooltip: tooltip, reverseLookupResult: reverseLookupResult
)
}
@available(macOS 12, *)
public var theViewVertical: VwrCandidateVertical {
.init(controller: self, thePool: thePoolVertical, tooltip: tooltip)
.init(
controller: self, thePool: thePoolVertical,
tooltip: tooltip, reverseLookupResult: reverseLookupResult
)
}
public var theViewHorizontalBackports: VwrCandidateHorizontalBackports {
.init(controller: self, thePool: thePoolHorizontal, tooltip: tooltip)
.init(
controller: self, thePool: thePoolHorizontal,
tooltip: tooltip, reverseLookupResult: reverseLookupResult
)
}
public var theViewVerticalBackports: VwrCandidateVerticalBackports {
.init(controller: self, thePool: thePoolVertical, tooltip: tooltip)
.init(
controller: self, thePool: thePoolVertical,
tooltip: tooltip, reverseLookupResult: reverseLookupResult
)
}
public var thePool: CandidatePool {
@ -105,6 +117,7 @@ public class CtlCandidateTDK: CtlCandidate {
override open func updateDisplay() {
guard let window = window else { return }
reverseLookupResult = delegate?.annotate(for: currentSelectedCandidateText) ?? ""
switch currentLayout {
case .horizontal:
DispatchQueue.main.async { [self] in
@ -223,6 +236,13 @@ extension CtlCandidateTDK {
if #unavailable(macOS 12) { return false }
return true
}
private var currentSelectedCandidateText: String {
if thePool.candidateDataAll.count > highlightedIndex {
return thePool.candidateDataAll[highlightedIndex].displayedText
}
return ""
}
}
@available(macOS 10.15, *)

View File

@ -38,6 +38,7 @@ public struct VwrCandidateHorizontal: View {
public var controller: CtlCandidateTDK
@State public var thePool: CandidatePool
@State public var tooltip: String = ""
@State public var reverseLookupResult: String = ""
private var positionLabel: String {
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
@ -91,16 +92,21 @@ public struct VwrCandidateHorizontal: View {
}
.fixedSize(horizontal: false, vertical: true).padding(5)
.background(Color(nsColor: NSColor.controlBackgroundColor).ignoresSafeArea())
ZStack(alignment: .leading) {
ZStack(alignment: .trailing) {
Color(nsColor: tooltip.isEmpty ? .windowBackgroundColor : CandidateCellData.highlightBackground)
.ignoresSafeArea()
HStack(alignment: .bottom) {
Text(tooltip).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold)).lineLimit(1)
Spacer()
Text(positionLabel).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.lineLimit(
1)
if !tooltip.isEmpty {
Text(tooltip).lineLimit(1)
Spacer()
}
if !reverseLookupResult.isEmpty, !(controller.delegate?.isVerticalTyping ?? true) {
Text(reverseLookupResult).lineLimit(1)
Spacer()
}
Text(positionLabel).lineLimit(1)
}
.font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.padding(7).foregroundColor(
.init(nsColor: tooltip.isEmpty ? .controlTextColor : .selectedMenuItemTextColor.withAlphaComponent(0.9))
)

View File

@ -37,6 +37,7 @@ public struct VwrCandidateVertical: View {
public var controller: CtlCandidateTDK
@State public var thePool: CandidatePool
@State public var tooltip: String = ""
@State public var reverseLookupResult: String = ""
private var positionLabel: String {
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
@ -99,20 +100,26 @@ public struct VwrCandidateVertical: View {
}
.fixedSize(horizontal: true, vertical: false).padding(5)
.background(Color(nsColor: NSColor.controlBackgroundColor).ignoresSafeArea())
ZStack(alignment: .leading) {
ZStack(alignment: .trailing) {
Color(nsColor: tooltip.isEmpty ? .windowBackgroundColor : CandidateCellData.highlightBackground)
.ignoresSafeArea()
HStack(alignment: .bottom) {
Text(tooltip).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold)).lineLimit(1)
Spacer()
Text(positionLabel).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.lineLimit(
1)
if !tooltip.isEmpty {
Text(tooltip).lineLimit(1)
Spacer()
}
if !reverseLookupResult.isEmpty, !(controller.delegate?.isVerticalTyping ?? true) {
Text(reverseLookupResult).lineLimit(1)
Spacer()
}
Text(positionLabel).lineLimit(1)
}
.font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.padding(7).foregroundColor(
.init(nsColor: tooltip.isEmpty ? .controlTextColor : .selectedMenuItemTextColor.withAlphaComponent(0.9))
)
}
.fixedSize(horizontal: false, vertical: true)
}
.overlay(
RoundedRectangle(cornerRadius: 10).stroke(.white.opacity(0.2), lineWidth: 1)

View File

@ -40,6 +40,7 @@ public struct VwrCandidateHorizontalBackports: View {
public var controller: CtlCandidateTDK
@State public var thePool: CandidatePool
@State public var tooltip: String = ""
@State public var reverseLookupResult: String = ""
private var positionLabel: String {
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
@ -93,7 +94,7 @@ public struct VwrCandidateHorizontalBackports: View {
}
.fixedSize(horizontal: false, vertical: true).padding(5)
.background(Color(white: colorScheme == .dark ? 0.1 : 1))
ZStack(alignment: .leading) {
ZStack(alignment: .trailing) {
if tooltip.isEmpty {
Color(white: colorScheme == .dark ? 0.2 : 0.9)
} else {
@ -101,12 +102,17 @@ public struct VwrCandidateHorizontalBackports: View {
controller.highlightedColorUIBackports
}
HStack(alignment: .bottom) {
Text(tooltip).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold)).lineLimit(1)
Spacer()
Text(positionLabel).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.lineLimit(
1)
if !tooltip.isEmpty {
Text(tooltip).lineLimit(1)
Spacer()
}
if !reverseLookupResult.isEmpty, !(controller.delegate?.isVerticalTyping ?? true) {
Text(reverseLookupResult).lineLimit(1)
Spacer()
}
Text(positionLabel).lineLimit(1)
}
.font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.padding(7).foregroundColor(
tooltip.isEmpty && colorScheme == .light ? Color(white: 0.1) : Color(white: 0.9)
)

View File

@ -39,6 +39,7 @@ public struct VwrCandidateVerticalBackports: View {
public var controller: CtlCandidateTDK
@State public var thePool: CandidatePool
@State public var tooltip: String = ""
@State public var reverseLookupResult: String = ""
private var positionLabel: String {
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
@ -101,7 +102,7 @@ public struct VwrCandidateVerticalBackports: View {
}
.fixedSize(horizontal: true, vertical: false).padding(5)
.background(Color(white: colorScheme == .dark ? 0.1 : 1))
ZStack(alignment: .leading) {
ZStack(alignment: .trailing) {
if tooltip.isEmpty {
Color(white: colorScheme == .dark ? 0.2 : 0.9)
} else {
@ -109,16 +110,22 @@ public struct VwrCandidateVerticalBackports: View {
controller.highlightedColorUIBackports
}
HStack(alignment: .bottom) {
Text(tooltip).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold)).lineLimit(1)
Spacer()
Text(positionLabel).font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.lineLimit(
1)
if !tooltip.isEmpty {
Text(tooltip).lineLimit(1)
Spacer()
}
if !reverseLookupResult.isEmpty, !(controller.delegate?.isVerticalTyping ?? true) {
Text(reverseLookupResult).lineLimit(1)
Spacer()
}
Text(positionLabel).lineLimit(1)
}
.font(.system(size: max(CandidateCellData.unifiedSize * 0.7, 11), weight: .bold))
.padding(7).foregroundColor(
tooltip.isEmpty && colorScheme == .light ? Color(white: 0.1) : Color(white: 0.9)
)
}
.fixedSize(horizontal: false, vertical: true)
}
.overlay(
RoundedRectangle(cornerRadius: 10).stroke(.white.opacity(0.2), lineWidth: 1)

View File

@ -27,6 +27,7 @@ extension vChewingLM {
public private(set) var keyNameMap: [String: String] = [:]
public private(set) var charDefMap: [String: [String]] = [:]
public private(set) var charDefWildcardMap: [String: [String]] = [:]
public private(set) var reverseLookupMap: [String: [String]] = [:]
/// [:]
public private(set) var octagramMap: [String: Int] = [:]
/// [:(, )]
@ -91,13 +92,15 @@ extension vChewingLM {
if loadingKeys, !cells[0].contains("%keyname") {
keyNameMap[strFirstCell] = String(cells[1])
} else if loadingCharDefinitions, !strLine.contains("%chardef") {
let strSecondCell = String(cells[1])
theMaxKeyLength = max(theMaxKeyLength, cells[0].count)
charDefMap[strFirstCell, default: []].append(String(cells[1]))
charDefMap[strFirstCell, default: []].append(strSecondCell)
reverseLookupMap[strSecondCell, default: []].append(strFirstCell)
var keyComps = strFirstCell.charComponents
while !keyComps.isEmpty, !wildcardKey.isEmpty {
keyComps.removeLast()
if !wildcardKey.isEmpty {
charDefWildcardMap[keyComps.joined() + wildcardKey, default: []].append(String(cells[1]))
charDefWildcardMap[keyComps.joined() + wildcardKey, default: []].append(strSecondCell)
}
}
} else if loadingOctagramData, !strLine.contains("%octagram") {

View File

@ -12,11 +12,14 @@ public protocol CtlCandidateDelegate {
func candidatePairs(conv: Bool) -> [(String, String)]
func candidatePairSelected(at index: Int)
func candidates(_ sender: Any!) -> [Any]!
@discardableResult func annotate(for value: String) -> String
var selectionKeys: String { get }
var isVerticalTyping: Bool { get }
}
public protocol CtlCandidateProtocol {
var tooltip: String { get set }
var reverseLookupResult: String { get set }
var locale: String { get set }
var currentLayout: NSUserInterfaceLayoutOrientation { get set }
var delegate: CtlCandidateDelegate? { get set }

View File

@ -51,6 +51,7 @@ public protocol PrefMgrProtocol {
var inlineDumpPinyinInLieuOfZhuyin: Bool { get set }
var showTranslatedStrokesInCompositionBuffer: Bool { get set }
var forceCassetteChineseConversion: Int { get set }
var showReverseLookupInCandidateUI: Bool { get set }
var cns11643Enabled: Bool { get set }
var cassetteEnabled: Bool { get set }
var symbolInputEnabled: Bool { get set }

View File

@ -64,6 +64,7 @@ public enum UserDef: String, CaseIterable {
case kOnlyLoadFactoryLangModelsIfNeeded = "OnlyLoadFactoryLangModelsIfNeeded"
case kShowTranslatedStrokesInCompositionBuffer = "ShowTranslatedStrokesInCompositionBuffer"
case kForceCassetteChineseConversion = "ForceCassetteChineseConversion"
case kShowReverseLookupInCandidateUI = "ShowReverseLookupInCandidateUI"
case kUseIMKCandidateWindow = "UseIMKCandidateWindow"
case kHandleDefaultCandidateFontsByLangIdentifier = "HandleDefaultCandidateFontsByLangIdentifier"

View File

@ -150,6 +150,9 @@ public class PrefMgr: PrefMgrProtocol {
@AppProperty(key: UserDef.kForceCassetteChineseConversion.rawValue, defaultValue: 0)
public var forceCassetteChineseConversion: Int
@AppProperty(key: UserDef.kShowReverseLookupInCandidateUI.rawValue, defaultValue: true)
public var showReverseLookupInCandidateUI: Bool
// MARK: - Settings (Tier 2)
@AppProperty(key: UserDef.kUseIMKCandidateWindow.rawValue, defaultValue: false)

View File

@ -19,6 +19,7 @@ extension PrefMgr {
shiftKeyAccommodationBehavior = 0
disableShiftTogglingAlphanumericalMode = true
togglingAlphanumericalModeWithLShift = false
showReverseLookupInCandidateUI = false
}
// ( didSet )
candidateKeys = candidateKeys

View File

@ -56,6 +56,16 @@ extension SessionCtl: InputHandlerDelegate {
// MARK: - Candidate Controller Delegate
extension SessionCtl: CtlCandidateDelegate {
@discardableResult public func annotate(for value: String) -> String {
//
if !PrefMgr.shared.showReverseLookupInCandidateUI { return "" }
if isVerticalTyping { return "" } //
if value.isEmpty { return "" } // 西
if value.contains("_") { return "" }
guard let lookupResult = LMMgr.currentLM.currentCassette.reverseLookupMap[value] else { return "" }
return lookupResult.joined(separator: " ")
}
public var selectionKeys: String {
PrefMgr.shared.useIMKCandidateWindow ? "123456789" : PrefMgr.shared.candidateKeys
}

View File

@ -12,6 +12,7 @@ import Shared
/// IMKCandidates bridging header Swift Package
public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
public var tooltip: String = ""
public var reverseLookupResult: String = ""
public var locale: String = ""
public var useLangIdentifier: Bool = false
public var currentLayout: NSUserInterfaceLayoutOrientation = .horizontal

View File

@ -36,6 +36,8 @@ struct VwrPrefPaneGeneral: View {
@State private var selEnableAutoUpdateCheck = UserDefaults.standard.bool(
forKey: UserDef.kCheckUpdateAutomatically.rawValue)
@State private var selEnableDebugMode = UserDefaults.standard.bool(forKey: UserDef.kIsDebugModeEnabled.rawValue)
@State private var selShowReverseLookupInCandidateUI = UserDefaults.standard.bool(
forKey: UserDef.kShowReverseLookupInCandidateUI.rawValue)
private let contentMaxHeight: Double = 440
private let contentWidth: Double = {
@ -129,6 +131,14 @@ struct VwrPrefPaneGeneral: View {
.pickerStyle(RadioGroupPickerStyle())
Text(LocalizedStringKey("Choose your preferred layout of the candidate window."))
.preferenceDescription()
Toggle(
LocalizedStringKey("Show available reverse-lookup results in candidate window"),
isOn: $selShowReverseLookupInCandidateUI.onChange {
PrefMgr.shared.showReverseLookupInCandidateUI = selShowReverseLookupInCandidateUI
}
)
.controlSize(.small)
.disabled(PrefMgr.shared.useIMKCandidateWindow)
}
SSPreferences.Section(label: { Text(LocalizedStringKey("Output Settings:")) }) {
Toggle(

View File

@ -223,6 +223,7 @@
"Selection Keys:" = "Selection Keys:";
"Shift+BackSpace:" = "Shift+BackSpace:";
"Shift+Letter:" = "Shift+Letter:";
"Show available reverse-lookup results in candidate window" = "Show available reverse-lookup results in candidate window";
"Show Hanyu-Pinyin in the inline composition buffer" = "Show Hanyu-Pinyin in the inline composition buffer";
"Show notifications when toggling Caps Lock" = "Show notifications when toggling Caps Lock";
"Show translated strokes in composition buffer" = "Show translated strokes in composition buffer";

View File

@ -223,6 +223,7 @@
"Selection Keys:" = "Selection Keys:";
"Shift+BackSpace:" = "Shift+BackSpace:";
"Shift+Letter:" = "Shift+Letter:";
"Show available reverse-lookup results in candidate window" = "Show available reverse-lookup results in candidate window";
"Show Hanyu-Pinyin in the inline composition buffer" = "Show Hanyu-Pinyin in the inline composition buffer";
"Show notifications when toggling Caps Lock" = "Show notifications when toggling Caps Lock";
"Show translated strokes in composition buffer" = "Show translated strokes in composition buffer";

View File

@ -223,6 +223,7 @@
"Selection Keys:" = "言選り用キー:";
"Shift+BackSpace:" = "Shift+BackSpace:";
"Shift+Letter:" = "Shift+文字キー:";
"Show available reverse-lookup results in candidate window" = "候補陳列ウィンドウで可能な逆引参照結果を示す";
"Show Hanyu-Pinyin in the inline composition buffer" = "弁音合併入力(入力緩衝列で音読みを漢語弁音に)";
"Show notifications when toggling Caps Lock" = "Caps Lock で切り替えの時に吹出通知メッセージを";
"Show translated strokes in composition buffer" = "原始キーネームでなく、筆画を入力緩衝列で表示する";

View File

@ -223,6 +223,7 @@
"Selection Keys:" = "选字键:";
"Shift+BackSpace:" = "Shift+退格键:";
"Shift+Letter:" = "Shift+字母键:";
"Show available reverse-lookup results in candidate window" = "在选字窗内显示可用的字根反查结果";
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音并击(组字区内显示汉语拼音)";
"Show notifications when toggling Caps Lock" = "以 Caps Lock 切换输入法/中英模式时显示通知";
"Show translated strokes in composition buffer" = "在组字区内显示字根、而非原始键盘码";

View File

@ -223,6 +223,7 @@
"Selection Keys:" = "選字鍵:";
"Shift+BackSpace:" = "Shift+退格鍵:";
"Shift+Letter:" = "Shift+字母鍵:";
"Show available reverse-lookup results in candidate window" = "在選字窗內顯示可用的字根反查結果";
"Show Hanyu-Pinyin in the inline composition buffer" = "拼音並擊(組字區內顯示漢語拼音)";
"Show notifications when toggling Caps Lock" = "以 Caps Lock 切換輸入法/中英模式時顯示通知";
"Show translated strokes in composition buffer" = "在組字區內顯示字根、而非原始鍵盤碼";