続き.今回はvJoyの大まかな仕組みを調べた範囲で書き留めておきます.
vJoyのコンフィギュレーション
vJoyは作成する仮想ジョイスティックの軸の数やボタンの数,POVキーの数を設定することができます.
この設定はvJoyConf.exe
というユーティリティを通じて行います(左バージョン2.0.4以前,右バージョン2.0.5以降).
これらは実際にはvJoyConfig.exe
というコマンドラインツールのGUIフロントエンドとなっています.
たとえば,3つの軸,8つのボタン,4つのPOVキーをもつ仮想ジョイスティックを作るには以下のようにします(詳しくはvJoyConfig.exe -h
).
vJoyConfig.exe 1 -a x,y,z -b 8 -s 4
vJoyConfig.exe
は以下のレジストリキーにこれらの設定を書き込んで,vJoyドライバーをリロードします.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Servicesvjoy
ちなみにバージョンにより多少違いますが,vJoyがインストールするドライバは以下の二つです.
C:\Windows\System32\drivers\vjoy.sys
C:\Windows\System32\drivers\hidkmdf.sys
以前にインストールしたドライバーが残っているとインストールに失敗する場合があるようです. とあるレジストリキーを無理矢理削除するとインストールに成功するかもしれません(結構怖いことしているので自己責任で).
- 以下のレジストリキーがあれば削除する.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SetupPnpLockdownFiles%SystemRoot%/System32/drivers/vjoy.sys
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SetupPnpLockdownFiles%SystemRoot%/System32/drivers/hidkmdf.sys
- このレジストリキーは通常は削除できないので,以下のようにする.
- レジストリキーを右クリックする.
- 「アクセス許可」をクリックする.
- Administratorsの権限に「フルコントロール」を加える.
- 「詳細」をクリックする.
- 所有者をSYSTEMからAdministratorsに変更する.
- ダメな場合は
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SetupPnpLockdownFiles
のAdministrators権限にフルコントロールを加えてみる.
- ダメな場合は
- キーを削除する.
pnputil
をつかってドライバストアから削除してもインストールがうまくいく場合があります.
- 「同じinfでバイナリだけ異なるドライバ」に更新できないとき ( Windows ) – もしかしたら開発室附属雑記帳 – Yahoo!ブログ
- ドライバストアからのサードパーティ製のドライバ削除|窓のくすり箱
このへんはいろんな状況があり得るので正直よくわかりません.
vJoyのビルド方法
vJoyはWinDDKでビルドする必要があります. Windowsの最新のドライバ開発環境はWDKと呼ばれるものですが,配布されているvJoyは古いWinDDK(WDK7.1)で, WLH(Windows Longhorn, Vista以降のWindows)用のドライバとしてビルドされているようです.
以下にvJoyのビルド方法をまとめておきます.
- vJoyはWinDDKでビルドする.
- 開発コンソール”Windows Vista and Windows Server 2008″の”x64 Free Build Environment”でビルドする.
- ビルドの課程でsnv_version.hを生成するために,
SubWCRev.exe
が必要となる.- これはTortoiseSVNの一部.ただし若干古いバージョン(ココで使ったのは1.6.16)が必要です.
- ビルド環境のコマンドプロンプトで事前に,
C:Program FilesTortoiseSVNbin
にパスを通しておく.
- installディレクトリに移って,自己署名証明書を作成する.
- テストサイニングモードでは不要かも知れない.
MakeCert -r -pe -ss PrivateCertStore -n "CN=vJoy Certificate" testcert.cer
- これで証明書が作成される.certmgr.mscでPrivateCertStoreに証明書が作られていることを確認.
- 詳しくはdocs/HowToTestSign.odtを参照.
- ソースルートで
build
を実行.- プロジェクト間の依存関係がうまく設定されていないのか,初回のビルド時にはvJoyInterface.libがないので2件ほどエラーが出る.
- 二度目の
build
では特に問題は出ない.
install/objref_wlh_amd64/amd64
に必要なファイルが集められている.- vJoyInstall.exeを使ってインストールを行う.
- コマンドプロンプトが管理者権限である必要がある.
vJoyInstall.exe Install
でインストール,vJoyInstall.exe Uninstall
でアンインストール,vJoyInstall.exe Repair
で修復(?)
この手順でビルドしたドライバは通常のWindows8ではインストール不可です.テストサイニングモードを有効にする必要があります.
bcdedit /set testsigning on
ただし,セキュアブートが有効になっている場合はテストサイニングモードを有効にすることができないので,セキュアブートを 無効にする必要があります.
vJoyの不具合
まず,いくつかのWindows8(64bit)個体で試したのですが,必ずしもWin8環境でvJoyが動かないというわけではないようです. というより,私のデスクトップでだけうまくいってない感じです(泣)
症状としては,設定した軸やボタン数が正常に読み取られない,という感じです. 私の環境ではvJoyConfやvJoyConfigでどのようにvJoyデバイスを設定しても,軸は全部あり,ボタンとPOVが一つも無いという状況でした.
上のスクリーンショットのように,コントロールパネルのゲームコントローラーのプロパティでは,ボタンが32個見えているのですが UJRからはボタンが全く見えていません.
以下,vJoyのAPIを通じて何が起きているのかを調査した結果です.
vJoyの中で何が起きているのか
vJoyInterface.dllがvJoyの状態を設定したり取得したりするインターフェースライブラリ.
デバッグ情報を生成してステップインしてみたところ,以下のようなコールグラフが得られた. これは仮想ジョイスティックのボタン数を得るところ.
GetVJDButtonNumber ----> GetDeviceIndexByReportId ----> GetDeviceIndexById ------+
(vJoyInterface.cpp:378) (vJoyInterface.cpp:1072) (vJoyInterface.cpp:1035) |
+-------------------------------------------------------------------------------------+
+-> GetHandleByIndex ----> CreateFile
(vJoyInterface.cpp:872) (win32api)
CreateFileには以下のような(おそらく)デバイスを指し示すための文字列が渡されている.
\?hid#vid_047d&pid_2041#7&f325d6b&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
ここで呼び出しがエラーになり読み込みが失敗している.ACCESS DENIED(アクセスが拒否されました)となっている.
vJoyのAPIの呼び出しで,状態の読み取り書き込みの前にAcquireVJD
を呼び出す必要がある.
このときVJOYINTERFACELOGLEVEL
環境変数に1などの値が設定されていればロギングが開始される(数字であれば何でもよい.ログレベルのつもりのようだがログレベルによって云々するような挙動は実装されていない).
ちなみにログ出力のファイル名はVJOYINTERFACELOGFILE
で設定可能である.
若干改造して上記のタイミングでGetLastErrorの結果が出るようにしたが,ログにはおおよそ以下のような出力が残されている.
[10004]Info: GetDeviceIndexById(BaseIndex=0) - Returning -1
[10004]Error: GetDeviceIndexByReportId(1) - No match
[10004]Info: GetHandleByIndex(index=-1) - Starting
[10004]Warning: GetHandleByIndex(index=-1) - Failed SetupDiEnumDeviceInterfaces() with error 0x103
[10004]Info: GetDeviceIndexByReportId(1) - Starting
[10004]Info: GetDeviceIndexById(BaseIndex=0) - Starting
[10004]Info: GetHandleByIndex(index=0) - Starting
[10004]Error: GetHandleByIndex(index=0) - Failed to CreateFile(?hid#vid_047d&pid_2041#7&f325d6b&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030})
[10004]Error: GetHandleByIndex(index=0) - REASON : アクセスが拒否されました。
ちなみに管理者権限で実行しても結果は変わらない.
Win8でデバイスハンドルを得るときにCreateFileが失敗するというのはコモンケースなのかもしれない.
- CreateFile returns invalid handle while trying to access HID device on Windows 8 Desktop App
- Opening HID device stream from a MetroApp : CreateFile(2) failed 🙁
- CreateFile: direct write operation to raw disk “Access is denied” – Vista, Win7 – Stack Overflow
- Opening device with CreateFile fails with error code 5 ERROR_ACCESS_DENIED
デバイスハンドルを得るのにCreateFileを使うのは正しい方法のようではあるが…
続く.