> ## 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" />

从每个设备接收的原始输入数据包封装在“读取”对象中。读取包含原始数据包，以及（通常）对原始数据的一种或多种更高层格式的转换。除了作为数据容器的作用之外，读取还充当引用输入流中特定位置的标识符。

<a id="acquisitionSection" />

## 获取读取

GameInput API 提供两种获取读取的方式。最常见的方式是通过 [IGameInput](/reference/input/gameinput/interfaces/igameinput/igameinput) 接口上的方法直接从输入流中访问。

```c++ theme={null}
HRESULT GetCurrentReading(
    _In_ GameInputKind inputKind,
    _In_opt_ IGameInputDevice * device,
    _COM_Outptr_ IGameInputReading ** reading);
```

调用 [GetCurrentReading](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getcurrentreading) 检索输入流中的最新读取。可以传入一个可选的 [GameInputKind](/reference/input/gameinput/enums/gameinputkind) 筛选器，将返回的读取限制为特定输入种类，例如游戏手柄或键盘。还可以传入一个可选的 [IGameInputDevice](/reference/input/gameinput/interfaces/igameinputdevice/igameinputdevice) 筛选器，将返回的读取限制为仅由指定设备产生的读取。这些筛选器可以单独使用，也可以组合使用。

[IGameInputReading](/reference/input/gameinput/interfaces/igameinputreading/igameinputreading) 实例是按引用计数的单例。检索读取是极快且轻量的操作——不会进行内存分配或复制，API 调用是无锁的，也不会切换到内核态。由于读取是单例，应用程序可比较读取指针的相等性，以判断两次对 [GetCurrentReading](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getcurrentreading) 的调用是否返回了同一个读取（意味着没有产生新的输入）。

输入需求较简单的游戏可以每帧仅轮询一次新输入，并比较两个读取中存储的状态差异（若不是同一个读取）。而输入需求较复杂的游戏则可能需要遍历输入流，以获取自上一帧以来发生的所有输入状态变化的完整情况。可通过 [GetNextReading](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getnextreading) 和 [GetPreviousReading](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getpreviousreading) 方法实现，二者所允许的筛选器与 [GetCurrentReading](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getcurrentreading) 相同。输入流在其缓冲区中保留过去半秒的历史读取。

```c++ theme={null}
HRESULT GetNextReading(
    _In_ IGameInputReading * referenceReading,
    _In_ GameInputKind inputKind,
    _In_opt_ IGameInputDevice * device,
    _COM_Outptr_ IGameInputReading ** reading);

HRESULT GetPreviousReading(
    _In_ IGameInputReading * referenceReading,
    _In_ GameInputKind inputKind,
    _In_opt_ IGameInputDevice * device,
    _COM_Outptr_ IGameInputReading ** reading);
```

或者，应用程序可以注册一个回调，在产生输入时调用。与前述同步方法类似，可以应用若干筛选器来控制返回的读取类型和来源设备。有关详细信息，请参阅“GameInput 高级主题”一节中的 [GameInput 回调](/build/core-features/common/input/advanced/input-callbacks)。

<a id="gettingStateSection" />

## 从读取中获取数据

尽管每个读取都包含来自设备的原始输入数据包数据，但读取通常还包含该数据的一种或多种高层转换。例如，来自游戏手柄的输入还会被解析为具有已知按键和拇指摇杆标识符的标准固定格式结构。读取通常包含对同一原始输入数据的若干不同表示，允许应用程序选择最适合其需求的格式。

应用程序可通过调用读取的 [GetInputKind](/reference/input/gameinput/interfaces/igameinputreading/methods/igameinputreading_getinputkind) 方法查询读取包含哪些种类的数据。此方法返回一个或多个来自 [GameInputKind](/reference/input/gameinput/enums/gameinputkind) 枚举的标志值。

```c++ theme={null}
typedef enum GameInputKind
{
    GameInputKindUnknown         = 0x00000000,
    GameInputKindRawDeviceReport = 0x00000001,
    GameInputKindController      = 0x00000002,
    GameInputKindKeyboard        = 0x00000004,
    GameInputKindMouse           = 0x00000008,
    GameInputKindTouch           = 0x00000100,
    GameInputKindMotion          = 0x00001000,
    GameInputKindArcadeStick     = 0x00010000,
    GameInputKindFlightStick     = 0x00020000,
    GameInputKindGamepad         = 0x00040000,
    GameInputKindRacingWheel     = 0x00080000,
    GameInputKindUiNavigation    = 0x01000000
} GameInputKind;
```

读取中可用的数据种类取决于输入设备及其物理属性。例如，来自标准键盘的读取可能只包含键盘数据，而带有集成轨迹球的键盘所产生的读取可能同时包含键盘和鼠标数据。

几乎所有游戏控制器都会产生包含通用“控制器”数据的读取，即匿名的轴和按键状态集合。这为具有输入映射 UI 的应用程序提供了广泛的设备支持。然而，许多游戏控制器（例如游戏手柄）在其读取中还公开熟悉的固定格式状态，对典型游戏而言更易于使用。

```c++ theme={null}
typedef struct GameInputGamepadState
{
    GameInputGamepadButtons buttons;
    float leftTrigger;
    float rightTrigger;
    float leftThumbstickX;
    float leftThumbstickY;
    float rightThumbstickX;
    float rightThumbstickY;
} GameInputGamepadState;
```

[IGameInputReading](/reference/input/gameinput/interfaces/igameinputreading/igameinputreading) 接口包含以读取所支持的任意格式检索状态的方法。读取中可用的所有不同表示均为预计算，因此这些方法只需复制少量字节的数据即可返回。

<a id="sampleSection" />

## 一个简单的游戏手柄输入循环

以下示例代码是游戏手柄的完整输入循环示例。请注意，此示例中没有显式的设备枚举。[IGameInputDevice](/reference/input/gameinput/interfaces/igameinputdevice/igameinputdevice) 仅用作设备标识，从未调用其任何方法。这体现了 GameInput API 的“以输入为中心”，以及它如何简化常见输入场景的代码。

```c++ theme={null}
IGameInput* g_gameInput = nullptr;
IGameInputDevice* g_gamepad = nullptr;

HRESULT InitializeInput()
{
    return GameInputCreate(&g_gameInput);
}

void ShutdownInput()
{
    if (g_gamepad) g_gamepad->Release();
    if (g_gameInput) g_gameInput->Release();
}

void PollGamepadInput()
{
    // Ask for the latest reading from devices that provide fixed-format
    // gamepad state. If a device has been assigned to g_gamepad, filter
    // readings to just the ones coming from that device. Otherwise, if
    // g_gamepad is null, it will allow readings from any device.
    IGameInputReading * reading;
    if (SUCCEEDED(g_gameInput->GetCurrentReading(GameInputKindGamepad, g_gamepad, &reading)))
    {
        // If no device has been assigned to g_gamepad yet, set it
        // to the first device we receive input from. (This must be
        // the one the player is using because it's generating input.)
        if (!g_gamepad) reading->GetDevice(&g_gamepad);

        // Retrieve the fixed-format gamepad state from the reading.
        GameInputGamepadState state;
        reading->GetGamepadState(&state);
        reading->Release();

        // Application-specific code to process the gamepad state goes here.
    }

    // If an error is returned from GetCurrentReading(), it means the
    // gamepad we were reading from has disconnected. Reset the
    // device pointer, and go back to looking for an active gamepad.
    else if (g_gamepad)
    {
        g_gamepad->Release();
        g_gamepad = nullptr;
    }
}
```

<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)

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