Photoshopカラー設定内容をメニューバーに表示させる（Mac）

![SS 2020-05-11 13.20.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/66261b17-15d7-2976-a8f9-bd268fa2379b.png)

:::note
アプリ化しています。バイナリをテキスト化してから解析するのではなく、直接バイナリを触るようにしています。
[最新記事はこちら](https://qiita.com/yamo74/items/18f01dbb8db22ba3cfb5)
:::

:::note info
追記220111：カスタム拾えました！というわけでAppleScriptもKeyboard Maestroも使わないようにして作り直しました。
[新しい方はこちら](https://qiita.com/yamo74/items/17f0a09e125bf1c7ac74)
:::


追記200512：ACEConfigCache2.lst経由だと、カスタムを拾えないことが分かりました…あーあ。
osascriptで問い合わせるしかないか。というわけで途中書き替えました。od/tr/perlregexのあたりが無駄に😨
でも、カラー設定を触ってOKするとACEConfigCache2.lstも書き換えが発生するようで、イベントを拾う手段としてはまだ使えます。と言うわけで、イベント取得のあたりはそのままにして、PhotoshopColorWatch_Extract.commandでAppleScript使うだけの変更で済みました。

#カラー設定は常に確認しておきたい
Photoshopのカラー設定はアプリケーションデフォルトとして動作します。**ドキュメントのプロファイル無し警告や作業用と違う警告表示がオンになっていればカラー設定がどうあれ正しく開けます**が、顧客の要望や仕事内容に応じてカラー設定を切り替えるとスムーズに作業できます。
と言うわけで私は結構頻繁にカラー設定を切り替えるため、Photoshopを開いたらCmd+Shift+Kして、今どんなカラー設定プリセットになっているのか毎回確認していました。
**ただこれ、面倒くさいっちゃめんどくさい。なんかどこかで常時表示させて確認したい。**
JavaScriptもShellScriptもはじっこ囓ってるだけなので、迷走しつつなんとか形にした経緯と結果を紹介します。

##いつ、取得するか？
JSXでapp.ColorSettingsをPhotoshopに投げれば、ローカライズ前のプリセット名が得られます。KeyboardMaestroなどから、AppleScript（osascript）で問い合わせればいい…んですが、ただ定期的にJSXを投げ続けるのもPhotoshop操作に支障があるし（PSはね、JSX実行速度がうんこなのです）、できればなんらかのイベントを拾って、その時だけやるようにしたい。
これはPhotoshopのスクリプトイベントマネージャーやKeyboard Maestroでウインドウを拾うなど考えましたが、迂遠な気がして・難しくて止めました。

##ACEConfigCache2.lst
カラー設定は、Bridgeから同期させたりできます。Bridge側では、各アプリケーションのカラー設定がどうなっているのか見えている、ということですよね。ということは、どこかに同期用のファイルがあるはず。
それが「ACEConfigCache2.lst」でした。Macでは、~/Library/Preferences/Adobe/Colorの中にあります。
![file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/f8b51c31-6429-dca2-c20d-3b068ea3f6b2.png)
Cache2とあるので1とかあんのかも？ファイル名は環境依存かもしれません。

このファイルは、Bridgeからカラー設定同期させたときや、Photoshop等でカラー設定を変更したときに随時、書き替えられています。つまり、このファイルに変更があったことを検知できれば、その時だけ処理すればいいので負荷も少なくて済みます。

###fswatch
で、このファイルが変更されたことを検出するため、brewでfswatchを導入しました。
`brew install fswatch`
名前の通り変更があるか監視するツールです。監視対象に何か起きたときだけ、コマンドを実行します。

###どのシェルで実行する？
勉強中というのもおこがましいほど知らないのでアレですが、
fswatchは常時起動して監視するものですので、これをKeyboard Maestroのexec shellでやってしまうと、マクロが終了したらシェルも終了してしまいます（のはず）。また実行中はPhotoshopのキーボードショートカットが効かないなどの症状があり、よろしくありません。
さてどうするか、daemonとしてMac側で起動してやればいいのでは？と思いつき、Launchdで実行させることにしました。

#### Lingon3導入
サービスとして実行させる場合、plistを書いて読み込ませる必要があります。plistを間違い無く書くためにLingon3を導入し、新規サービスを作ります。
![SS 2020-05-12 13.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/719df8e0-2464-4ea9-e0dd-4f23f1731798.png)
全部オフで可。commandの所に、シェルスクリプトのファイルを後であてがいましょう。
このスクリプトは、`/Users/Shared/`以下に作っておくとMojave以降厳しくなった権限まわりを回避できるようです（Catalinaで確認）。
`~/Library/LaunchAgents` 内になんとかかんとか、plistができています。このファイル名メモっておきます。

####シェルスクリプトを書く
処理を試すたびにplist書き替えたりするのが面倒くさそうだったんで、テキストの処理部分は別ファイルにしておき、まずはfswatchを起動させるスクリプトを書きます。これをLingonの`What`欄に置いた場所のパスごと記入します（Shared以下ね）。

```shell:PhotoshopColorWatch.command
#!/bin/sh
/usr/local/bin/fswatch  -o -l 2 /Users/（ほむ）/Library/Preferences/Adobe/Color/ACEConfigCache2.lst | xargs -I{} /Users/Shared/（適当なフォルダ）/PhotoshopColorWatch_Extract.command
```
fswatchで件のACEConfigCache2.lstを監視させます。書き替え時にはしょっちゅうイベント発生するため、-lと-oで余裕持たせます。発動するとパイプ以降が実行されますが、ここは処理をいろいろ試したかったので別ファイルに飛ばします。
`chmod +x`して実行権限付けときましょう。ちなみに拡張子`.command`にしとくとターミナルで開きます。

Mac OSのセキュリティにひっかかるとLaunchctlでコマンドがOperation not permittedになって動作しません。実行シェルshにフルディスクアクセス与える方法もありますが恐ろしいので、うまく行かないときは、Lingonで指定するコマンドは `/Users/Shared/` 内に入れておけば実行できます。

####ACEConfig……のバイナリからテキストを取り出す（不使用）
最後に書きましたがこの項は結局使用しませんでした。取り出しの参考に残しておきます。

このファイルバイナリで、かつカラー設定のあるアプリの設定が全て入ってます。
stringで取り出せればいいんですが、マルチバイト文字は化ける…
Mac版のodダンプだと日本語も正常に表示されるのを発見し、これでなんとかすることにしました。
まず`od -A -n -c -v`でダンプします。
![SS 2020-05-11 22.58.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/e5c540d2-a7b2-1df8-06e6-b97f2f6ef05f.png)
日本語も出てますね。欲しいのは、Photoshop2020のカラー設定「2011知覚変換」というプリセット名称です。プリセットはcsfファイルがそのまま拡張子含め記載されていて、この後は必ず0033になります。

これを、trで整形します。スペースとバックスラッシュ、アスタリスク、改行を除去。
`tr -d ' \\*\n'`
![SS 2020-05-11 22.59.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/3a1defb1-80a2-0fd5-aa68-2dc45487fd05.png)
読めるテキストになってきました。
これから、正規表現でPhotoshop2020以降にあるプリセット名を取り出します。今回はperlを使いました。macのBSDなsedでやろうとすると訳分かんなくなって💦
`perl -pe 's|.*?Photoshop2020.+?([^/]+?)\.csf0033.*|$1|g'`
 ![SS 2020-05-11 23.00.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/06a76ffc-c2cc-c026-7596-856660cab303.png)
これでプリセット名のみ取り出せました。パイプで繋げてテキストファイルに起こしましょう。

```shell:PhotoshopColorWatch_Extract.command
#!/bin/bash
export LANG=ja_JP.UTF-8
# func
ColOD() {
od -A n -c -v /Users/yamo74/Library/Preferences/Adobe/Color/ACEConfigCache2.lst | tr -d ' \\*\n' | perl -pe 's|.*?Photoshop2020.+?([^/]*?)\.csf0033.*|$1|g'
}
a=(`ColOD`)

echo $a > /Users/yamo74/Library/Logs/PSColorSetting.txt
```

### 結局ASで探ることに… 
200512追記：上のようにして共有ファイル解釈で拾おうとすると、カラー設定がカスタムになっているときに正しく拾えないことが分かりました。残念。なので、AppleScriptで問い合わせます。しょうがない……
これはLingonで指定したスクリプトから呼び出して実行しているスクリプトです。こいつも`/Users/Shared/`以下においときましょう。

```shell:PhotoshopColorWatch_Extract.command
#!/bin/bash
export LANG=ja_JP.UTF-8
a=`osascript -e 'tell application "Adobe Photoshop 2020" to color settings'`
echo $a > /Users/（ほむ）/Library/Logs/PSColorSetting.txt
```
Photoshop以外をメインにする場合はここと、後の「Photoshop起動中だけ動作させる」のあたりを修正してください。Logs以下に設定値を吐ければ良いので。

###Photoshop起動中だけ動作させる
先のplistはロードしてスタートさせないと動作しません。
Keyboard MaestroのトリガーにPhotoshopのlaunchとquitを設定し、それぞれに
起動時
`launchctl load PSColorSettings.plist`
`launchctl start PSColorSettings`
と
終了時
`launchctl stop PSColorSettings`
を当てます。
起動時マクロには、pgrepを入れてfswatchが起動しているかどうかのチェックもさせておきます。
`pgrep -f fswatch`
戻り値がPIDなら起動中、nullなら起動していません。
修了時マクロにはpkillを入れて、fswatchを終了させます。
`pkill fswatch`

Keyboard MaestroのLaunch/Quitトリガに汎用性を持たせるため、それぞれのトリガのマクロに起動中の「Photoshop」の名前の付いているアプリを数えるAppleScriptを仕込みます。

```AppleScript
tell application "System Events"
	count of (name of every process whose visible is true and name contains "Photoshop")
end tell
```

戻り値が1以上の場合Launchマクロは停止、quitマクロも停止させれば、複数バージョンのPhotoshopの起動/終了に対応できます。

##メニューバーに表示させる
GeekToolでメニューバー上に最前面表示させるか、メニューバー以外にならGeektoolで先のシェルスクリプトで書き出したtxtをcatしとけばいいと思います。
今回はメニューバー項目として表示したかったので、Bitbar.appを使いました。
[bitbar](https://getbitbar.com/)
これに、またシェルスクリプトのファイルをあてがいます。Bitbarのプラグインフォルダーに次のファイルを保存します。ファイル名で実行間隔を指定できます（ここでは2s）。

```PhotoshopColorWatch.2s.sh
#!/bin/sh

export LANG=ja_JP.UTF-8

a=`cat /Users/yamo74/Library/Logs/PSColorSetting.txt`
b=`pgrep -f fswatch`
if [ "$b" = "" ] ; then
c="#"
else
c=""
fi
echo $c$a 
```

ここで何してるかと言うと、Photoshop起動時、つまりfswatch起動時は常に情報更新されているため現在のプリセット名が出ていますが、Photoshop終了時＝fswatch終了時にはこの情報は怪しいかもしれません。
特に、Bridgeでカラー設定を同期したときには、Photoshopを起動するまでPSには設定は反映されません。問題無いっちゃないんですが、気持ち悪いので一応その旨「#」を付けて表示したいと思いました。
pgrepでfswatchが起動してるか確かめて、起動中は無し、そうでないときは#を付けてメニューバーにechoします。

#複雑！
~~ですが、Photoshopには一切触らず処理できました。jsxを一定間隔で飛ばすとか怖すぎる。~~
結局osascriptで問い合わせてますが、最小限に抑えてるしいいかな……
全てにおいて初心者なので、とりあえず動いたからいいや状態です。これを元に勉強いたしやす。