Win8.1とフライトスティック奮闘記2

続き.今回はvJoyの大まかな仕組みを調べた範囲で書き留めておきます.

vJoyのコンフィギュレーション

vJoyは作成する仮想ジョイスティックの軸の数やボタンの数,POVキーの数を設定することができます. この設定はvJoyConf.exeというユーティリティを通じて行います(左バージョン2.0.4以前,右バージョン2.0.5以降).

vjoy204_ss vjoy205_ss

これらは実際には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
    • このレジストリキーは通常は削除できないので,以下のようにする.
      1. レジストリキーを右クリックする.
      2. 「アクセス許可」をクリックする.
      3. Administratorsの権限に「フルコントロール」を加える.
      4. 「詳細」をクリックする.
      5. 所有者をSYSTEMからAdministratorsに変更する.
        • ダメな場合はHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SetupPnpLockdownFilesのAdministrators権限にフルコントロールを加えてみる.
      6. キーを削除する.

pnputilをつかってドライバストアから削除してもインストールがうまくいく場合があります.

このへんはいろんな状況があり得るので正直よくわかりません.

-クリックで非表示

vJoyのビルド方法

vJoyはWinDDKでビルドする必要があります. Windowsの最新のドライバ開発環境はWDKと呼ばれるものですが,配布されているvJoyは古いWinDDK(WDK7.1)で, WLH(Windows Longhorn, Vista以降のWindows)用のドライバとしてビルドされているようです.

以下にvJoyのビルド方法をまとめておきます.

  1. vJoyはWinDDKでビルドする.
    • 開発コンソール”Windows Vista and Windows Server 2008″の”x64 Free Build Environment”でビルドする.
  2. ビルドの課程でsnv_version.hを生成するために,SubWCRev.exeが必要となる.
    • これはTortoiseSVNの一部.ただし若干古いバージョン(ココで使ったのは1.6.16)が必要です.
    • ビルド環境のコマンドプロンプトで事前に,C:Program FilesTortoiseSVNbinにパスを通しておく.
  3. installディレクトリに移って,自己署名証明書を作成する.
    • テストサイニングモードでは不要かも知れない.
    • MakeCert -r -pe -ss PrivateCertStore -n "CN=vJoy Certificate" testcert.cer
    • これで証明書が作成される.certmgr.mscでPrivateCertStoreに証明書が作られていることを確認.
    • 詳しくはdocs/HowToTestSign.odtを参照.
  4. ソースルートでbuildを実行.
    • プロジェクト間の依存関係がうまく設定されていないのか,初回のビルド時にはvJoyInterface.libがないので2件ほどエラーが出る.
    • 二度目のbuildでは特に問題は出ない.
  5. install/objref_wlh_amd64/amd64に必要なファイルが集められている.
  6. 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が一つも無いという状況でした.

vjoy_trouble

上のスクリーンショットのように,コントロールパネルのゲームコントローラーのプロパティでは,ボタンが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を使うのは正しい方法のようではあるが…

続く.

Leave a Reply