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
39 changes: 35 additions & 4 deletions Input Source Pro/Models/ApplicationVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ final class ApplicationVM: ObservableObject {

let cancelBag = CancelBag()
let preferencesVM: PreferencesVM
private var lastResolvedBrowserAppKinds = [String: AppKind]()

lazy var windowAXNotificationPublisher = ApplicationVM
.createWindowAXNotificationPublisher(preferencesVM: preferencesVM)

init(preferencesVM: PreferencesVM) {
self.preferencesVM = preferencesVM
appKind = .from(NSWorkspace.shared.frontmostApplication, preferencesVM: preferencesVM)
appKind = resolveAppKind(for: NSWorkspace.shared.frontmostApplication)

activateAccessibilitiesForCurrentApp()
watchApplicationChange()
Expand Down Expand Up @@ -62,10 +63,14 @@ extension ApplicationVM {
else { return Empty().eraseToAnyPublisher() }

guard NSApplication.isBrowser(app)
else { return Just(.from(app, preferencesVM: preferencesVM)).eraseToAnyPublisher() }
else {
return Just(app)
.compactMap { [weak self] in self?.resolveAppKind(for: $0) }
.eraseToAnyPublisher()
}

return Timer
.interval(seconds: 1)
.interval(seconds: 0.05)
.prepend(Date())
.compactMap { _ in app.focusedUIElement(preferencesVM: preferencesVM) }
.first()
Expand All @@ -79,7 +84,7 @@ extension ApplicationVM {
.map { event in event.runningApp }
}
.prepend(app)
.compactMap { app -> AppKind? in .from(app, preferencesVM: preferencesVM) }
.compactMap { [weak self] in self?.resolveAppKind(for: $0) }
.eraseToAnyPublisher()
}
.removeDuplicates(by: { $0.isSameAppOrWebsite(with: $1, detectAddressBar: true) })
Expand All @@ -103,4 +108,30 @@ extension ApplicationVM {
.sink { $0.getApp().activateAccessibilities() }
.store(in: cancelBag)
}

private func resolveAppKind(for app: NSRunningApplication?) -> AppKind? {
guard let app else { return nil }

let resolved = AppKind.from(app, preferencesVM: preferencesVM)

if let browserInfo = resolved.getBrowserInfo(),
!browserInfo.isFocusedOnAddressBar,
browserInfo.url != .newtab,
let bundleIdentifier = app.bundleIdentifier
{
lastResolvedBrowserAppKinds[bundleIdentifier] = resolved
return resolved
}

guard preferencesVM.isBrowserAndEnabled(app),
let bundleIdentifier = app.bundleIdentifier,
case .normal = resolved,
let fallback = lastResolvedBrowserAppKinds[bundleIdentifier]
else {
return resolved
}

logger.debug { "Reusing cached browser context for \(bundleIdentifier) while waiting for the focused tab to resolve." }
return fallback
}
}
6 changes: 5 additions & 1 deletion Input Source Pro/Models/IndicatorVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,11 @@ extension IndicatorVM {

return updateState(appKind: state.appKind, inputSource: inputSource, inputSourceChangeReason: .system)
case let .switchInputSourceByShortcut(inputSource):
inputSourceVM.select(inputSource: inputSource, app: state.appKind?.getApp())
inputSourceVM.select(
inputSource: inputSource,
app: state.appKind?.getApp(),
allowShortcutFallback: false
)

return updateState(appKind: state.appKind, inputSource: inputSource, inputSourceChangeReason: .shortcut)
}
Expand Down
40 changes: 34 additions & 6 deletions Input Source Pro/Models/InputSourceVM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class InputSourceVM: ObservableObject {
private struct SelectionRequest {
let inputSource: InputSource
let app: NSRunningApplication?
let allowShortcutFallback: Bool
}

let preferencesVM: PreferencesVM
Expand All @@ -35,22 +36,49 @@ class InputSourceVM: ObservableObject {
selectInputSourceSubject
.tap { [weak self] in
if let self {
$0.inputSource.select(cJKVFixStrategy: self.preferencesVM.activeCJKVFixStrategy(for: $0.app))
$0.inputSource.select(
cJKVFixStrategy: self.preferencesVM.activeCJKVFixStrategy(for: $0.app),
allowShortcutFallback: $0.allowShortcutFallback
)
}
}
.flatMapLatest({ _ in
Timer
.interval(seconds: 1)
.eraseToAnyPublisher()
Publishers.MergeMany([
Just(())
.eraseToAnyPublisher(),
Timer
.delay(seconds: 0.05)
.mapToVoid()
.eraseToAnyPublisher(),
Timer
.delay(seconds: 0.15)
.mapToVoid()
.eraseToAnyPublisher(),
Timer
.delay(seconds: 0.3)
.mapToVoid()
.eraseToAnyPublisher()
])
.eraseToAnyPublisher()
})
.sink { [weak self] _ in
self?.inputSourceChangesSubject.send(())
}
.store(in: cancelBag)
}

func select(inputSource: InputSource, app: NSRunningApplication? = nil) {
selectInputSourceSubject.send(SelectionRequest(inputSource: inputSource, app: app))
func select(
inputSource: InputSource,
app: NSRunningApplication? = nil,
allowShortcutFallback: Bool = true
) {
selectInputSourceSubject.send(
SelectionRequest(
inputSource: inputSource,
app: app,
allowShortcutFallback: allowShortcutFallback
)
)
}

private func watchSystemNotification() {
Expand Down
2 changes: 1 addition & 1 deletion Input Source Pro/Utilities/AppKit/AppRuleMenuItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class AppRuleMenuItem: NSMenuItem {
}

if let inputSource {
inputSourceVM.select(inputSource: inputSource, app: app)
inputSourceVM.select(inputSource: inputSource, app: app, allowShortcutFallback: false)
}

watchChanges()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class BrowserRuleMenuItem: NSMenuItem {
}

if let inputSource {
inputSourceVM.select(inputSource: inputSource, app: app)
inputSourceVM.select(inputSource: inputSource, app: app, allowShortcutFallback: false)
}

watchChanges()
Expand Down
8 changes: 6 additions & 2 deletions Input Source Pro/Utilities/InputSource/InputSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,12 @@ class InputSource {
}()
}

func select(cJKVFixStrategy: CJKVFixStrategy?) {
InputSourceSwitcher.switchToInputSource(self, cJKVFixStrategy: cJKVFixStrategy)
func select(cJKVFixStrategy: CJKVFixStrategy?, allowShortcutFallback: Bool = true) {
InputSourceSwitcher.switchToInputSource(
self,
cJKVFixStrategy: cJKVFixStrategy,
allowShortcutFallback: allowShortcutFallback
)
}

private var normalizedInputModeID: String? {
Expand Down
Loading