Macbookのリファレンスモードをショートカットキーで変えたい

# リファレンスモードってなんぞ
Mac使いの方は知っているかもしれませんが、Apple製のディスプレイには画面のガンマカーブや白点をプリセットで保存しておけます。

https://support.apple.com/ja-jp/HT210435

自分は趣味で写真を撮るのですが、編集の際には写真用のプリセット'Photography (P3-D65)'を使い、
それ以外の時には`Apple XDR Display (P3-1600 nits)`を使っています。

しかし、切り替える際にコントロールセンターの項目を3階層ほど掘る必要があり、かなり面倒くさい

この記事では、どうにかショートカットキーでリファレンスモードを変更できないかというのを試していきます。

# Automation / Shortcut / AppleScriptでできる?
私が調べた範囲ではこれらでの実現は不可能そうでした。
できるのはせいぜい画面の明るさ変更程度だけ。

自分が愛用しているBetterTouchToolにもそういった項目はありませんでした。

# 実現
MacOSのAPIとか細かいことはわかっていませんが、実現だけはできました。
なので簡単に手順だけを書きます。
また、実現の際に使わせてもらった第三者のライブラリがあるため、コード配布はしません。
手順に沿って再現してください。

# 実施環境
CPU: Apple M1 Pro
OS: 13.3.1 (a) 
shell: fish


Xcode導入済み
(shellでswiftコマンド叩ける状態)

Swift歴5分(今回で初めて触った)

# 手順
## 1. ターミナルからプリセットを変更できるようにする

とりあえずはディレクトリ作成

```
$ mkdir ChangeReferenceMode
$ cd ChangeReferenceMode
```

プリセット変更用のswiftコード実装
Apple XDR Display (P3-1600 nits)とPhotography (P3-D65)をトグルするような実装にしています

``` presets.swift
guard let mgr = MPDisplayMgr(), let display = mgr.displays.first(where: \.hasPresets) else {
    exit(1)
}

print("before: \(display.displayName!): \"\(display.activePreset!.presetName!)\"")

let preset_xdr = "Apple XDR Display (P3-1600 nits)"
let preset_photography = "Photography (P3-D65)"

switch display.activePreset!.presetName! {
    case preset_xdr:
        let preset = display.presets.first(where: { $0.presetName ==  preset_photography})
        display.setActivePreset(preset)
    case preset_photography:
        let preset = display.presets.first(where: { $0.presetName ==  preset_xdr})
        display.setActivePreset(preset)
    default:
        print("other")
}
print("after: \(display.displayName!): \"\(display.activePreset!.presetName!)\"")
```

この実装は以下を参考にしました

https://stackoverflow.com/questions/69773562/is-it-possible-to-programmatically-change-the-xdr-display-reference-mode-aka-pr


自分で実装するのはこれだけ
あとはライブラリを使います

以下のRepoをCloneまたはZipでダウンロード

https://github.com/alin23/mac-utils

必要なファイルをコピーして持ってくる
```
$ cp -r mac-utils/Headers ./
```

Headers/Bridging-Header.hだけpresets.swiftと同じレイヤにコピー
```
$ mv Headers/Bridging-Header.h ./
```

この時点でのディレクトリ構成は以下のようになっているはず

```
$ tree -L 2
.
├── Bridging-Header.h
├── Headers
│   ├── MonitorPanel.framework
│   └── OSD.framework
└── presets.swift

4 directories, 2 files
```

ビルドしてみる Warningは出るけどビルド通ってるしヨシ!!

```
$ swiftc -F $PWD/Headers \
         -F /System/Library/PrivateFrameworks \
         -framework MonitorPanel \
         -import-objc-header Bridging-Header.h \
         presets.swift -o presets


Bridging-Header.h:44:25: warning: 'IOMasterPort' is deprecated: first deprecated in macOS 12.0
    IOReturn ioReturn = IOMasterPort(MACH_PORT_NULL, &masterPort);
                        ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Headers/IOKitLib.h:143:1: note: 'IOMasterPort' has been explicitly marked deprecated here
IOMasterPort( mach_port_t       bootstrapPort,
^
1 warning generated.
```

成果物が`presets`として生成されているので叩いてみる

```
$ ./presets

before: Built-in Liquid Retina XDR Display: "Apple XDR Display (P3-1600 nits)"
after: Built-in Liquid Retina XDR Display: "Photography (P3-D65)"

$ ./presets
before: Built-in Liquid Retina XDR Display: "Photography (P3-D65)"
after: Built-in Liquid Retina XDR Display: "Apple XDR Display (P3-1600 nits)"
```

これで叩くたびに"Apple XDR Display (P3-1600 nits)"と"Photography (P3-D65)"がトグルされます

あとはこれを好きな場所に移動しておけばOK
自分は `~/bin/`に置きます


## 2. ショートカットキーで変更できるようにする
これに関しては好きな方法でMacのShellを叩ければ良いです
自分は[Karabiner-Elements](https://karabiner-elements.pqrs.org)を使って実現します

細かいところの説明は省きますが、大変参考になるのが以下の記事

https://qiita.com/s-show/items/a1fd228b04801477729c

`Fn + r`で、先ほど作ったpresetを叩くように設定


``` karabiner.json
        {
          "type": "basic",
          "from": {
            "key_code": "r",
            "modifiers": {
              "mandatory": [
                "fn"
              ]
            }
          },
          "to": [
            {
              "shell_command": "/Users/republicofkorokke/bin/presets"
            }
          ]
        }
 
```

`Fn + r`を押すと`presets`が実行され、リファレンスモードを切り替えられます

# 〆

以上が自分がMacbookのリファレンスモードをショートカットキーで変えるためにやったことです。
専門的な知識も何もないので、Qiitaに相応しくない記事かもしれませんが、誰かの役に立てば光栄です。