2016年8月5日金曜日

SimConnectのUI入力イベント

数年前に開発終了したFSX情報とか誰得だよ、とか思わないでもないですが、おそらくロッキード・マーティンが開発・販売を継続しているP3Dも互換性があると思うので気にせず続けていきます。


さて、SimConnectのUI入力イベントについて。
ここで言うUI入力イベントというのはキーボードの入力やジョイスティックの入力の事を指します。SimConnectでイベントの送信(各種数値の変更等の操作)はすでにできていますから、UI入力イベントをトリガにすることができれば、様々な操作をFSXの設定以上にきめ細やかに作ることが可能となります。

入力イベントを受け取るには、MapClientEventToSimEvent, AddClientEventToNotificationGroup, MapInputEventToClientEvent, SetInputGroupStateが必要になるようです。かなり大変です。

どの順番で操作するのが正しいのかはわかりませんが、P3D Devページのサンプルを元にすると
1) MapClientEventToSimEventでイベントの宣言
2) AddClientEventToNotificationGroupでイベントをグループに関連付け
3) MapInputEventToClientEventでイベントの条件を設定
4) SetInputGroupStateでグループを有効化
という感じのようです。

ソースコードとしては以下のようになります。
simConnect.MapClientEventToSimEvent(EventID.KeyA, null);
simConnect.AddClientEventToNotificationGroup(GroupID.UserInput, EventID.KeyA, false);
simConnect.MapInputEventToClientEvent(GroupID.UserInput, "a", EventID.KeyA, 0, SIMCONNECT_UNUSED, 0, false);

simConnect.MapClientEventToSimEvent(EventID.KeyCtrlA, null);
simConnect.AddClientEventToNotificationGroup(GroupID.UserInput, EventID.KeyCtrlA, false);
simConnect.MapInputEventToClientEvent(GroupID.UserInput, "ctrl+a", EventID.KeyCtrlA, 0, SIMCONNECT_UNUSED, 0, false);

simConnect.MapClientEventToSimEvent(EventID.JoyBtn0, null);
simConnect.AddClientEventToNotificationGroup(GroupID.UserInput, EventID.JoyBtn0, false);
simConnect.MapInputEventToClientEvent(GroupID.UserInput, "joystick:0:button:0", EventID.JoyBtn0, 0, SIMCONNECT_UNUSED, 0, false);

simConnect.SetInputGroupState(GroupID.UserInput, (uint)SIMCONNECT_STATE.ON);

また、クラスの先頭で
enum SIMCONNECT_UNUSED_ { };
readonly Enum SIMCONNECT_UNUSED;
を宣言し、コンストラクタ内で
SIMCONNECT_UNUSED = (SIMCONNECT_UNUSED_)0xFFFF;
のように値を設定しておきます。
SIMCONNECT_UNUSEDはSimConnect内で宣言されていますが、型がuintとなっており、Enum型を受け取るMapInputEventToClientEventには直接渡せないために必要となる措置です。DLLを作った奴が気づかないわけがないので、何らかのうまい対策があるんでしょうが。


上記のコードではAキー、Ctrl-A組み合わせキー、ジョイスティックボタンのイベントを受け取ります。
イベントの発生条件はキーボードとジョイスティックで違い、キーボードの場合はキーを押している間常にキーUpイベント(詳細は後述)が発生します。
ジョイスティックボタンの場合はボタンを押した際にDownイベントが発生し、ボタンを放した際にUpイベントが発生します。
ジョイスティックPoVの場合はボタンを押した際に100倍した度がDataに渡されたイベントが発生します。例えばPoVを右に操作すれば9000、左に操作すれば27000、上に操作すれば0となります。PoVを放した際は4294967295が渡されますが、これはDataがuint型であるためで、int(符号あり32bit)にキャストすれば-1となります。
ジョイスティックAxisの場合は値が変更するたびにイベントが発生し、範囲は符号あり16bitを32bitにキャストしたデータが渡されます。

イベントを受け取るにはOnRecvEventを使いますが、イベントの内容によりSIMCONNECT_RECV_EVENT data.dwDataの内容が変化します。キーボード入力の場合は常に0ですが、ジョイスティックボタンの場合はDownで1、Upで0となり、PoV,Axisは前述のとおりです。


キーボード入力に関しては+でコンビネーションを設定できますが、ジョイスティックの場合は常に1つのボタンしか設定できません。+で組み合わせた場合は一番最初のボタンイベントのみがキャプチャされるようです。
ジョイスティックのボタンを組み合わせたい場合は、自前でBool配列等を用意し、イベントに応じてTrue,Falseを設定、複数のBoolが予め決めた組み合わせになれば何らかの動作をする、という方法になると思います。

ジョイスティックのインデックスは0始まりとなる点に注意して下さい。Windowsのゲームコントローラのプロパティは1始まりなので、プロパティでボタンのインデックスを確認する際には要注意です。



CSVか何かに入力イベントの組み合わせと出力イベントを書いておいて、指定した入力が来れば出力を返すというプログラムを作ったら機体に合わせて設定ファイルを変えたりできて便利かなーと思ってましたが、ボタン組み合わせは結構鬼門ですね。
FSXで設定可能な組み合わせ(キーのコンビネーション or 単一のボタン)だけなら比較的簡単そうですが。
僕が使ってるジョイスティックは親指の届く範囲にボタン5個とPoV、人差し指にトリガ、小指にボタンが1個割り当てられているので、小指でボタンを押しながらPoVを動かせばトリム、とかやりたいので、ジョイスティックの組み合わせが可能ないい方法を考えなくては。。。

0 件のコメント:

コメントを投稿