カーソルのサイズをトグルするために Apple Script を書いてみた。
以下がこのスクリプトの YouTube の動画へのリンクである。16 秒程度の動画なので、是非見てみてほしい。
Apple Script とは
すごい昔(1993 年)から Apple のコンピュータに搭載されているオブジェクト指向のスクリプト言語。定期的に古いアーキテクチャを捨て、イチから構築する Apple において、唯一受け継がれているテクノロジーでもある(CPU が ARM 化しても生き残りそうだ)。ちょっと昔(2015 年)に JavaScript で同等のことができるようになったが、ドキュメントやサンプルが圧倒的に不足しているため、Apple Script の方が捗る。
Windows では Windows Scripting Host の位置付けに近いような気がするが、WSH よりは Apple Script の方が自動操作に強い。ObjC と組み合わせてより高度なことをしたり、署名して Mac App Store で配布することもできる。
スクリプトエディタ
Launchpad の奥の方にひっそりと存在するアプリ。このアプリで Apple Script および JavaScript の開発ができる。できるが、エディタ機能は最低限、ステップ実行やブレイクポイントは使えないため、自分の好きなエディタで開発したほうが捗る。
なお、スクリプトエディタには記録機能が備わっているが、残念ながら筆者の試した限りどのアプリケーションに対しても機能しなかった。この記録機能を使用するにはどうやらアプリケーション側に特別な対応が必要らしく、その対応が Mac のプリインストールアプリですら対応されていないようだ。
また、スクリプトエディタは、スクリプトを保存するとコンパイルしてバイトコードとして上書き保存してしまう。バイトコードにコンパイルされていると確かに実行時のオーバーヘッドが軽減するが、バイトコードはもはやスクリプトエディタ以外のテキストエディタでは編集ができなくなってしまい、またバージョン管理的にも扱いにくい。バイトコードに保存するのは良いが、別ファイルにして欲しかったものである。
ただし、後述するスクリプトエディタ付属の用語説明は大変役に立つ。
カーソルサイズをトグルするコード
以下が動画で動かしたスクリプトの全容だ。
#!/usr/bin/env osascript
-- システム環境設定が起動しているかどうか。
-- 起動していない場合、処理の最後に起動したシステム環境設定を終了させる
set didRunSystemPreferences to get running of application "System Preferences"
-- システム環境設定を起動し特定の画面を開く。
tell application "System Preferences"
-- アクセシビリティを開く
set current pane to pane "com.apple.preference.universalaccess"
tell current pane
-- ディスプレイを開く
reveal anchor "Seeing_Display"
end tell
end tell
try
tell application "System Events" to tell tab group 1 of group 1 of window 1 of application process "System Preferences"
-- ラジオボタン(セグメント)の 2 番目をクリックする。
click radio button 2
tell slider 1
-- 最初のスライダーの値を読み取り、別の値を設定する。
if value is 1.0 then
set value to 2.0
else
set value to 1.0
end if
end tell
end tell
on error errMsg
display dialog "Error: " & errMsg
end try
-- システム環境設定を起動したのであれば終了させる。
if not didRunSystemPreferences then
quit application "System Preferences"
end if
このファイルを toggle-cursor.applescript
という名前で保存し、以下のように実行する。
$ chmod a+x toggle-cursor.applescript
$ ./toggle-cursor.applescript
$
解説
"System Preferences"
というのがシステム環境設定のアプリケーション名で、これはスクリプトエディタで調べられる。
ここから目的のシステム環境設定を選択すると、以下のような用語説明を参照することができる。
このウィンドウのタイトル部分がアプリケーション名である。例えばフォントブックなら "Font Book"
、Google Chrome なら "Google Chrome"
となる。
Apple Script は自然言語に近い文法で記述できるのが特徴で、例えば:
tell application "System Events" to tell tab group 1 of group 1 of window 1 of application process "System Preferences"
の部分は「システム環境設定アプリケーションプロセスのウィンドウ 1 のグループ 1 のタブグループ 1 にシステムイベントを伝える」と読る。また:
click radio button 2
tell slider 1
はより自然言語らしく:
click second radio button
tell first slider
と書くこともできる。なお、インデックスは 1 から始まる。
上の説明書を見ると、変数が n
、関数が v
と、自然言語のそれで定義されており、Apple Script のターゲットがプログラマではなく一般ユーザである(あった)ことが伺える。
tell application "System Preferences"
set current pane to pane "com.apple.preference.universalaccess"
tell current pane
reveal anchor "Seeing_Display"
end tell
end tell
上記は以下の画面を開く処理だが:
以下の用語説明によると:
システム環境設定には pane
と current pane
というものがあり、これが要するに開かれている画面を参照、または操作できる。
"com.apple.preference.universalaccess"
をどうやって調べるか、については:
tell application "System Preferences"
log id of every pane as list
end tell
上記のようにすべての pane
の id
をログ出力すると:
com.apple.preferences.AppleIDPrefPane,
com.apple.preferences.Bluetooth,
com.apple.preference.dock,
com.apple.preference.expose,
com.apple.preference.speech,
com.apple.preference.spotlight,
com.apple.prefs.backup,
com.apple.preference.universalaccess,
com.apple.preferences.internetaccounts,
com.apple.preference.keyboard,
com.apple.preference.sound,
com.apple.preference.screentime,
com.apple.preference.security,
com.apple.preferences.softwareupdate,
com.apple.preference.displays,
com.apple.preference.desktopscreeneffect,
com.apple.preference.trackpad,
com.apple.preference.network,
com.apple.preferences.FamilySharingPrefPane,
com.apple.preference.printfax,
com.apple.preference.mouse,
com.apple.preferences.users,
com.apple.preference.general,
com.apple.preferences.extensions,
com.apple.preference.startupdisk,
com.apple.preferences.sharing,
com.apple.Localization,
com.apple.preference.energysaver,
com.apple.preference.notifications,
com.apple.preference.datetime
のような出力が得られるので(見やすいように改行を追加)、これをそれっぽい名前のものからひとつずつ試して目的の画面の pane
id
を調べた。
次は "Seeing_Display"
の調べ方だが:
tell application "System Preferences"
set current pane to pane "com.apple.preference.universalaccess"
tell current pane
log name of every anchor as list
end tell
end tell
という感じで以下のリストが得られる。
Accessibility_Shortcut,
Seeing_Cursor,
Seeing_Zoom,
Keyboard,
Seeing_VoiceOver,
Virtual_Keyboard,
TextToSpeech,
Dwell,
Dictation,
Switch,
Siri,
Alternate_Pointer_Actions,
Mouse,
Captioning,
Media_Descriptions,
Head_Pointer,
General,
Seeing_ColorFilters,
Seeing_Display,
Hearing
次は tell application "System Events" to tell tab group 1 of group 1 of window 1 of application process "System Preferences"
の要素の階層の調べ方だが:
tell application "System Events" to tell application process "System Preferences"
log every UI element as list
activate
end tell
で:
window アクセシビリティ of application process System Preferences,
menu bar 1 of application process System Preferences
が得られ:
tell application "System Events" to tell window "アクセシビリティ" of application process "System Preferences"
log every UI element as list
activate
end tell
で:
button 1 of window アクセシビリティ of application process System Preferences,
checkbox メニューバーにアクセシビリティの状況を表示 of window アクセシビリティ of application process System Preferences,
scroll area 1 of window アクセシビリティ of application process System Preferences,
group 1 of window アクセシビリティ of application process System Preferences,
toolbar 1 of window アクセシビリティ of application process System Preferences,
button 2 of window アクセシビリティ of application process System Preferences,
button 3 of window アクセシビリティ of application process System Preferences,
button 4 of window アクセシビリティ of application process System Preferences
が得られ:
tell application "System Events" to tell group 1 of window "アクセシビリティ" of application process "System Preferences"
log every UI element as list
activate
end tell
で:
radio button ディスプレイ of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
radio button カーソル of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
radio button カラーフィルタ of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
checkbox カラーを反転 of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
checkbox 視差効果を減らす of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
checkbox コントラストを上げる of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
checkbox 透明度を下げる of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
checkbox カラー以外で区別 of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
static text 最大 of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
static text 通常 of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
slider コントラスト: of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
static text コントラスト: of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences,
checkbox 反転(クラシック) of tab group 1 of group 1 of window アクセシビリティ of application process System Preferences
が得られる。
activate
を入れるか、quit application "System Preferences"
を無くすことで以下のようにアプリが起動中のままになるので、少しずつ確認しながら要素の階層を調べていく。
この画面で「カーソル」セグメントを表示するには:
click radio button "カーソル"
とすれば良い。
最終的に以下のようなコードになるが:
tell application "System Events" to tell tab group 1 of group 1 of window "アクセシビリティ" of application process "System Preferences"
click radio button "カーソル"
end tell
このままでは日本語環境でしか動作しないため、日本語が含まれている window "アクセシビリティ"
を window 1
に、radio button "カーソル"
を radio button 2
変更する。汎用性を取ると可読性が落ちてしまうこのあたりは残念だが仕方がない。