GameInput のコールバック
GameInput
は主にポーリング モデルに基づいて設計されていますが、アプリケーションに対して非同期に通知することが適している場合もあります。 これをサポートするために、IGameInput インターフェイスでは、対象とする特定のイベントが発生すると呼び出されるコールバック関数を登録するためのメソッドをいくつか公開しています。
内部的には、GameInput
はコールバックのディスパッチをシリアル化して、一度に 1 つのコールバックのみが実行されるようにします。
GameInput
は、コールバックが時系列でディスパッチされることを保証します。 この保証により、アプリケーションがコールバック関数で作成する必要があるコードが簡素化されます。
GameInput
では、種類に関係なく最大 64 個のコールバックをいつでも登録できます。 コールバックは、GameInput
の内部ワーカー スレッドからディスパッチされます。 この機能に関する詳細と手動でこの機能をスケジュールするためのオプションについては、「GameInput の作業キュー」を参照してください。
デバイス コールバック
次の構文で示すように、デバイス コールバックを使用すると、アプリケーションは入力デバイスの状態が変更されたときに通知を受け取ることができます。 多くの場合、この方法はデバイスの接続および切断のタイミングを検出するときに使用されますが、他の状態変更についても、デバイス コールバックを使用することができます。
HRESULT RegisterDeviceCallback(
_In_opt_ IGameInputDevice * device,
_In_ GameInputKind inputKind,
_In_ GameInputDeviceStatus statusFilter,
_In_ GameInputEnumerationKind enumerationKind,
_In_opt_ void * context,
_In_ GameInputDeviceCallback callbackFunc,
_Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken * callbackToken);
デバイス コールバックは、いくつかのオプション フィルターを指定して登録できます。 これには、特定の種類の入力を生成するデバイスのフィルタリング、特定のステータスの状態変更のフィルタリング、特定のデバイスのフィルタリング、これらのフィルターの任意の組み合わせが含まれます。 たとえば、アプリケーションはデバイスがシステムから切断されたときに通知を受け取るようにコールバックを設定できます。
デバイスのステータス変更に加え、デバイスの列挙には RegisterDeviceCallback メソッドを使用できます。
enumerationKind
パラメーターは GameInputEnumerationKind 列挙型から、コールバック登録の一環として列挙を行うかどうか、列挙を行う場合はブロッキングまたは非同期のいずれで行うかを示す値を取ります。 デバイスの列挙とそれに続く状態変更を単一のアトミック操作に結合することにより、多くのアプリケーションの入力コードで意図せずに発生する競合状態を回避できます。
読み取りコールバック
次の構文で示すように、読み取りコールバックを使用すると、アプリケーションは新しい読み取り値が入力ストリームに到着したときに通知を受け取ることができます。 多くのアプリケーションでは入力のポーリングの方が適していますが、イベント駆動型の入力の方が望ましい場合もあります。 たとえば、ゲームのメイン メニュー UI にはイベント ベースの入力の方が適している場合があります。 別の例としては、ユーザーに選択を求めた後に入力を待機する必要がある入力マッピング UI があります。
HRESULT RegisterReadingCallback(
_In_opt_ IGameInputDevice * device,
_In_ GameInputKind inputKind,
_In_ float analogThreshold,
_In_opt_ void * context,
_In_ GameInputReadingCallback callbackFunc,
_Out_opt_ _Result_zeroonfailure_ GameInputCallbackToken * callbackToken);
デバイス コールバックと同様に、読み取りコールバックもいくつかのオプション フィルターを指定して登録できます。 これは読み取りコールバックには特に役立ちます。アプリケーションは入力ストリームからの読み取り値の一部だけを必要としている場合があるからです。 RegisterReadingCallback メソッドを使用すると、特定の種類の入力を生成するデバイスにフィルタリングしたり、特定のデバイスの入力にフィルタリングしたりできます。
アプリケーションでは、コールバックが発生する前に何らかの最小限の動きを必要とするアナログ入力値 (ゲームパッドのサムスティックなど) をフィルタリングするよう指定することもできます。 これにより、高解像度のアナログ状態の変化が不要な場合にコールバックの頻度を大幅に減らすことができます。 その良い例は、ユーザーに選択を求めた後に入力の変更を待機する場合の入力マッピング UI の実装です。
コールバックの登録解除
コールバックが正常に登録されたら、アプリケーションでは、コールバックの実行に必要なすべてのリソースが有効な状態を維持することを保証する必要があります。 これには、コールバックのコードによって使用されるリソースと、コールバック関数自体によって使用されるリソース (たとえば、アプリケーションがオンデマンドでロード/アンロードする DLL でコールバック関数がホストされている場合) の両方が含まれます。
これらのリソースを安全に解放するには、アプリケーションでまず、Register*Callback
メソッドから受け取ったトークンを UnregisterCallback メソッドに渡して、コールバックを登録解除する必要があります。 このメソッドが呼び出されたときにコールバックが実行中の場合は、コールバックの実行が完了するまでメソッドがブロックされます。 そのため、コールバックが自身のコールバック関数内部から自身を登録解除することはできません。
StopCallback メソッドを呼び出してコールバックを停止することもできます。 この場合、コールバックは登録解除されませんが、コールバックが再度呼び出されないことは保証されます。 コールバックが登録解除されないため、このメソッドは、コールバック自身のコールバック関数内部から安全に呼び出すことができます。 これにより現在のコールバックの実行が終了しますが、コールバックが再度呼び出されることはありません。 一度に登録できるコールバックは 64 個までであるため、コールバックは最終的には登録解除する必要があります。