我希望能够在我的程序中设置光标大小的系统偏好设置(如辅助功能偏好设置中所见),然后在程序退出时将其恢复。
是否有一种方法可以从应用程序中设置光标大小(特别是)或系统偏好设置?
我希望能够在我的程序中设置光标大小的系统偏好设置(如辅助功能偏好设置中所见),然后在程序退出时将其恢复。
是否有一种方法可以从应用程序中设置光标大小(特别是)或系统偏好设置?
首先,如果你只是想在光标指向窗口/视图/小部件时获得更大的光标,那么你正在错误的方式下进行。阅读介绍光标管理器以了解正确的方法。
其次,即使你认为你确实想在程序运行时设置系统范围内的光标,请在继续之前仔细考虑一下。即使你的应用程序在后台或隐藏时,光标仍将保持较大。如果您已经采取了任何透明生命周期思想(用户通常不应注意到或关心您的应用程序不可见和您的应用程序已退出之间的区别),这将变得更加混乱。如果两个应用程序尝试执行此操作,会发生什么?等等。(不用说,苹果公司将拒绝App Store中执行此操作的任何应用程序。)
第三,设置系统偏好设置实际上并没有做任何事情,直到系统读取该偏好设置的新时间。而且无法保证何时会发生这种情况。因此,除非您的应用程序满足于更改可能在用户注销并重新登录(然后在退出后更改回来)之前可能无效的首选项,否则它并不是很有用。
但是,如果这确实是您要做的事情...
设置系统偏好设置非常容易。大多数由“系统偏好设置”修改的值都在默认存储中。辅助功能面板中的大多数值都在com.apple.universalaccess
域中。光标大小的特定键是mouseDriverCursorSize
。
因此,要从bash更改光标的最大大小:
defaults write com.apple.universalaccess mouseDriverCursorSize 4.0
从 Objective-C 来说,可能需要稍微费点功夫,但是像这样(未经测试):
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *olddict = [defaults persistentDomainForName:@"com.apple.universalaccess"];
NSMutableDictionary *newdict = [olddict mutableCopy];
[newdict setObject:@4.0 forKey:@"mouseDriverCursorSize"];
[defaults setPersistentDomain:newdict forName:@"com.apple.universalaccess"];
[defaults synchronize]
那么,假设你想设置首选项,然后强制系统注意到更改呢?显然,“系统偏好设置”应用程序正在执行某些操作,并且您可以始终跟踪它以确切了解其所做的操作。
往往情况下,它会调用一些未记录或公开的私有函数。并且在不同的操作系统版本之间可能会有所不同。而且,即使这样做,结果也可能不是最好的。但从快速测试来看:
只要接受如果光标被隐藏则取消隐藏,调用CGSShowCursor
似乎有效。连续两次调用CGSGetGlobalCursorData
也似乎有效,尽管我不知道为什么。
当然,这些都是未记录或公开的CGSPrivate函数,但至少其他人已经对它们进行了逆向工程,因此您无需自己去完成。您需要做的就是从一些开源项目中借用代码(iTerm2拥有较完整的头文件集之一),并在苹果每次发布新的次要操作系统版本后进行测试,并调试黑魔法,即使它可用于75%的用户,却无法为那剩余的25%的用户解决问题(通常无法获得这25%的机器,甚至无法从它们获取合适的问题或答案)。
如果您想跟踪“系统偏好设置”,而且在OS X中没有追踪进程的经验,则最简单的方法是通过GUI工具“Instruments”:
请注意,系统偏好设置可能不是调用特殊的系统调用来完成所需操作;例如,它可能会向窗口服务器任务发送特定的 mach 消息。幸运的是,您可以从任何看起来合理的地方开始逆向寻找。通过这样做,我发现它似乎在 UniversalAccessCore 中调用了 UACursorSetScale
,该函数调用 /System/Library/PrivateFrameworks/UniversalAccess.framework/Versions/A/Libraries/libUAPreferences.dylib
中的 UAPreferencesSetValue
函数,而后者似乎会执行 CFPreferencesSetValue
并发送 CFNotificationCenterPostNotification
。也许只有通知很重要?您可以在 Xcode/gdb/lldb 中对相关函数设置断点,并查看参数是什么来测试它。或者您可以弄清楚如何自己调用 UAPreferencesSetValue
(我的第一个猜测是参数与 CFPreferencesSetValue
相同)。
简单检查一下:它发送的通知是“UniversalAccessDomainMouseSettingsDidChangeNotification”,带有 nil
的 object
和像 @{@"mouseDriverCursorSize": @1.8327533, @"pid": @12345}
这样的 userInfo
字典到默认分布式通知中心,如果在更改 NSUserDefaults
偏好后自己执行相同的操作,不会产生任何效果。此外,UAPreferencesSetValue
显然需要与 CFPreferencesSetValue
不同的参数,因为如果传递明显的值,您将在 CFNotificationCenterPostNotification
中崩溃,因此您可能需要在系统偏好设置中断点调用以查看它发送的内容。
如果您对继续进行感到舒适,请继续前进。如果不是,您需要学习很多东西,然后才能考虑如何使其正常工作。
另一种方法是通过脚本编写。如果您可以让“系统偏好设置”应用程序执行与鼠标执行相同的操作,则完成了,对吗?
只要启用了 UI 脚本(请参见您已经在“系统偏好设置”中查看的同一面板中的“启用辅助功能设备访问”复选框,或者如果您具有根访问权限,则搜索如何在编程方式下打开和关闭它),那就可以通过 System Events 进行冗长但容易操作的UI脚本。
事实上,尽管“系统偏好设置”不会公开足够的细节来实际更改任何内容,但它确实公开了足够的内容来使我们导航到正确的面板,这节省了很多UI脚本步骤。因此,这是要做的 AppleScript:
tell application "System Preferences"
reveal anchor "Seeing_Display" of pane id "com.apple.preference.universalaccess"
end tell
tell application "System Events"
set theSlider to slider "Cursor Size:" of group 1 of window 1 of application process "System Preferences"
set stash to value of theSlider
set value of theSlider to 4.0
stash
end tell
使用NSAppleScript
在ObjC中运行它,或者,如果您愿意,将其翻译为ScriptingBridge
、Appscript
或其他能够本地运行的内容即可完成。