Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Input Source Pro/Models/IndicatorVM+Triggers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ extension IndicatorVM {
}
}

if previous?.inputSource.id != current.inputSource.id {
if previous?.inputSource.persistentIdentifier != current.inputSource.persistentIdentifier {
switch current.inputSourceChangeReason {
case .noChanges:
return .justHide
Expand Down
4 changes: 2 additions & 2 deletions Input Source Pro/Models/IndicatorVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ extension IndicatorVM {
guard appKind1.isSameAppOrWebsite(with: appKind2, detectAddressBar: true)
else { return false }

guard lhs.inputSource.id == rhs.inputSource.id
guard lhs.inputSource.persistentIdentifier == rhs.inputSource.persistentIdentifier
else { return false }

return true
Expand Down Expand Up @@ -249,7 +249,7 @@ extension IndicatorVM {
)
}
case let .inputSourceChanged(inputSource):
guard inputSource.id != state.inputSource.id else { return state }
guard inputSource.persistentIdentifier != state.inputSource.persistentIdentifier else { return state }

return updateState(appKind: state.appKind, inputSource: inputSource, inputSourceChangeReason: .system)
case let .switchInputSourceByShortcut(inputSource):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extension PreferencesVM {
let defaultKeyboard = getAppDefaultKeyboard(appKind)

if appNeedCacheKeyboard(appKind),
defaultKeyboard?.id != keyboard.id
defaultKeyboard?.persistentIdentifier != keyboard.persistentIdentifier
{
appKeyboardCache.save(appKind, keyboard: keyboard)
} else {
Expand Down
4 changes: 2 additions & 2 deletions Input Source Pro/Models/PreferencesVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -537,11 +537,11 @@ extension Preferences {

extension PreferencesVM {
var systemWideDefaultKeyboard: InputSource? {
return InputSource.sources.first { $0.id == preferences.systemWideDefaultKeyboardId }
return InputSource.resolvePersistedIdentifier(preferences.systemWideDefaultKeyboardId)
}

var browserAddressDefaultKeyboard: InputSource? {
return InputSource.sources.first { $0.id == preferences.browserAddressDefaultKeyboardId }
return InputSource.resolvePersistedIdentifier(preferences.browserAddressDefaultKeyboardId)
}
}

Expand Down
4 changes: 1 addition & 3 deletions Input Source Pro/Persistence/AppRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ extension AppRule {
extension AppRule {
@MainActor
var forcedKeyboard: InputSource? {
guard let inputSourceId = inputSourceId else { return nil }

return InputSource.sources.first { $0.id == inputSourceId }
return InputSource.resolvePersistedIdentifier(inputSourceId)
}

var functionKeyMode: FKeyMode? {
Expand Down
4 changes: 1 addition & 3 deletions Input Source Pro/Persistence/BrowserRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ enum BrowserRuleType: Int32, CaseIterable {
extension BrowserRule {
@MainActor
var forcedKeyboard: InputSource? {
guard let inputSourceId = inputSourceId else { return nil }

return InputSource.sources.first { $0.id == inputSourceId }
return InputSource.resolvePersistedIdentifier(inputSourceId)
}

var type: BrowserRuleType {
Expand Down
10 changes: 8 additions & 2 deletions Input Source Pro/UI/Components/BrowserRuleEditView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ struct BrowserRuleEditView: View {

var inputSourceItems: [PickerItem] {
[PickerItem.empty]
+ InputSource.sources.map { PickerItem(id: $0.id, title: $0.name, toolTip: $0.id) }
+ InputSource.sources.map {
PickerItem(id: $0.persistentIdentifier, title: $0.name, toolTip: $0.persistentIdentifier)
}
}

var restoreStrategyItems: [PickerItem] {
Expand Down Expand Up @@ -199,7 +201,11 @@ struct BrowserRuleEditView: View {
hideIndicator = rule?.hideIndicator ?? false

if let inputSource = rule?.forcedKeyboard {
inputSourceItem = PickerItem(id: inputSource.id, title: inputSource.name, toolTip: inputSource.id)
inputSourceItem = PickerItem(
id: inputSource.persistentIdentifier,
title: inputSource.name,
toolTip: inputSource.persistentIdentifier
)
}

if let keyboardRestoreStrategy = rule?.keyboardRestoreStrategy {
Expand Down
12 changes: 9 additions & 3 deletions Input Source Pro/UI/Components/RulesApplicationDetail.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct ApplicationDetail: View {
@State var functionKeyModeItem: PickerItem?

var mixed: Bool {
Set(selectedApp.map { $0.forcedKeyboard?.id }).count > 1
Set(selectedApp.map { $0.forcedKeyboard?.persistentIdentifier }).count > 1
}

var isFunctionKeyModeMixed: Bool {
Expand All @@ -36,7 +36,9 @@ struct ApplicationDetail: View {

var items: [PickerItem] {
[mixed ? PickerItem.mixed : nil, PickerItem.empty].compactMap { $0 }
+ InputSource.sources.map { PickerItem(id: $0.id, title: $0.name, toolTip: $0.id) }
+ InputSource.sources.map {
PickerItem(id: $0.persistentIdentifier, title: $0.name, toolTip: $0.persistentIdentifier)
}
}

var functionKeyItems: [PickerItem] {
Expand Down Expand Up @@ -208,7 +210,11 @@ struct ApplicationDetail: View {
if mixed {
forceKeyboard = PickerItem.mixed
} else if let keyboard = selectedApp.first?.forcedKeyboard {
forceKeyboard = PickerItem(id: keyboard.id, title: keyboard.name, toolTip: keyboard.id)
forceKeyboard = PickerItem(
id: keyboard.persistentIdentifier,
title: keyboard.name,
toolTip: keyboard.persistentIdentifier
)
} else {
forceKeyboard = PickerItem.empty
}
Expand Down
8 changes: 6 additions & 2 deletions Input Source Pro/UI/Screens/BrowserRulesSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ struct BrowserRulesSettingsView: View {

var inputSourceItems: [PickerItem] {
[PickerItem.empty]
+ InputSource.sources.map { PickerItem(id: $0.id, title: $0.name, toolTip: $0.id) }
+ InputSource.sources.map {
PickerItem(id: $0.persistentIdentifier, title: $0.name, toolTip: $0.persistentIdentifier)
}
}

var body: some View {
Expand All @@ -39,7 +41,9 @@ struct BrowserRulesSettingsView: View {
PopUpButtonPicker<PickerItem?>(
items: inputSourceItems,
width: 150,
isItemSelected: { $0?.id == preferencesVM.preferences.browserAddressDefaultKeyboardId },
isItemSelected: {
$0?.id == (preferencesVM.browserAddressDefaultKeyboard?.persistentIdentifier ?? PickerItem.empty.id)
},
getTitle: { $0?.title ?? "" },
getToolTip: { $0?.toolTip },
onSelect: handleBrowserAddressDefaultKeyboardSelect
Expand Down
8 changes: 6 additions & 2 deletions Input Source Pro/UI/Screens/GeneralSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ struct GeneralSettingsView: View {

var items: [PickerItem] {
[PickerItem.empty]
+ InputSource.sources.map { PickerItem(id: $0.id, title: $0.name, toolTip: $0.id) }
+ InputSource.sources.map {
PickerItem(id: $0.persistentIdentifier, title: $0.name, toolTip: $0.persistentIdentifier)
}
}

var body: some View {
Expand Down Expand Up @@ -41,7 +43,9 @@ struct GeneralSettingsView: View {

PopUpButtonPicker<PickerItem?>(
items: items,
isItemSelected: { $0?.id == preferencesVM.preferences.systemWideDefaultKeyboardId },
isItemSelected: {
$0?.id == (preferencesVM.systemWideDefaultKeyboard?.persistentIdentifier ?? PickerItem.empty.id)
},
getTitle: { $0?.title ?? "" },
getToolTip: { $0?.toolTip },
onSelect: handleSystemWideDefaultKeyboardSelect
Expand Down
4 changes: 2 additions & 2 deletions Input Source Pro/Utilities/AppKeyboardCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AppKeyboardCache {
func save(_ kind: AppKind, keyboard: InputSource?) {
guard let id = kind.getId() else { return }

if let keyboardId = keyboard?.id {
if let keyboardId = keyboard?.persistentIdentifier {
logger.debug { "Save \(id)#\(keyboardId)" }
cache[id] = keyboardId
}
Expand All @@ -31,7 +31,7 @@ class AppKeyboardCache {

logger.debug { "Retrieve \(id)#\(keyboardId)" }

return InputSource.sources.first { $0.id == keyboardId }
return InputSource.resolvePersistedIdentifier(keyboardId)
}

func clear() {
Expand Down
4 changes: 2 additions & 2 deletions Input Source Pro/Utilities/AppKit/AppRuleMenuItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class AppRuleMenuItem: NSMenuItem {
}

@objc func forceKeyboard(_: Any) {
let inputSourceId = inputSource?.id ?? ""
let inputSourceId = inputSource?.persistentIdentifier ?? ""

if let appCustomization = appCustomization {
preferencesVM.setForceKeyboard(appCustomization, inputSourceId)
Expand All @@ -56,6 +56,6 @@ class AppRuleMenuItem: NSMenuItem {
}

func updateState() {
state = appCustomization?.inputSourceId == inputSource?.id ? .on : .off
state = appCustomization?.forcedKeyboard?.persistentIdentifier == inputSource?.persistentIdentifier ? .on : .off
}
}
4 changes: 2 additions & 2 deletions Input Source Pro/Utilities/AppKit/BrowserRuleMenuItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class BrowserRuleMenuItem: NSMenuItem {
}

@objc func forceKeyboard(_: Any) {
let inputSourceId = inputSource?.id ?? ""
let inputSourceId = inputSource?.persistentIdentifier ?? ""
let host = url.host ?? ""

if let browserRule = browserRule {
Expand Down Expand Up @@ -69,6 +69,6 @@ class BrowserRuleMenuItem: NSMenuItem {
}

func updateState() {
state = browserRule?.inputSourceId == inputSource?.id ? .on : .off
state = browserRule?.forcedKeyboard?.persistentIdentifier == inputSource?.persistentIdentifier ? .on : .off
}
}
71 changes: 69 additions & 2 deletions Input Source Pro/Utilities/InputSource/InputSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import CryptoKit

@MainActor
class InputSource {
private static let persistentIdentifierSeparator = "::"

static let logger = ISPLogger(
category: "🤖 " + String(describing: InputSource.self),
disabled: true
Expand All @@ -16,6 +18,13 @@ class InputSource {
var id: String { tisInputSource.id }
var name: String { tisInputSource.name }
var inputModeID: String? { tisInputSource.inputModeID }
var persistentIdentifier: String {
if let inputModeID = normalizedInputModeID {
return "\(id)\(Self.persistentIdentifierSeparator)\(inputModeID)"
}

return id
}

var isCJKVR: Bool {
guard let lang = tisInputSource.sourceLanguages.first else { return false }
Expand Down Expand Up @@ -64,11 +73,16 @@ class InputSource {
func select(useCJKVFix: Bool) {
InputSourceSwitcher.switchToInputSource(self, useCJKVFix: useCJKVFix)
}

private var normalizedInputModeID: String? {
guard let inputModeID, !inputModeID.isEmpty else { return nil }
return inputModeID
}
}

extension InputSource: @preconcurrency Equatable {
static func == (lhs: InputSource, rhs: InputSource) -> Bool {
return lhs.id == rhs.id
return lhs.persistentIdentifier == rhs.persistentIdentifier
}
}

Expand All @@ -79,6 +93,47 @@ extension InputSource {
static func getCurrentInputSource() -> InputSource {
return InputSource(tisInputSource: TISCopyCurrentKeyboardInputSource().takeRetainedValue())
}

static func resolvePersistedIdentifier(_ persistedIdentifier: String?) -> InputSource? {
guard let persistedIdentifier, !persistedIdentifier.isEmpty else { return nil }

let sources = Self.sources
let (sourceID, inputModeID) = splitPersistedIdentifier(persistedIdentifier)

if let inputModeID {
if let exactMatch = sources.first(where: { $0.persistentIdentifier == persistedIdentifier }) {
return exactMatch
}

if let modeMatch = sources.first(where: { $0.inputModeID == inputModeID }) {
return modeMatch
}
}

if let modeMatch = sources.first(where: { $0.inputModeID == persistedIdentifier }) {
return modeMatch
}

let matches = sources.filter { $0.id == sourceID }

guard !matches.isEmpty else { return nil }

if let inputModeID,
let modeMatch = matches.first(where: { $0.inputModeID == inputModeID })
{
return modeMatch
}

if matches.count > 1 {
logger.debug { "Ambiguous persisted input source identifier \(persistedIdentifier); preferring an input-mode match." }
}

if let preferredModeMatch = matches.first(where: { $0.inputModeID != nil }) {
return preferredModeMatch
}

return matches.first
}
}

extension InputSource {
Expand All @@ -98,6 +153,18 @@ extension InputSource {
static func anotherCJKVSource(current: InputSource) -> InputSource? {
return sources.first(where: { $0 != current && $0.isCJKVR })
}

private static func splitPersistedIdentifier(_ persistedIdentifier: String) -> (sourceID: String, inputModeID: String?) {
let components = persistedIdentifier.components(separatedBy: persistentIdentifierSeparator)

guard components.count >= 2 else {
return (persistedIdentifier, nil)
}

let sourceID = components[0]
let inputModeID = components.dropFirst().joined(separator: persistentIdentifierSeparator)
return (sourceID, inputModeID.isEmpty ? nil : inputModeID)
}
}

private extension URL {
Expand All @@ -116,6 +183,6 @@ private extension URL {

extension InputSource: @preconcurrency CustomStringConvertible {
var description: String {
id
persistentIdentifier
}
}