2.6.1 // Security enhancement. Merge PR #136 from upd/2.6.1
This commit is contained in:
commit
cd20b97a7b
|
@ -60,7 +60,7 @@ public class NSAttributedTextView: NSView {
|
|||
}
|
||||
}
|
||||
|
||||
public var attributedStringValue: NSAttributedString {
|
||||
public func attributedStringValue(areaCalculation: Bool = false) -> NSAttributedString {
|
||||
var newAttributes = attributes
|
||||
let isVertical: Bool = !(direction == .horizontal)
|
||||
newAttributes[.verticalGlyphForm] = isVertical
|
||||
|
@ -71,23 +71,14 @@ public class NSAttributedTextView: NSView {
|
|||
newStyle.minimumLineHeight = fontSize * 1.1
|
||||
}
|
||||
newAttributes[.paragraphStyle] = newStyle
|
||||
var text: String = text ?? ""
|
||||
if !(direction == .horizontal) {
|
||||
text = text.replacingOccurrences(of: "˙", with: "・")
|
||||
text = text.replacingOccurrences(of: "\u{A0}", with: " ")
|
||||
text = text.replacingOccurrences(of: "+", with: "")
|
||||
text = text.replacingOccurrences(of: "Shift", with: "⇧")
|
||||
text = text.replacingOccurrences(of: "Control", with: "⌃")
|
||||
text = text.replacingOccurrences(of: "Enter", with: "⏎")
|
||||
text = text.replacingOccurrences(of: "Command", with: "⌘")
|
||||
text = text.replacingOccurrences(of: "Delete", with: "⌦")
|
||||
text = text.replacingOccurrences(of: "BackSpace", with: "⌫")
|
||||
text = text.replacingOccurrences(of: "SHIFT", with: "⇧")
|
||||
text = text.replacingOccurrences(of: "CONTROL", with: "⌃")
|
||||
text = text.replacingOccurrences(of: "ENTER", with: "⏎")
|
||||
text = text.replacingOccurrences(of: "COMMAND", with: "⌘")
|
||||
text = text.replacingOccurrences(of: "DELETE", with: "⌦")
|
||||
text = text.replacingOccurrences(of: "BACKSPACE", with: "⌫")
|
||||
var text: String = text ?? text ?? ""
|
||||
if areaCalculation {
|
||||
text = text.replacingOccurrences(
|
||||
of: "[^\n]",
|
||||
with: "國",
|
||||
options: .regularExpression,
|
||||
range: text.range(of: text)
|
||||
)
|
||||
}
|
||||
let attributedText = NSMutableAttributedString(string: text, attributes: newAttributes)
|
||||
return attributedText
|
||||
|
@ -109,10 +100,33 @@ public class NSAttributedTextView: NSView {
|
|||
private var ctFrame: CTFrame?
|
||||
private(set) var currentRect: NSRect?
|
||||
|
||||
@discardableResult public func shrinkFrame() -> NSRect {
|
||||
let attrString: NSAttributedString = {
|
||||
switch direction {
|
||||
case .horizontal: return attributedStringValue()
|
||||
default: return attributedStringValue(areaCalculation: true)
|
||||
}
|
||||
}()
|
||||
var rect = attrString.boundingRect(
|
||||
with: NSSize(width: 1600.0, height: 1600.0),
|
||||
options: [.usesLineFragmentOrigin, .usesFontLeading, .usesDeviceMetrics]
|
||||
)
|
||||
rect.size.height *= 1.03
|
||||
rect.size.height = max(rect.size.height, NSFont.systemFontSize * 1.1)
|
||||
rect.size.height = ceil(rect.size.height)
|
||||
rect.size.width *= 1.03
|
||||
rect.size.width = max(rect.size.width, NSFont.systemFontSize * 1.05)
|
||||
rect.size.width = ceil(rect.size.width)
|
||||
if direction != .horizontal {
|
||||
rect = .init(x: rect.minX, y: rect.minY, width: rect.height, height: rect.width)
|
||||
}
|
||||
return rect
|
||||
}
|
||||
|
||||
override public func draw(_ rect: CGRect) {
|
||||
let context = NSGraphicsContext.current?.cgContext
|
||||
guard let context = context else { return }
|
||||
let setter = CTFramesetterCreateWithAttributedString(attributedStringValue)
|
||||
let setter = CTFramesetterCreateWithAttributedString(attributedStringValue())
|
||||
let path = CGPath(rect: rect, transform: nil)
|
||||
let theCTFrameProgression: CTFrameProgression = {
|
||||
switch direction {
|
||||
|
@ -134,3 +148,46 @@ public class NSAttributedTextView: NSView {
|
|||
CTFrameDraw(newFrame, context)
|
||||
}
|
||||
}
|
||||
|
||||
public class NSAttributedTooltipTextView: NSAttributedTextView {
|
||||
override public func attributedStringValue(areaCalculation: Bool = false) -> NSAttributedString {
|
||||
var newAttributes = attributes
|
||||
let isVertical: Bool = !(direction == .horizontal)
|
||||
newAttributes[.verticalGlyphForm] = isVertical
|
||||
let newStyle: NSMutableParagraphStyle = newAttributes[.paragraphStyle] as! NSMutableParagraphStyle
|
||||
if #available(macOS 10.13, *) {
|
||||
newStyle.lineSpacing = isVertical ? (fontSize / -2) : fontSize * 0.1
|
||||
newStyle.maximumLineHeight = fontSize * 1.1
|
||||
newStyle.minimumLineHeight = fontSize * 1.1
|
||||
}
|
||||
newAttributes[.paragraphStyle] = newStyle
|
||||
var text: String = text ?? text ?? ""
|
||||
if !(direction == .horizontal) {
|
||||
text = text.replacingOccurrences(of: "˙", with: "・")
|
||||
text = text.replacingOccurrences(of: "\u{A0}", with: " ")
|
||||
text = text.replacingOccurrences(of: "+", with: "")
|
||||
text = text.replacingOccurrences(of: "Shift", with: "⇧")
|
||||
text = text.replacingOccurrences(of: "Control", with: "⌃")
|
||||
text = text.replacingOccurrences(of: "Enter", with: "⏎")
|
||||
text = text.replacingOccurrences(of: "Command", with: "⌘")
|
||||
text = text.replacingOccurrences(of: "Delete", with: "⌦")
|
||||
text = text.replacingOccurrences(of: "BackSpace", with: "⌫")
|
||||
text = text.replacingOccurrences(of: "SHIFT", with: "⇧")
|
||||
text = text.replacingOccurrences(of: "CONTROL", with: "⌃")
|
||||
text = text.replacingOccurrences(of: "ENTER", with: "⏎")
|
||||
text = text.replacingOccurrences(of: "COMMAND", with: "⌘")
|
||||
text = text.replacingOccurrences(of: "DELETE", with: "⌦")
|
||||
text = text.replacingOccurrences(of: "BACKSPACE", with: "⌫")
|
||||
}
|
||||
if areaCalculation {
|
||||
text = text.replacingOccurrences(
|
||||
of: "[^\n]",
|
||||
with: "國",
|
||||
options: .regularExpression,
|
||||
range: text.range(of: text)
|
||||
)
|
||||
}
|
||||
let attributedText = NSMutableAttributedString(string: text, attributes: newAttributes)
|
||||
return attributedText
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit eeff2e3f7073873c07b4011717e32430db01227f
|
||||
Subproject commit c5b2fe7f08971cf2719f553de9de967097bd56b6
|
|
@ -174,7 +174,10 @@ extension KeyHandler {
|
|||
} else if currentLM.hasUnigramsFor(key: " ") {
|
||||
compositor.insertKey(" ")
|
||||
walk()
|
||||
let inputting = buildInputtingState
|
||||
// 一邊吃一邊屙(僅對位列黑名單的 App 用這招限制組字區長度)。
|
||||
let textToCommit = commitOverflownComposition
|
||||
var inputting = buildInputtingState
|
||||
inputting.textToCommit = textToCommit
|
||||
stateCallback(inputting)
|
||||
}
|
||||
return true
|
||||
|
@ -293,7 +296,10 @@ extension KeyHandler {
|
|||
if composer.isEmpty {
|
||||
compositor.insertKey("_punctuation_list")
|
||||
walk()
|
||||
let inputting = buildInputtingState
|
||||
// 一邊吃一邊屙(僅對位列黑名單的 App 用這招限制組字區長度)。
|
||||
let textToCommit = commitOverflownComposition
|
||||
var inputting = buildInputtingState
|
||||
inputting.textToCommit = textToCommit
|
||||
stateCallback(inputting)
|
||||
stateCallback(buildCandidate(state: inputting))
|
||||
} else { // 不要在注音沒敲完整的情況下叫出統合符號選單。
|
||||
|
|
|
@ -274,7 +274,10 @@ extension KeyHandler {
|
|||
|
||||
compositor.insertKey(customPunctuation)
|
||||
walk()
|
||||
let inputting = buildInputtingState
|
||||
// 一邊吃一邊屙(僅對位列黑名單的 App 用這招限制組字區長度)。
|
||||
let textToCommit = commitOverflownComposition
|
||||
var inputting = buildInputtingState
|
||||
inputting.textToCommit = textToCommit
|
||||
stateCallback(inputting)
|
||||
|
||||
// 從這一行之後開始,就是針對逐字選字模式的單獨處理。
|
||||
|
|
|
@ -81,11 +81,12 @@ class ctlInputMethod: IMKInputController {
|
|||
keyHandler.composer.clear()
|
||||
handle(state: keyHandler.buildInputtingState)
|
||||
}
|
||||
if state.hasComposition {
|
||||
let isSecureMode = mgrPrefs.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
|
||||
if state.hasComposition, !isSecureMode {
|
||||
/// 將傳回的新狀態交給調度函式。
|
||||
handle(state: IMEState.ofCommitting(textToCommit: state.displayedText))
|
||||
}
|
||||
handle(state: IMEState.ofEmpty())
|
||||
handle(state: isSecureMode ? IMEState.ofAbortion() : IMEState.ofEmpty())
|
||||
}
|
||||
|
||||
// MARK: - IMKInputController 方法
|
||||
|
|
|
@ -13,6 +13,15 @@ import Cocoa
|
|||
// MARK: - Tooltip Display and Candidate Display Methods
|
||||
|
||||
extension ctlInputMethod {
|
||||
// 有些 App 會濫用內文組字區的內容來預測使用者的輸入行為。
|
||||
// 對此類 App 有疑慮者,可以將這類 App 登記到客體管理員當中。
|
||||
// 這樣,不但強制使用(限制讀音 20 個的)浮動組字窗,而且內文組字區只會顯示一個空格。
|
||||
var attributedStringSecured: (NSAttributedString, NSRange) {
|
||||
mgrPrefs.clientsIMKTextInputIncapable.contains(clientBundleIdentifier)
|
||||
? (state.data.attributedStringPlaceholder, NSRange(location: 0, length: 0))
|
||||
: (state.attributedString, NSRange(state.data.u16MarkedRange))
|
||||
}
|
||||
|
||||
func lineHeightRect(zeroCursor: Bool = false) -> NSRect {
|
||||
var lineHeightRect = NSRect.seniorTheBeast
|
||||
guard let client = client() else {
|
||||
|
|
|
@ -83,6 +83,7 @@ extension ctlInputMethod {
|
|||
}
|
||||
// 浮動組字窗的顯示判定
|
||||
if state.hasComposition, mgrPrefs.clientsIMKTextInputIncapable.contains(clientBundleIdentifier) {
|
||||
ctlInputMethod.popupCompositionBuffer.isTypingDirectionVertical = isVerticalTyping
|
||||
ctlInputMethod.popupCompositionBuffer.show(
|
||||
state: state, at: lineHeightRect(zeroCursor: true).origin
|
||||
)
|
||||
|
@ -96,7 +97,7 @@ extension ctlInputMethod {
|
|||
guard let client = client() else { return }
|
||||
if state.type == .ofAssociates {
|
||||
client.setMarkedText(
|
||||
state.attributedString, selectionRange: NSRange(location: 0, length: 0),
|
||||
state.data.attributedStringPlaceholder, selectionRange: NSRange(location: 0, length: 0),
|
||||
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
||||
)
|
||||
return
|
||||
|
@ -107,7 +108,7 @@ extension ctlInputMethod {
|
|||
/// 是 0 且取代範圍(replacementRange)為「NSNotFound」罷了。
|
||||
/// 也就是說,內文組字區該在哪裡出現,得由客體軟體來作主。
|
||||
client.setMarkedText(
|
||||
state.attributedString, selectionRange: NSRange(state.data.u16MarkedRange),
|
||||
attributedStringSecured.0, selectionRange: attributedStringSecured.1,
|
||||
replacementRange: NSRange(location: NSNotFound, length: NSNotFound)
|
||||
)
|
||||
return
|
||||
|
|
|
@ -208,7 +208,9 @@ extension ctlInputMethod {
|
|||
|
||||
@objc func showCheatSheet(_: Any?) {
|
||||
guard let url = Bundle.main.url(forResource: "shortcuts", withExtension: "html") else { return }
|
||||
NSWorkspace.shared.openFile(url.path, withApplication: "Safari")
|
||||
DispatchQueue.main.async {
|
||||
NSWorkspace.shared.openFile(url.path, withApplication: "Safari")
|
||||
}
|
||||
}
|
||||
|
||||
@objc func showClientListMgr(_: Any?) {
|
||||
|
|
|
@ -125,7 +125,9 @@ public enum IME {
|
|||
// MARK: - Open a phrase data file.
|
||||
|
||||
static func openPhraseFile(fromURL url: URL) {
|
||||
openPhraseFile(userFileAt: url.path)
|
||||
DispatchQueue.main.async {
|
||||
openPhraseFile(userFileAt: url.path)
|
||||
}
|
||||
}
|
||||
|
||||
static func openPhraseFile(userFileAt path: String) {
|
||||
|
|
|
@ -9,6 +9,14 @@
|
|||
import Cocoa
|
||||
|
||||
public class ctlPopupCompositionBuffer: NSWindowController {
|
||||
public var isTypingDirectionVertical: Bool = false {
|
||||
didSet {
|
||||
if #unavailable(macOS 10.14) {
|
||||
isTypingDirectionVertical = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var messageTextField: NSTextField
|
||||
private var textShown: NSAttributedString = .init(string: "") {
|
||||
didSet {
|
||||
|
@ -18,18 +26,15 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
|||
}
|
||||
|
||||
public init() {
|
||||
let transparentVisualEffect = NSVisualEffectView()
|
||||
transparentVisualEffect.blendingMode = .behindWindow
|
||||
transparentVisualEffect.state = .active
|
||||
let contentRect = NSRect(x: 128.0, y: 128.0, width: 300.0, height: 20.0)
|
||||
let styleMask: NSWindow.StyleMask = [.borderless, .nonactivatingPanel]
|
||||
let panel = NSPanel(
|
||||
contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: false
|
||||
)
|
||||
panel.contentView = transparentVisualEffect
|
||||
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 1)
|
||||
panel.hasShadow = true
|
||||
panel.backgroundColor = NSColor.clear
|
||||
panel.backgroundColor = NSColor.controlBackgroundColor
|
||||
panel.styleMask = .fullSizeContentView
|
||||
|
||||
messageTextField = NSTextField()
|
||||
messageTextField.isEditable = false
|
||||
|
@ -40,6 +45,7 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
|||
messageTextField.backgroundColor = NSColor.clear
|
||||
messageTextField.font = .systemFont(ofSize: 18)
|
||||
panel.contentView?.addSubview(messageTextField)
|
||||
panel.contentView?.wantsLayer = true
|
||||
super.init(window: panel)
|
||||
}
|
||||
|
||||
|
@ -53,31 +59,74 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
|||
hide()
|
||||
return
|
||||
}
|
||||
// 在這個視窗內的下畫線繪製方法就得單獨設計了。
|
||||
|
||||
let attrString: NSMutableAttributedString = .init(string: state.data.displayedTextConverted)
|
||||
attrString.setAttributes(
|
||||
[
|
||||
.backgroundColor: NSColor.alternateSelectedControlColor,
|
||||
.foregroundColor: NSColor.alternateSelectedControlTextColor,
|
||||
let verticalAttributes: [NSAttributedString.Key: Any] = [
|
||||
.verticalGlyphForm: true,
|
||||
.paragraphStyle: {
|
||||
let newStyle = NSMutableParagraphStyle()
|
||||
if #available(macOS 10.13, *) {
|
||||
let fontSize = messageTextField.font?.pointSize ?? 18
|
||||
newStyle.lineSpacing = fontSize / -3
|
||||
newStyle.maximumLineHeight = fontSize
|
||||
newStyle.minimumLineHeight = fontSize
|
||||
}
|
||||
return newStyle
|
||||
}(),
|
||||
]
|
||||
|
||||
if isTypingDirectionVertical {
|
||||
attrString.setAttributes(
|
||||
verticalAttributes, range: NSRange(location: 0, length: attrString.string.utf16.count)
|
||||
)
|
||||
}
|
||||
|
||||
let markerAttributes: [NSAttributedString.Key: Any] = {
|
||||
var result: [NSAttributedString.Key: Any] = [
|
||||
.backgroundColor: IME.isDarkMode ? NSColor.systemRed : NSColor.systemYellow,
|
||||
.markedClauseSegment: 0,
|
||||
],
|
||||
]
|
||||
if isTypingDirectionVertical {
|
||||
result[.paragraphStyle] = verticalAttributes[.paragraphStyle]
|
||||
result[.verticalGlyphForm] = true
|
||||
}
|
||||
return result
|
||||
}()
|
||||
|
||||
// 在這個視窗內的下畫線繪製方法就得單獨設計了。
|
||||
attrString.setAttributes(
|
||||
markerAttributes,
|
||||
range: NSRange(
|
||||
location: state.data.u16MarkedRange.lowerBound,
|
||||
length: state.data.u16MarkedRange.upperBound - state.data.u16MarkedRange.lowerBound
|
||||
)
|
||||
)
|
||||
let attrCursor = NSMutableAttributedString(string: "_")
|
||||
if #available(macOS 10.13, *) {
|
||||
attrCursor.setAttributes(
|
||||
[
|
||||
.kern: -18,
|
||||
.baselineOffset: -2,
|
||||
.markedClauseSegment: 1,
|
||||
],
|
||||
range: NSRange(location: 0, length: attrCursor.string.utf16.count)
|
||||
)
|
||||
}
|
||||
|
||||
let cursorAttributes: [NSAttributedString.Key: Any] = {
|
||||
var result: [NSAttributedString.Key: Any] = [
|
||||
.kern: -18,
|
||||
.foregroundColor: NSColor.textColor,
|
||||
]
|
||||
if isTypingDirectionVertical {
|
||||
result[.paragraphStyle] = verticalAttributes[.paragraphStyle]
|
||||
result[.verticalGlyphForm] = true
|
||||
result[.baselineOffset] = 3
|
||||
} else {
|
||||
result[.baselineOffset] = -2
|
||||
}
|
||||
if #unavailable(macOS 10.13) {
|
||||
result[.kern] = 0
|
||||
result[.baselineOffset] = 0
|
||||
}
|
||||
return result
|
||||
}()
|
||||
|
||||
let attrCursor: NSAttributedString =
|
||||
isTypingDirectionVertical
|
||||
? NSMutableAttributedString(string: "▔", attributes: cursorAttributes)
|
||||
: NSMutableAttributedString(string: "_", attributes: cursorAttributes)
|
||||
attrString.insert(attrCursor, at: state.data.u16Cursor)
|
||||
|
||||
textShown = attrString
|
||||
messageTextField.maximumNumberOfLines = 1
|
||||
if let editor = messageTextField.currentEditor() {
|
||||
|
@ -105,7 +154,11 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
|||
adjustedPoint.y = min(max(adjustedPoint.y, screenFrame.minY + windowSize.height), screenFrame.maxY)
|
||||
adjustedPoint.x = min(max(adjustedPoint.x, screenFrame.minX), screenFrame.maxX - windowSize.width)
|
||||
|
||||
window.setFrameOrigin(adjustedPoint)
|
||||
if isTypingDirectionVertical {
|
||||
window.setFrameTopLeftPoint(adjustedPoint)
|
||||
} else {
|
||||
window.setFrameOrigin(adjustedPoint)
|
||||
}
|
||||
}
|
||||
|
||||
private func adjustSize() {
|
||||
|
@ -115,12 +168,21 @@ public class ctlPopupCompositionBuffer: NSWindowController {
|
|||
options: [.usesLineFragmentOrigin, .usesFontLeading]
|
||||
)
|
||||
rect.size.width = max(rect.size.width, 20 * CGFloat(attrString.string.count)) + 2
|
||||
rect.size.height = 22
|
||||
rect.size.height *= 1.2
|
||||
rect.size.height = max(22, rect.size.height)
|
||||
if isTypingDirectionVertical {
|
||||
rect = .init(x: rect.minX, y: rect.minY, width: rect.height, height: rect.width)
|
||||
}
|
||||
var bigRect = rect
|
||||
bigRect.size.width += NSFont.systemFontSize
|
||||
bigRect.size.height += NSFont.systemFontSize
|
||||
rect.origin.x += ceil(NSFont.systemFontSize / 2)
|
||||
rect.origin.y += ceil(NSFont.systemFontSize / 2)
|
||||
if isTypingDirectionVertical {
|
||||
messageTextField.boundsRotation = 90
|
||||
} else {
|
||||
messageTextField.boundsRotation = 0
|
||||
}
|
||||
messageTextField.frame = rect
|
||||
window?.setFrame(bigRect, display: true)
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ public class ctlTooltip: NSWindowController {
|
|||
case prompt
|
||||
}
|
||||
|
||||
private var messageText: NSAttributedTextView
|
||||
private var messageText: NSAttributedTooltipTextView
|
||||
private var tooltip: String = "" {
|
||||
didSet {
|
||||
messageText.text = tooltip.isEmpty ? nil : tooltip
|
||||
|
@ -26,7 +26,7 @@ public class ctlTooltip: NSWindowController {
|
|||
}
|
||||
}
|
||||
|
||||
public var direction: NSAttributedTextView.writingDirection = .horizontal {
|
||||
public var direction: NSAttributedTooltipTextView.writingDirection = .horizontal {
|
||||
didSet {
|
||||
if #unavailable(macOS 10.13) { direction = .horizontal }
|
||||
if Bundle.main.preferredLocalizations[0] == "en" { direction = .horizontal }
|
||||
|
@ -43,7 +43,7 @@ public class ctlTooltip: NSWindowController {
|
|||
panel.level = NSWindow.Level(Int(kCGPopUpMenuWindowLevel) + 2)
|
||||
panel.hasShadow = true
|
||||
panel.backgroundColor = NSColor.controlBackgroundColor
|
||||
messageText = NSAttributedTextView()
|
||||
messageText = NSAttributedTooltipTextView()
|
||||
messageText.backgroundColor = NSColor.controlBackgroundColor
|
||||
messageText.textColor = NSColor.textColor
|
||||
panel.contentView?.addSubview(messageText)
|
||||
|
@ -58,7 +58,7 @@ public class ctlTooltip: NSWindowController {
|
|||
public func show(
|
||||
tooltip: String = "", at point: NSPoint,
|
||||
bottomOutOfScreenAdjustmentHeight heightDelta: CGFloat,
|
||||
direction: NSAttributedTextView.writingDirection = .horizontal
|
||||
direction: NSAttributedTooltipTextView.writingDirection = .horizontal
|
||||
) {
|
||||
self.direction = direction
|
||||
self.tooltip = tooltip
|
||||
|
@ -147,24 +147,7 @@ public class ctlTooltip: NSWindowController {
|
|||
}
|
||||
|
||||
private func adjustSize() {
|
||||
let attrString = messageText.attributedStringValue
|
||||
var rect = attrString.boundingRect(
|
||||
with: NSSize(width: 1600.0, height: 1600.0),
|
||||
options: [.usesLineFragmentOrigin, .usesFontLeading, .usesDeviceMetrics]
|
||||
)
|
||||
if direction != .horizontal {
|
||||
rect = .init(x: rect.minX, y: rect.minY, width: rect.height, height: rect.width)
|
||||
rect.size.height += NSFont.systemFontSize
|
||||
rect.size.width *= 1.03
|
||||
rect.size.width = max(rect.size.width, NSFont.systemFontSize * 1.05)
|
||||
rect.size.width = ceil(rect.size.width)
|
||||
} else {
|
||||
rect = .init(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height)
|
||||
rect.size.width += NSFont.systemFontSize
|
||||
rect.size.height *= 1.03
|
||||
rect.size.height = max(rect.size.height, NSFont.systemFontSize * 1.05)
|
||||
rect.size.height = ceil(rect.size.height)
|
||||
}
|
||||
var rect = messageText.shrinkFrame()
|
||||
var bigRect = rect
|
||||
bigRect.size.width += NSFont.systemFontSize
|
||||
bigRect.size.height += NSFont.systemFontSize
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed.";
|
||||
"Just Select" = "Just Select";
|
||||
"Client Manager" = "Client Manager";
|
||||
"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable.";
|
||||
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable.";
|
||||
"Add Client" = "Add Client";
|
||||
"Remove Selected" = "Remove Selected";
|
||||
"Choose the target application bundle." = "Choose the target application bundle.";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed.";
|
||||
"Just Select" = "Just Select";
|
||||
"Client Manager" = "Client Manager";
|
||||
"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable.";
|
||||
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable.";
|
||||
"Add Client" = "Add Client";
|
||||
"Remove Selected" = "Remove Selected";
|
||||
"Choose the target application bundle." = "Choose the target application bundle.";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "毎行は1つ記録とみなす。Option+Enter キーで改行。\n空白の記録値は無視される。";
|
||||
"Just Select" = "直接に選ぶ";
|
||||
"Client Manager" = "客体アプリの管理";
|
||||
"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "IMKTextInput 議定規約に従っていない客体アプリはここでご登録ください。登録済みのアプリは客体アプリ(文字入力を受くアプリ)とされた時に、威注音入力アプリは「吹き出し入力緩衝列ウィンドウ」と「緩衝列容量制限」を起用し、その容量制限は最大限音読み20箇とする。";
|
||||
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "下記の種類の客体アプリはここでご登録ください:1)IMKTextInput 議定規約に反するもの;2)文脈内入力緩衝列の内容の不正利用の疑いのあるもの。登録済みのアプリには、威注音入力アプリは「吹き出し入力緩衝列ウィンドウ」と「緩衝列容量制限」を起用し、容量制限は最大限音読み20箇とする。";
|
||||
"Add Client" = "入れる";
|
||||
"Remove Selected" = "外す";
|
||||
"Choose the target application bundle." = "登録したいアプリのバンドルのお選びを。";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "每行一笔记录,用 Option+Enter 换行。\n空白值会被无视。";
|
||||
"Just Select" = "直接选取";
|
||||
"Client Manager" = "管理客体应用";
|
||||
"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "请在此管理那些不遵守 IMKTextInput 协定的客体应用。威注音输入法对于任何位列在此的客体应用均启用浮动组字窗、且对组字区内容设定容量上限(最多二十个读音)。";
|
||||
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "请在此管理这两类客体应用:1) 不遵守 IMKTextInput 协定;2)有滥用内文组字区的嫌疑。威注音输入法对于任何位列在此的客体应用均启用浮动组字窗、且对组字区内容设定容量上限(最多二十个读音)。";
|
||||
"Add Client" = "登记新客体";
|
||||
"Remove Selected" = "移除所选条目";
|
||||
"Choose the target application bundle." = "请选择要登记的应用程式的封包。";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"One record per line. Use Option+Enter to break lines.\nBlank lines will be dismissed." = "每行一筆記錄,用 Option+Enter 換行。\n空白值會被無視。";
|
||||
"Just Select" = "直接選取";
|
||||
"Client Manager" = "管理客體應用";
|
||||
"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable." = "請在此管理那些不遵守 IMKTextInput 協定的客體應用。威注音輸入法對於任何位列在此的客體應用均啟用浮動組字窗、且對組字區內容設定容量上限(最多二十個讀音)。";
|
||||
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable." = "請在此管理這兩類客體應用:1) 不遵守 IMKTextInput 協定;2)有濫用內文組字區的嫌疑。威注音輸入法對於任何位列在此的客體應用均啟用浮動組字窗、且對組字區內容設定容量上限(最多二十個讀音)。";
|
||||
"Add Client" = "登記新客體";
|
||||
"Remove Selected" = "移除所選條目";
|
||||
"Choose the target application bundle." = "請選擇要登記的應用程式的封包。";
|
||||
|
|
|
@ -165,7 +165,7 @@ extension ctlClientListMgr {
|
|||
guard let window = window else { return }
|
||||
window.title = NSLocalizedString("Client Manager", comment: "")
|
||||
lblClientMgrWindow.stringValue = NSLocalizedString(
|
||||
"Please manage the list of IMKTextInput-incompatible clients here. Clients listed here will trigger vChewing's built-in popup composition buffer window with maximum 20 reading counts holdable.",
|
||||
"Please manage the list of those clients here which are: 1) IMKTextInput-incompatible; 2) suspected from abusing the contents of the inline composition buffer. Clients listed here will only use popup composition buffer with maximum 20 reading counts holdable.",
|
||||
comment: ""
|
||||
)
|
||||
btnAddClient.title = NSLocalizedString("Add Client", comment: "")
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.6.0</string>
|
||||
<string>2.6.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2602</string>
|
||||
<string>2610</string>
|
||||
<key>UpdateInfoEndpoint</key>
|
||||
<string>https://gitee.com/vchewing/vChewing-macOS/raw/main/Update-Info.plist</string>
|
||||
<key>UpdateInfoSite</key>
|
||||
|
|
|
@ -726,7 +726,7 @@
|
|||
<key>USE_HFS+_COMPRESSION</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>2.6.0</string>
|
||||
<string>2.6.1</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
|
|
|
@ -1483,7 +1483,7 @@
|
|||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
|
@ -1493,7 +1493,7 @@
|
|||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
|
||||
|
@ -1522,13 +1522,13 @@
|
|||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
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;
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewingTests;
|
||||
|
@ -1560,7 +1560,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
|
@ -1582,7 +1582,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1612,7 +1612,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
|
@ -1630,7 +1630,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingPhraseEditor;
|
||||
|
@ -1746,7 +1746,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1775,7 +1775,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1805,7 +1805,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
|
@ -1828,7 +1828,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.inputmethod.vChewing;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1852,7 +1852,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
|
@ -1873,7 +1873,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
@ -1896,7 +1896,7 @@
|
|||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 2602;
|
||||
CURRENT_PROJECT_VERSION = 2610;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
|
@ -1911,7 +1911,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.6.0;
|
||||
MARKETING_VERSION = 2.6.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.atelierInmu.vChewing.vChewingInstaller;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
Loading…
Reference in New Issue