GameInput 읽기
모든 장치에서 수신된 원시 입력 패킷은 "읽기" 개체에 캡슐화됩니다. 읽기에는 원본 원시 패킷 데이터와 (보통) 원시 데이터를 상위 수준 형식으로 변환한 하나 이상의 변형 데이터가 포함되어 있습니다. 읽은 정보는 데이터 컨테이너로서의 역할 외에도 입력 스트림 내의 특정 위치를 참조하는 식별자 역할을 합니다.
읽은 정보 받기
GameInput API는 읽은 정보를 획득하는 두 가지 방법을 제공합니다. 가장 일반적인 방법은 IGameInput 인터페이스의 메서드를 통해 입력 스트림에서 직접 액세스하는 것입니다.
HRESULT GetCurrentReading(
_In_ GameInputKind inputKind,
_In_opt_ IGameInputDevice * device,
_COM_Outptr_ IGameInputReading ** reading);
GetCurrentReading을 호출하면 입력 스트림에서 최근 읽기를 검색합니다. 선택적 GameInputKind 필터는 반환된 읽기 값을 게임 패드 또는 키보드와 같은 특정 유형의 입력으로 제한하는 방식으로 통과될 수 있습니다. 선택적 IGameInputDevice 필터는 반환된 읽기 값을 지정한 장치에서 생성된 값으로 제한하는 방식으로도 통과될 수 있습니다. 이러한 필터는 개별적으로 또는 함께 적용될 수 있습니다.
IGameInputReading 인스턴스는 참조 수가 계산되는 싱글톤입니다. 읽기 값을 검색하는 것은 매우 빠르고 가벼운 작업입니다. 메모리 할당이나 복사가 수행되지 않으며 API 호출은 커널 모드 전환이 없고 잠기지 않습니다. 읽기 값이 싱글톤이기 때문에 응용 프로그램은 읽기 포인터가 같은지 비교하여 GetCurrentReading에 대한 두 호출이 동일한 읽기를 반환했는지 여부를 확인할 수 있습니다(새 입력이 생성되지 않음).
복잡한 입력 요구가 적은 게임은 프레임당 한 번 새로운 입력을 찾기 위해 단순히 폴링 할 수 있으며, 두 읽기에 저장된 상태를 비교하여 같은 읽기 값인지 확인할 수 있습니다. 그러나 더 입력이 복잡해야 하는 게임은 이전 프레임 이후 발생한 모든 입력 상태 변경에 대한 완전한 정보를 얻기 위해 입력 스트림을 탐색하고 싶을 수 있습니다. 이는 GetNextReading 및 GetPreviousReading 메서드에서 가능하며, GetCurrentReading과 동일한 필터를 사용할 수 있습니다. 입력 스트림은 지난 0.5초의 입력 내용을 버퍼에 유지합니다.
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 콜백을 참조하세요.
읽은 값에서 데이터 가져오기
모든 읽기에는 장치의 원시 입력 패킷 데이터가 포함되어 있지만 일반적으로 하나 이상의 고급 변환도 포함됩니다. 예를 들어, 게임 패드에서 수신된 입력은 잘 알려진 버튼과 엄지스틱 식별자를 사용한 표준 고정 형식 구조를 대상으로 구문 분석됩니다. 읽은 값에는 종종 동일한 원시 입력 데이터의 여러 표현이 포함되어 있어, 애플리케이션이 자신의 요구에 가장 적합한 형식을 선택할 수 있습니다.
응용 프로그램은 GetInputKind 메서드를 호출하여 읽기에 포함된 데이터 종류를 쿼리할 수 있습니다. 이를 통해 GameInputKind 열거형에서 하나 이상의 플래그 값이 반환됩니다.
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를 사용하는 애플리케이션을 위한 광범위한 장치 지원이 가능합니다. 그러나 많은 게임 컨트롤러(게임 패드와 같은)는 읽은 값에서 익숙한 고정 형식 상태를 제공하므로 일반적인 게임이 소비하기가 훨씬 쉽습니다.
typedef struct GameInputGamepadState
{
GameInputGamepadButtons buttons;
float leftTrigger;
float rightTrigger;
float leftThumbstickX;
float leftThumbstickY;
float rightThumbstickX;
float rightThumbstickY;
} GameInputGamepadState;
IGameInputReading 인터페이스에는 읽기에 지원되는 형식으로 상태를 검색하기 위한 메서드가 포함되어 있습니다. 읽은 값에서 사용할 수 있는 다른 모든 표현은 미리 계산되므로 이러한 메서드는 단순히 몇 바이트만 복사하여 반환합니다.
단순 게임 패드 입력 루프
다음 샘플 코드는 게임 패드에 대한 완전한 기능을 가진 입력 루프의 예입니다. 이 샘플에 대해 알아야 할 한 가지는 명시적인 장치 열거가 없다는 것입니다. IGameInputDevice는 장치 식별자로만 사용됩니다. 해당 메서드는 전혀 호출되지 않습니다. 이는 GameInput API의 입력 중심 특성과 공통 입력 시나리오에 대한 코드를 단순화하는 방법을 보여주는 것입니다.
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;
}
}