Joystick(GamePad)の入力を受け付けてみた。 JoyStickの動作確認、構造体の値を表示するアプリができた。
入手先
使い方
GitHubのReadMe参照。 実際にJoyStickを挿して入力してみたほうが早い。
実装パターン
Raw Input API
- WinDDK
- Download
- Library
- C:\WinDDK\7600.16385.1\lib\wxp\i386
- hid.lib
- hidclass.lib
- hidparse.lib
- C:\WinDDK\7600.16385.1\lib\wxp\i386
- Include
- C:\WinDDK\7600.16385.1\inc\api
- hidpi.h
- hidsdi.h
- hidusage.h
- C:\WinDDK\7600.16385.1\inc\api
- 参照設定
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1386142753
Raw Input API にて Joystick を使用するときは、WinDDKを使う。 WinDDK の hidsdi.h をインクルードすることでHidP_GetValueCaps関数などを使用する。
例によって、追加インクルードフォルダと追加ライブラリファイルを設定する。
C:\WinDDK\7600.16385.1\inc\crt;C:\WinDDK\7600.16385.1\inc\api;
hid.lib;gdiplus.lib;
ところが、hidsdi.h をインクルードすると以下のエラーがでる。
1> Program.cpp
1>c:\winddk\7600.16385.1\inc\api\imm.h(707): error C2143: 構文エラー : ';' が '}' の前にありません。
1>c:\winddk\7600.16385.1\inc\api\imm.h(707): error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
どうやらインクルードファイルの順序を変える必要があるらしい。 http://so-zou.jp/software/tech/device/wii/library/wiiyourself/
プロジェクト・プロパティ→構成プロパティ→VC++ディレクトリ インクルードディレクトリ
前
$(VCInstallDir)include
$(VCInstallDir)atlmfc\include
$(WindowsSdkDir)include
$(FrameworkSDKDir)\include
後1
C:\WinDDK\7600.16385.1\inc\ddk
$(VCInstallDir)include
$(VCInstallDir)atlmfc\include
C:\WinDDK\7600.16385.1\inc\api
$(WindowsSdkDir)\include
$(FrameworkSDKDir)include
後2
C:\WinDDK\7600.16385.1\inc\crt
$(VCInstallDir)include
$(VCInstallDir)atlmfc\include
C:\WinDDK\7600.16385.1\inc\api
$(WindowsSdkDir)\include
$(FrameworkSDKDir)include
後3
C:\WinDDK\7600.16385.1\inc\crt
$(VCInstallDir)include
$(VCInstallDir)atlmfc\include
C:\WinDDK\7600.16385.1\inc\api
$(WindowsSdkDir)\include
$(FrameworkSDKDir)include
上記パターンを試してみたが、エラーは解決しなかった。 どうやら、WinDDKのwindows.hをインクルードすると当該のエラーが発生するようだ。
実際に「;」を「}」の前に追記してみたが、新たなエラーが出て解決しなかった。 Raw Input API は諦めて、joy~関数にて実装を試みる。
joy~関数
関数 | ボタン数 | 取得契機 |
---|---|---|
joyGetPos | JOYINFO | 関数実行時 |
joyGetPosEx | JOYINFOEX | 関数実行時 |
joySetCapture | JOYINFO | 指定時間毎(ポーリング) |
- JOYINFO
- JOYINFOEX
JOYINFOはボタンが4つしか認識できない。 手持ちのJoystickはボタンが12ある。 JOYINFOEXを使いたい。 対応する関数はjoyGetPosExしかない。 自前でポーリングする必要がある。
ポーリングは、タイマースレッドを立てることになるのだろうか。 面倒そう。
JOYINFOEX
JoyStick装置 | 構造体メンバ | 値 |
---|---|---|
ボタン1~32 | dwButtons | 各ボタンに2n値が設定されている。フラグとしてor演算子で同時押しを表現できる。 |
十字キー | dwPOV | 360度*100。0=↑、9000=→、18000=↓、27000=←。4500=→↑、13500=→↓、22500=←↓、31500=←↑ |
スティック | dwXpos,dwYpos,dwZpos,dwRpos,dwUpos,dwVpos | 0x0000~0xFFFF。中間値が中央の状態を意味する。0x0000は↑or←の端。0xFFFFは↓or→の端。 |
http://akiba.geocities.jp/directx7help/devdoc/live/directx/diover_44vo.htm
http://sackys-blog-extend.cocolog-nifty.com/blog/2012/10/post-5d05.html
JOYCAPS
wMid:1133
wPid:49686
szPname:Microsoft PC ジョイスティック ドライバ
wXmin:0
wXmax:65535
wYmin:0
wYmax:65535
wZmin:0
wZmax:65535
wNumButtons:12
wPeriodMin:10
wPeriodMax:1000
wRmin:0
wRmax:65535
wUmin:0
wUmax:65535
wVmin:0
wVmax:65535
wCaps:51
wMaxAxes:6
wNumAxes:4
wMaxButtons:32
szRegKey:DINPUT.DLL
szOEMVxD:
変数 | 意味 | 例 |
---|---|---|
wMid | Manufacturer Identifiers(製造者ID) | 1133(Logicool, Inc.?) |
wPid | Product Identifiers(製品区分) | 49686(Logicool DUAL ACTION?) |
szPname | Product Name(製品名) | 今回は専用ドライバを入れていないせいかMicrosoftのドライバ名が入っている |
wPeriodMin | 最小ポーリング時間隔 | 10ミリ秒間隔まで反応できる |
https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd757103(v=vs.85).aspx
joySetCapture
WindowsMessageで制御できるようになる。 でも、JOYINFO構造体なのでボタンが4つまでしか認識できない。 今回は使わない。紹介だけ。
Windows Message
- joySetCapture
上記の関数はポーリングの時間隔を入力するだけでポーリングできる。 ポーリングの時間隔には、JOYCAPSのwPeriodMin~wPeriodMaxの値を入力すればいい。
ボタン入力はUP/DOWNの状態が区別されてWindows Messageとして飛んでくる。 それをキャッチすればいい。
どう設計したらいいか
今回の実装とは関係ない話。
もし、JoyStickのclassをつくるなら、どんなインタフェース設計がいいか妄想してみた。
Joystickの入力受付インタフェースはどのように設計すべきか。 考える項目を出してみた。
性能的に、joyGetPosExを使うことになる。 ボタンを4つしか使えないjoyGetPos、joySetCaptureは論外。 すると、自前ポーリングの実装が必要になる。
- joyGetPosEx
- 自前ポーリングの実装
そもそも、どのような入力を受け付けるようにするかで異なる。 複雑になるのは以下の場合。
- 単キーDown
- 単キーUp
- 単キーPress(Down&Up)
- 同時押し
- 長押し
連射するか否かも考慮する必要がある。 押しっぱなしのとき、連射するのか、しないのか。
- 連射(する/しない。ON/OFF)
- 連射速度
アナログ入力があるなら、ON/OFFスイッチだけでなく加速度などの量を入力できる。 アナログ入力は遊びの部分をうまく調整しないとピーキーすぎて誤動作してしまうこともあるっぽい。
- 方向
- 量
デバイスによっては振動(バイブレーション)機能もある。 でもAPIで制御できない。
アプリケーションの機能を呼び出すコマンドとして紐付ける必要がある。 キーバインドはユーザが任意に変更できたほうが望ましい。 たとえば、ジャンプコマンドは、↑キー押下か、1キー押下か、1と2の同時押しかなど。 場面ごとに異なるキーバーインドを用いる。いくつものキーバインドがあり、場面ごとに使い分ける。
- キーバインド(キー・コマンドとアプリ・コマンドの紐付け)
アプリで使用する論理キーは、物理キーが発行する論理キーのいずれかである必要がある。 さもなければ、Joystickで実行できないコマンドが出てしまう。 キーバインドは必ず物理キーにあわせる必要がある。
また、Joystickの種別ごとにどのボタンでどの仮想キーが送られてくるか異なる。 デバイスごとに物理的なキーと仮想キーを調整できるようにしたい。 Joystickの機種ごとに、どの位置にあるボタンが、何の仮想キーを送出するかは統一されていない。 ユーザは異なる仕様のJoystickでも同じ位置にあるボタンで同じ意味として使いたいことがあるだろう。 ユーザ自身がJoystickの個体ごとに適切に設定する必要がある。 毎回設定しなおすのは大変。 できることならデバイスの固有IDか何かで紐付けた設定ファイルを読書することで使いまわせるようにしたい。
- 物理キーと論理キーの紐付け
要素
- Joystickデバイス
- デバイス仕様
- ボタンの数(使用するフラグ値)
- スティックの数(使用する変数)
- 接続状態
- デバイス仕様
- 接続アルゴリズム(デバイスIDで識別できるか否かに関わる)
- Windows API
- Raw Input
- joyGetPosEx
- DirectX
- DirectInput
- XInput
- Windows API
- Joystickデバイス設定
- デバイスIDと設定ファイルの対応表
- 物理キーと論理キーの対応表
- コマンド
- キー・コマンド(キーの組み合わせや時間)
- アプリ・コマンド(アプリの機能)
- 場面で使うフラグなどの変数(SceneState)
カプセル化の度合い
- TCHAR化
メモリ確保・解放
仮想コード作成
- JOYSTICKID1, JOYSTICKID2, を enum化する
- BUTTON1, ...
スティック値の使用変数パターン https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd757112(v=vs.85).aspx
- JOY_CAL_READ3
- JOY_CAL_READ4
- JOY_CAL_READ5
- ...
契機
- WindowsMessageを発行するか
- コールバック関数を用意するか
キー・コマンド
- 状態変数そのまま
- Down/Up/Press
- 同時押し/長押し
- 連射/速度
アプリ・コマンド
- コマンドclass
- 名前文字列
場面変数(アプリ・コマンドで用いる状態変数)
キー・バインディング
- アプリ・コマンド
- キー・コマンド
ポーリング
- メインループ
- 独自タイマースレッド
所感
満足。かなり勉強になった。 今までの中で一番、自分で作った感がある。
以下のような項目を学習できた。