2.8.0 // Tadokoro Candidate Window. Merge PR#149 from upd/2.8.0

This commit is contained in:
ShikiSuen 2022-09-29 16:28:08 +08:00 committed by GitHub
commit 74d2ca6a09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 867 additions and 894 deletions

View File

@ -1,6 +1,6 @@
$ Main contributors and volunteers of this repository (vChewing for macOS):
- Shiki Suen // Main developer of vChewing for macOS, Megrez language engine, Hotenka Chinese Converter, and Tekkon syllable composer engine.
- Shiki Suen // Main developer of vChewing for macOS, Megrez language engine, Hotenka Chinese Converter, Tadokoro Candidate Window, 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 (NSSound ver.) and StringView Ranges Extension.
@ -16,7 +16,6 @@ $ Contributors and volunteers of the upstream repo, having no responsibility in
- Zonble Yang:
- McBopomofo for macOS 2.x architect.
- Voltaire candidate window MK2 (massively modified as MK3 in vChewing by Shiki Suen).
- App-style installer (only preserved for developer purposes).
- Mengjuei Hsieh:
- McBopomofo for macOS 1.x main developer and architect.

View File

@ -1,9 +0,0 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

View File

@ -1,28 +0,0 @@
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "Voltaire",
platforms: [
.macOS(.v10_11)
],
products: [
.library(
name: "Voltaire",
targets: ["Voltaire"]
)
],
dependencies: [
.package(path: "../vChewing_CandidateWindow"),
.package(path: "../vChewing_Shared"),
],
targets: [
.target(
name: "Voltaire",
dependencies: [
.product(name: "Shared", package: "vChewing_Shared"),
.product(name: "CandidateWindow", package: "vChewing_CandidateWindow"),
]
)
]
)

View File

@ -1,48 +0,0 @@
# Voltaire
Voltaire is a UI component replacement for Apple's InputMethodKit (IMK). The
built-in candidate UI has a limited interaction model and is not very
extensible nor customizable.
The project also comes with a test app that demonstrates the features of the
UI component.
Voltaire MK3 provides following new features comparing to MK1 and MK2:
1. A brand-new candidate window design conforming to the latest macOS UI design style, plus a floating label indicating the current page number of candidates (a frequently-asked feature by vChewing users).
2. One class for both vertical and horizontal display purposes. This can be specified as a parameter on init().
3. Can specify whether default candidate fonts conform to MOE glyphs standard or continental glyphs standard, requiring macOS 12 Monterey or later.
4. Can specify whether page buttons are shown.
Regarding the horizontal and vertical layout:
1. It is recommended to use init() in lieu of directly changing the layout variable since the latter doesn't redraw page buttons correctly.
2. Vertical candidate mode doesn't support scrolling. This is a deliberated design.
---
Copyrights:
```
- (c) 2022 Shiki Suen for all modifications introduced to Voltaire MK3.
- (c) 2021 Zonble Yang for rewriting Voltaire MK2 in Swift.
- (c) 2012 Lukhnos Liu for Voltaire MK1 development in Objective-C.
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.
```

View File

@ -1,596 +0,0 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
// Zonble Voltaire
import CandidateWindow
import Cocoa
import Shared
private class vwrCandidateUniversal: NSView {
var highlightedIndex: Int = 0 {
didSet { highlightedIndex = min(max(highlightedIndex, 0), dispCandidatesWithLabels.count - 1) }
}
var action: Selector?
weak var target: AnyObject?
weak var controller: AnyObject?
var isVerticalLayout = false
var fractionFontSize: Double = 12.0
private var keyLabels: [String] = []
private var displayedCandidates: [String] = []
private var dispCandidatesWithLabels: [String] = []
private var keyLabelHeight: Double = 0
private var keyLabelWidth: Double = 0
private var candidateTextHeight: Double = 0
private var cellPadding: Double = 0
private var keyLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var candidateWithLabelAttrDict: [NSAttributedString.Key: AnyObject] = [:]
private var windowWidth: Double = 0 //
private var elementWidths: [Double] = []
private var elementHeights: [Double] = [] //
private var trackingHighlightedIndex: Int = .max {
didSet { trackingHighlightedIndex = max(trackingHighlightedIndex, 0) }
}
override var isFlipped: Bool {
true
}
var sizeForView: NSSize {
var result = NSSize.zero
if !elementWidths.isEmpty {
switch isVerticalLayout {
case true:
result.width = windowWidth
result.height = elementHeights.reduce(0, +)
case false:
result.width = elementWidths.reduce(0, +) + Double(elementWidths.count)
result.height = candidateTextHeight + cellPadding
}
}
return result
}
func set(keyLabels labels: [String], displayedCandidates candidates: [String]) {
guard let delegate = (controller as? CtlCandidateUniversal)?.delegate else { return }
let candidates = candidates.map { theCandidate -> String in
let theConverted = delegate.kanjiConversionIfRequired(theCandidate)
return (theCandidate == theConverted) ? theCandidate : "\(theConverted)(\(theCandidate))"
}
let count = min(labels.count, candidates.count)
keyLabels = Array(labels[0..<count])
displayedCandidates = Array(candidates[0..<count])
dispCandidatesWithLabels = zip(keyLabels, displayedCandidates).map { $0 + $1 }
var newWidths = [Double]()
var calculatedWindowWidth = Double()
var newHeights = [Double]()
let baseSize = NSSize(width: 10240.0, height: 10240.0)
for index in 0..<count {
let rctCandidate = (dispCandidatesWithLabels[index] as NSString).boundingRect(
with: baseSize, options: .usesLineFragmentOrigin,
attributes: candidateWithLabelAttrDict
)
var cellWidth = rctCandidate.size.width + cellPadding
let cellHeight = rctCandidate.size.height + cellPadding
switch isVerticalLayout {
case true:
if calculatedWindowWidth < rctCandidate.size.width {
calculatedWindowWidth = rctCandidate.size.width + cellPadding * 2
}
case false:
if cellWidth < cellHeight * 1.4 {
cellWidth = cellHeight * 1.4
}
}
newWidths.append(round(cellWidth))
newHeights.append(round(cellHeight)) //
}
elementWidths = newWidths
elementHeights = newHeights
//
windowWidth = round(calculatedWindowWidth + cellPadding)
}
@objc(setKeyLabelFont:candidateFont:)
func set(keyLabelFont labelFont: NSFont, candidateFont: NSFont) {
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = isVerticalLayout ? .left : .center
candidateWithLabelAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // We still need this dummy section to make sure that
// the space occupations of the candidates are correct.
keyLabelAttrDict = [
.font: labelFont,
.paragraphStyle: paraStyle,
.verticalGlyphForm: true as AnyObject,
.foregroundColor: NSColor.secondaryLabelColor,
] // Candidate phrase text color
candidateAttrDict = [
.font: candidateFont,
.paragraphStyle: paraStyle,
.foregroundColor: NSColor.labelColor,
] // Candidate index text color
let labelFontSize = labelFont.pointSize
let candidateFontSize = candidateFont.pointSize
let biggestSize = max(labelFontSize, candidateFontSize)
fractionFontSize = round(biggestSize * 0.75)
keyLabelWidth = ceil(labelFontSize)
keyLabelHeight = ceil(labelFontSize * 2)
candidateTextHeight = ceil(candidateFontSize * 1.20)
cellPadding = ceil(biggestSize / 4.0) * 2
}
override func draw(_: NSRect) {
guard let controller = controller as? CtlCandidateUniversal else { return }
let bounds = bounds
NSColor.controlBackgroundColor.setFill() // Candidate list panel base background
NSBezierPath.fill(bounds)
switch isVerticalLayout {
case true:
var accuHeight: Double = 0
for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight
let rctCandidateArea = NSRect(
x: 3.0, y: accuHeight + 3.0, width: windowWidth - 6.0,
height: candidateTextHeight + cellPadding - 6.0
)
let rctLabel = NSRect(
x: cellPadding / 2 + 2, y: accuHeight + cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: cellPadding / 2 + 2 + keyLabelWidth, y: accuHeight + cellPadding / 2 - 1,
width: windowWidth - keyLabelWidth, height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex {
controller.highlightedColor().setFill()
// Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84)
// Highlightened phrase text color
activeCandidateAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
let path: NSBezierPath = .init(roundedRect: rctCandidateArea, xRadius: 6, yRadius: 6)
path.fill()
}
if #available(macOS 12, *) {
if controller.useLangIdentifier {
activeCandidateAttr[.languageIdentifier] = controller.locale as AnyObject
}
}
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuHeight += currentHeight
}
case false:
var accuWidth: Double = 0
for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth
let rctCandidateArea = NSRect(
x: accuWidth + 3.0, y: 3.0, width: currentWidth + 1.0 - 6.0,
height: candidateTextHeight + cellPadding - 6.0
)
let rctLabel = NSRect(
x: accuWidth + cellPadding / 2 - 1, y: cellPadding / 2, width: keyLabelWidth,
height: keyLabelHeight * 2.0
)
let rctCandidatePhrase = NSRect(
x: accuWidth + keyLabelWidth - 1, y: cellPadding / 2 - 1,
width: currentWidth - keyLabelWidth,
height: candidateTextHeight
)
var activeCandidateIndexAttr = keyLabelAttrDict
var activeCandidateAttr = candidateAttrDict
if index == highlightedIndex {
controller.highlightedColor().setFill()
// Highlightened index text color
activeCandidateIndexAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
.withAlphaComponent(0.84)
// Highlightened phrase text color
activeCandidateAttr[.foregroundColor] = NSColor.selectedMenuItemTextColor
let path: NSBezierPath = .init(roundedRect: rctCandidateArea, xRadius: 6, yRadius: 6)
path.fill()
}
if #available(macOS 12, *) {
if controller.useLangIdentifier {
activeCandidateAttr[.languageIdentifier] = controller.locale as AnyObject
}
}
(keyLabels[index] as NSString).draw(
in: rctLabel, withAttributes: activeCandidateIndexAttr
)
(displayedCandidates[index] as NSString).draw(
in: rctCandidatePhrase, withAttributes: activeCandidateAttr
)
accuWidth += currentWidth + 1.0
}
}
}
private func findHitIndex(event: NSEvent) -> Int {
let location = convert(event.locationInWindow, to: nil)
if !bounds.contains(location) {
return NSNotFound
}
switch isVerticalLayout {
case true:
var accuHeight = 0.0
for (index, elementHeight) in elementHeights.enumerated() {
let currentHeight = elementHeight
if location.y >= accuHeight, location.y <= accuHeight + currentHeight {
return index
}
accuHeight += currentHeight
}
case false:
var accuWidth = 0.0
for (index, elementWidth) in elementWidths.enumerated() {
let currentWidth = elementWidth
if location.x >= accuWidth, location.x <= accuWidth + currentWidth {
return index
}
accuWidth += currentWidth + 1.0
}
}
return NSNotFound
}
override func mouseUp(with event: NSEvent) {
trackingHighlightedIndex = highlightedIndex
let newIndex = findHitIndex(event: event)
guard newIndex != NSNotFound else {
return
}
highlightedIndex = newIndex
setNeedsDisplay(bounds)
}
override func mouseDown(with event: NSEvent) {
let newIndex = findHitIndex(event: event)
guard newIndex != NSNotFound else {
return
}
var triggerAction = false
if newIndex == highlightedIndex {
triggerAction = true
} else {
highlightedIndex = trackingHighlightedIndex
}
trackingHighlightedIndex = 0
setNeedsDisplay(bounds)
if triggerAction {
if let target = target as? NSObject, let action = action {
target.perform(action, with: self)
}
}
}
}
public class CtlCandidateUniversal: CtlCandidate {
private var candidateView: vwrCandidateUniversal
private var prevPageButton: NSButton
private var nextPageButton: NSButton
private var pageCounterLabel: NSTextField
private var currentPageIndex: Int = 0
override public var currentLayout: CandidateLayout {
get { candidateView.isVerticalLayout ? .vertical : .horizontal }
set {
switch newValue {
case .vertical: candidateView.isVerticalLayout = true
case .horizontal: candidateView.isVerticalLayout = false
}
}
}
public required init(_ layout: CandidateLayout = .horizontal) {
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
let panel = NSPanel(
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
)
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 2)
panel.hasShadow = true
panel.isOpaque = false
panel.backgroundColor = NSColor.clear
contentRect.origin = NSPoint.zero
candidateView = vwrCandidateUniversal(frame: contentRect)
candidateView.wantsLayer = true
// candidateView.layer?.borderColor = NSColor.selectedMenuItemTextColor.withAlphaComponent(0.20).cgColor
// candidateView.layer?.borderWidth = 1.0
if #available(macOS 10.13, *) {
candidateView.layer?.cornerRadius = 9.0
}
panel.contentView?.addSubview(candidateView)
// MARK: Add Buttons
contentRect.size = NSSize(width: 20.0, height: 10.0) // Reduce the button width
let buttonAttribute: [NSAttributedString.Key: Any] = [.font: NSFont.systemFont(ofSize: 9.0)]
nextPageButton = .init(frame: contentRect)
nextPageButton.wantsLayer = true
nextPageButton.layer?.masksToBounds = true
nextPageButton.layer?.borderColor = NSColor.clear.cgColor
nextPageButton.layer?.borderWidth = 0.0
nextPageButton.setButtonType(.momentaryLight)
nextPageButton.bezelStyle = .disclosure
nextPageButton.userInterfaceLayoutDirection = .leftToRight
nextPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Next Page Arrow
prevPageButton = .init(frame: contentRect)
prevPageButton.wantsLayer = true
prevPageButton.layer?.masksToBounds = true
prevPageButton.layer?.borderColor = NSColor.clear.cgColor
prevPageButton.layer?.borderWidth = 0.0
prevPageButton.setButtonType(.momentaryLight)
prevPageButton.bezelStyle = .disclosure
prevPageButton.userInterfaceLayoutDirection = .rightToLeft
prevPageButton.attributedTitle = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
) // Previous Page Arrow
panel.contentView?.addSubview(nextPageButton)
panel.contentView?.addSubview(prevPageButton)
// MARK: Add Page Counter
contentRect = NSRect(x: 128.0, y: 128.0, width: 48.0, height: 20.0)
pageCounterLabel = .init(frame: contentRect)
pageCounterLabel.isEditable = false
pageCounterLabel.isSelectable = false
pageCounterLabel.isBezeled = false
pageCounterLabel.attributedStringValue = NSMutableAttributedString(
string: " ", attributes: buttonAttribute
)
panel.contentView?.addSubview(pageCounterLabel)
// MARK: Post-Init()
super.init(layout)
window = panel
currentLayout = layout
candidateView.controller = self
candidateView.target = self
candidateView.action = #selector(candidateViewMouseDidClick(_:))
nextPageButton.target = self
nextPageButton.action = #selector(pageButtonAction(_:))
prevPageButton.target = self
prevPageButton.action = #selector(pageButtonAction(_:))
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func reloadData() {
candidateView.highlightedIndex = 0
currentPageIndex = 0
layoutCandidateView()
}
@discardableResult override public func showNextPage() -> Bool {
guard let delegate = delegate else { return false }
if pageCount == 1 { return highlightNextCandidate() }
if currentPageIndex + 1 >= pageCount { delegate.buzz() }
currentPageIndex = (currentPageIndex + 1 >= pageCount) ? 0 : currentPageIndex + 1
if currentPageIndex == pageCount - 1 {
candidateView.highlightedIndex = min(lastPageContentCount - 1, candidateView.highlightedIndex)
}
// candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
@discardableResult override public func showPreviousPage() -> Bool {
guard let delegate = delegate else { return false }
if pageCount == 1 { return highlightPreviousCandidate() }
if currentPageIndex == 0 { delegate.buzz() }
currentPageIndex = (currentPageIndex == 0) ? pageCount - 1 : currentPageIndex - 1
if currentPageIndex == pageCount - 1 {
candidateView.highlightedIndex = min(lastPageContentCount - 1, candidateView.highlightedIndex)
}
// candidateView.highlightedIndex = 0
layoutCandidateView()
return true
}
@discardableResult override public func highlightNextCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex + 1 >= delegate.candidatePairs().count)
? 0 : selectedCandidateIndex + 1
return true
}
@discardableResult override public func highlightPreviousCandidate() -> Bool {
guard let delegate = delegate else { return false }
selectedCandidateIndex =
(selectedCandidateIndex == 0)
? delegate.candidatePairs().count - 1 : selectedCandidateIndex - 1
return true
}
override public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int {
guard let delegate = delegate else {
return Int.max
}
let result = currentPageIndex * keyLabels.count + index
return result < delegate.candidatePairs().count ? result : Int.max
}
override public var selectedCandidateIndex: Int {
get {
currentPageIndex * keyLabels.count + candidateView.highlightedIndex
}
set {
guard let delegate = delegate else {
return
}
let keyLabelCount = keyLabels.count
if newValue < delegate.candidatePairs().count {
currentPageIndex = newValue / keyLabelCount
candidateView.highlightedIndex = newValue % keyLabelCount
layoutCandidateView()
}
}
}
}
extension CtlCandidateUniversal {
private var pageCount: Int {
guard let delegate = delegate else {
return 0
}
let totalCount = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
}
private var lastPageContentCount: Int {
guard let delegate = delegate else {
return 0
}
let totalCount = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count
return totalCount % keyLabelCount
}
private func layoutCandidateView() {
guard let delegate = delegate, let window = window else { return }
candidateView.set(keyLabelFont: keyLabelFont, candidateFont: candidateFont)
var candidates = [(String, String)]()
let count = delegate.candidatePairs().count
let keyLabelCount = keyLabels.count
let begin = currentPageIndex * keyLabelCount
for index in begin..<min(begin + keyLabelCount, count) {
let candidate = delegate.candidatePairAt(index)
candidates.append(candidate)
}
candidateView.set(
keyLabels: keyLabels.map(\.displayedText), displayedCandidates: candidates.map(\.1)
)
var newSize = candidateView.sizeForView
var frameRect = candidateView.frame
frameRect.size = newSize
candidateView.frame = frameRect
let counterHeight: Double = newSize.height - 24.0
if pageCount > 1, showPageButtons {
var buttonRect = nextPageButton.frame
let spacing = 0.0
if currentLayout == .horizontal { buttonRect.size.height = floor(newSize.height / 2) }
let buttonOriginY: Double = {
if currentLayout == .vertical {
return counterHeight
}
return (newSize.height - (buttonRect.size.height * 2.0 + spacing)) / 2.0
}()
buttonRect.origin = NSPoint(x: newSize.width, y: buttonOriginY)
nextPageButton.frame = buttonRect
buttonRect.origin = NSPoint(
x: newSize.width, y: buttonOriginY + buttonRect.size.height + spacing
)
prevPageButton.frame = buttonRect
newSize.width += 20
nextPageButton.isHidden = false
prevPageButton.isHidden = false
} else {
nextPageButton.isHidden = true
prevPageButton.isHidden = true
}
if pageCount >= 2 {
let attrString = NSMutableAttributedString(
string: "\(currentPageIndex + 1)/\(pageCount)",
attributes: [
.font: NSFont.systemFont(ofSize: candidateView.fractionFontSize)
]
)
pageCounterLabel.attributedStringValue = attrString
var rect = attrString.boundingRect(
with: NSSize(width: 1600.0, height: 1600.0),
options: .usesLineFragmentOrigin
)
rect.size.height += 3
rect.size.width += 4
let rectOriginY: Double =
(currentLayout == .horizontal)
? (newSize.height - rect.height) / 2
: counterHeight
let rectOriginX: Double =
showPageButtons
? newSize.width
: newSize.width + 4
rect.origin = NSPoint(x: rectOriginX, y: rectOriginY)
pageCounterLabel.frame = rect
newSize.width += rect.width + 4
pageCounterLabel.isHidden = false
} else {
pageCounterLabel.isHidden = true
}
frameRect = window.frame
let topLeftPoint = NSPoint(x: frameRect.origin.x, y: frameRect.origin.y + frameRect.size.height)
frameRect.size = newSize
frameRect.origin = NSPoint(x: topLeftPoint.x, y: topLeftPoint.y - frameRect.size.height)
window.setFrame(frameRect, display: false)
candidateView.setNeedsDisplay(candidateView.bounds)
}
@objc private func pageButtonAction(_ sender: Any) {
guard let sender = sender as? NSButton else {
return
}
if sender == nextPageButton {
_ = showNextPage()
} else if sender == prevPageButton {
_ = showPreviousPage()
}
}
@objc private func candidateViewMouseDidClick(_: Any) {
delegate?.candidatePairSelected(at: selectedCandidateIndex)
}
}

