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
11 changes: 10 additions & 1 deletion Cotabby/Support/Focus/Applications/BrowserAppDetector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,23 @@ nonisolated enum BrowserAppDetector {
/// editor, the Copilot chat, or the integrated terminal, so no suggestions appear anywhere in the
/// app even though screenshot-based OCR keeps working.
///
/// Obsidian (`md.obsidian`, issue #791) is the same failure in a different editor. Its
/// CodeMirror 6 surface is a `contenteditable` with `role="textbox"`, which Chromium exposes as
/// `AXTextArea` only once the web-AX tree is awake. A read-only probe of Obsidian 1.12.7
/// (Electron 39) showed the application element advertising `AXManualAccessibility` (settable,
/// value 0) while the focused window held a single bare `AXGroup`: the dormant renderer view.
/// With the bundle absent here nothing ever flipped that switch, so the system-wide focus query
/// returned nil and the tracker reported "No focused Accessibility element" on every tick.
///
/// Cursor is intentionally absent: it ships under opaque ToDesktop bundle ids
/// (`com.todesktop.<hash>`) that change between builds, so there is no stable id to allowlist
/// here without a broad `com.todesktop.` prefix that would also prime unrelated ToDesktop apps.
private static let electronEditorBundleIdentifiers: Set<String> = [
"com.clickup.desktop-app",
"com.microsoft.vscode", // Visual Studio Code
"com.microsoft.vscodeinsiders", // VS Code - Insiders
"com.vscodium" // VSCodium (FOSS VS Code build)
"com.vscodium", // VSCodium (FOSS VS Code build)
"md.obsidian" // Obsidian (Electron, CodeMirror 6 editor) — #791
]

/// Broad check: is the user typing inside any web browser? Used for prompt tone hints.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ final class WebContentFieldDetectorTests: XCTestCase {
vendsDOMAttributes: false
)
)
// Obsidian is an allowlisted Electron editor (#791), so its fields count as web content even
// before the DOM-reflection attributes arrive on the focused node.
XCTAssertTrue(
WebContentFieldDetector.isWebContentField(
bundleIdentifier: "md.obsidian",
vendsDOMAttributes: false
)
)
}

func test_nativeAppIsNotWebContent() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ final class BrowserAppDetectorTests: XCTestCase {
XCTAssertTrue(BrowserAppDetector.isElectronEditor(bundleIdentifier: "com.microsoft.VSCode"))
XCTAssertTrue(BrowserAppDetector.isElectronEditor(bundleIdentifier: "com.microsoft.VSCodeInsiders"))
XCTAssertTrue(BrowserAppDetector.isElectronEditor(bundleIdentifier: "com.vscodium"))
// Obsidian (#791): Electron 39 / CodeMirror 6. Its app element advertises
// AXManualAccessibility, but nothing flips it unless the bundle is allowlisted here, so the
// editor's web-AX tree stays dormant and no focused field ever resolves.
XCTAssertTrue(BrowserAppDetector.isElectronEditor(bundleIdentifier: "md.obsidian"))
XCTAssertTrue(BrowserAppDetector.isElectronEditor(bundleIdentifier: "MD.Obsidian"))
// Electron, but not a text-editing surface we cover: must stay out of the priming allowlist.
XCTAssertFalse(BrowserAppDetector.isElectronEditor(bundleIdentifier: "com.hnc.Discord"))
XCTAssertFalse(BrowserAppDetector.isElectronEditor(bundleIdentifier: nil))
Expand All @@ -49,6 +54,8 @@ final class BrowserAppDetectorTests: XCTestCase {
BrowserAppDetector.needsWebAccessibilityPriming(bundleIdentifier: "com.clickup.desktop-app"))
XCTAssertTrue(
BrowserAppDetector.needsWebAccessibilityPriming(bundleIdentifier: "com.microsoft.VSCode"))
XCTAssertTrue(
BrowserAppDetector.needsWebAccessibilityPriming(bundleIdentifier: "md.obsidian"))
XCTAssertFalse(
BrowserAppDetector.needsWebAccessibilityPriming(bundleIdentifier: "com.apple.Safari"))
XCTAssertFalse(
Expand Down