MacOSのSpace関連の操作をコマンド化する

## 完成図
- Spaceの作成
alt-space -> type "new-space"
-> 新しいスペースが現在のスペースの右側に作成されます．
![new.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320576/96a6500c-d2e6-4583-21d2-046684d8a6fe.gif)
- Spaceの削除
alt-space -> type "del-space [削除したいスペースの番号]"
-> その番号のスペースが削除されます．
![del.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320576/8e972e0f-7c41-a394-8da5-8d7785472b21.gif)
- Spaceの移動
alt-space -> type "move-space [移動したいスペースの番号] [移動先のスペースの番号]"
-> 移動したいスペースが，移動先の右側に移動します．
![move.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320576/e69e93ca-72a6-e2ea-9081-bb71a324b4d7.gif)


## システム情報
- M1 MacBook Air(2022)
- macOS 13.0.1


## 使用アプリ
- [cliclick](https://github.com/BlueM/cliclick)
- [Raycast](https://www.raycast.com)
スクリプトの登録ができ，実行時に引数が取れるなら他のランチャーアプリでも良いです．

## 必要な許可
Raycastのアクセシビリティ許可のみ
（Filesystem Protectionsの無効化などは必要ありません．）


## コード
以下の3つコードを好きなフォルダに保存するか，リポジトリをダウンロードしてください.

### リポジトリ
https://github.com/ootsumasaya/applescript-about-space

### 1.Spaceの作成
参考文献
- https://apple.stackexchange.com/questions/407422/create-a-new-space-using-a-keyboard-shortcut-in-macos-big-sur
- https://qiita.com/tororu/items/512100b563956f723286

```applescript:new-space.applescript
#!/usr/bin/osascript

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title new-space
# @raycast.mode silent

# Optional parameters:
# @raycast.icon 🤖
#!/usr/bin/osascript

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title new-space
# @raycast.mode silent

# Optional parameters:
# @raycast.icon 🤖

on run
    my make_new_space()
    delay 0.3
    my move_new_space()
end run

on make_new_space()
    do shell script "open -b 'com.apple.exposelauncher'"
    delay 0.3
    tell application id "com.apple.systemevents"
        tell (every application process whose bundle identifier = "com.apple.dock")
            click (button 1 of group 2 of group 1 of group 1)
        end tell
    end tell
end make_new_space

on move_new_space()
    -- search current and new space
    set command to "/usr/libexec/PlistBuddy -c " & ¬
        "\"print :SpacesDisplayConfiguration:Management\\ Data:Monitors:0:Current\\ Space:uuid\" " & ¬
        "${HOME}/Library/Preferences/com.apple.spaces.plist"
    set current_uuid to (do shell script command)
    set i to 0
    repeat
        try
            set command to "/usr/libexec/PlistBuddy -c " & ¬
                "\"print :SpacesDisplayConfiguration:Management\\ Data:Monitors:0:Spaces:" & i & ":uuid\" " & ¬
                "${HOME}/Library/Preferences/com.apple.spaces.plist"
            set tmp_uuid to (do shell script command)
            if current_uuid = tmp_uuid then
                set current_space_num to i + 1
            end if
            set i to i + 1
        on error
            exit repeat
        end try
        tell application id "com.apple.systemevents"
            tell list 1 of group 2 of group 1 of group 1 of process "Dock"
                set new_space_num to count of buttons
            end tell
        end tell
    end repeat
    -- move new space to right of current space
    tell application id "com.apple.systemevents"
        tell (every application process whose bundle identifier = "com.apple.dock")
            tell button new_space_num of list 1 of group 2 of group 1 of group 1
                set p to position
                set s to size
                set x1 to {(item 1 of item 1 of p) + (item 1 of item 1 of s) / 2} as integer
                set y1 to {(item 2 of item 1 of p) + (item 2 of item 1 of s) / 2} as integer
            end tell
            tell button current_space_num of list 1 of group 2 of group 1 of group 1
                set p to position
                set s to size
                set x2 to {(item 1 of item 1 of p) + (item 1 of item 1 of s)*0.8} as integer
                set y2 to {(item 2 of item 1 of p) + (item 2 of item 1 of s) / 2} as integer
            end tell
            do shell script "/opt/homebrew/bin/cliclick -e 50 -w 500 m:" & x1 & "," & y1 & " dd:" & x1 & "," & y1 & " dm:" & x2 & "," & y2 & " du:" & x2 & "," & y2 & " kp:esc"
        end tell
    end tell
end move_new_space
```

### 2.Spaceの削除
参考文献：https://stackoverflow.com/questions/66892255/how-to-write-applescript-to-that-closes-a-desktop-space

```applescript:del-space.applescript
#!/usr/bin/osascript

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title del-space
# @raycast.mode silent

# Optional parameters:
# @raycast.icon 🤖
# @raycast.argument1 { "type": "text", "placeholder": "del_space_number","optional": false}


on run argv
    do shell script "open -b 'com.apple.exposelauncher'"
    delay 0.3
    -- do shell script "/opt/homebrew/bin/cliclick m:+0,0"
    tell application id "com.apple.systemevents"
        tell list 1 of group 2 of group 1 of group 1 of process "Dock"
            set countSpaces to count of buttons
            if countSpaces is greater than 1 then
                perform action "AXRemoveDesktop" of button (item 1 of argv as integer)
            end if
        end tell
        delay 0.7
        key code 53 -- esc key
    end tell
end run
```


### 3.Spaceの移動
```applescript:move-space.applescript
#!/usr/bin/osascript

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title move-space
# @raycast.mode silent

# Optional parameters:
# @raycast.icon 🤖
# @raycast.argument1 { "type": "text", "placeholder": "from_space_number","optional": false}
# @raycast.argument2 { "type": "text", "placeholder": "to_space_number","optional": false}


on run argv
    do shell script "open -b 'com.apple.exposelauncher'"
    delay 0.3
    do shell script "/opt/homebrew/bin/cliclick m:+0,0"
    tell application id "com.apple.systemevents"
        tell (every application process whose bundle identifier = "com.apple.dock")
            tell button (item 1 of argv as integer) of list 1 of group 2 of group 1 of group 1
                set p to position
                set s to size
                set x1 to {(item 1 of item 1 of p) + (item 1 of item 1 of s) / 2} as integer
                set y1 to {(item 2 of item 1 of p) + (item 2 of item 1 of s) / 2} as integer
            end tell
            tell button (item 2 of argv as integer) of list 1 of group 2 of group 1 of group 1
                set p to position
                set s to size
                set x2 to {(item 1 of item 1 of p) + (item 1 of item 1 of s)*0.8} as integer
                set y2 to {(item 2 of item 1 of p) + (item 2 of item 1 of s) / 2} as integer
            end tell
            do shell script "/opt/homebrew/bin/cliclick -e 50 -w 500 m:" & x1 & "," & y1 & " dd:" & x1 & "," & y1 & " dm:" & x2 & "," & y2 & " du:" & x2 & "," & y2 & " kp:esc"
        end tell
    end tell
end run
```

## Raycastへの登録
Setting>Extensions>Script Commands>Add Directories
で先ほど作成したファイルのディレクトリを追加してください．

<span style="font-size: 200%; color: red;">完成</span>
うまく動かない場合はdelayやcliclickのオプションをいじってみてください．

---
# 余談（作成動機）
1. Spaceを操作ときにカーソルを動かすのが面倒
1. かといってショートカットがない（本当？）
1. Space用のApplescriptのクラスとかもない（本当？）
1. 結果，Raycastでscriptを発火させ，Spaceの座標を取得してcliclickにやらせた


より高速で安定する方法があったら教えて下さい．
そもそも本当にSpace関連のショートカットってないんですか？