> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GameInput 回调

> GameInput 回调

<a id="introductionSection" />

尽管 `GameInput` 主要围绕轮询模型设计，但在某些情况下，异步通知应用程序会更佳。为此，[IGameInput](/reference/input/gameinput/interfaces/igameinput/igameinput) 接口提供了若干方法，用于注册在特定关注事件发生时被调用的回调函数。

在内部，`GameInput` 会对回调调度进行序列化，一次只执行一个回调。`GameInput` 会保证按时间先后顺序调度回调。这些保证简化了应用程序在其回调函数中所需编写的代码。

无论回调类型如何，`GameInput` 允许在任意时刻最多注册 64 个回调。回调由 `GameInput` 内部的工作线程调度。有关其工作原理以及手动调度此工作的方式，请参阅 [GameInput 工作队列](/build/core-features/common/input/advanced/input-work-queues)。

<a id="deviceCallbacksSection" />

## 设备回调

设备回调可让应用程序在输入设备状态发生变化时收到通知，其语法如下。最常见的场景是检测设备的连接与断开，但其他状态变化也可能值得关注。

```c++ theme={null}
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](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_registerdevicecallback) 方法还可用于设备枚举。`enumerationKind` 参数接受来自 [GameInputEnumerationKind](/reference/input/gameinput/enums/gameinputenumerationkind) 枚举的值，指示是否在回调注册过程中执行枚举，以及枚举应以阻塞方式还是异步方式执行。将设备枚举与后续状态变化合并为单一原子操作，可避免许多应用程序在输入代码中无意中出现的争用条件。

<a id="readingCallbacksSection" />

## 读取回调

通过读取回调，应用程序可以在输入流中有新的读取到来时收到通知，其语法如下。虽然许多应用程序会发现轮询输入更为合适，但仍存在某些情况下事件驱动的输入可能更佳。例如，游戏的主菜单 UI 可能更适合基于事件的输入。再如输入映射 UI，在提示用户选择后需要等待输入。

```c++ theme={null}
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](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_registerreadingcallback) 方法允许按产生特定输入类型的设备进行筛选，或按特定设备的输入进行筛选。

应用程序还可以为模拟输入值（例如游戏手柄的拇指摇杆）指定一个筛选阈值，要求在触发回调之前至少产生一定量的移动。当无需高分辨率的模拟状态变化时，这可以显著降低回调频率。一个很好的例子是在提示用户进行选择后等待输入变化的输入映射 UI 实现。

<a id="unregisteringSection" />

## 注销回调

回调注册成功后，应用程序必须确保执行该回调所需的所有资源保持有效，包括回调代码所使用的资源以及回调函数本身，例如，回调函数托管在应用程序按需加载和卸载的 DLL 中的情形。

要安全回收这些资源，应用程序必须先注销回调，方法是将 `Register*Callback` 方法返回的令牌传给 [UnregisterCallback](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_unregistercallback) 方法。如果调用此方法时回调正在执行，则该方法会阻塞，直到回调执行完成。因此，回调不能在自己的回调函数内注销自身。

也可以通过调用 [StopCallback](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_stopcallback) 方法来停止回调。此方法不会注销回调，但可确保回调不再被调用。因为回调未被注销，所以从回调自身的回调函数中调用此方法是安全的。它会完成当前回调的执行，但不再调用该回调。回调最终仍必须注销，因为在任意时刻最多允许存在 64 个回调。

<a id="seeAlsoSection" />

## 参考 API 文档

* [GameInput（API 目录）](/reference/input/gameinput/gameinput_members)

## 另请参阅

[GameInput 基础](/build/core-features/common/input/overviews/input-fundamentals)

[GameInput 高级主题](/build/core-features/common/input/advanced/input-advanced-topics)

[输入 API 参考](/reference/input/gc-reference-input-toc)


## Related topics

- [GameInput 高级主题：力反馈与回调](/zh-CN/build/core-features/common/input/advanced/index.md)
- [GameInputEnumerationKind](/zh-CN/reference/input/gameinput/enums/gameinputenumerationkind.md)
- [GameInput 高级主题](/zh-CN/build/core-features/common/input/advanced/input-advanced-topics.md)
- [GameInput 读取](/zh-CN/build/core-features/common/input/overviews/input-readings.md)
- [GameInput](/zh-CN/reference/input/gameinput/gameinput_members.md)
