GameInput 回调

尽管 GameInput 主要是围绕轮询模型设计的,但有些情况最好以异步方式通知应用程序。 若支持此功能,IGameInput 界面公开了一些用于注册回调函数的方法,这些回调函数在发生相关事件时进行调用。

在内部,GameInput 序列化回调的调度,以便一次只执行一个回调。 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 个回调。

另请参阅

GameInput 基础知识

高级 GameInput 主题

输入 API 参考