VR空間内からワンボタンで録画する奴を作ったけど作ってない話

# VR空間内からワンボタンで録画する奴とは
うちが開発した[RecordVRCWithGeForceExperience](https://github.com/forno/RecordVRCWithGeForceExperience)の宣伝文句である

機能は単純で，フォーカスをゲームに当ててその後Sendkeysを用いてGeForce Experienceのホットキーを起動するだけ
あまりにも単純なスクリプトファイルなので，パブリックドメインにして著作権も破棄している．自由に使ってほしい

使い方は[Twitterの宣伝](https://twitter.com/forno_recsys/status/1191731372467146752)を見るか，[noteのインストール案内](https://note.com/forno/n/nb0fd8c602468)を見て欲しい

# 前置き
この記事では最終的に，やっぱりコードは書かないに限る。使えるものを使っていこうって話をしたいだけです
そのためにRecordVRCWithGeForceExperienceの開発手順を述べ，実装を解説します

また，この記事は[VRChat Advent Calendar 2019](https://adventar.org/calendars/3950) 12月22日の記事でもあります

前日はfotflaさんの「[VRChatで動くポスターを作る](https://qiita.com/fotfla/items/69011f91554e21995399)」です

# なぜこの機能は必要だったのか
VR空間内から録画する方法は，様々に開発されてきた

ひとつ，OBSの録画開始と終了をファンクションキーに割り当ててVaNiiMenuを用いて押す
ひとつ，OpenVR-InputEmulatorを用いてコントローラに任意のキーを割り当てて録画ソフトを起動する
ひとつ，Autohotkeyを使った録画実装があったが，Autohotkeyが爆散しておりインストールできなかった

これらの問題点は

- OBSなどの追加ソフトウェアが必要
- ユーザによる環境独自の追加の設定が必要
- OSSに依存してプロジェクトが消失

があげられる．これに対処するには，すべての人にインストールされている録画システムを用いるのが最も良いと考えた

## 何も追加せずに使える録画ソフトウェア
GeForce ExperienceはNVIDIAのグラフィックドライバーを最新に保つためにほぼすべてのNVIDIA製品所持者のパソコンにインストールされている．このソフトウェアは，おまけで配信や録画が可能であり，その品質はGPUの性能をフルに使っているだけあって確かなものである

また使用するのにAlt+F9やAlt+F10のホットキーが設定されており，これが他と干渉しづらいため使い勝手が良い

VRC上で話を聞く限りは，Ryzen CPUを使っている人も多くはNVIDIAのGPUを選択しており，intel CPUを使っている人はほぼすべてがNVIDIA製のGPUであることから，GeForce Experienceを採用するだけでVR顧客の大半をカバーできる
ちゃんとしたソースはないが，PC VR人口の7割以上はカバーできそうな勢いだ

## VR空間内からの操作を達成する方法
VR空間に干渉するソフトウェアを一から開発するのは非常に手間であり，かつ録画は必要なときにのみ呼び出されれば良いため
立ち上げを別ソフトウェアに任せることとした

安定性や任意のプログラムを起動できる点からVaNiiMenuを採用したが，ほかの選択肢はそもそも見つからなかった．何かいいものがあれば教えてください

以後開発終了までの開発プロセスをそのまま載せる

# 要件定義
- きちんとゲーム画面が録画できること(別のものを録画しない)
- 望んだ区間の録画が可能なこと
- 安定した機能にのみ依存すること
- VR空間内から操作できること

# 外部定義
- ゲームにフォーカスを当てられること
- GeForceExperienceの録画開始/終了/インスタントリプレイが起動できること
- VR空間内の操作はみんな大好きVaNiiMenu

実はGeForce Experienceにはモニタ1の全画面しか保存できないという重大な制限がある
また，VRゲームをしていると，ゲームからフォーカスが外れてしまうのはよくある現象である
そしてゲームからフォーカスが外れると，モニタ1にゲーム以外が映り込みゲーム画面の録画ができなくなってしまう
このため，フォーカスの管理は必須であった

# 内部定義
VR空間内から任意のプログラムをVaNiiMenuを介して呼び出せるので，VR周りはすべてそちらに投げ，起動したらゲームにフォーカスが当たって録画開始するものを作る

フォーカスの管理はWindowsの責任であるため，Windowsの標準機能を用いることにした
選択したのはPowerShell．Windowsの基礎機能のひとつで大変安定しているため要件定義も満たす

外部定義のフローそのままに「VRCを見つけ出し」「フォーカスを当てて」「Alt+F9などのキーを送信」して録画を行う機能を実装する

https://github.com/forno/RecordVRCWithGeForceExperience/blob/master/recordVRC.ps1 より引用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164828/05ace3c9-da23-049c-0a90-a43b6fe2de48.png)

以上で完成だ

# 動作原理

3行目のGet-Processでプロセス名からプロセスのオブジェクトを検索
プロセス名を用いるのはウィンドウタイトルと比較して圧倒的に安定しているからである

```powershell
$process = Get-process -Name $title
```

4行目はWScriptを生成してAppActivateで検索したプロセスにフォーカスを当てる

```powershell
(New-Object -ComObject WScript.Shell).AppActivate($process.MainWindowTitle)
```

5行目でSendkeys機能を有効化し，6行目でキーストロークを送信(GeForce Experienceのホットキー)

```powershell
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait("%{F9}")
```

(なぜか6行目の表示がおかしいので画像版もおいておく)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164828/7b7b92e5-bc65-03ac-9a6c-81127da2b10c.png)

# こんなもの見せびらかして何が言いたかったのか

最も優れたプログラムコードは存在しないコードだとはよく言われている
(早いプログラムは実行されないプログラム)
今回作成したRecordVRCWithGeForceExperienceは実はGeForce Experienceに実装上依存などしていないし，皆さんお気づきのようにVRCは一切関係ない(デフォルトでフォーカスを当てる対象になっているだけ)．当然録画機能も持っていない

そう，このソフトウェアは「任意のウィンドウにフォーカスを当ててキーを送信するだけのプログラム」で，決してRecordもVRCもGeForce Experienceも関係ない
さらに言うと宣伝文句の「VR空間内からワンボタン」の部分はVaNiiMenuの機能の事だし，「録画する」はGeForce Experienceのことで，一行もそんな機能は作っていない
プロジェクトが成功したのはひとえに一番初めに名前とクリティカルユースケースを決めて，それをぶれることなく発表したからである

プログラマは開発中に汎化を行うし，ライブラリは汎化した抽象度の高い名前を付けるのが当然のこととなっている．よく，開発途中でプロジェクト名を汎化した名前に付け替えたくなることだってあるが，たまには我慢する選択肢も考えなければならないようだ

このプロジェクトの宣伝は2019/12/18日現在このように伸びている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164828/05847d1d-c3c9-9717-606e-9b532c1de0a5.png)

# 別の世界線の話
ちなみに配布単位の問題でRecordVRCWithGeForceExperienceという名前で配布することに決定したが，当然，汎化したプロジェクト「任意のウィンドウにフォーカスを当ててホットキー押す奴」を作って，VaNiiMenuに登録するときLauncher.jsonのargumentで処理を分岐する手法も考えられた

採用しなかった理由は単純で，「ユーザが書き換えられるところが増えるとミスが増えてサポートが非常に面倒になるから」である
実際に発表当初はconfig/Launcher.jsonを書き間違えるユーザがちらほら観測されており，これに加えてargument問題まで発生したら面倒この上なかったと思う

現在は[FORNOsVaNiiMenu](https://github.com/forno/FORNOsVaNiiMenu/releases)に同梱しているのでそういった問題は一切起きていない．今なら汎化したバージョンを開発して同梱することもできるが…結局それができるユーザは勝手に書き換えるので必要はなさそうだ

# 最後に
最高のライブラリは適切に汎化されたものだけれど，一般に出すときはクリティカルユースケースに直接届く名前が一番いいねってお話しでした

明日はせちろーさんの「しーわんカフェスタッフから見たコミュニティとコミュニティ運営」です