2.8.0 // Tadokoro Candidate Window. Merge PR#149 from upd/2.8.0
This commit is contained in:
commit
74d2ca6a09
3
AUTHORS
3
AUTHORS
|
@ -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.
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -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"),
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
|
@ -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.
|
||||
```
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -21,6 +21,10 @@ let package = Package(
|
|||
dependencies: [
|
||||
.product(name: "Shared", package: "vChewing_Shared")
|
||||
]
|
||||
)
|
||||
),
|
||||
.testTarget(
|
||||
name: "CandidateWindowTests",
|
||||
dependencies: ["CandidateWindow"]
|
||||
),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
# CandidateWindow
|
||||
|
||||
用以定義與威注音的選字窗有關的基礎內容,目前尚未完工。
|
||||
用以定義與威注音的選字窗有關的基礎內容。此外,還包含了威注音自家的次世代選字窗「田所(TDK)」。
|
||||
|
||||
> 命名緣由:野獸先輩「田所」的姓氏。
|
||||
|
||||
TDK 選字窗以純 SwiftUI 構築,用以取代此前自上游繼承來的 Voltaire 選字窗。
|
||||
|
||||
然而,TDK 選字窗目前有下述侷限:
|
||||
|
||||
- 因 SwiftUI 自身特性所導致的嚴重的效能問題。基本上來講,如果您經常使用全字庫模式的話,請在偏好設定內啟用效能更高的 IMK 選字窗。
|
||||
- 同樣出於上述原因,為了讓田所選字窗至少處於可在生產力環境下正常使用的狀態,就犧牲了捲動檢視的功能。也就是說,每次只顯示三行,但顯示內容則隨著使用者的游標操作而更新。
|
||||
- TDK 選字窗目前僅完成了橫版矩陣陳列模式的實作,且尚未引入對縱排選字窗陳列佈局的支援。
|
||||
|
||||
因為這些問題恐怕需要很久才能全部解決,所以威注音會在這段時間內推薦使用者們優先使用 IMK 選字窗。
|
||||
|
||||
```
|
||||
// (c) 2021 and onwards The vChewing Project (MIT-NTL License).
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -91,7 +91,6 @@ P.S.: 威注音输入法的 Shift 按键监测功能仅借由对 NSEvent 讯号
|
|||
威注音专案目前仅用到小麦注音的下述程式组件(MIT License):
|
||||
|
||||
- 仅供研发人员调试方便而使用的 App 版安装程式 (by Zonble Yang),不对公众使用。
|
||||
- Voltaire MK2 选字窗 (by Zonble Yang),有大幅度修改。
|
||||
|
||||
威注音专案目前还用到如下的来自 Lukhnos Liu 的算法:
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 副廠輸入法的常見失誤之處。
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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: ""
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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] {
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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ここで陳列されている諸機能は予想通り動けるだと思わないでください。";
|
||||
|
|
|
@ -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在此列出的功能并非处于完全可用之状态。";
|
||||
|
|
|
@ -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在此列出的功能並非處於完全可用之狀態。";
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.";
|
||||
|
|
|
@ -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 動態注音キーボード (大千と倚天伝統) を使うには、共通語分析器の注音配列を大千と設定すべきである。";
|
||||
|
|
|
@ -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 动态注音键盘布局(大千与倚天)要求普通话/国音分析器的注音排列得配置为大千排列。";
|
||||
|
|
|
@ -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 動態注音鍵盤佈局(大千與倚天)要求普通話/國音分析器的注音排列得配置為大千排列。";
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
||||
# 輸入法偏好設定檔案:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
Loading…
Reference in New Issue