> ## 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.

# XInput에서 GameInput으로 포팅

> XInput에서 GameInput으로 포팅

<a id="introductionSection" />

XInput에서 GameInput으로의 포팅은 기존 API 중에서 가장 덜 복잡합니다. GameInput이 XInput의 단순하고 사용하기 쉬운 프로그래밍 모델의 영향을 크게 받았기 때문에, 많은 XInput API가 GameInput의 동등한 함수와 1:1로 매핑됩니다.

<a id="keyDifferencesSection" />

## 주요 차이점

XInput과 GameInput 간의 주요 차이점은 다음 섹션에서 설명합니다.

<a id="cVsCppSection" />

### C vs. C++

XInput API는 플랫 C 함수의 모음입니다. 반면 GameInput은 (그래픽 및 오디오 API와 마찬가지로) C++이며 인터페이스를 사용합니다. 실제로는 이로 인해 GameInput API를 사용하는 코드가 복잡해지지 않으며, 성능에 영향을 주지 않고, GameInput의 작동 방식에 익숙해지면 몇 가지 이점이 명확해집니다.

이러한 인터페이스가 COM처럼 보일 수 있지만, COM은 아니라는 점을 이해하는 것이 중요합니다. 이러한 인터페이스를 사용하려면 참조 카운팅에 대한 기본적인 이해만 있으면 됩니다. 자세한 내용은 [GameInput 기본 사항의 인터페이스 섹션](/build/core-features/common/input/overviews/input-fundamentals#interfacesSection) 항목을 참조하세요.

<a id="gettingInputSection" />

### 입력 얻기

XInput에서는 대부분의 게임이 연결된 장치가 있는 사용자 인덱스가 발견될 때까지 사용자 인덱스를 순회하고, 그 다음 해당 장치에서 상태를 읽습니다. 게임은 다음 번에 다시 순회하지 않아도 되도록 종종 사용자 인덱스를 기억합니다. 예를 들어 다음 코드는 사용자에게 컨트롤러에서 "A를 누르세요"라고 안내하는 게임에 일반적입니다.

```c++ theme={null}
// This function looks for a gamepad that currently has the "A" button pressed.
void FindActiveGamepad()
{
    for (DWORD index = 0; index < XUSER_MAX_COUNT; index++)
    {
        XINPUT_STATE state;
        if (XInputGetState(index, &state) == ERROR_SUCCESS)
        {
            if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A)
            {
                // Found the user's gamepad at this index.
            }
        }
    }
}
```

GameInput에서는 먼저 장치를 지정하지 않고 입력을 얻고, 필요하다면 그 입력이 어떤 장치에서 왔는지 쿼리할 수 있습니다. 코드는 유사해 보이지만 명시적인 장치 열거가 필요하지 않으므로 더 단순한 알고리즘으로 이어질 수 있습니다.

```c++ theme={null}
// This function looks for a gamepad that currently has the "A" button pressed.
void FindActiveGamepad(IGameInput * gameInput)
{
    // This checks for input from all gamepads simultaneously.
    IGameInputReading * reading;
    if (SUCCEEDED(gameInput->GetCurrentReading(GameInputKindGamepad, nullptr, &reading)))
    {
        GameInputGamepadState state;
        reading->GetGamepadState(&state);

        if (state.buttons & GameInputGamepadA)
        {
            // Found the user's gamepad.  At this point we can
            // get the device that generated this input, and then
            // pass that into future calls to the GetCurrentReading
            // method to receive input only from that gamepad.
        }

        reading->Release():
    }
}
```

코드가 XInput만큼 간단하지는 않지만, 매우 유사합니다. GameInput API에 익숙해지면 이 모델이 XInput에는 없는 강력한 입력 처리 옵션을 제공한다는 것을 알게 될 것입니다.

XInput은 트리거의 아날로그 값을 **BYTE** 유형으로, 썸스틱의 아날로그 값을 **SHORT** 유형으로 반환한다는 점도 주목할 만합니다. GameInput API에서는 이러한 아날로그 값이 0에서 1 사이(트리거) 또는 -1에서 1 사이(썸스틱)의 **float** 값으로 반환됩니다.

<a id="rumbleFeedbackSection" />

### 럼블 피드백

XInput에서는 게임이 단순히 `XInputSetState`를 호출하여 장치로 럼블(진동) 명령을 보냅니다. GameInput에서는 게임이 장치에 대한 [IGameInputDevice](/reference/input/gameinput/interfaces/igameinputdevice/igameinputdevice) 인스턴스를 얻은 다음 해당 [SetRumbleState](/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_setrumblestate) 메서드를 호출해야 합니다. 이 두 메서드 사이의 사용법은 비슷합니다. 이는 장치가 단순한 식별자가 아니라 장치 인터페이스의 함수를 호출하는 경우의 예입니다.

<a id="appFocusSection" />

### 애플리케이션 포커스

콘솔에서는 GameInput이 애플리케이션이 포커스 상태일 때만 입력을 제공합니다. 그렇지 않으면 반환되는 상태에는 마치 사용자가 장치를 전혀 만지지 않은 것처럼 중립 또는 "정지(rest)" 값이 포함됩니다. 이렇게 하면 포커스 변경을 처리하는 추가 입력 코드(예: `XInputEnable` 호출)가 필요 없어집니다.

PC에서는 입력이 기본적으로 모든 프로세스로 전달됩니다. 앞으로 이 동작은 [SetFocusPolicy](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_setfocuspolicy) 메서드를 사용하여 변경할 수 있게 됩니다.

<a id="xinputWrapperSection" />

## XInputOnGameInput 래퍼

Microsoft Game Development Kit(GDK)에는 GameInput 위에 XInput API 구현을 포함하는 `XInputOnGameInput.h`라는 헤더 파일이 함께 제공됩니다. 특히 키보드와 마우스 또는 기타 입력 장치를 사용하려는 경우 GameInput으로 직접 포팅하는 것을 권장합니다. 그러나 XInputOnGameInput 래퍼는 기존 XInput 코드에 아무런 변경 없이 초기 포팅 작업을 부트스트랩하는 데 도움이 되도록 사용할 수 있습니다.

XInputOnGameInput 래퍼를 사용하려면 다음 코드를

```c++ theme={null}
#include <XInput.h>
```

다음 코드로 교체하고,

```c++ theme={null}
#include <XInputOnGameInput.h>
using namespace XInputOnGameInput;
```

코드를 다시 컴파일합니다.

XInput 래퍼 코드의 구현은 전적으로 헤더 파일 안에 있으므로, GameInput API 사용 예로 살펴보거나 필요에 따라 수정할 수도 있습니다.

<a id="wrapperDifferencesSection" />

### XInput과 XInputOnGameInput의 차이점

일반적으로 XInputOnGameInput 래퍼는 기존 XInput API의 직접 대체입니다. 그러나 몇 가지 사소한 차이점이 있습니다.

* 간결성을 위해 게임패드 장치 지원만 래퍼에 코딩되어 있습니다. 레이싱 휠이나 아케이드 스틱과 같은 다른 장치를 지원해야 하는 경우, GameInput을 직접 사용하거나 XInputOnGameInput 코드에서 해당 장치에 대한 지원을 추가하세요.

* 래퍼는 게임이 포커스 상태일 때만 게임패드 입력을 반환합니다. 게임이 포커스 상태가 아닐 때는 반환된 모든 게임패드 상태가 마치 사용자가 게임패드를 만지고 있지 않은 것처럼 중립 또는 "정지(rest)" 값으로 설정됩니다. 이는 `XInputEnable` 호출 여부에 관계없이 수행됩니다.

* `XUSER_MAX_COUNT`의 값이 4에서 8로 증가되었습니다. 이는 대부분의 기존 XInput 코드에 대해 일반적으로 투명해야 합니다. 그러나 코드에서 `XInputGetKeystroke` 함수를 사용하는 부분이 있다면, `XINPUT_KEYSTROKE` 구조체의 `UserIndex` 멤버에서 최대값 4가 반환된다고 가정하여 하드 코딩된 것이 없는지 신중히 검토하세요. 그렇지 않으면 버퍼 오버런이 발생할 수 있습니다.

* 몇 가지 새로운 함수가 추가되었습니다(다음 참조). 이는 프로덕션 코드에서 XInput 래퍼를 계속 사용할 계획인 경우에만 관심의 대상이 되어야 합니다.

<a id="productionWrapperUseSection" />

### 프로덕션 코드에서 XInputOnGameInput 사용

XInputOnGameInput 래퍼는 고성능이고 락 프리로 작성되었으며, GameInput API의 모든 성능 최적화를 상속받으므로 프로덕션 코드에서 사용하기에 적합합니다. 또한 GameInput의 더 넓은 장치 지원(예: 인기 있는 HID 게임패드)을 상속받으며, API에 다음의 새 함수를 추가합니다.

* \_\_`XInputSetStateEx`\_\_는 `XInputSetState`와 유사하지만 트리거 모터에 대한 지원을 추가합니다.

* \_\_`XInputGetStateWithToken`\_\_은 `XInputGetState`와 유사하지만, 호출자가 D3DX 프레임 파이프라인 토큰을 제공하여 특정 입력 판독값을 그래픽 프레임과 연결해 나중에 PIX에서 분석할 수 있도록 합니다.

  > \[!NOTE]
  > 5월 프리뷰 릴리스에서는 기반 GameInput 코드가 완전히 구현되지 않았기 때문에 `XInputGetStateWithToken`이 현재 `XInputGetState`와 동일하게 동작합니다.

* \_\_`XInputGetDeviceId`\_\_는 주어진 사용자 인덱스에 있는 장치의 `APP_LOCAL_DEVICE_ID`를 반환합니다. 이 ID를 [IGameInput](/reference/input/gameinput/interfaces/igameinput/igameinput)의 [FindDeviceFromId](/reference/input/gameinput/interfaces/igameinput/methods/igameinput_finddevicefromid) 메서드에 전달하면 해당 사용자 인덱스에 대응하는 [IGameInputDevice](/reference/input/gameinput/interfaces/igameinputdevice/igameinputdevice)가 반환됩니다. 그런 다음 이를 사용하여 XInput 래퍼를 통해 노출되지 않는 GameInput API의 추가 기능에 액세스할 수 있습니다.

<a id="optimizingSection" />

#### 래퍼 코드 최적화

기본적으로 XInputOnGameInput 래퍼는 기존 XInput API와 직접 호환되도록 구성되어 있습니다. 100% 호환되는 동작이 필요하지 않은 게임은 다음 전처리기 매크로 중 하나를 정의하여 래퍼의 동작과 성능을 세부 조정할 수 있습니다.

##### XINPUT\_ON\_GAMEINPUT\_EXPLICIT\_INITIALIZATION

기본적으로 XInput 래퍼는 래퍼 함수 중 하나가 처음 호출될 때 자동으로 기반 GameInput API를 지연 초기화합니다. 이는 기존 XInput 코드와의 직접 호환성을 보장하지만 몇 가지 사소한 단점이 있습니다.

1. 첫 번째 XInput 래퍼 함수 호출의 실행 시간이 평소보다 길어집니다.

2. 모든 XInput 래퍼 함수는 호출될 때마다 지연 초기화가 수행되었는지 확인해야 합니다. 이는 전역 변수의 단순한 테스트이므로 분기 예측기가 비용을 줄여야 하지만, 여분의 오버헤드입니다.

3. 실패해서는 안 되지만, 기반 GameInput API의 지연 초기화가 성공했는지 확인할 방법이 없습니다.

4. 기반 [IGameInput](/reference/input/gameinput/interfaces/igameinput/igameinput) 인스턴스는 XInput 래퍼의 전역 변수가 정리될 때까지(모듈 언로드 또는 프로세스 종료로 인해) 해제되지 않습니다.

게임은 `XINPUT_ON_GAMEINPUT_EXPLICIT_INITIALIZATION` 매크로를 정의하여 래퍼의 초기화와 종료를 수동으로 제어할 수 있습니다. 이렇게 하면 초기화와 종료가 발생하는 시점을 정확하게 제어할 수 있는 두 개의 새 함수 `XInputOnGameInputInitialize`와 `XInputOnGameInputUninitialize`가 추가됩니다.

##### XINPUT\_ON\_GAMEINPUT\_NO\_XINPUTENABLE

`XInputEnable` 함수를 구현하는 데 필요한 코드는 `XInputGetState`, `XInputGetStateWithToken`, `XInputSetState`, `XInputSetStateEx`, `XInputGetKeystroke` 함수의 매 호출마다 추가 오버헤드를 발생시킵니다. 코드에서 `XInputEnable`을 호출하지 않거나 코드에서 쉽게 제거할 수 있다면, `XINPUT_ON_GAMEINPUT_NO_XINPUTENABLE` 매크로를 정의하여 `XInputEnable` 지원과 관련 오버헤드를 제거할 수 있습니다. 기반 GameInput 코드는 어차피 포커스 변경 시 `XInputEnable`의 기능을 자동으로 수행하므로, 가능하다면 대부분의 게임이 이 매크로를 정의하고 싶어할 것입니다.

##### XINPUT\_ON\_GAMEINPUT\_NO\_XINPUTGETKEYSTROKE

`XInputGetKeystroke` 함수를 구현하는 데 필요한 코드는 래퍼의 구현에 몇 가지 추가 함수와 변수를 추가합니다. 다른 XInput API 함수에 오버헤드를 추가하지는 않지만, 코드에서 `XInputGetKeystroke`를 호출하지 않는 경우 `XINPUT_ON_GAMEINPUT_NO_XINPUTGETKEYSTROKE` 매크로를 정의하여 XInput 래퍼의 코드/데이터 크기를 약간 줄일 수 있습니다.

<a id="seeAlsoSection" />

## 참조 API 문서

* [GameInput(API 콘텐츠)](/reference/input/gameinput/gameinput_members)
* [XInputOnGameInput(API 콘텐츠)](/reference/input/xinputongameinput/xinputongameinput_members)

## 함께 보기

[GameInput 개요](/build/core-features/common/input/overviews/input-overview)

[GameInput API 참조](/reference/input/gc-reference-input-toc)

[Microsoft Game Development Kit](/services/playfab/sdks/platforms/gdk)


## Related topics

- [기존 입력 코드를 GameInput으로 이식하기](/ko/build/core-features/common/input/porting/index.md)
- [GameInput 자주 묻는 질문](/ko/build/core-features/common/input/overviews/input-faq.md)
- [기존 입력 스택과 GameInput 결합](/ko/build/core-features/common/input/porting/input-porting.md)
- [Windows.Xbox.Input에서 GameInput으로 포팅](/ko/build/core-features/common/input/porting/input-porting-wxi.md)
- [XBOX GDK로의 포팅 가이드](/ko/home/build-first-title/porting-guides.md)
