Swift で Mac の ScriptingBridge を無理矢理つかう
ちょいちょい「環境設定」→「セキュリティとプライバシー」→「アクセシビリティ」を開かせたいケースがあるが、openURL とかで Security.prefPane を開くだけだと「どこやねん」となりがちなので、アクセシビリティを設定するところまで一気に移動したくなる。
ScriptingBridge を使えばできるのだが、Objective-C でやる場合でもメソッド定義のヘッダファイルを生成して使うみたいな感じになっており、Swift からちょっと気軽に使おうと思うとダルくなってしまう。
フル機能を使うなら一度 Objective-C でラッパー書くのが正当だと思うが、一行も Objective-C を書きたくない気分のときは、プロトコルとエクステンションで必要なメソッドを強制的に定義してコンパイラを騙せば乘りきることができるようだ。
import Cocoa
import ScriptingBridge
// 元にないやつは optional にしないと extension でエラーになる
@objc protocol SBSystemPreferencesApplication {
optional var panes: SBElementArray {get}
func activate()
}
@objc protocol SBSystemPreferencesPane {
optional var anchors: SBElementArray {get}
optional var id: NSString {get}
}
@objc protocol SBSystemPreferencesAnchor {
optional var name: NSString {get}
optional func reveal() -> id_t
}
// protocol 定義を無理矢理使えるようにする
extension SBApplication : SBSystemPreferencesApplication {}
extension SBObject : SBSystemPreferencesPane, SBSystemPreferencesAnchor {}
struct Accessibility {
static func checkAccessibilityEnabled(app: NSApplicationDelegate) {
if AXIsProcessTrusted() != 1 {
let alert = NSAlert()
alert.messageText = "Require accessibility setting"
alert.alertStyle = NSAlertStyle.CriticalAlertStyle
alert.addButtonWithTitle("Open System Preference")
alert.addButtonWithTitle("Quit")
if alert.runModal() == 1000 {
openSecurityPane()
NSApplication.sharedApplication().terminate(app)
} else {
NSApplication.sharedApplication().terminate(app)
}
}
}
static func openSecurityPane() {
// openURL 使うのが最も簡単だが、アクセシビリティの項目まで選択された状態で開くことができない
// NSWorkspace.sharedWorkspace().openURL( NSURL.fileURLWithPath("/System/Library/PreferencePanes/Security.prefPane")! )
// ScriptingBridge を使い、表示したいところまで自動で移動させる
// open System Preference -> Security and Privacy -> Accessibility
let prefs = SBApplication.applicationWithBundleIdentifier("com.apple.systempreferences")! as SBSystemPreferencesApplication
prefs.activate()
for pane_ in prefs.panes! {
let pane = pane_ as SBSystemPreferencesPane
if pane.id == "com.apple.preference.security" {
for anchor_ in pane.anchors! {
let anchor = anchor_ as SBSystemPreferencesAnchor
if anchor.name == "Privacy_Accessibility" {
println(pane, anchor)
anchor.reveal!()
break
}
}
break
}
}
}
}
関連エントリー
- macOS の EOS Utility 「カメラとUSB接続できませんでした」 どうあがいても接続できなくて困った。 どうやらなんか Google Chrome が USB デバイスをかたっぱしからオープンする挙動をして...
- Mac でウェブカメラの定期撮影を Swift で書く macOS 用にウェブカメラからjpgを取得するコマンドラインツールにimagesnapというのがある。単発で使うには問題ないんだけど、イン...
- ccls + vim-lsp で補完時に後続のwhitespaceが削除される 以下をいれるととりあえずおさまる。ccls と相性が悪い?? let g:lsp_insert_text_enabled = 0 let g...
- AngularJS のテストでページ側のスクリプトを実行する protractor (webdriver) を使った場合、外から executeAsyncScript を使うと文字列でページ側で実行でき...
- Angular JS で View を伴う Service 的なことをしたいとき、あるいは Directive に Controller をつけたいとき。 クソコード を書いたはいいが、釈然としなかった。 "View independent business logic: Services" と...