Utility to set Mouse Pointer to Ignores

By PaulMartz, 4 September, 2026

Forum
macOS and Mac Apps

I vibe-coded a small Swift command-line utility that sets VoiceOver’s Mouse Pointer setting to “Ignores VoiceOver Cursor,” regardless of its current state.

Here's exactly what it does: It uses the private ScreenReaderCore framework and SCRCUserDefaults to set SCRConfigurationCursorTrackingMToVO and SCRConfigurationCursorTrackingVOToM to false, synchronizes the settings, then makes an announcement using "say."

Save the source as vo-ignore.swift and compile it with:
swiftc -O -o vo-ignore vo-ignore.swift

Then run ./vo-ignore whenever you need to force the Mouse Pointer setting back to Ignore. I wrapped it in an AppleScript and associated it with the keyboard commander VO+I shortcut.

This code works for me on Golden Gate. But it relies on a private Apple framework, so there’s no guarantee Apple won’t change or break it in a future macOS release.

I might put this in a github repo if there's demand for it. All the cool kids use github, right? In the meantime, here's the source:

import Foundation
import ObjectiveC.runtime

// Use VoiceOver's private preferences API so changes reach the running process.
let framework = "/System/Library/PrivateFrameworks/ScreenReaderCore.framework"

guard let bundle = Bundle(path: framework) else {
fatalError("Cannot locate ScreenReaderCore")
}

try bundle.loadAndReturnError()

guard let cls: AnyClass = NSClassFromString("SCRCUserDefaults") else {
fatalError("Cannot find SCRCUserDefaults")
}

// Get the shared VoiceOver preferences object.
let sharedSelector = NSSelectorFromString("sharedUserDefaults")

guard let sharedMethod = class_getClassMethod(cls, sharedSelector) else {
fatalError("Cannot find sharedUserDefaults")
}

typealias SharedFunction =
@convention(c) (AnyClass, Selector) -> AnyObject

let sharedFunction = unsafeBitCast(
method_getImplementation(sharedMethod),
to: SharedFunction.self
)

let defaults = sharedFunction(cls, sharedSelector)

// Set both cursor-tracking directions off.
let setSelector = NSSelectorFromString("setValue:forKey:")

guard let setMethod = class_getInstanceMethod(cls, setSelector) else {
fatalError("Cannot find setValue:forKey:")
}

typealias SetFunction =
@convention(c) (AnyObject, Selector, AnyObject, AnyObject) -> Void

let setFunction = unsafeBitCast(
method_getImplementation(setMethod),
to: SetFunction.self
)

let off = NSNumber(value: false)

setFunction(
defaults,
setSelector,
off,
"SCRConfigurationCursorTrackingMToVO" as NSString
)

setFunction(
defaults,
setSelector,
off,
"SCRConfigurationCursorTrackingVOToM" as NSString
)

// Flush preferences and propagate the change.
let syncSelector = NSSelectorFromString("synchronize")

guard let syncMethod = class_getInstanceMethod(cls, syncSelector) else {
fatalError("Cannot find synchronize")
}

typealias SyncFunction =
@convention(c) (AnyObject, Selector) -> Void

let syncFunction = unsafeBitCast(
method_getImplementation(syncMethod),
to: SyncFunction.self
)

syncFunction(defaults, syncSelector)

// Speak a short confirmation.
let say = Process()
say.executableURL = URL(fileURLWithPath: "/usr/bin/say")
say.arguments = ["Mouse set to ignores."]

try? say.run()

Options

Comments

By Maldalain on Friday, September 4, 2026 - 13:57

It’s so interesting to see developers accomplishing what Apple itself should have done. Clearly, we need to take matters into our own hands to address long-standing issues with VoiceOver.

Paul, I suggest sharing this solution with Apple’s Accessibility team—it might help show them how this issue can finally be resolved.

Thanks again!