UserDef // + dodgeInvalidEdgeCandidateCursorPosition.

This commit is contained in:
ShikiSuen 2024-02-11 00:08:44 +08:00
parent 095a0a34c5
commit 28e53c27ad
12 changed files with 73 additions and 9 deletions

View File

@ -31,7 +31,7 @@ public protocol InputHandlerProtocol {
func clearComposerAndCalligrapher() func clearComposerAndCalligrapher()
func ensureKeyboardParser() func ensureKeyboardParser()
func triageInput(event input: InputSignalProtocol) -> Bool func triageInput(event input: InputSignalProtocol) -> Bool
func generateStateOfCandidates() -> IMEStateProtocol func generateStateOfCandidates(dodge: Bool) -> IMEStateProtocol
func generateStateOfInputting(sansReading: Bool, guarded: Bool) -> IMEStateProtocol func generateStateOfInputting(sansReading: Bool, guarded: Bool) -> IMEStateProtocol
func generateStateOfAssociates(withPair pair: Megrez.KeyValuePaired) -> IMEStateProtocol func generateStateOfAssociates(withPair pair: Megrez.KeyValuePaired) -> IMEStateProtocol
func consolidateNode( func consolidateNode(
@ -46,6 +46,10 @@ extension InputHandlerProtocol {
generateStateOfInputting(sansReading: sansReading, guarded: guarded) generateStateOfInputting(sansReading: sansReading, guarded: guarded)
} }
func generateStateOfCandidates() -> IMEStateProtocol {
generateStateOfCandidates(dodge: true)
}
func consolidateNode(candidate: (keyArray: [String], value: String), respectCursorPushing: Bool, preConsolidate: Bool) { func consolidateNode(candidate: (keyArray: [String], value: String), respectCursorPushing: Bool, preConsolidate: Bool) {
consolidateNode( consolidateNode(
candidate: candidate, respectCursorPushing: respectCursorPushing, candidate: candidate, respectCursorPushing: respectCursorPushing,
@ -83,6 +87,9 @@ public class InputHandler: InputHandlerProtocol {
public var delegate: InputHandlerDelegate? public var delegate: InputHandlerDelegate?
public var prefs: PrefMgrProtocol public var prefs: PrefMgrProtocol
///
var backupCursor: Int?
/// ///
let kEpsilon: Double = 0.000_001 let kEpsilon: Double = 0.000_001
@ -115,6 +122,7 @@ public class InputHandler: InputHandlerProtocol {
compositor.clear() compositor.clear()
isCodePointInputMode = false isCodePointInputMode = false
isHaninKeyboardSymbolMode = false isHaninKeyboardSymbolMode = false
backupCursor = nil
} }
/// / /// /
@ -155,6 +163,43 @@ public class InputHandler: InputHandlerProtocol {
public var isCompositorEmpty: Bool { compositor.isEmpty } public var isCompositorEmpty: Bool { compositor.isEmpty }
func isInvalidEdgeCursorSituation(givenCursor: Int? = nil) -> Bool {
let cursorToCheck = givenCursor ?? compositor.cursor
// prefs.useRearCursorMode 0 (false) macOS
// prefs.useRearCursorMode 1 (true)
switch prefs.useRearCursorMode {
case false where cursorToCheck == 0: return true
case true where cursorToCheck == compositor.length: return true
default: return false
}
}
public func removeBackupCursor() {
backupCursor = nil
}
public func dodgeInvalidEdgeCursorForCandidateState() {
guard !prefs.useSCPCTypingMode else { return }
guard prefs.dodgeInvalidEdgeCandidateCursorPosition else { return }
guard isInvalidEdgeCursorSituation() else { return }
backupCursor = compositor.cursor
switch prefs.useRearCursorMode {
case false where compositor.cursor < compositor.length:
compositor.cursor += 1
if isCursorCuttingChar() { compositor.jumpCursorBySpan(to: .front) }
case true where compositor.cursor > 0:
compositor.cursor -= 1
if isCursorCuttingChar() { compositor.jumpCursorBySpan(to: .rear) }
default: break
}
}
public func restoreBackupCursor() {
guard let theBackupCursor = backupCursor else { return }
compositor.cursor = Swift.max(Swift.min(theBackupCursor, compositor.length), 0)
backupCursor = nil
}
/// ///
/// - Returns: /// - Returns:
func currentMarkedRange() -> Range<Int> { func currentMarkedRange() -> Range<Int> {

View File

@ -25,6 +25,7 @@ extension InputHandler {
/// - Returns: /// - Returns:
public func generateStateOfInputting(sansReading: Bool = false, guarded: Bool = false) -> IMEStateProtocol { public func generateStateOfInputting(sansReading: Bool = false, guarded: Bool = false) -> IMEStateProtocol {
if isConsideredEmptyForNow, !guarded { return IMEState.ofAbortion() } if isConsideredEmptyForNow, !guarded { return IMEState.ofAbortion() }
restoreBackupCursor() // Inputting
var segHighlightedAt: Int? var segHighlightedAt: Int?
let cpInput = isCodePointInputMode && !sansReading let cpInput = isCodePointInputMode && !sansReading
/// (Update the composing buffer) /// (Update the composing buffer)
@ -134,11 +135,15 @@ extension InputHandler {
/// ///
/// - Returns: /// - Returns:
public func generateStateOfCandidates() -> IMEStateProtocol { public func generateStateOfCandidates(dodge: Bool = true) -> IMEStateProtocol {
guard let delegate = delegate else { return IMEState.ofAbortion() }
if dodge, delegate.state.type == .ofInputting {
dodgeInvalidEdgeCursorForCandidateState()
}
var result = IMEState.ofCandidates( var result = IMEState.ofCandidates(
candidates: generateArrayOfCandidates(fixOrder: prefs.useFixedCandidateOrderOnSelection), candidates: generateArrayOfCandidates(fixOrder: prefs.useFixedCandidateOrderOnSelection),
displayTextSegments: compositor.walkedNodes.values, displayTextSegments: compositor.walkedNodes.values,
cursor: delegate?.state.cursor ?? generateStateOfInputting().cursor cursor: compositor.cursor
) )
if !prefs.useRearCursorMode { if !prefs.useRearCursorMode {
let markerBackup = compositor.marker let markerBackup = compositor.marker
@ -1001,7 +1006,7 @@ extension InputHandler {
inputting.textToCommit = textToCommit inputting.textToCommit = textToCommit
delegate.switchState(inputting) delegate.switchState(inputting)
// //
let newState = generateStateOfCandidates() let newState = generateStateOfCandidates(dodge: false)
_ = newState.candidates.isEmpty ? delegate.callError("B5127D8A") : delegate.switchState(newState) _ = newState.candidates.isEmpty ? delegate.callError("B5127D8A") : delegate.switchState(newState)
} else { // } else { //
delegate.callError("17446655") delegate.callError("17446655")

View File

@ -106,6 +106,9 @@ import SwiftExtension
@AppProperty(key: UserDef.kMoveCursorAfterSelectingCandidate.rawValue, defaultValue: true) @AppProperty(key: UserDef.kMoveCursorAfterSelectingCandidate.rawValue, defaultValue: true)
public dynamic var moveCursorAfterSelectingCandidate: Bool public dynamic var moveCursorAfterSelectingCandidate: Bool
@AppProperty(key: UserDef.kDodgeInvalidEdgeCandidateCursorPosition.rawValue, defaultValue: true)
public dynamic var dodgeInvalidEdgeCandidateCursorPosition: Bool
@AppProperty(key: UserDef.kUseDynamicCandidateWindowOrigin.rawValue, defaultValue: true) @AppProperty(key: UserDef.kUseDynamicCandidateWindowOrigin.rawValue, defaultValue: true)
public dynamic var useDynamicCandidateWindowOrigin: Bool public dynamic var useDynamicCandidateWindowOrigin: Bool

View File

@ -281,7 +281,7 @@ extension SessionCtl: CtlCandidateDelegate {
// //
var newState: IMEStateProtocol = updateResult var newState: IMEStateProtocol = updateResult
? inputHandler.generateStateOfCandidates() ? inputHandler.generateStateOfCandidates(dodge: false)
: IMEState.ofCommitting(textToCommit: state.displayedText) : IMEState.ofCommitting(textToCommit: state.displayedText)
newState.tooltipDuration = 1.85 newState.tooltipDuration = 1.85
var tooltipMessage = "" var tooltipMessage = ""

View File

@ -51,6 +51,7 @@ public extension SettingsPanesCocoa {
UserDef.kUseRearCursorMode.render(fixWidth: contentWidth) UserDef.kUseRearCursorMode.render(fixWidth: contentWidth)
UserDef.kMoveCursorAfterSelectingCandidate.render(fixWidth: contentWidth) UserDef.kMoveCursorAfterSelectingCandidate.render(fixWidth: contentWidth)
UserDef.kUseDynamicCandidateWindowOrigin.render(fixWidth: contentWidth) UserDef.kUseDynamicCandidateWindowOrigin.render(fixWidth: contentWidth)
UserDef.kDodgeInvalidEdgeCandidateCursorPosition.render(fixWidth: contentWidth)
}?.boxed() }?.boxed()
NSStackView.buildSection(width: contentWidth) { NSStackView.buildSection(width: contentWidth) {
UserDef.kShowReverseLookupInCandidateUI.render(fixWidth: contentWidth) UserDef.kShowReverseLookupInCandidateUI.render(fixWidth: contentWidth)

View File

@ -41,6 +41,9 @@ public struct VwrSettingsPaneCandidates: View {
@AppStorage(wrappedValue: true, UserDef.kUseDynamicCandidateWindowOrigin.rawValue) @AppStorage(wrappedValue: true, UserDef.kUseDynamicCandidateWindowOrigin.rawValue)
private var useDynamicCandidateWindowOrigin: Bool private var useDynamicCandidateWindowOrigin: Bool
@AppStorage(wrappedValue: true, UserDef.kDodgeInvalidEdgeCandidateCursorPosition.rawValue)
private var dodgeInvalidEdgeCandidateCursorPosition: Bool
@AppStorage(wrappedValue: false, UserDef.kUseFixedCandidateOrderOnSelection.rawValue) @AppStorage(wrappedValue: false, UserDef.kUseFixedCandidateOrderOnSelection.rawValue)
private var useFixedCandidateOrderOnSelection: Bool private var useFixedCandidateOrderOnSelection: Bool
@ -62,6 +65,7 @@ public struct VwrSettingsPaneCandidates: View {
UserDef.kUseDynamicCandidateWindowOrigin.bind($useDynamicCandidateWindowOrigin).render() UserDef.kUseDynamicCandidateWindowOrigin.bind($useDynamicCandidateWindowOrigin).render()
.disabled(useRearCursorMode) .disabled(useRearCursorMode)
} }
UserDef.kDodgeInvalidEdgeCandidateCursorPosition.bind($dodgeInvalidEdgeCandidateCursorPosition).render()
} }
Section { Section {
VwrSettingsPaneCandidates_SelectionKeys() VwrSettingsPaneCandidates_SelectionKeys()

View File

@ -31,6 +31,7 @@ public protocol PrefMgrProtocol {
var shouldAutoReloadUserDataFiles: Bool { get set } var shouldAutoReloadUserDataFiles: Bool { get set }
var useRearCursorMode: Bool { get set } var useRearCursorMode: Bool { get set }
var moveCursorAfterSelectingCandidate: Bool { get set } var moveCursorAfterSelectingCandidate: Bool { get set }
var dodgeInvalidEdgeCandidateCursorPosition: Bool { get set }
var useDynamicCandidateWindowOrigin: Bool { get set } var useDynamicCandidateWindowOrigin: Bool { get set }
var useHorizontalCandidateList: Bool { get set } var useHorizontalCandidateList: Bool { get set }
var chooseCandidateUsingSpace: Bool { get set } var chooseCandidateUsingSpace: Bool { get set }

View File

@ -63,6 +63,7 @@ public enum UserDef: String, CaseIterable, Identifiable {
case kCurrencyNumeralsEnabled = "CurrencyNumeralsEnabled" case kCurrencyNumeralsEnabled = "CurrencyNumeralsEnabled"
case kHalfWidthPunctuationEnabled = "HalfWidthPunctuationEnable" case kHalfWidthPunctuationEnabled = "HalfWidthPunctuationEnable"
case kMoveCursorAfterSelectingCandidate = "MoveCursorAfterSelectingCandidate" case kMoveCursorAfterSelectingCandidate = "MoveCursorAfterSelectingCandidate"
case kDodgeInvalidEdgeCandidateCursorPosition = "DodgeInvalidEdgeCandidateCursorPosition"
case kEscToCleanInputBuffer = "EscToCleanInputBuffer" case kEscToCleanInputBuffer = "EscToCleanInputBuffer"
case kAcceptLeadingIntonations = "AcceptLeadingIntonations" case kAcceptLeadingIntonations = "AcceptLeadingIntonations"
case kSpecifyIntonationKeyBehavior = "SpecifyIntonationKeyBehavior" case kSpecifyIntonationKeyBehavior = "SpecifyIntonationKeyBehavior"
@ -183,6 +184,7 @@ public extension UserDef {
case .kCurrencyNumeralsEnabled: return .bool case .kCurrencyNumeralsEnabled: return .bool
case .kHalfWidthPunctuationEnabled: return .bool case .kHalfWidthPunctuationEnabled: return .bool
case .kMoveCursorAfterSelectingCandidate: return .bool case .kMoveCursorAfterSelectingCandidate: return .bool
case .kDodgeInvalidEdgeCandidateCursorPosition: return .bool
case .kEscToCleanInputBuffer: return .bool case .kEscToCleanInputBuffer: return .bool
case .kAcceptLeadingIntonations: return .bool case .kAcceptLeadingIntonations: return .bool
case .kSpecifyIntonationKeyBehavior: return .integer case .kSpecifyIntonationKeyBehavior: return .integer
@ -357,6 +359,9 @@ public extension UserDef {
case .kMoveCursorAfterSelectingCandidate: return .init( case .kMoveCursorAfterSelectingCandidate: return .init(
userDef: self, shortTitle: "Push the cursor in front of the phrase after selection" userDef: self, shortTitle: "Push the cursor in front of the phrase after selection"
) )
case .kDodgeInvalidEdgeCandidateCursorPosition: return .init(
userDef: self, shortTitle: "i18n:UserDef.kDodgeInvalidEdgeCandidateCursorPosition.shortTitle"
)
case .kEscToCleanInputBuffer: return .init( case .kEscToCleanInputBuffer: return .init(
userDef: self, shortTitle: "Use ESC key to clear the entire input buffer", userDef: self, shortTitle: "Use ESC key to clear the entire input buffer",
description: "If unchecked, the ESC key will try cleaning the unfinished readings / strokes first, and will commit the current composition buffer if there's no unfinished readings / strokes." description: "If unchecked, the ESC key will try cleaning the unfinished readings / strokes first, and will commit the current composition buffer if there's no unfinished readings / strokes."

View File

@ -1,4 +1,3 @@
"! Succeeded in filtering a candidate." = "! Succeeded in filtering a candidate."; "! Succeeded in filtering a candidate." = "! Succeeded in filtering a candidate.";
"! Succeeded in filtering a user phrase." = "! Succeeded in filtering a user phrase."; "! Succeeded in filtering a user phrase." = "! Succeeded in filtering a user phrase.";
"%@-Stroke" = "%@-Stroke"; "%@-Stroke" = "%@-Stroke";
@ -191,6 +190,7 @@
"i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "Bypass the vChewing built-in Caps Lock handling"; "i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "Bypass the vChewing built-in Caps Lock handling";
"i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "Such abuse of SecureEventInput API in the background can hinder all 3rd-party input methods from being able to switch to. It is fine to use SecureEventInput for sensitive input fields. However, an app calling EnableSecureEventInput() is responsible to call DisableSecureEventInput() immediately right after the input field loses focus. This situation may also happen if an app is hanging in the background (or working as a helper application in the background) with its SecureEventInput left enabled."; "i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "Such abuse of SecureEventInput API in the background can hinder all 3rd-party input methods from being able to switch to. It is fine to use SecureEventInput for sensitive input fields. However, an app calling EnableSecureEventInput() is responsible to call DisableSecureEventInput() immediately right after the input field loses focus. This situation may also happen if an app is hanging in the background (or working as a helper application in the background) with its SecureEventInput left enabled.";
"i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "Actively check those processes abusing the SecureEventInput API"; "i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "Actively check those processes abusing the SecureEventInput API";
"i18n:UserDef.kDodgeInvalidEdgeCandidateCursorPosition.shortTitle" = "Dodge Invalid Edge Candidate Cursor Position";
"i18n:UserDef.kNumPadCharInputBehavior.description" = "Choose the behavior of numeric pad inputs."; "i18n:UserDef.kNumPadCharInputBehavior.description" = "Choose the behavior of numeric pad inputs.";
"i18n:UserDef.kNumPadCharInputBehavior.option.0" = "Always directly commit half-width chars"; "i18n:UserDef.kNumPadCharInputBehavior.option.0" = "Always directly commit half-width chars";
"i18n:UserDef.kNumPadCharInputBehavior.option.1" = "Always directly commit full-width chars"; "i18n:UserDef.kNumPadCharInputBehavior.option.1" = "Always directly commit full-width chars";

View File

@ -1,4 +1,3 @@
"! Succeeded in filtering a candidate." = "! 指定された文字候補は排除リストに登録しました。"; "! Succeeded in filtering a candidate." = "! 指定された文字候補は排除リストに登録しました。";
"! Succeeded in filtering a user phrase." = "! この語彙は排除リストに登録完了。"; "! Succeeded in filtering a user phrase." = "! この語彙は排除リストに登録完了。";
"%@-Stroke" = "%@画"; "%@-Stroke" = "%@画";
@ -191,6 +190,7 @@
"i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "威注音入力アプリの内蔵CapsLock処理を不使用"; "i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "威注音入力アプリの内蔵CapsLock処理を不使用";
"i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "このような不正利用は「システム内蔵入力以外の全ての入力アプリがメニューで灰色状態で選べなくて使えない」の元凶である。センシティブな資料の記入どころでSecureEventInputをEnableSecureEventInput()で使うのは当然であるが、「入力中」状態が終わった後必ずDisableSecureEventInput()で状態解消すべきだと義務である。いくつかヘルパーアプリも、あるいはSecureEventInputを呼び起こしてからすぐ固まったアプリも、この状態になりやすい。特に、他のアプリの画面へ切り替えたとしても、固まったアプリのSecureEventInput状態は自動的に解消できぬ。"; "i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "このような不正利用は「システム内蔵入力以外の全ての入力アプリがメニューで灰色状態で選べなくて使えない」の元凶である。センシティブな資料の記入どころでSecureEventInputをEnableSecureEventInput()で使うのは当然であるが、「入力中」状態が終わった後必ずDisableSecureEventInput()で状態解消すべきだと義務である。いくつかヘルパーアプリも、あるいはSecureEventInputを呼び起こしてからすぐ固まったアプリも、この状態になりやすい。特に、他のアプリの画面へ切り替えたとしても、固まったアプリのSecureEventInput状態は自動的に解消できぬ。";
"i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "SecureEventInput API を不正利用しているバクグラウンド・プロセスを自動検知"; "i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "SecureEventInput API を不正利用しているバクグラウンド・プロセスを自動検知";
"i18n:UserDef.kDodgeInvalidEdgeCandidateCursorPosition.shortTitle" = "端末での不合理的な候補選択用カーソル位置を是正";
"i18n:UserDef.kNumPadCharInputBehavior.description" = "テンキー文字の入力行為をご指定ください。"; "i18n:UserDef.kNumPadCharInputBehavior.description" = "テンキー文字の入力行為をご指定ください。";
"i18n:UserDef.kNumPadCharInputBehavior.option.0" = "いつでも半角で直接出力"; "i18n:UserDef.kNumPadCharInputBehavior.option.0" = "いつでも半角で直接出力";
"i18n:UserDef.kNumPadCharInputBehavior.option.1" = "いつでも全角で直接出力"; "i18n:UserDef.kNumPadCharInputBehavior.option.1" = "いつでも全角で直接出力";

View File

@ -1,4 +1,3 @@
"! Succeeded in filtering a candidate." = "! 候选字词滤除成功。"; "! Succeeded in filtering a candidate." = "! 候选字词滤除成功。";
"! Succeeded in filtering a user phrase." = "! 成功滤除该词音配对。"; "! Succeeded in filtering a user phrase." = "! 成功滤除该词音配对。";
"%@-Stroke" = "%@画"; "%@-Stroke" = "%@画";
@ -191,6 +190,7 @@
"i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "不使用威注音输入法内建的 Caps Lock 处理"; "i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "不使用威注音输入法内建的 Caps Lock 处理";
"i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "这种滥用会导致系统内的所有第三方输入法全都无法正常使用(在输入法选单内会变成灰色)。针对需要填写敏感数据的场合,使用 SecureEventInput 无可厚非。但是,用 EnableSecureEventInput() 开启该模式之后,就有义务在输入窗格失焦的那一刻呼叫 DisableSecureEventInput() 来结束这种状态。这种状态还常见于后台辅助 App 当中、或者某个 App 在叫出该模式之后失去响应这样的话哪怕被切换到后台SecureEventInput 也不会自动解除)。"; "i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "这种滥用会导致系统内的所有第三方输入法全都无法正常使用(在输入法选单内会变成灰色)。针对需要填写敏感数据的场合,使用 SecureEventInput 无可厚非。但是,用 EnableSecureEventInput() 开启该模式之后,就有义务在输入窗格失焦的那一刻呼叫 DisableSecureEventInput() 来结束这种状态。这种状态还常见于后台辅助 App 当中、或者某个 App 在叫出该模式之后失去响应这样的话哪怕被切换到后台SecureEventInput 也不会自动解除)。";
"i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "主动检测正在滥用 SecureEventInput API 的后台进程"; "i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "主动检测正在滥用 SecureEventInput API 的后台进程";
"i18n:UserDef.kDodgeInvalidEdgeCandidateCursorPosition.shortTitle" = "糾正不合理的端点选字游标位置";
"i18n:UserDef.kNumPadCharInputBehavior.description" = "指定数字小键盘的输入行为。"; "i18n:UserDef.kNumPadCharInputBehavior.description" = "指定数字小键盘的输入行为。";
"i18n:UserDef.kNumPadCharInputBehavior.option.0" = "始终以半形文字直接递交"; "i18n:UserDef.kNumPadCharInputBehavior.option.0" = "始终以半形文字直接递交";
"i18n:UserDef.kNumPadCharInputBehavior.option.1" = "始终以全形文字直接递交"; "i18n:UserDef.kNumPadCharInputBehavior.option.1" = "始终以全形文字直接递交";

View File

@ -1,4 +1,3 @@
"! Succeeded in filtering a candidate." = "! 候選字詞濾除成功。"; "! Succeeded in filtering a candidate." = "! 候選字詞濾除成功。";
"! Succeeded in filtering a user phrase." = "! 成功濾除該詞音配對。"; "! Succeeded in filtering a user phrase." = "! 成功濾除該詞音配對。";
"%@-Stroke" = "%@畫"; "%@-Stroke" = "%@畫";
@ -191,6 +190,7 @@
"i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "不使用威注音輸入法內建的 Caps Lock 處理"; "i18n:UserDef.kBypassNonAppleCapsLockHandling.shortTitle" = "不使用威注音輸入法內建的 Caps Lock 處理";
"i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "這種濫用會導致系統內的所有第三方輸入法全都無法正常使用(在輸入法選單內會變成灰色)。針對需要填寫敏感資料的場合,使用 SecureEventInput 無可厚非。但是,用 EnableSecureEventInput() 開啟該模式之後,就有義務在輸入窗格失焦的那一刻呼叫 DisableSecureEventInput() 來結束這種狀態。這種狀態還常見於後檯輔助 App 當中、或者某個 App 在叫出該模式之後失去回應這樣的話哪怕被切換到後檯SecureEventInput 也不會自動解除)。"; "i18n:userdef.kCheckAbusersOfSecureEventInputAPI.description" = "這種濫用會導致系統內的所有第三方輸入法全都無法正常使用(在輸入法選單內會變成灰色)。針對需要填寫敏感資料的場合,使用 SecureEventInput 無可厚非。但是,用 EnableSecureEventInput() 開啟該模式之後,就有義務在輸入窗格失焦的那一刻呼叫 DisableSecureEventInput() 來結束這種狀態。這種狀態還常見於後檯輔助 App 當中、或者某個 App 在叫出該模式之後失去回應這樣的話哪怕被切換到後檯SecureEventInput 也不會自動解除)。";
"i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "主動偵測正在濫用 SecureEventInput API 的後檯執行緒"; "i18n:UserDef.kCheckAbusersOfSecureEventInputAPI.shortTitle" = "主動偵測正在濫用 SecureEventInput API 的後檯執行緒";
"i18n:UserDef.kDodgeInvalidEdgeCandidateCursorPosition.shortTitle" = "糾正不合理的端點選字游標位置";
"i18n:UserDef.kNumPadCharInputBehavior.description" = "指定數字小鍵盤的輸入行為。"; "i18n:UserDef.kNumPadCharInputBehavior.description" = "指定數字小鍵盤的輸入行為。";
"i18n:UserDef.kNumPadCharInputBehavior.option.0" = "始終以半形文字直接遞交"; "i18n:UserDef.kNumPadCharInputBehavior.option.0" = "始終以半形文字直接遞交";
"i18n:UserDef.kNumPadCharInputBehavior.option.1" = "始終以全形文字直接遞交"; "i18n:UserDef.kNumPadCharInputBehavior.option.1" = "始終以全形文字直接遞交";