View File

@ -21,6 +21,10 @@ let package = Package(
dependencies: [
.product(name: "Shared", package: "vChewing_Shared")
]
)
),
.testTarget(
name: "CandidateWindowTests",
dependencies: ["CandidateWindow"]
),
]
)

View File

@ -1,6 +1,18 @@
# CandidateWindow
用以定義與威注音的選字窗有關的基礎內容,目前尚未完工。
用以定義與威注音的選字窗有關的基礎內容。此外,還包含了威注音自家的次世代選字窗「田所(TDK)」。
> 命名緣由:野獸先輩「田所」的姓氏。
TDK 選字窗以純 SwiftUI 構築,用以取代此前自上游繼承來的 Voltaire 選字窗。
然而TDK 選字窗目前有下述侷限:
- 因 SwiftUI 自身特性所導致的嚴重的效能問題。基本上來講,如果您經常使用全字庫模式的話,請在偏好設定內啟用效能更高的 IMK 選字窗。
- 同樣出於上述原因,為了讓田所選字窗至少處於可在生產力環境下正常使用的狀態,就犧牲了捲動檢視的功能。也就是說,每次只顯示三行,但顯示內容則隨著使用者的游標操作而更新。
- TDK 選字窗目前僅完成了橫版矩陣陳列模式的實作,且尚未引入對縱排選字窗陳列佈局的支援。
因為這些問題恐怕需要很久才能全部解決,所以威注音會在這段時間內推薦使用者們優先使用 IMK 選字窗。
```
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).

View File

@ -0,0 +1,135 @@
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
import Cocoa
import Shared
///
public class CandidatePool {
public let blankCell = CandidateCellData(key: " ", displayedText: " ", isSelected: false)
public var currentRowNumber = 0
public var maximumLinesPerPage = 3
public private(set) var selectionKeys: String
public private(set) var highlightedIndex: Int = 0
public private(set) var maxColumnCapacity: Int = 6
public private(set) var candidateDataAll: [CandidateCellData] = []
public private(set) var candidateRows: [[CandidateCellData]] = []
public var isVerticalLayout: Bool { maxColumnCapacity == 1 }
public var maxColumnWidth: Int { Int(Double(maxColumnCapacity + 3) * 2) * Int(ceil(CandidateCellData.unifiedSize)) }
public var maxWindowWidth: Double {
ceil(Double(maxColumnCapacity + 3) * 2.7 * ceil(CandidateCellData.unifiedSize) * 1.2)
}
public var rangeForCurrentPage: Range<Int> {
currentRowNumber..<min(candidateRows.count, currentRowNumber + maximumLinesPerPage)
}
public var rangeForLastPageBlanked: Range<Int> { 0..<(maximumLinesPerPage - rangeForCurrentPage.count) }
public enum VerticalDirection {
case up
case down
}
///
/// - Parameters:
/// - candidates:
/// - columnCapacity: (, )
public init(candidates: [String], columnCapacity: Int = 6, selectionKeys: String = "123456789", locale: String = "") {
maxColumnCapacity = max(1, columnCapacity)
self.selectionKeys = selectionKeys
candidateDataAll = candidates.map { .init(key: "0", displayedText: $0) }
var currentColumn: [CandidateCellData] = []
for (i, candidate) in candidateDataAll.enumerated() {
candidate.index = i
candidate.whichRow = candidateRows.count
let isOverflown: Bool = currentColumn.map(\.cellLength).reduce(0, +) + candidate.cellLength > maxColumnWidth
if isOverflown || currentColumn.count == maxColumnCapacity, !currentColumn.isEmpty {
candidateRows.append(currentColumn)
currentColumn.removeAll()
candidate.whichRow += 1
}
candidate.subIndex = currentColumn.count
candidate.locale = locale
currentColumn.append(candidate)
}
candidateRows.append(currentColumn)
}
public func selectNewNeighborRow(direction: VerticalDirection) {
let currentSubIndex = candidateDataAll[highlightedIndex].subIndex
var result = currentSubIndex
switch direction {
case .up:
if currentRowNumber <= 0 {
if candidateRows.isEmpty { break }
let firstRow = candidateRows[0]
let newSubIndex = min(currentSubIndex, firstRow.count - 1)
highlight(at: firstRow[newSubIndex].index)
break
}
if currentRowNumber >= candidateRows.count - 1 { currentRowNumber = candidateRows.count - 1 }
if candidateRows[currentRowNumber].count != candidateRows[currentRowNumber - 1].count {
let ratio: Double = min(1, Double(currentSubIndex) / Double(candidateRows[currentRowNumber].count))
result = Int(floor(Double(candidateRows[currentRowNumber - 1].count) * ratio))
}
let targetRow = candidateRows[currentRowNumber - 1]
let newSubIndex = min(result, targetRow.count - 1)
highlight(at: targetRow[newSubIndex].index)
case .down:
if currentRowNumber >= candidateRows.count - 1 {
if candidateRows.isEmpty { break }
let finalRow = candidateRows[candidateRows.count - 1]
let newSubIndex = min(currentSubIndex, finalRow.count - 1)
highlight(at: finalRow[newSubIndex].index)
break
}
if candidateRows[currentRowNumber].count != candidateRows[currentRowNumber + 1].count {
let ratio: Double = min(1, Double(currentSubIndex) / Double(candidateRows[currentRowNumber].count))
result = Int(floor(Double(candidateRows[currentRowNumber + 1].count) * ratio))
}
let targetRow = candidateRows[currentRowNumber + 1]
let newSubIndex = min(result, targetRow.count - 1)
highlight(at: targetRow[newSubIndex].index)
}
}
public func highlight(at indexSpecified: Int) {
var indexSpecified = indexSpecified
highlightedIndex = indexSpecified
if !(0..<candidateDataAll.count).contains(highlightedIndex) {
NSSound.beep()
switch highlightedIndex {
case candidateDataAll.count...:
currentRowNumber = candidateRows.count - 1
highlightedIndex = max(0, candidateDataAll.count - 1)
indexSpecified = highlightedIndex
case ..<0:
highlightedIndex = 0
currentRowNumber = 0
indexSpecified = highlightedIndex
default: break
}
}
for (i, candidate) in candidateDataAll.enumerated() {
candidate.isSelected = (indexSpecified == i)
if candidate.isSelected { currentRowNumber = candidate.whichRow }
}
for (i, candidateColumn) in candidateRows.enumerated() {
if i != currentRowNumber {
candidateColumn.forEach {
$0.key = " "
}
} else {
for (i, neta) in candidateColumn.enumerated() {
neta.key = selectionKeys.map { String($0) }[i]
}
}
}
}
}

View File

@ -10,8 +10,9 @@ import Cocoa
import Shared
open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
open var hint: String = ""
open var showPageButtons: Bool = false
open var currentLayout: CandidateLayout = .horizontal
open var currentLayout: NSUserInterfaceLayoutOrientation = .horizontal
open var locale: String = ""
open var useLangIdentifier: Bool = false
@ -21,7 +22,7 @@ open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
if #available(macOS 10.14, *), !NSApplication.isDarkMode, locale == "zh-Hant" {
colorBlendAmount = 0.15
}
// The background color of the highlightened candidate
//
switch locale {
case "zh-Hans":
result = NSColor.systemRed
@ -67,21 +68,18 @@ open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
}
}
public required init(_: CandidateLayout = .horizontal) {
public required init(_: NSUserInterfaceLayoutOrientation = .horizontal) {
super.init(window: .init())
visible = false
}
/// Sets the location of the candidate window.
///
///
/// Please note that the method has side effects that modifies
/// `windowTopLeftPoint` to make the candidate window to stay in at least
/// in a screen.
/// 使
///
/// - Parameters:
/// - windowTopLeftPoint: The given location.
/// - height: The height that helps the window not to be out of the bottom
/// of a screen.
/// - windowTopLeftPoint:
/// - heightDelta:
public func set(windowTopLeftPoint: NSPoint, bottomOutOfScreenAdjustmentHeight heightDelta: Double) {
DispatchQueue.main.async { [self] in
guard let window = window, var screenFrame = NSScreen.main?.visibleFrame else { return }
@ -106,16 +104,16 @@ open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
}
}
// MARK: - Contents that are not needed to be implemented here.
// MARK: -
@available(*, unavailable)
public required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
open var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
open var keyLabels: [CandidateCellData] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map {
CandidateKeyLabel(key: $0, displayedText: $0)
CandidateCellData(key: $0, displayedText: $0)
}
open var candidateFont = NSFont.systemFont(ofSize: 18)
@ -144,4 +142,6 @@ open class CtlCandidate: NSWindowController, CtlCandidateProtocol {
}
open func reloadData() {}
open func updateDisplay() {}
}

View File

@ -0,0 +1,122 @@
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
import Cocoa
import CocoaExtension
import Shared
import SwiftUI
@available(macOS 12, *)
public class CtlCandidateTDK: CtlCandidate {
public var thePool: CandidatePool = .init(candidates: [])
public var theView: VwrCandidateTDK { .init(controller: self, thePool: thePool, hint: hint) }
public required init(_ layout: NSUserInterfaceLayoutOrientation = .horizontal) {
var contentRect = NSRect(x: 128.0, y: 128.0, width: 0.0, height: 0.0)
let styleMask: NSWindow.StyleMask = [.nonactivatingPanel]
let panel = NSPanel(
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
)
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 2)
panel.hasShadow = true
panel.isOpaque = false
panel.backgroundColor = NSColor.clear
contentRect.origin = NSPoint.zero
super.init(layout)
window = panel
currentLayout = layout
reloadData()
}
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func reloadData() {
CandidateCellData.highlightBackground = highlightedColor()
CandidateCellData.unifiedSize = candidateFont.pointSize
guard let delegate = delegate else { return }
thePool = .init(
candidates: delegate.candidatePairs(conv: true).map(\.1),
selectionKeys: delegate.selectionKeys, locale: locale
)
thePool.highlight(at: 0)
updateDisplay()
}
override open func updateDisplay() {
DispatchQueue.main.async { [self] in
let newView = NSHostingView(rootView: theView.fixedSize())
let newSize = newView.fittingSize
var newFrame = NSRect.zero
if let window = window { newFrame = window.frame }
newFrame.size = newSize
window?.setFrame(newFrame, display: false)
window?.contentView = NSHostingView(rootView: theView.fixedSize())
window?.setContentSize(newSize)
}
}
@discardableResult override public func showNextPage() -> Bool {
for _ in 0..<thePool.maximumLinesPerPage {
thePool.selectNewNeighborRow(direction: .down)
}
updateDisplay()
return true
}
@discardableResult override public func showPreviousPage() -> Bool {
for _ in 0..<thePool.maximumLinesPerPage {
thePool.selectNewNeighborRow(direction: .up)
}
updateDisplay()
return true
}
@discardableResult public func showNextLine() -> Bool {
thePool.selectNewNeighborRow(direction: .down)
updateDisplay()
return true
}
@discardableResult public func showPreviousLine() -> Bool {
thePool.selectNewNeighborRow(direction: .up)
updateDisplay()
return true
}
@discardableResult override public func highlightNextCandidate() -> Bool {
thePool.highlight(at: thePool.highlightedIndex + 1)
updateDisplay()
return true
}
@discardableResult override public func highlightPreviousCandidate() -> Bool {
thePool.highlight(at: thePool.highlightedIndex - 1)
updateDisplay()
return true
}
override public func candidateIndexAtKeyLabelIndex(_ id: Int) -> Int {
let currentRow = thePool.candidateRows[thePool.currentRowNumber]
let actualID = max(0, min(id, currentRow.count - 1))
return thePool.candidateRows[thePool.currentRowNumber][actualID].index
}
override public var selectedCandidateIndex: Int {
get {
thePool.highlightedIndex
}
set {
thePool.highlight(at: newValue)
updateDisplay()
}
}
}

View File

@ -0,0 +1,127 @@
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
import Cocoa
import Shared
import SwiftUI
// MARK: - Some useless tests
@available(macOS 12, *)
struct CandidatePoolViewUI_Previews: PreviewProvider {
@State static var testCandidates: [String] = [
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "八月", "中秋",
"山林", "風吹", "大地", "草枝", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "",
]
static var thePool: CandidatePool {
let result = CandidatePool(candidates: testCandidates, columnCapacity: 6)
// 使
result.highlight(at: 14)
return result
}
static var previews: some View {
VwrCandidateTDK(controller: .init(.horizontal), thePool: thePool).fixedSize()
}
}
@available(macOS 12, *)
public struct VwrCandidateTDK: View {
public var controller: CtlCandidateTDK
@State public var thePool: CandidatePool
@State public var hint: String = ""
private var positionLabel: String {
(thePool.highlightedIndex + 1).description + "/" + thePool.candidateDataAll.count.description
}
private func didSelectCandidateAt(_ pos: Int) {
if let delegate = controller.delegate {
delegate.candidatePairSelected(at: pos)
}
}
public var body: some View {
VStack(alignment: .leading, spacing: 0) {
ScrollView(.vertical, showsIndicators: true) {
VStack(alignment: .leading, spacing: 1.6) {
ForEach(thePool.rangeForCurrentPage, id: \.self) { columnIndex in
HStack(spacing: 10) {
ForEach(Array(thePool.candidateRows[columnIndex]), id: \.self) { currentCandidate in
currentCandidate.attributedStringForSwiftUI.fixedSize()
.frame(maxWidth: .infinity, alignment: .topLeading)
.contentShape(Rectangle())
.onTapGesture { didSelectCandidateAt(currentCandidate.index) }
}
Spacer()
}.frame(
minWidth: 0,
maxWidth: .infinity,
alignment: .topLeading
).id(columnIndex)
Divider()
}
if thePool.maximumLinesPerPage - thePool.rangeForCurrentPage.count > 0 {
ForEach(thePool.rangeForLastPageBlanked, id: \.self) { _ in
HStack(spacing: 0) {
thePool.blankCell.attributedStringForSwiftUI.fixedSize()
.frame(maxWidth: .infinity, alignment: .topLeading)
.contentShape(Rectangle())
Spacer()
}.frame(
minWidth: 0,
maxWidth: .infinity,
alignment: .topLeading
)
Divider()
}
}
}
}
.fixedSize(horizontal: false, vertical: true).padding(5)
.background(Color(nsColor: NSColor.controlBackgroundColor).ignoresSafeArea())
HStack(alignment: .bottom) {
Text(hint).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)
}.padding(6).foregroundColor(.init(nsColor: .controlTextColor))
.shadow(color: .init(nsColor: .textBackgroundColor), radius: 1)
}
.frame(minWidth: thePool.maxWindowWidth, maxWidth: thePool.maxWindowWidth)
}
}
@available(macOS 12, *)
extension CandidateCellData {
public var attributedStringForSwiftUI: some View {
var result: some View {
ZStack(alignment: .leading) {
if isSelected {
Color(nsColor: CandidateCellData.highlightBackground).ignoresSafeArea().cornerRadius(6)
}
VStack(spacing: 0) {
HStack(spacing: 4) {
if UserDefaults.standard.bool(forKey: UserDef.kHandleDefaultCandidateFontsByLangIdentifier.rawValue) {
Text(AttributedString(attributedStringHeader)).frame(width: CandidateCellData.unifiedSize / 2)
Text(AttributedString(attributedString))
} else {
Text(key).font(.system(size: fontSizeKey).monospaced())
.foregroundColor(.init(nsColor: fontColorKey)).lineLimit(1)
Text(displayedText).font(.system(size: fontSizeCandidate))
.foregroundColor(.init(nsColor: fontColorCandidate)).lineLimit(1)
}
}.padding(4)
}
}.fixedSize(horizontal: false, vertical: true)
}
return result
}
}

View File

@ -0,0 +1,46 @@
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
import Cocoa
import XCTest
@testable import CandidateWindow
final class CandidatePoolTests: XCTestCase {
let testCandidates: [String] = [
"八月中秋山林涼", "八月中秋", "風吹大地", "山林涼", "草枝擺", "八月", "中秋",
"山林", "風吹", "大地", "草枝", "", "", "", "", "", "", "", "",
"", "", "", "",
]
func testPoolHorizontal() throws {
let pool = CandidatePool(candidates: testCandidates, columnCapacity: 8)
var strOutput = ""
pool.candidateRows.forEach {
$0.forEach {
strOutput += $0.displayedText + ", "
}
strOutput += "\n"
}
print("The matrix:")
print(strOutput)
}
func testPoolVertical() throws {
let pool = CandidatePool(candidates: testCandidates, columnCapacity: 8)
var strOutput = ""
pool.candidateRows.forEach {
$0.forEach {
strOutput += $0.displayedText + ", "
}
strOutput += "\n"
}
print("The matrix:")
print(strOutput)
}
}

View File

@ -1,4 +1,4 @@
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:

View File

@ -9,7 +9,7 @@
import Foundation
import InputMethodKit
// MARK: - TISInputSource Extension by The vChewing Project (MIT License).
// MARK: - TISInputSource Extension by The vChewing Project (MIT-NTL License).
extension TISInputSource {
public static var allRegisteredInstancesOfThisInputMethod: [TISInputSource] {

View File

@ -21,17 +21,33 @@ public class Notifier: NSWindowController {
}
}
private var currentMessage: String //
private var isNew = true //
// MARK: - Private Declarations
private static var instanceStack: [Notifier] = []
private let blankValue = ""
@discardableResult private init(_ message: String) {
currentMessage = message
let rawMessage = message.replacingOccurrences(of: "\n", with: "")
guard let screenRect = NSScreen.main?.visibleFrame, !rawMessage.isEmpty else {
let isDuplicated: Bool = {
if let firstInstanceExisted = Self.instanceStack.first {
return message == firstInstanceExisted.currentMessage && firstInstanceExisted.isNew
}
return false
}()
guard let screenRect = NSScreen.main?.visibleFrame, !rawMessage.isEmpty, !isDuplicated else {
super.init(window: nil)
return
}
//
defer { // 0.3 false
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.isNew = false
}
}
let kLargeFontSize: Double = 17
let kSmallFontSize: Double = 15
let messageArray = message.components(separatedBy: "\n")
@ -142,7 +158,10 @@ extension Notifier {
private func display() {
let existingInstanceArray = Self.instanceStack.compactMap(\.window)
if !existingInstanceArray.isEmpty {
existingInstanceArray.forEach { $0.alphaValue *= 0.5 }
existingInstanceArray.forEach {
$0.alphaValue -= 0.1
$0.contentView?.subviews.forEach { $0.alphaValue *= 0.5 }
}
}
shiftExistingWindowPositions()
fadeIn()

View File

@ -0,0 +1,116 @@
// (c) 2022 and onwards The vChewing Project (MIT-NTL License).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
// ... with NTL restriction stating that:
// 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 defined in MIT License.
import Cocoa
// MARK: - Classes used by Candidate Window
/// class 便
public class CandidateCellData: Hashable {
public var locale = ""
public static var unifiedSize: Double = 16
public static var highlightBackground: NSColor = {
if #available(macOS 10.14, *) {
return .selectedContentBackgroundColor
}
return NSColor.alternateSelectedControlColor
}()
public var key: String
public var displayedText: String
public var size: Double { Self.unifiedSize }
public var isSelected: Bool = false
public var whichRow: Int = 0
public var index: Int = 0
public var subIndex: Int = 0
public var fontSizeCandidate: Double { CandidateCellData.unifiedSize }
public var fontSizeKey: Double { ceil(CandidateCellData.unifiedSize * 0.8) }
public var fontColorKey: NSColor {
isSelected ? .selectedMenuItemTextColor.withAlphaComponent(0.8) : .secondaryLabelColor
}
public var fontColorCandidate: NSColor { isSelected ? .selectedMenuItemTextColor : .labelColor }
public init(key: String, displayedText: String, isSelected: Bool = false) {
self.key = key
self.displayedText = displayedText
self.isSelected = isSelected
}
public var cellLength: Int {
if displayedText.count <= 2 { return Int(ceil(size * 3)) }
let rect = attributedStringForLengthCalculation.boundingRect(
with: NSSize(width: 1600.0, height: 1600.0), options: [.usesLineFragmentOrigin]
)
let rawResult = ceil(rect.width + size / size)
return Int(rawResult)
}
public var attributedStringHeader: NSAttributedString {
let paraStyleKey = NSMutableParagraphStyle()
paraStyleKey.setParagraphStyle(NSParagraphStyle.default)
paraStyleKey.alignment = .natural
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .natural
var attrKey: [NSAttributedString.Key: AnyObject] = [
.font: NSFont.monospacedDigitSystemFont(ofSize: size * 0.7, weight: .regular),
.paragraphStyle: paraStyleKey,
]
if isSelected {
attrKey[.foregroundColor] = NSColor.white.withAlphaComponent(0.8)
} else {
attrKey[.foregroundColor] = NSColor.secondaryLabelColor
}
let attrStrKey = NSMutableAttributedString(string: key, attributes: attrKey)
return attrStrKey
}
public var attributedStringForLengthCalculation: NSAttributedString {
let attrCandidate: [NSAttributedString.Key: AnyObject] = [
.font: NSFont.monospacedDigitSystemFont(ofSize: size, weight: .regular)
]
let attrStrCandidate = NSMutableAttributedString(string: displayedText + " ", attributes: attrCandidate)
return attrStrCandidate
}
public var attributedString: NSAttributedString {
let paraStyleKey = NSMutableParagraphStyle()
paraStyleKey.setParagraphStyle(NSParagraphStyle.default)
paraStyleKey.alignment = .natural
let paraStyle = NSMutableParagraphStyle()
paraStyle.setParagraphStyle(NSParagraphStyle.default)
paraStyle.alignment = .natural
var attrCandidate: [NSAttributedString.Key: AnyObject] = [
.font: NSFont.monospacedDigitSystemFont(ofSize: size, weight: .regular),
.paragraphStyle: paraStyle,
]
if isSelected {
attrCandidate[.foregroundColor] = NSColor.white
} else {
attrCandidate[.foregroundColor] = NSColor.labelColor
}
if #available(macOS 12, *) {
if UserDefaults.standard.bool(forKey: UserDef.kHandleDefaultCandidateFontsByLangIdentifier.rawValue) {
attrCandidate[.languageIdentifier] = self.locale as AnyObject
}
}
let attrStrCandidate = NSMutableAttributedString(string: displayedText, attributes: attrCandidate)
return attrStrCandidate
}
public static func == (lhs: CandidateCellData, rhs: CandidateCellData) -> Bool {
lhs.key == rhs.key && lhs.displayedText == rhs.displayedText
}
public func hash(into hasher: inout Hasher) {
hasher.combine(key)
hasher.combine(displayedText)
}
}

View File

@ -9,29 +9,32 @@
import Cocoa
public protocol CtlCandidateDelegate: AnyObject {
func candidatePairs() -> [(String, String)]
func candidatePairs(conv: Bool) -> [(String, String)]
func candidatePairAt(_ index: Int) -> (String, String)
func candidatePairSelected(at index: Int)
func candidates(_ sender: Any!) -> [Any]!
func buzz()
func kanjiConversionIfRequired(_ target: String) -> String
var selectionKeys: String { get }
}
public protocol CtlCandidateProtocol {
var hint: String { get set }
var locale: String { get set }
var currentLayout: CandidateLayout { get set }
var currentLayout: NSUserInterfaceLayoutOrientation { get set }
var delegate: CtlCandidateDelegate? { get set }
var selectedCandidateIndex: Int { get set }
var visible: Bool { get set }
var windowTopLeftPoint: NSPoint { get set }
var keyLabels: [CandidateKeyLabel] { get set }
var keyLabels: [CandidateCellData] { get set }
var keyLabelFont: NSFont { get set }
var candidateFont: NSFont { get set }
var tooltip: String { get set }
var useLangIdentifier: Bool { get set }
var showPageButtons: Bool { get set }
init(_ layout: CandidateLayout)
init(_ layout: NSUserInterfaceLayoutOrientation)
func reloadData()
func updateDisplay()
func showNextPage() -> Bool
func showPreviousPage() -> Bool
func highlightNextCandidate() -> Bool

View File

@ -103,23 +103,6 @@ public enum UserDef: String, CaseIterable {
}
}
// MARK: - Enums and Structs used by Candidate Window
public enum CandidateLayout {
case horizontal
case vertical
}
public struct CandidateKeyLabel {
public private(set) var key: String
public private(set) var displayedText: String
public init(key: String, displayedText: String) {
self.key = key
self.displayedText = displayedText
}
}
// MARK: - Tooltip Color States
public enum TooltipColorState {

View File

@ -91,7 +91,6 @@ P.S.: 威注音输入法的 Shift 按键监测功能仅借由对 NSEvent 讯号
威注音专案目前仅用到小麦注音的下述程式组件MIT License
- 仅供研发人员调试方便而使用的 App 版安装程式 (by Zonble Yang),不对公众使用。
- Voltaire MK2 选字窗 (by Zonble Yang),有大幅度修改。
威注音专案目前还用到如下的来自 Lukhnos Liu 的算法:

View File

@ -91,7 +91,6 @@ P.S.: 威注音輸入法的 Shift 按鍵監測功能僅藉由對 NSEvent 訊號
威注音專案目前僅用到小麥注音的下述程式組件MIT License
- 僅供研發人員調試方便而使用的 App 版安裝程式 (by Zonble Yang),不對公眾使用。
- Voltaire MK2 選字窗 (by Zonble Yang),有大幅度修改。
威注音專案目前還用到如下的來自 Lukhnos Liu 的算法:

@ -1 +1 @@
Subproject commit 6f71610f126eee8efcce4a4ff832bec03af7c79b
Subproject commit 0d626ef32f831357ca83aead519bba2970e997de

View File

@ -8,6 +8,7 @@
/// 調
import CandidateWindow
import Shared
// MARK: - § 調 (Handle Candidate State).
@ -133,6 +134,8 @@ extension KeyHandler {
if !ctlCandidate.showPreviousPage() {
errorCallback("1919810D")
}
@unknown default:
break
}
return true
}
@ -149,6 +152,8 @@ extension KeyHandler {
if !ctlCandidate.showNextPage() {
errorCallback("9244908D")
}
@unknown default:
break
}
return true
}
@ -158,13 +163,28 @@ extension KeyHandler {
if input.isUp {
switch ctlCandidate.currentLayout {
case .horizontal:
if !ctlCandidate.showPreviousPage() {
errorCallback("9B614524")
if #available(macOS 12, *) {
if let ctlCandidate = ctlCandidate as? CtlCandidateTDK {
ctlCandidate.showPreviousLine()
break
} else {
if !ctlCandidate.showPreviousPage() {
errorCallback("9B614524")
break
}
}
} else {
if !ctlCandidate.showPreviousPage() {
errorCallback("9B614524")
break
}
}
case .vertical:
if !ctlCandidate.highlightPreviousCandidate() {
errorCallback("ASD9908D")
}
@unknown default:
break
}
return true
}
@ -174,13 +194,28 @@ extension KeyHandler {
if input.isDown {
switch ctlCandidate.currentLayout {
case .horizontal:
if !ctlCandidate.showNextPage() {
errorCallback("92B990DD")
if #available(macOS 12, *) {
if let ctlCandidate = ctlCandidate as? CtlCandidateTDK {
ctlCandidate.showNextLine()
break
} else {
if !ctlCandidate.showNextPage() {
errorCallback("92B990DD")
break
}
}
} else {
if !ctlCandidate.showNextPage() {
errorCallback("92B990DD")
break
}
}
case .vertical:
if !ctlCandidate.highlightNextCandidate() {
errorCallback("6B99908D")
}
@unknown default:
break
}
return true
}
@ -223,7 +258,7 @@ extension KeyHandler {
(state.type == .ofAssociates) ? input.inputTextIgnoringModifiers ?? "" : input.text
for j in 0..<ctlCandidate.keyLabels.count {
let label: CandidateKeyLabel = ctlCandidate.keyLabels[j]
let label: CandidateCellData = ctlCandidate.keyLabels[j]
if match.compare(label.key, options: .caseInsensitive, range: nil, locale: .current) == .orderedSame {
index = j
break
@ -286,8 +321,16 @@ extension KeyHandler {
// MARK: - Flipping pages by using symbol menu keys (when they are not occupied).
if input.isSymbolMenuPhysicalKey {
let updated: Bool =
input.isShiftHold ? ctlCandidate.showPreviousPage() : ctlCandidate.showNextPage()
var updated = true
if #available(macOS 12, *) {
if let ctlCandidate = ctlCandidate as? CtlCandidateTDK {
updated = input.isShiftHold ? ctlCandidate.showPreviousLine() : ctlCandidate.showNextLine()
} else {
updated = input.isShiftHold ? ctlCandidate.showPreviousPage() : ctlCandidate.showNextPage()
}
} else {
updated = input.isShiftHold ? ctlCandidate.showPreviousPage() : ctlCandidate.showNextPage()
}
if !updated {
errorCallback("66F3477B")
}

View File

@ -56,9 +56,7 @@ extension KeyHandler {
// MARK: Caps Lock processing.
/// Caps Lock
/// Shift Chromium
/// IMK Shift 使
/// Caps Lock
/// Caps Lock
if input.isBackSpace || input.isEnter
|| input.isCursorClockLeft || input.isCursorClockRight
|| input.isCursorForward || input.isCursorBackward

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)

View File

@ -15,7 +15,7 @@ extension PrefMgr {
// macOS 10.11 IMK macOS 10.13 IMK
// IMK macOS 10.09
// macOS 10.14 IMKCandidates
if #unavailable(macOS 10.13) { useIMKCandidateWindow = false }
if #unavailable(macOS 12) { useIMKCandidateWindow = true }
if #unavailable(macOS 10.15) {
handleDefaultCandidateFontsByLangIdentifier = false
shiftKeyAccommodationBehavior = 0

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
@ -8,12 +6,13 @@
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
import CandidateWindow
import CocoaExtension
import IMKUtils
import PopupCompositionBuffer
import Shared
import ShiftKeyUpChecker
import TooltipUI
import Voltaire
///
///
@ -29,8 +28,16 @@ class SessionCtl: IMKInputController {
static var areWeNerfing = false
///
static var ctlCandidateCurrent: CtlCandidateProtocol =
PrefMgr.shared.useIMKCandidateWindow ? CtlCandidateIMK(.horizontal) : CtlCandidateUniversal(.horizontal)
static var ctlCandidateCurrent: CtlCandidateProtocol = {
let direction: NSUserInterfaceLayoutOrientation =
PrefMgr.shared.useHorizontalCandidateList ? .horizontal : .vertical
if #available(macOS 12, *) {
return PrefMgr.shared.useIMKCandidateWindow
? CtlCandidateIMK(direction) : CtlCandidateTDK(direction)
} else {
return CtlCandidateIMK(direction)
}
}()
///
static var tooltipInstance = TooltipUI()
@ -40,6 +47,9 @@ class SessionCtl: IMKInputController {
// MARK: -
/// CapsLock
var isCapsLocked: Bool { NSEvent.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(.capsLock) }
/// SessionCtl
var isASCIIMode = false {
didSet {
@ -159,7 +169,8 @@ extension SessionCtl {
keyHandler.clear() // handle State.Empty()
keyHandler.ensureKeyboardParser()
if isASCIIMode, PrefMgr.shared.disableShiftTogglingAlphanumericalMode { isASCIIMode = false }
if isASCIIMode, !isCapsLocked, PrefMgr.shared.disableShiftTogglingAlphanumericalMode { isASCIIMode = false }
if isCapsLocked { isASCIIMode = isCapsLocked } // CapsLock
///
/// macOS

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
@ -48,16 +46,24 @@ extension SessionCtl: KeyHandlerDelegate {
// MARK: - Candidate Controller Delegate
extension SessionCtl: CtlCandidateDelegate {
var selectionKeys: String { PrefMgr.shared.candidateKeys }
func buzz() {
IMEApp.buzz()
}
func kanjiConversionIfRequired(_ target: String) -> String {
ChineseConverter.kanjiConversionIfRequired(target)
}
func candidatePairs() -> [(String, String)] {
state.isCandidateContainer ? state.candidates : []
func candidatePairs(conv: Bool = false) -> [(String, String)] {
if !state.isCandidateContainer || state.candidates.isEmpty { return [] }
if !conv || PrefMgr.shared.cns11643Enabled || state.candidates[0].0.contains("_punctuation") {
return state.candidates
}
let convertedCandidates: [(String, String)] = state.candidates.map { theCandidatePair -> (String, String) in
let theCandidate = theCandidatePair.1
let theConverted = ChineseConverter.kanjiConversionIfRequired(theCandidate)
let result = (theCandidate == theConverted) ? theCandidate : "\(theConverted)(\(theCandidate))"
return (theCandidatePair.0, result)
}
return convertedCandidates
}
func candidatePairAt(_ index: Int) -> (String, String) {

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
@ -8,9 +6,9 @@
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
import CandidateWindow
import NSAttributedTextView
import Shared
import Voltaire
// MARK: - Tooltip Display and Candidate Display Methods
@ -74,21 +72,20 @@ extension SessionCtl {
func showCandidates() {
guard let client = client() else { return }
var isCandidateWindowVertical: Bool {
var candidates: [(String, String)] = .init()
if state.isCandidateContainer {
candidates = state.candidates
}
// var candidates: [(String, String)] = .init()
// if state.isCandidateContainer { candidates = state.candidates }
if isVerticalTyping { return true }
// IMK
guard Self.ctlCandidateCurrent is CtlCandidateUniversal else { return false }
// guard Self.ctlCandidateCurrent is CtlCandidateUniversal else { return false }
// 使
//
// 使
// Beer emoji
let maxCandidatesPerPage = PrefMgr.shared.candidateKeys.count
let firstPageCandidates = candidates[0..<min(maxCandidatesPerPage, candidates.count)].map(\.1)
return firstPageCandidates.joined().count > Int(round(Double(maxCandidatesPerPage) * 1.8))
// let maxCandidatesPerPage = PrefMgr.shared.candidateKeys.count
// let firstPageCandidates = candidates[0..<min(maxCandidatesPerPage, candidates.count)].map(\.1)
// return firstPageCandidates.joined().count > Int(round(Double(maxCandidatesPerPage) * 1.8))
// true
return false
}
state.isVerticalCandidateWindow = (isCandidateWindowVertical || !PrefMgr.shared.useHorizontalCandidateList)
@ -101,14 +98,18 @@ extension SessionCtl {
/// layoutCandidateView
/// macOS 10.x SwiftUI
let candidateLayout: CandidateLayout =
let candidateLayout: NSUserInterfaceLayoutOrientation =
((isCandidateWindowVertical || !PrefMgr.shared.useHorizontalCandidateList)
? CandidateLayout.vertical
: CandidateLayout.horizontal)
? .vertical
: .horizontal)
Self.ctlCandidateCurrent =
PrefMgr.shared.useIMKCandidateWindow
? CtlCandidateIMK(candidateLayout) : CtlCandidateUniversal(candidateLayout)
if #available(macOS 12, *) {
Self.ctlCandidateCurrent =
PrefMgr.shared.useIMKCandidateWindow
? CtlCandidateIMK(candidateLayout) : CtlCandidateTDK(candidateLayout)
} else {
Self.ctlCandidateCurrent = CtlCandidateIMK(candidateLayout)
}
// set the attributes for the candidate panel (which uses NSAttributedString)
let textSize = PrefMgr.shared.candidateListTextSize
@ -134,10 +135,13 @@ extension SessionCtl {
candidateKeys.count > 4 ? Array(candidateKeys) : Array(CandidateKey.defaultKeys)
let keyLabelSuffix = state.type == .ofAssociates ? "^" : ""
Self.ctlCandidateCurrent.keyLabels = keyLabels.map {
CandidateKeyLabel(key: String($0), displayedText: String($0) + keyLabelSuffix)
CandidateCellData(key: String($0), displayedText: String($0) + keyLabelSuffix)
}
if state.type == .ofAssociates {
Self.ctlCandidateCurrent.hint = NSLocalizedString("Hold ⇧ to choose associates.", comment: "")
}
Self.ctlCandidateCurrent.delegate = self
Self.ctlCandidateCurrent.showPageButtons = PrefMgr.shared.showPageButtonsInCandidateWindow
Self.ctlCandidateCurrent.useLangIdentifier = PrefMgr.shared.handleDefaultCandidateFontsByLangIdentifier
Self.ctlCandidateCurrent.locale = {
@ -151,7 +155,6 @@ extension SessionCtl {
default: return ""
}
}()
Self.ctlCandidateCurrent.reloadData()
if #available(macOS 10.14, *) {
// Spotlight IMK
@ -162,6 +165,7 @@ extension SessionCtl {
}
}
Self.ctlCandidateCurrent.delegate = self
Self.ctlCandidateCurrent.visible = true
if isVerticalTyping {

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)
@ -8,6 +6,7 @@
// marks, or product names of Contributor, except as required to fulfill notice
// requirements defined in MIT License.
import CocoaExtension
import InputMethodKit
import NotifierUI
import Shared
@ -36,6 +35,18 @@ extension SessionCtl {
return false
}
// Caps Lock
if event.type == .flagsChanged, event.keyCode == KeyCode.kCapsLock.rawValue {
let isCapsLockTurnedOn = event.modifierFlags.intersection(.deviceIndependentFlagsMask).contains(.capsLock)
let status = NSLocalizedString("NotificationSwitchASCII", comment: "")
Notifier.notify(
message: isCapsLockTurnedOn
? "Caps Lock" + NSLocalizedString("Alphanumerical Input Mode", comment: "") + "\n" + status
: NSLocalizedString("Chinese Input Mode", comment: "") + "\n" + status
)
isASCIIMode = isCapsLockTurnedOn
}
// Shift macOS 10.15 macOS
let shouldUseShiftToggleHandle: Bool = {
switch PrefMgr.shared.shiftKeyAccommodationBehavior {
@ -50,7 +61,7 @@ extension SessionCtl {
if #available(macOS 10.15, *) {
if Self.theShiftKeyDetector.check(event), !PrefMgr.shared.disableShiftTogglingAlphanumericalMode {
if !shouldUseShiftToggleHandle || (!rencentKeyHandledByKeyHandlerEtc && shouldUseShiftToggleHandle) {
let status = NSLocalizedString("NotificationSwitchShift", comment: "")
let status = NSLocalizedString("NotificationSwitchASCII", comment: "")
Notifier.notify(
message: isASCIIMode.toggled()
? NSLocalizedString("Alphanumerical Input Mode", comment: "") + "\n" + status
@ -67,7 +78,7 @@ extension SessionCtl {
// MARK:
// Shift
if isASCIIMode { return false }
if isASCIIMode, !isCapsLocked { return false }
/// flags使 KeyHandler
/// flags
@ -185,6 +196,7 @@ extension SessionCtl {
switch imkC.currentLayout {
case .horizontal: _ = event.isShiftHold ? imkC.moveUp(self) : imkC.moveDown(self)
case .vertical: _ = event.isShiftHold ? imkC.moveLeft(self) : imkC.moveRight(self)
@unknown default: break
}
return true
} else if event.isSpace {

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)

View File

@ -1,5 +1,3 @@
// (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).
// ====================
// This code is released under the MIT license (SPDX-License-Identifier: MIT)

View File

@ -11,10 +11,11 @@ import Shared
/// IMKCandidates bridging header Swift Package
public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
public var hint: String = ""
public var showPageButtons: Bool = false
public var locale: String = ""
public var useLangIdentifier: Bool = false
public var currentLayout: CandidateLayout = .horizontal
public var currentLayout: NSUserInterfaceLayoutOrientation = .horizontal
public static let defaultIMKSelectionKey: [UInt16: String] = [
18: "1", 19: "2", 20: "3", 21: "4", 23: "5", 22: "6", 26: "7", 28: "8", 25: "9",
]
@ -38,9 +39,9 @@ public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
}
}
public var keyLabels: [CandidateKeyLabel] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
public var keyLabels: [CandidateCellData] = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
.map {
CandidateKeyLabel(key: $0, displayedText: $0)
CandidateCellData(key: $0, displayedText: $0)
}
public var keyLabelFont = NSFont.monospacedDigitSystemFont(
@ -68,7 +69,7 @@ public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
var keyCount = 0
var displayedCandidates = [String]()
public func specifyLayout(_ layout: CandidateLayout = .horizontal) {
public func specifyLayout(_ layout: NSUserInterfaceLayoutOrientation = .horizontal) {
currentLayout = layout
switch currentLayout {
case .horizontal:
@ -80,10 +81,14 @@ public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
}
case .vertical:
setPanelType(kIMKSingleColumnScrollingCandidatePanel)
@unknown default:
setPanelType(kIMKSingleRowSteppingCandidatePanel)
}
}
public required init(_ layout: CandidateLayout = .horizontal) {
public func updateDisplay() {}
public required init(_ layout: NSUserInterfaceLayoutOrientation = .horizontal) {
super.init(server: theServer, panelType: kIMKScrollingGridCandidatePanel)
specifyLayout(layout)
// true ctlIME
@ -115,7 +120,7 @@ public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
private var pageCount: Int {
guard let delegate = delegate else { return 0 }
let totalCount = delegate.candidatePairs().count
let totalCount = delegate.candidatePairs(conv: false).count
let keyLabelCount = keyLabels.count
return totalCount / keyLabelCount + ((totalCount % keyLabelCount) != 0 ? 1 : 0)
}
@ -147,7 +152,7 @@ public class CtlCandidateIMK: IMKCandidates, CtlCandidateProtocol {
public func candidateIndexAtKeyLabelIndex(_ index: Int) -> Int {
guard let delegate = delegate else { return Int.max }
let result = currentPageIndex * keyLabels.count + index
return result < delegate.candidatePairs().count ? result : Int.max
return result < delegate.candidatePairs(conv: false).count ? result : Int.max
}
public var selectedCandidateIndex: Int {

View File

@ -50,20 +50,22 @@ struct suiPrefPaneDevZone: View {
)
.fixedSize(horizontal: false, vertical: true)
Divider()
Toggle(
LocalizedStringKey("Use IMK Candidate Window instead (will reboot the IME)"),
isOn: $selUseIMKCandidateWindow.onChange {
PrefMgr.shared.useIMKCandidateWindow = selUseIMKCandidateWindow
NSLog("vChewing App self-terminated due to enabling / disabling IMK candidate window.")
NSApplication.shared.terminate(nil)
}
)
Text(
LocalizedStringKey(
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases."
if #available(macOS 12, *) {
Toggle(
LocalizedStringKey("Use IMK Candidate Window instead of Tadokoro (will reboot the IME)"),
isOn: $selUseIMKCandidateWindow.onChange {
PrefMgr.shared.useIMKCandidateWindow = selUseIMKCandidateWindow
NSLog("vChewing App self-terminated due to enabling / disabling IMK candidate window.")
NSApplication.shared.terminate(nil)
}
)
)
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
Text(
LocalizedStringKey(
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements."
)
)
.preferenceDescription().fixedSize(horizontal: false, vertical: true)
}
Toggle(
LocalizedStringKey("Use .langIdentifier to handle UI fonts in candidate window"),
isOn: $selHandleDefaultCandidateFontsByLangIdentifier.onChange {
@ -74,7 +76,7 @@ struct suiPrefPaneDevZone: View {
.disabled(!isMontereyOrAbove)
Text(
LocalizedStringKey(
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later."
"This only works with Tadokoro candidate window."
)
)
.preferenceDescription().fixedSize(horizontal: false, vertical: true)

View File

@ -129,7 +129,7 @@ struct suiPrefPaneDictionary: View {
}
)
Toggle(
LocalizedStringKey("Enable CNS11643 Support (2022-08-02)"),
LocalizedStringKey("Enable CNS11643 Support (2022-09-12)"),
isOn: $selEnableCNS11643.onChange {
PrefMgr.shared.cns11643Enabled = selEnableCNS11643
LMMgr.setCNSEnabled(PrefMgr.shared.cns11643Enabled)

View File

@ -129,16 +129,18 @@ struct suiPrefPaneGeneral: View {
.labelsHidden()
.horizontalRadioGroupLayout()
.pickerStyle(RadioGroupPickerStyle())
Text(LocalizedStringKey("Choose your preferred layout of the candidate window."))
.disabled(!PrefMgr.shared.useIMKCandidateWindow)
if PrefMgr.shared.useIMKCandidateWindow {
Text(LocalizedStringKey("Choose your preferred layout of the candidate window."))
.preferenceDescription()
} else {
Text(
LocalizedStringKey(
"Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window."
)
)
.preferenceDescription()
Toggle(
LocalizedStringKey("Show page buttons in candidate window"),
isOn: $selShowPageButtonsInCandidateUI.onChange {
PrefMgr.shared.showPageButtonsInCandidateWindow = selShowPageButtonsInCandidateUI
}
)
.controlSize(.small)
.disabled(PrefMgr.shared.useIMKCandidateWindow)
}
}
Preferences.Section(label: { Text(LocalizedStringKey("Output Settings:")) }) {
Toggle(

View File

@ -225,7 +225,7 @@ struct suiPrefPaneKeyboard: View {
HStack {
Text(
NSLocalizedString(
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key.",
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only.",
comment: ""
)
)

View File

@ -135,6 +135,7 @@ class ctlPrefWindow: NSWindowController {
}
selectionKeyComboBox.stringValue = candidateSelectionKeys
selectionKeyComboBox.isEnabled = false // IMKCandidates
}
// CNS
@ -281,8 +282,9 @@ extension ctlPrefWindow: NSToolbarDelegate {
}
var toolbarIdentifiers: [NSToolbarItem.Identifier] {
if #unavailable(macOS 10.13) { return [.ofGeneral, .ofExperience, .ofDictionary, .ofKeyboard] }
return [.ofGeneral, .ofExperience, .ofDictionary, .ofKeyboard, .ofDevZone]
// if #unavailable(macOS 10.13) { return [.ofGeneral, .ofExperience, .ofDictionary, .ofKeyboard] }
// return [.ofGeneral, .ofExperience, .ofDictionary, .ofKeyboard, .ofDevZone]
[.ofGeneral, .ofExperience, .ofDictionary, .ofKeyboard]
}
func toolbarDefaultItemIdentifiers(_: NSToolbar) -> [NSToolbarItem.Identifier] {

View File

@ -38,7 +38,7 @@
"Force KangXi Writing" = "Force KangXi Writing";
"NotificationSwitchON" = "✔ ON";
"NotificationSwitchOFF" = "✘ OFF";
"NotificationSwitchShift" = "↺ Switched";
"NotificationSwitchASCII" = "↺ Switched";
"Edit User Phrases…" = "Edit User Phrases…";
"Reload User Phrases" = "Reload User Phrases";
"Unable to create the user phrase file." = "Unable to create the user phrase file.";
@ -82,7 +82,7 @@
"Optimize Memorized Phrases" = "Optimize Memorized Phrases";
"Clear Memorized Phrases" = "Clear Memorized Phrases";
"Currency Numeral Output" = "Currency Numeral Output";
"Alphanumerical Mode" = "Alphanumerical Mode";
"Hold ⇧ to choose associates." = "Hold ⇧ to choose associates.";
// The followings are the category names used in the Symbol menu.
"catCommonSymbols" = "CommonSymbols";
@ -145,7 +145,7 @@
"Choose the behavior of (Shift+)Tab key in the candidate window." = "Choose the behavior of (Shift+)Tab key in the candidate window.";
"Choose the behavior of Shift+Letter key with letter inputs." = "Choose the behavior of Shift+Letter key with letter inputs.";
"Choose the cursor position where you want to list possible candidates." = "Choose the cursor position where you want to list possible candidates.";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key." = "Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key.";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only." = "Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only.";
"Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only." = "Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only.";
"Choose the phonetic layout for Mandarin parser." = "Choose the phonetic layout for Mandarin parser.";
"Choose your desired user data folder path. Will be omitted if invalid." = "Choose your desired user data folder path. Will be omitted if invalid.";
@ -166,7 +166,7 @@
"Disassemble the previous reading, dropping its intonation" = "Disassemble the previous reading, dropping its intonation";
"Disassembling process does not work with non-phonetic reading keys." = "Disassembling process does not work with non-phonetic reading keys.";
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
"Enable CNS11643 Support (2022-08-02)" = "Enable CNS11643 Support (2022-08-02)";
"Enable CNS11643 Support (2022-09-12)" = "Enable CNS11643 Support (2022-09-12)";
"Enable Space key for calling candidate window" = "Enable Space key for calling candidate window";
"Enable symbol input support (incl. certain emoji symbols)" = "Enable symbol input support (incl. certain emoji symbols)";
"English" = "English";
@ -185,7 +185,7 @@
"Hsu" = "Hsu";
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
"IBM" = "IBM";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases." = "IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases.";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements." = "IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements.";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
"Intonation Key:" = "Intonation Key:";
"Japanese" = "Japanese";
@ -217,7 +217,8 @@
"Specify the behavior of intonation key when syllable composer is empty." = "Specify the behavior of intonation key when syllable composer is empty.";
"Starlight" = "Starlight";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)";
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later.";
"Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window." = "Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window.";
"This only works with Tadokoro candidate window." = "This only works with Tadokoro candidate window.";
"Traditional Chinese" = "Traditional Chinese";
"Trim unfinished readings on commit" = "Trim unfinished readings on commit";
"Type them into inline composition buffer" = "Type them into inline composition buffer";
@ -226,7 +227,7 @@
"Universal Pinyin with Numeral Intonation" = "Universal Pinyin with Numeral Intonation";
"Use .langIdentifier to handle UI fonts in candidate window" = "Use .langIdentifier to handle UI fonts in candidate window";
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
"Use IMK Candidate Window instead (will reboot the IME)" = "Use IMK Candidate Window instead (will reboot the IME)";
"Use IMK Candidate Window instead of Tadokoro (will reboot the IME)" = "Use IMK Candidate Window instead of Tadokoro (will reboot the IME)";
"Use Shift key accommodation in all cases" = "Use Shift key accommodation in all cases";
"Vertical" = "Vertical";
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "Warning: This page is for testing future features. \nFeatures listed here may not work as expected.";

View File

@ -38,7 +38,7 @@
"Force KangXi Writing" = "Force KangXi Writing";
"NotificationSwitchON" = "✔ ON";
"NotificationSwitchOFF" = "✘ OFF";
"NotificationSwitchShift" = "↺ Switched";
"NotificationSwitchASCII" = "↺ Switched";
"Edit User Phrases…" = "Edit User Phrases…";
"Reload User Phrases" = "Reload User Phrases";
"Unable to create the user phrase file." = "Unable to create the user phrase file.";
@ -82,7 +82,7 @@
"Optimize Memorized Phrases" = "Optimize Memorized Phrases";
"Clear Memorized Phrases" = "Clear Memorized Phrases";
"Currency Numeral Output" = "Currency Numeral Output";
"Alphanumerical Mode" = "Alphanumerical Mode";
"Hold ⇧ to choose associates." = "Hold ⇧ to choose associates.";
// The followings are the category names used in the Symbol menu.
"catCommonSymbols" = "CommonSymbols";
@ -145,7 +145,7 @@
"Choose the behavior of (Shift+)Tab key in the candidate window." = "Choose the behavior of (Shift+)Tab key in the candidate window.";
"Choose the behavior of Shift+Letter key with letter inputs." = "Choose the behavior of Shift+Letter key with letter inputs.";
"Choose the cursor position where you want to list possible candidates." = "Choose the cursor position where you want to list possible candidates.";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key." = "Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key.";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only." = "Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only.";
"Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only." = "Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only.";
"Choose the phonetic layout for Mandarin parser." = "Choose the phonetic layout for Mandarin parser.";
"Choose your desired user data folder path. Will be omitted if invalid." = "Choose your desired user data folder path. Will be omitted if invalid.";
@ -166,7 +166,7 @@
"Disassemble the previous reading, dropping its intonation" = "Disassemble the previous reading, dropping its intonation";
"Disassembling process does not work with non-phonetic reading keys." = "Disassembling process does not work with non-phonetic reading keys.";
"Emulating select-candidate-per-character mode" = "Emulating select-candidate-per-character mode";
"Enable CNS11643 Support (2022-08-02)" = "Enable CNS11643 Support (2022-08-02)";
"Enable CNS11643 Support (2022-09-12)" = "Enable CNS11643 Support (2022-09-12)";
"Enable Space key for calling candidate window" = "Enable Space key for calling candidate window";
"Enable symbol input support (incl. certain emoji symbols)" = "Enable symbol input support (incl. certain emoji symbols)";
"English" = "English";
@ -185,7 +185,7 @@
"Hsu" = "Hsu";
"Hualuo Pinyin with Numeral Intonation" = "Hualuo Pinyin with Numeral Intonation";
"IBM" = "IBM";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases." = "IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases.";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements." = "IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements.";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "in front of the phrase (like macOS built-in Zhuyin IME)";
"Intonation Key:" = "Intonation Key:";
"Japanese" = "Japanese";
@ -217,7 +217,8 @@
"Specify the behavior of intonation key when syllable composer is empty." = "Specify the behavior of intonation key when syllable composer is empty.";
"Starlight" = "Starlight";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "Stop farting (when typed phonetic combination is invalid, etc.)";
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later.";
"Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window." = "Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window.";
"This only works with Tadokoro candidate window." = "This only works with Tadokoro candidate window.";
"Traditional Chinese" = "Traditional Chinese";
"Trim unfinished readings on commit" = "Trim unfinished readings on commit";
"Type them into inline composition buffer" = "Type them into inline composition buffer";
@ -226,7 +227,7 @@
"Universal Pinyin with Numeral Intonation" = "Universal Pinyin with Numeral Intonation";
"Use .langIdentifier to handle UI fonts in candidate window" = "Use .langIdentifier to handle UI fonts in candidate window";
"Use ESC key to clear the entire input buffer" = "Use ESC key to clear the entire input buffer";
"Use IMK Candidate Window instead (will reboot the IME)" = "Use IMK Candidate Window instead (will reboot the IME)";
"Use IMK Candidate Window instead of Tadokoro (will reboot the IME)" = "Use IMK Candidate Window instead of Tadokoro (will reboot the IME)";
"Use Shift key accommodation in all cases" = "Use Shift key accommodation in all cases";
"Vertical" = "Vertical";
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "Warning: This page is for testing future features. \nFeatures listed here may not work as expected.";

View File

@ -38,7 +38,7 @@
"Force KangXi Writing" = "康熙文字変換モード";
"NotificationSwitchON" = "✔ 機能起動";
"NotificationSwitchOFF" = "✘ 機能停止";
"NotificationSwitchShift" = "↺ 切替完了";
"NotificationSwitchASCII" = "↺ 切替完了";
"Edit User Phrases…" = "ユーザー辞書を編集…";
"Reload User Phrases" = "ユーザー辞書を再び読込む";
"Unable to create the user phrase file." = "ユーザー辞書ファイルの作成は失敗しました。";
@ -82,7 +82,7 @@
"Optimize Memorized Phrases" = "臨時記憶資料を整う";
"Clear Memorized Phrases" = "臨時記憶資料を削除";
"Currency Numeral Output" = "数字大字変換";
"Alphanumerical Mode" = "英数入力モード";
"Hold ⇧ to choose associates." = "⇧を押しながら連想候補をご選択ください。";
// The followings are the category names used in the Symbol menu.
"catCommonSymbols" = "常用";
@ -145,7 +145,7 @@
"Choose the behavior of (Shift+)Tab key in the candidate window." = "入力候補陳列での (Shift+)Tab キーの輪番切替対象をご指定ください。";
"Choose the behavior of Shift+Letter key with letter inputs." = "Shift+文字キーの行為をご指定ください。";
"Choose the cursor position where you want to list possible candidates." = "カーソルはどこで入力候補を呼び出すかとご指定ださい。";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key." = "macOS 英数キーボード配置をご指定ください。「Shift キーで切り替える英数入力モード」に使われる配置である。";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only." = "macOS 英数キーボード配置をご指定ください。英数入力モードだけに使われる配置である。";
"Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only." = "macOS 基礎キーボード配置をご指定ください。QWERTY 以外の英数キーボードは弁音以外の配列に不適用。";
"Choose the phonetic layout for Mandarin parser." = "共通語分析器の注音配列をご指定ください。";
"Choose your desired user data folder path. Will be omitted if invalid." = "欲しがるユーザー辞書保存先をご指定ください。無効なる保存先設定は省かれる。";
@ -166,7 +166,7 @@
"Disassemble the previous reading, dropping its intonation" = "カーソルの後部の音読みを解き、その音調を除く";
"Disassembling process does not work with non-phonetic reading keys." = "実の意味の音読みだけを解くことができる。";
"Emulating select-candidate-per-character mode" = "漢字1つづつ全候補選択入力モード";
"Enable CNS11643 Support (2022-08-02)" = "全字庫モード // 入力可能な漢字数を倍増す (2022-08-02)";
"Enable CNS11643 Support (2022-09-12)" = "全字庫モード // 入力可能な漢字数を倍増す (2022-09-12)";
"Enable Space key for calling candidate window" = "Space キーで入力候補を呼び出す";
"Enable symbol input support (incl. certain emoji symbols)" = "僅かなる絵文字も含む符号入力サポートを起用";
"English" = "英語";
@ -185,7 +185,7 @@
"Hsu" = "許氏国音自然配列";
"Hualuo Pinyin with Numeral Intonation" = "中華ローマ弁音 (ローマ字+数字音調)";
"IBM" = "IBM 配列";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases." = "IMK 候補陳列ウィンドウは、Apple の未公開のAPIを「bridging-header」という強引的な手段で引き出して利用した機能である。現時点で macOS 10.14 Mojave から macOS 13 Ventura まで利用可能であるが、その後の新しい macOS との互換性の話はまだ早い。";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements." = "IMK 候補陳列ウィンドウは、Apple の未公開のAPIを「bridging-header」という強引的な手段で引き出して利用した機能である。現時点で macOS 10.14 Mojave から macOS 13 Ventura まで利用可能であるが、その後の新しい macOS との互換性の話はまだ早い。とはいえ、田所候補陳列ウィンドウにはまだ改善できるところがあるため、IMK 候補陳列ウィンドウは現時点で推奨選択とする。";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "単語の前で // macOS 内蔵注音入力のやり方";
"Intonation Key:" = "音調キー:";
"Japanese" = "和語";
@ -217,7 +217,8 @@
"Specify the behavior of intonation key when syllable composer is empty." = "音読組立緩衝列が空かされた時の音調キーの行為をご指定ください。";
"Starlight" = "星光配列";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "マナーモード // 外すと入力間違った時に変な声が出る";
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "これは Apple Bug Report #FB10978412 の臨時対策であり、macOS 12 からの macOS に効き、IMK 以外の候補陳列ウィンドウに作用する。Apple は macOS 11 からの macOS のために該当 Bug を修復すべきである。";
"Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window." = "田所候補陳列ウィンドウは格子状横型陳列しかできません。開発道場のページで IMK 候補陳列ウィンドウを起用してから、今のこのページで縦型・横型陳列の選択はできます。";
"This only works with Tadokoro candidate window." = "これは田所候補陳列ウィンドウだけに効ける機能である。";
"Traditional Chinese" = "繁体中国語";
"Trim unfinished readings on commit" = "送り出す緩衝列内容から未完成な音読みを除く";
"Type them into inline composition buffer" = "入力緩衝列にローマ字入力";
@ -226,7 +227,7 @@
"Universal Pinyin with Numeral Intonation" = "汎用弁音 (ローマ字+数字音調)";
"Use .langIdentifier to handle UI fonts in candidate window" = "「.langIdentifier」を使って候補陳列ウィンドウのフォントを取り扱う";
"Use ESC key to clear the entire input buffer" = "ESC キーで入力緩衝列を消す";
"Use IMK Candidate Window instead (will reboot the IME)" = "IMK 候補陳列ウィンドウを起用(入力アプリは自動的に再起動)";
"Use IMK Candidate Window instead of Tadokoro (will reboot the IME)" = "IMK 候補陳列ウィンドウを起用(入力アプリは自動的に再起動)";
"Use Shift key accommodation in all cases" = "いずれの客体アプリにも Shift キーの互換性措置を起用";
"Vertical" = "縦型陳列";
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "警告:これからの新機能テストのために作ったページですから、\nここで陳列されている諸機能は予想通り動けるだと思わないでください。";

View File

@ -38,7 +38,7 @@
"Force KangXi Writing" = "康熙正体字模式";
"NotificationSwitchON" = "✔ 已启用";
"NotificationSwitchOFF" = "✘ 已停用";
"NotificationSwitchShift" = "↺ 切换完毕";
"NotificationSwitchASCII" = "↺ 切换完毕";
"Edit User Phrases…" = "编辑自订语汇…";
"Reload User Phrases" = "重载自订语汇";
"Unable to create the user phrase file." = "无法创建自订语汇档案。";
@ -82,7 +82,7 @@
"Optimize Memorized Phrases" = "精简临时记忆语汇资料";
"Clear Memorized Phrases" = "清除临时记忆语汇资料";
"Currency Numeral Output" = "大写汉字数字输出";
"Alphanumerical Mode" = "英数输入模式";
"Hold ⇧ to choose associates." = "摁住⇧以选取联想词。";
// The followings are the category names used in the Symbol menu.
"catCommonSymbols" = "常用";
@ -145,7 +145,7 @@
"Choose the behavior of (Shift+)Tab key in the candidate window." = "指定 (Shift+)Tab 在选字窗内的轮替操作对象。";
"Choose the behavior of Shift+Letter key with letter inputs." = "指定 Shift+字母键 的行为。";
"Choose the cursor position where you want to list possible candidates." = "请选择用以触发选字的游标相对位置。";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key." = "请选择 macOS 英数键盘布局。该布局用于以 Shift 切换至的英数输入模式。";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only." = "请选择 macOS 英数键盘布局。该布局用于英数输入模式。";
"Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only." = "请选择 macOS 基础键盘布局。QWERTY 以外的英数布局是为了拼音排列使用者而准备的。";
"Choose the phonetic layout for Mandarin parser." = "请指定普通话/国音分析器所使用的注音排列。";
"Choose your desired user data folder path. Will be omitted if invalid." = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。";
@ -166,7 +166,7 @@
"Disassemble the previous reading, dropping its intonation" = "析构游标正后方的字音,且剔除其声调";
"Disassembling process does not work with non-phonetic reading keys." = "析构行为仅针对组字器内「身为汉字读音」的读音索引单元有效。";
"Emulating select-candidate-per-character mode" = "模拟 90 年代前期注音逐字选字输入风格";
"Enable CNS11643 Support (2022-08-02)" = "启用 CNS11643 全字库支援 (2022-08-02)";
"Enable CNS11643 Support (2022-09-12)" = "启用 CNS11643 全字库支援 (2022-09-12)";
"Enable Space key for calling candidate window" = "敲空格键以呼出候选字窗";
"Enable symbol input support (incl. certain emoji symbols)" = "启用包括少许绘文字在内的符号输入支援";
"English" = "英语";
@ -185,7 +185,7 @@
"Hsu" = "许氏国音自然排列";
"Hualuo Pinyin with Numeral Intonation" = "华罗拼音+数字标调";
"IBM" = "IBM 排列";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases." = "IMK 选字窗依赖于 Apple 的私有 API而且是借由桥接档案头强制曝露的方法使用的。目前该功能仅在 macOS 10.14 Mojave 至 macOS 13 Ventura 系统内有测试过可用性。至于在未来的 macOS 发行版当中是否可用,则需要另行测试、才能下结论。";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements." = "IMK 选字窗依赖于 Apple 的私有 API而且是借由桥接档案头强制曝露的方法使用的。目前该功能仅在 macOS 10.14 Mojave 至 macOS 13 Ventura 系统内有测试过可用性。至于在未来的 macOS 发行版当中是否可用,则需要另行测试、才能下结论。然而,目前 IMK 选字窗属于建议启用的功能,因为田所选字窗仍需改善。";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "将游标置于词语前方 // macOS 内建注音风格";
"Intonation Key:" = "声调键:";
"Japanese" = "和语";
@ -217,7 +217,8 @@
"Specify the behavior of intonation key when syllable composer is empty." = "指定声调键(在注拼槽为「空」状态时)的行为。";
"Starlight" = "星光排列";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉耻模式 // 取消勾选的话,敲错字时会有异音";
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "该方法是 Apple Bug Report #FB10978412 的保守治疗方案,用来仅针对 macOS 12 开始的系统,且仅对非 IMK 选字窗起作用。Apple 应该对 macOS 11 开始的系统修复这个 Bug。";
"Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window." = "田所选字窗仅支援横排矩阵布局模式。如欲使用纵排布局模式者,请在开发道场内先启用 IMK 选字窗。";
"This only works with Tadokoro candidate window." = "该方法仅对田所选字窗起作用。";
"Traditional Chinese" = "繁体中文";
"Trim unfinished readings on commit" = "在递交时清理未完成拼写的读音";
"Type them into inline composition buffer" = "直接键入内文组字区";
@ -226,7 +227,7 @@
"Universal Pinyin with Numeral Intonation" = "通用拼音+数字标调";
"Use .langIdentifier to handle UI fonts in candidate window" = "使用 .langIdentifier 来管理选字窗的预设介面字型";
"Use ESC key to clear the entire input buffer" = "敲 ESC 键以清空整个组字缓冲区";
"Use IMK Candidate Window instead (will reboot the IME)" = "启用与 macOS 内建输入法相同的 IMK 选字窗(会自动重启输入法)";
"Use IMK Candidate Window instead of Tadokoro (will reboot the IME)" = "启用与 macOS 内建输入法相同的 IMK 选字窗(会自动重启输入法)";
"Use Shift key accommodation in all cases" = "对任何客体应用均启用 Shift 键相容性措施";
"Vertical" = "纵向布局";
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "警告:该页面仅作未来功能测试所用。\n在此列出的功能并非处于完全可用之状态。";

View File

@ -38,7 +38,7 @@
"Force KangXi Writing" = "康熙正體字模式";
"NotificationSwitchON" = "✔ 已啟用";
"NotificationSwitchOFF" = "✘ 已停用";
"NotificationSwitchShift" = "↺ 切換完畢";
"NotificationSwitchASCII" = "↺ 切換完畢";
"Edit User Phrases…" = "編輯自訂語彙…";
"Reload User Phrases" = "重載自訂語彙";
"Unable to create the user phrase file." = "無法創建自訂語彙檔案。";
@ -82,7 +82,7 @@
"Optimize Memorized Phrases" = "精簡臨時記憶語彙資料";
"Clear Memorized Phrases" = "清除臨時記憶語彙資料";
"Currency Numeral Output" = "大寫漢字數字輸出";
"Alphanumerical Mode" = "英數輸入模式";
"Hold ⇧ to choose associates." = "摁住⇧以選取聯想詞。";
// The followings are the category names used in the Symbol menu.
"catCommonSymbols" = "常用";
@ -145,7 +145,7 @@
"Choose the behavior of (Shift+)Tab key in the candidate window." = "指定 (Shift+)Tab 在選字窗內的輪替操作對象。";
"Choose the behavior of Shift+Letter key with letter inputs." = "指定 Shift+字母鍵 的行為。";
"Choose the cursor position where you want to list possible candidates." = "請選擇用以觸發選字的游標相對位置。";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode toggled by Shift key." = "請選擇 macOS 英數鍵盤佈局。該佈局用於以 Shift 切換至的英數輸入模式。";
"Choose the macOS-level alphanumerical keyboard layout. This setting is for the alphanumerical mode only." = "請選擇 macOS 英數鍵盤佈局。該佈局用於英數輸入模式。";
"Choose the macOS-level basic keyboard layout. Non-QWERTY alphanumerical keyboard layouts are for Pinyin parser only." = "請選擇 macOS 基礎鍵盤佈局。QWERTY 以外的英數佈局是為了拼音排列使用者而準備的。";
"Choose the phonetic layout for Mandarin parser." = "請指定普通話/國音分析器所使用的注音排列。";
"Choose your desired user data folder path. Will be omitted if invalid." = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。";
@ -166,7 +166,7 @@
"Disassemble the previous reading, dropping its intonation" = "析構游標正後方的字音,且剔除其聲調";
"Disassembling process does not work with non-phonetic reading keys." = "析構行為僅針對組字器內「身為漢字讀音」的讀音索引單元有效。";
"Emulating select-candidate-per-character mode" = "模擬 90 年代前期注音逐字選字輸入風格";
"Enable CNS11643 Support (2022-08-02)" = "啟用 CNS11643 全字庫支援 (2022-08-02)";
"Enable CNS11643 Support (2022-09-12)" = "啟用 CNS11643 全字庫支援 (2022-09-12)";
"Enable Space key for calling candidate window" = "敲空格鍵以呼出候選字窗";
"Enable symbol input support (incl. certain emoji symbols)" = "啟用包括少許繪文字在內的符號輸入支援";
"English" = "英語";
@ -185,7 +185,7 @@
"Hsu" = "許氏國音自然排列";
"Hualuo Pinyin with Numeral Intonation" = "華羅拼音+數字標調";
"IBM" = "IBM 排列";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases." = "IMK 選字窗依賴於 Apple 的私有 API而且是藉由橋接檔案頭強制曝露的方法使用的。目前該功能僅在 macOS 10.14 Mojave 至 macOS 13 Ventura 系統內有測試過可用性。至於在未來的 macOS 發行版當中是否可用,則需要另行測試、才能下結論。";
"IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements." = "IMK 選字窗依賴於 Apple 的私有 API而且是藉由橋接檔案頭強制曝露的方法使用的。目前該功能僅在 macOS 10.14 Mojave 至 macOS 13 Ventura 系統內有測試過可用性。至於在未來的 macOS 發行版當中是否可用,則需要另行測試、才能下結論。然而,目前 IMK 選字窗屬於建議啟用的功能,因為田所選字窗仍需改善。";
"in front of the phrase (like macOS built-in Zhuyin IME)" = "將游標置於詞語前方 // macOS 內建注音風格";
"Intonation Key:" = "聲調鍵:";
"Japanese" = "和語";
@ -217,7 +217,8 @@
"Specify the behavior of intonation key when syllable composer is empty." = "指定聲調鍵(在注拼槽為「空」狀態時)的行為。";
"Starlight" = "星光排列";
"Stop farting (when typed phonetic combination is invalid, etc.)" = "廉恥模式 // 取消勾選的話,敲錯字時會有異音";
"This only works since macOS 12 with non-IMK candidate window as an alternative wordaround of Apple Bug Report #FB10978412. Apple should patch that for macOS 11 and later." = "該方法是 Apple Bug Report #FB10978412 的保守治療方案,用來僅針對 macOS 12 開始的系統,且僅對非 IMK 選字窗起作用。Apple 應該對 macOS 11 開始的系統修復這個 Bug。";
"Tadokoro candidate window only supports horizontal grid view. Enable IMK candidate window in DevZone page first if you want to choose vertical candidate window." = "田所選字窗僅支援橫排矩陣佈局模式。如欲使用縱排佈局模式者,請在開發道場內先啟用 IMK 選字窗。";
"This only works with Tadokoro candidate window." = "該方法僅對田所選字窗起作用。";
"Traditional Chinese" = "繁體中文";
"Trim unfinished readings on commit" = "在遞交時清理未完成拼寫的讀音";
"Type them into inline composition buffer" = "直接鍵入內文組字區";
@ -226,7 +227,7 @@
"Universal Pinyin with Numeral Intonation" = "通用拼音+數字標調";
"Use .langIdentifier to handle UI fonts in candidate window" = "使用 .langIdentifier 來管理選字窗的預設介面字型";
"Use ESC key to clear the entire input buffer" = "敲 ESC 鍵以清空整個組字緩衝區";
"Use IMK Candidate Window instead (will reboot the IME)" = "啟用與 macOS 內建輸入法相同的 IMK 選字窗(會自動重啟輸入法)";
"Use IMK Candidate Window instead of Tadokoro (will reboot the IME)" = "啟用與 macOS 內建輸入法相同的 IMK 選字窗(會自動重啟輸入法)";
"Use Shift key accommodation in all cases" = "對任何客體應用均啟用 Shift 鍵相容性措施";
"Vertical" = "縱向佈局";
"Warning: This page is for testing future features. \nFeatures listed here may not work as expected." = "警告:該頁面僅作未來功能測試所用。\n在此列出的功能並非處於完全可用之狀態。";

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -688,6 +687,7 @@
</cells>
<connections>
<binding destination="32" name="selectedTag" keyPath="values.UseHorizontalCandidateList" id="105"/>
<binding destination="32" name="enabled" keyPath="values.UseIMKCandidateWindow" id="TVK-89-xXv"/>
</connections>
</matrix>
</gridCell>
@ -959,11 +959,11 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Yaj-QY-7xV" userLabel="chkCNSSupport">
<rect key="frame" x="-1" y="109.5" width="254" height="17"/>
<rect key="frame" x="-1" y="109.5" width="252" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="lGu-fQ-Nvc"/>
</constraints>
<buttonCell key="cell" type="check" title="Enable CNS11643 Support (2022-08-02)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="W24-T4-cg0">
<buttonCell key="cell" type="check" title="Enable CNS11643 Support (2022-09-12)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" inset="2" id="W24-T4-cg0">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>
@ -1375,7 +1375,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="7" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yH2-IC-kI1">
<rect key="frame" x="20" y="32" width="405" height="138"/>
<rect key="frame" x="20" y="32" width="409" height="138"/>
<subviews>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lblControlDevZoneTitleDescription" userLabel="lblControlDevZoneTitleDescription">
<rect key="frame" x="-2" y="108" width="278" height="30"/>
@ -1394,11 +1394,11 @@ Features listed here may not work as expected.</string>
</constraints>
</box>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="le7-59-tFK" userLabel="tglControlDevZoneIMKCandidate">
<rect key="frame" x="-1" y="76.5" width="340" height="17"/>
<rect key="frame" x="-1" y="76.5" width="410" height="17"/>
<constraints>
<constraint firstAttribute="height" constant="16" id="054-U2-1Xk"/>
</constraints>
<buttonCell key="cell" type="check" title="Use IMK Candidate Window instead (will reboot the IME)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="tglDevZoneIMKCandidate" userLabel="tglDevZoneIMKCandidate">
<buttonCell key="cell" type="check" title="Use IMK Candidate Window instead of Tadokoro (will reboot the IME)" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="tglDevZoneIMKCandidate" userLabel="tglDevZoneIMKCandidate">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="cellTitle"/>
</buttonCell>

View File

@ -66,7 +66,7 @@
"jQC-12-UuK.ibShadowedObjectValues[1]" = "Item 2";
"jQC-12-UuK.ibShadowedObjectValues[2]" = "Item 3";
"lblAlwaysShowTooltipTextsHorizontally.title" = "Always show tooltip texts horizontally";
"lblDevZoneIMKCandidate.title" = "IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases.";
"lblDevZoneIMKCandidate.title" = "IMK candidate window relies on certain Apple private APIs which are force-exposed by using bridging headers. Its usability, at this moment, is only guaranteed from macOS 10.14 Mojave to macOS 13 Ventura. Further tests are required in the future in order to tell whether it is usable in newer macOS releases. However, this mode is recommended at this moment since Tadokoro candidate window still needs possible improvements.";
"lblDevZoneTitleDescription.title" = "Warning: This page is for testing future features. \nFeatures listed here may not work as expected.";
"lblIntonationKeyBehavior.title" = "Specify what intonation key does when syllable composer is empty.";
"lblShiftBkspKeyBehavior.title" = "Choose the attempted behavior of Shift+BackSpace key.";
@ -91,13 +91,13 @@
"rVQ-Hx-cGi.title" = "Japanese";
"s7u-Fm-dVg.title" = "Cycling Pages";
"shc-Nu-UsM.title" = "Show page buttons in candidate list";
"tglDevZoneIMKCandidate.title" = "Use IMK Candidate Window instead (will reboot the IME)";
"tglDevZoneIMKCandidate.title" = "Use IMK Candidate Window instead of Tadokoro (will reboot the IME)";
"tglTrimUnfinishedReadingsOnCommit.title" = "Trim unfinished readings on commit";
"TXr-FF-ehw.title" = "Traditional Chinese";
"ueU-Rz-a1C.title" = "Choose the behavior of (Shift+)Tab key in the candidate window.";
"VdT-fw-7pQ.title" = "Debug Mode";
"vpd-zx-GIk.title" = "Seigyou (JinYei)";
"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-08-02)";
"W24-T4-cg0.title" = "Enable CNS11643 Support (2022-09-12)";
"wFR-zX-M8H.title" = "Show Hanyu-Pinyin in the inline composition buffer";
"wN3-k3-b2a.title" = "Choose your desired user data folder path. Will be omitted if invalid.";
"wQ9-px-b07.title" = "Apple Dynamic Bopomofo Basic Keyboard Layouts (Dachen & Eten Traditional) must match the Dachen parser in order to be functional.";

View File

@ -97,7 +97,7 @@
"ueU-Rz-a1C.title" = "入力候補陳列での (Shift+)Tab キーの輪番切替対象をご指定ください。";
"VdT-fw-7pQ.title" = "欠陥辿着モード";
"vpd-zx-GIk.title" = "精業配列";
"W24-T4-cg0.title" = "全字庫モード // 入力可能の漢字数倍増 (2022-08-02)";
"W24-T4-cg0.title" = "全字庫モード // 入力可能の漢字数倍増 (2022-09-12)";
"wFR-zX-M8H.title" = "弁音合併入力(入力緩衝列で音読みを漢語弁音に)";
"wN3-k3-b2a.title" = "欲しがるユーザー辞書保存先をご指定ください。無効の保存先設定は効かぬ。";
"wQ9-px-b07.title" = "Apple 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の注音配列を大千と設定すべきである。";

View File

@ -97,7 +97,7 @@
"ueU-Rz-a1C.title" = "指定 (Shift+)Tab 热键在选字窗内的轮替操作对象。";
"VdT-fw-7pQ.title" = "侦错模式";
"vpd-zx-GIk.title" = "精业";
"W24-T4-cg0.title" = "启用 CNS11643 全字库支援 (2022-08-02)";
"W24-T4-cg0.title" = "启用 CNS11643 全字库支援 (2022-09-12)";
"wFR-zX-M8H.title" = "拼音并击(组字区内显示汉语拼音)";
"wN3-k3-b2a.title" = "请在此指定您想指定的使用者语汇档案目录。无效值会被忽略。";
"wQ9-px-b07.title" = "Apple 动态注音键盘布局(大千与倚天)要求普通话/国音分析器的注音排列得配置为大千排列。";

View File

@ -97,7 +97,7 @@
"ueU-Rz-a1C.title" = "指定 (Shift+)Tab 熱鍵在選字窗內的輪替操作對象。";
"VdT-fw-7pQ.title" = "偵錯模式";
"vpd-zx-GIk.title" = "精業";
"W24-T4-cg0.title" = "啟用 CNS11643 全字庫支援 (2022-08-02)";
"W24-T4-cg0.title" = "啟用 CNS11643 全字庫支援 (2022-09-12)";
"wFR-zX-M8H.title" = "拼音並擊(組字區內顯示漢語拼音)";
"wN3-k3-b2a.title" = "請在此指定您想指定的使用者語彙檔案目錄。無效值會被忽略。";
"wQ9-px-b07.title" = "Apple 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器的注音排列得配置為大千排列。";

View File

@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>CFBundleShortVersionString</key>
<string>2.7.5</string>
<string>2.8.0</string>
<key>CFBundleVersion</key>
<string>2750</string>
<string>2800</string>
<key>UpdateInfoEndpoint</key>
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
<key>UpdateInfoSite</key>

View File

@ -19,7 +19,7 @@ rm ~/Library/Receipts/org.atelierInmu.vChewing.plist
# Also user phrase folder:
# 原廠預設的使用者辭典目錄不自動刪除了,讓使用者自己刪:
# rm -rf ~/Library/Application\ Support/vChewing/
# rm -rf /Users/shikisuen/Library/Containers/org.atelierInmu.inputmethod.vChewing/Data/Library/Application\ Support/vChewing/
# rm -rf ~/Library/Containers/org.atelierInmu.inputmethod.vChewing/Data/Library/Application\ Support/vChewing/
# Also the IME configuration file:
# 輸入法偏好設定檔案:

View File

@ -726,7 +726,7 @@
<key>USE_HFS+_COMPRESSION</key>
<false/>
<key>VERSION</key>
<string>2.7.5</string>
<string>2.8.0</string>
</dict>
<key>TYPE</key>
<integer>0</integer>

View File

@ -33,7 +33,6 @@
5B963CA828D5DB1400DCEE88 /* PrefMgr_Core.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B963CA728D5DB1400DCEE88 /* PrefMgr_Core.swift */; };
5B98114828D6198700CBC605 /* PinyinPhonaConverter in Frameworks */ = {isa = PBXBuildFile; productRef = 5B98114728D6198700CBC605 /* PinyinPhonaConverter */; };
5BA8C30328DF0360004C5CC4 /* CandidateWindow in Frameworks */ = {isa = PBXBuildFile; productRef = 5BA8C30228DF0360004C5CC4 /* CandidateWindow */; };
5BA8C30528DF0364004C5CC4 /* Voltaire in Frameworks */ = {isa = PBXBuildFile; productRef = 5BA8C30428DF0364004C5CC4 /* Voltaire */; };
5BA9FD0F27FEDB6B002DE248 /* suiPrefPaneGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */; };
5BA9FD1027FEDB6B002DE248 /* suiPrefPaneKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */; };
5BA9FD1127FEDB6B002DE248 /* ctlPrefUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA9FD0C27FEDB6B002DE248 /* ctlPrefUI.swift */; };
@ -222,7 +221,6 @@
5B963CA128D5C22D00DCEE88 /* vChewing_SwiftExtension */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_SwiftExtension; path = Packages/vChewing_SwiftExtension; sourceTree = "<group>"; };
5B963CA728D5DB1400DCEE88 /* PrefMgr_Core.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefMgr_Core.swift; sourceTree = "<group>"; };
5B98114628D6198000CBC605 /* vChewing_PinyinPhonaConverter */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_PinyinPhonaConverter; path = Packages/vChewing_PinyinPhonaConverter; sourceTree = "<group>"; };
5BA8C30028DEFE4F004C5CC4 /* OpenVanilla_Voltaire */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = OpenVanilla_Voltaire; path = Packages/OpenVanilla_Voltaire; sourceTree = "<group>"; };
5BA8C30128DEFE4F004C5CC4 /* vChewing_CandidateWindow */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = vChewing_CandidateWindow; path = Packages/vChewing_CandidateWindow; sourceTree = "<group>"; };
5BA9FD0A27FEDB6B002DE248 /* suiPrefPaneGeneral.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = suiPrefPaneGeneral.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
5BA9FD0B27FEDB6B002DE248 /* suiPrefPaneKeyboard.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; indentWidth = 2; lineEnding = 0; path = suiPrefPaneKeyboard.swift; sourceTree = "<group>"; tabWidth = 2; usesTabs = 0; };
@ -286,6 +284,7 @@
5BEDB71F283B4AEA0078EB25 /* data-zhuyinwen.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-zhuyinwen.plist"; path = "Data/data-zhuyinwen.plist"; sourceTree = "<group>"; };
5BEDB720283B4AEA0078EB25 /* data-cht.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "data-cht.plist"; path = "Data/data-cht.plist"; sourceTree = "<group>"; };
5BF255CD28B2694E003ECB60 /* vChewing-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewing-Bridging-Header.h"; sourceTree = "<group>"; };
5BF4A44628E5820C002AF9C5 /* vChewingInstaller.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = vChewingInstaller.entitlements; sourceTree = "<group>"; };
5BF56F9728C39A2700DD6839 /* IMEState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMEState.swift; sourceTree = "<group>"; };
5BF56F9928C39D1800DD6839 /* IMEStateData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IMEStateData.swift; sourceTree = "<group>"; };
5BF9DA2228840E6200DBD48E /* template-usersymbolphrases.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; lineEnding = 0; path = "template-usersymbolphrases.txt"; sourceTree = "<group>"; usesTabs = 0; };
@ -359,7 +358,6 @@
5BDB7A3B28D4824A001AC277 /* FolderMonitor in Frameworks */,
5BA8C30328DF0360004C5CC4 /* CandidateWindow in Frameworks */,
5BC5E01E28DDE4770094E427 /* NotifierUI in Frameworks */,
5BA8C30528DF0364004C5CC4 /* Voltaire in Frameworks */,
5B40113C28D71C0100A9D4CB /* Uninstaller in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -565,7 +563,6 @@
5BDB7A3128D47587001AC277 /* DanielGalasko_FolderMonitor */,
5BFC63C428D487AE004A77B7 /* Fuziki_NSAttributedTextView */,
5BDB7A3028D47587001AC277 /* Jad_BookmarkManager */,
5BA8C30028DEFE4F004C5CC4 /* OpenVanilla_Voltaire */,
5BDB7A3428D47587001AC277 /* Qwertyyb_ShiftKeyUpChecker */,
5BDB7A3528D47587001AC277 /* RMJay_LineReader */,
5BDB7A2F28D47587001AC277 /* Sindresorhus_Preferences */,
@ -607,6 +604,7 @@
6A0D4E9215FC0CFA00ABF4B3 = {
isa = PBXGroup;
children = (
5BF4A44628E5820C002AF9C5 /* vChewingInstaller.entitlements */,
5BDB7A2D28D47570001AC277 /* Packages */,
5B20430C28BEFC1200BFC6FD /* vChewingPhraseEditor.entitlements */,
5B20430B28BEFC0C00BFC6FD /* vChewing.entitlements */,
@ -783,7 +781,6 @@
5BC5E02028DDEFE00094E427 /* TooltipUI */,
5BC5E02328DE07860094E427 /* PopupCompositionBuffer */,
5BA8C30228DF0360004C5CC4 /* CandidateWindow */,
5BA8C30428DF0364004C5CC4 /* Voltaire */,
);
productName = vChewing;
productReference = 6A0D4EA215FC0D2D00ABF4B3 /* vChewing.app */;
@ -1265,7 +1262,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
@ -1276,7 +1273,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
@ -1305,14 +1302,14 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
ENABLE_NS_ASSERTIONS = NO;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GENERATE_INFOPLIST_FILE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
@ -1344,7 +1341,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
@ -1367,11 +1364,12 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@ -1396,7 +1394,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
DEAD_CODE_STRIPPING = YES;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_NS_ASSERTIONS = NO;
@ -1415,11 +1413,12 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
};
@ -1530,7 +1529,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1560,11 +1559,12 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Source/Headers/vChewing-Bridging-Header.h";
SWIFT_VERSION = 5.0;
WRAPPER_EXTENSION = app;
@ -1590,7 +1590,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "";
@ -1614,10 +1614,11 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Source/Headers/vChewing-Bridging-Header.h";
SWIFT_VERSION = 5.0;
WRAPPER_EXTENSION = app;
@ -1633,13 +1634,14 @@
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = vChewingInstaller.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_HARDENED_RUNTIME = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@ -1658,11 +1660,12 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = NO;
SWIFT_VERSION = 5.0;
WRAPPER_EXTENSION = app;
};
@ -1677,13 +1680,14 @@
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = vChewingInstaller.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2750;
CURRENT_PROJECT_VERSION = 2800;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = NO;
ENABLE_HARDENED_RUNTIME = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
@ -1696,10 +1700,11 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13.4;
MARKETING_VERSION = 2.7.5;
MARKETING_VERSION = 2.8.0;
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = NO;
SWIFT_VERSION = 5.0;
WRAPPER_EXTENSION = app;
};
@ -1780,10 +1785,6 @@
isa = XCSwiftPackageProductDependency;
productName = CandidateWindow;
};
5BA8C30428DF0364004C5CC4 /* Voltaire */ = {
isa = XCSwiftPackageProductDependency;
productName = Voltaire;
};
5BC5E01D28DDE4770094E427 /* NotifierUI */ = {
isa = XCSwiftPackageProductDependency;
productName = NotifierUI;

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>