다음을 통해 공유


키보드, 마우스 및 컨트롤러 입력(C++)

이 문서는 레거시 WinRT 네이티브 API와 관련이 있습니다. 새 네이티브 앱 프로젝트의 경우 OpenXR API를 사용하는 것이 좋습니다.

이 문서의 코드 조각은 현재 C++ 홀로그램 프로젝트 템플릿에서 사용되는 C++17 규격 C++/WinRT 대신 C++/CX를 사용하는 방법을 보여 줍니다. 개념은 C++/WinRT 프로젝트에 해당하지만 코드를 번역해야 합니다.

CoreWindow 입력 이벤트 구독

키보드 입력

Windows Holographic 앱 템플릿에는 다른 UWP 앱과 마찬가지로 키보드 입력에 대한 이벤트 처리기가 포함되어 있습니다. 앱은 Windows Mixed Reality 동일한 방식으로 키보드 입력 데이터를 사용합니다.

AppView.cpp에서:

// Register for keypress notifications.
   window->KeyDown +=
       ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &AppView::OnKeyPressed);

    …

   // Input event handlers

   void AppView::OnKeyPressed(CoreWindow^ sender, KeyEventArgs^ args)
   {
       //
       // TODO: Respond to keyboard input here.
       //
   }

가상 키보드 입력

몰입형 데스크톱 헤드셋의 경우 CoreTextEditContext를 구현하여 몰입형 보기를 통해 Windows에서 렌더링한 가상 키보드를 지원할 수 있습니다. 이렇게 하면 Windows에서 자체 앱 렌더링 텍스트 상자의 상태를 이해할 수 있으므로 가상 키보드가 텍스트에 올바르게 기여할 수 있습니다.

CoreTextEditContext 지원을 구현하는 방법에 대한 자세한 내용은 CoreTextEditContext 샘플을 참조하세요.

마우스 입력

UWP CoreWindow 입력 이벤트 처리기를 통해 마우스 입력을 다시 사용할 수도 있습니다. 누른 제스처와 동일한 방식으로 마우스 클릭을 지원하도록 Windows Holographic 앱 템플릿을 수정하는 방법은 다음과 같습니다. 이를 수정한 후 몰입형 헤드셋 장치를 착용하는 동안 마우스 클릭으로 큐브 위치가 변경됩니다.

참고

UWP 앱은 MouseDevice API를 사용하여 마우스에 대한 원시 XY 데이터를 가져올 수도 있습니다.

먼저 AppView.h에서 새 OnPointerPressed 처리기를 선언합니다.

protected:
       void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);

AppView.cpp에서 SetWindow에 다음 코드를 추가합니다.

// Register for pointer pressed notifications.
   window->PointerPressed +=
       ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &AppView::OnPointerPressed);

그런 다음 OnPointerPressed에 대한 이 정의를 파일의 맨 아래에 배치합니다.

void AppView::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
   {
       // Allow the user to interact with the holographic world using the mouse.
       if (m_main != nullptr)
       {
           m_main->OnPointerPressed();
       }
   }

방금 추가한 이벤트 처리기는 템플릿 기본 클래스에 대한 통과입니다. 이 통과를 지원하도록 기본 클래스를 수정해 보겠습니다. 헤더 파일에 다음 공용 메서드 선언을 추가합니다.

// Handle mouse input.
       void OnPointerPressed();

이 프라이빗 멤버 변수도 필요합니다.

// Keep track of mouse input.
       bool m_pointerPressed = false;

마지막으로 마우스 클릭을 지원하는 새 논리로 기본 클래스를 업데이트합니다. 먼저 이 이벤트 처리기를 추가합니다. 클래스 이름을 업데이트해야 합니다.

void MyHolographicAppMain::OnPointerPressed()
   {
       m_pointerPressed = true;
   }

이제 Update 메서드에서 포인터 포즈를 가져오기 위한 기존 논리를 다음으로 바꿉다.

SpatialInteractionSourceState^ pointerState = m_spatialInputHandler->CheckForInput();
   SpatialPointerPose^ pose = nullptr;
   if (pointerState != nullptr)
   {
       pose = pointerState->TryGetPointerPose(currentCoordinateSystem);
   }
   else if (m_pointerPressed)
   {
       pose = SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, prediction->Timestamp);
   }
   m_pointerPressed = false;

다시 컴파일하고 다시 배포합니다. 이제 마우스 클릭으로 몰입형 헤드셋의 큐브 위치가 변경되거나 Bluetooth 마우스가 연결된 HoloLens가 변경됩니다.

게임 컨트롤러 지원

게임 컨트롤러는 사용자가 몰입형 Windows Mixed Reality 환경을 제어할 수 있는 재미있고 편리한 방법이 될 수 있습니다.

기본 파일의 헤더 클래스에 다음 프라이빗 멤버 선언을 추가합니다.

// Recognize gamepads that are plugged in after the app starts.
       void OnGamepadAdded(Platform::Object^, Windows::Gaming::Input::Gamepad^ args);
// Stop looking for gamepads that are unplugged.
       void OnGamepadRemoved(Platform::Object^, Windows::Gaming::Input::Gamepad^ args);
Windows::Foundation::EventRegistrationToken                     m_gamepadAddedEventToken;
       Windows::Foundation::EventRegistrationToken                     m_gamepadRemovedEventToken;
// Keeps track of a gamepad and the state of its A button.
       struct GamepadWithButtonState
       {
           Windows::Gaming::Input::Gamepad^ gamepad;
           bool buttonAWasPressedLastFrame = false;
       };
       std::vector<GamepadWithButtonState>                             m_gamepads;

기본 클래스의 생성자에서 게임 패드 이벤트 및 현재 연결된 모든 게임 패드를 초기화합니다.

// If connected, a game controller can also be used for input.
   m_gamepadAddedEventToken = Gamepad::GamepadAdded +=
       ref new EventHandler<Gamepad^>(
           bind(&$safeprojectname$Main::OnGamepadAdded, this, _1, _2)
           );
m_gamepadRemovedEventToken = Gamepad::GamepadRemoved +=
       ref new EventHandler<Gamepad^>(
           bind(&$safeprojectname$Main::OnGamepadRemoved, this, _1, _2)
           );
for (auto const& gamepad : Gamepad::Gamepads)
   {
       OnGamepadAdded(nullptr, gamepad);
   }

이러한 이벤트 처리기를 기본 클래스에 추가합니다. 클래스 이름을 업데이트해야 합니다.

void MyHolographicAppMain::OnGamepadAdded(Object^, Gamepad^ args)
   {
       for (auto const& gamepadWithButtonState : m_gamepads)
       {
           if (args == gamepadWithButtonState.gamepad)
           {
               // This gamepad is already in the list.
               return;
           }
       }
       m_gamepads.push_back({ args, false });
   }
void MyHolographicAppMain::OnGamepadRemoved(Object^, Gamepad^ args)
   {
       m_gamepads.erase(
           std::remove_if(m_gamepads.begin(), m_gamepads.end(), [&](GamepadWithButtonState& gamepadWithState)
               {
                   return gamepadWithState.gamepad == args;
               }),
           m_gamepads.end());
   }

마지막으로 컨트롤러 상태의 변경 내용을 인식하도록 입력 논리를 업데이트합니다. 여기서는 마우스 이벤트를 추가하기 위해 위의 섹션에서 설명한 것과 동일한 m_pointerPressed 변수를 사용합니다. SpatialPointerPose를 확인하는 위치 바로 앞에 Update 메서드에 추가합니다.

// Check for new input state since the last frame.
   for (auto& gamepadWithButtonState : m_gamepads)
   {
       bool buttonDownThisUpdate = ((gamepadWithButtonState.gamepad->GetCurrentReading().Buttons & GamepadButtons::A) == GamepadButtons::A);
       if (buttonDownThisUpdate && !gamepadWithButtonState.buttonAWasPressedLastFrame)
       {
           m_pointerPressed = true;
       }
       gamepadWithButtonState.buttonAWasPressedLastFrame = buttonDownThisUpdate;
   }
// For context.
   SpatialInteractionSourceState^ pointerState = m_spatialInputHandler->CheckForInput();
   SpatialPointerPose^ pose = nullptr;
   if (pointerState != nullptr)
   {
       pose = pointerState->TryGetPointerPose(currentCoordinateSystem);
   }
   else if (m_pointerPressed)
   {
       pose = SpatialPointerPose::TryGetAtTimestamp(currentCoordinateSystem, prediction->Timestamp);
   }
   m_pointerPressed = false;

기본 클래스를 정리할 때 이벤트를 등록 취소하는 것을 잊지 마세요.

if (m_gamepadAddedEventToken.Value != 0)
   {
       Gamepad::GamepadAdded -= m_gamepadAddedEventToken;
   }
   if (m_gamepadRemovedEventToken.Value != 0)
   {
       Gamepad::GamepadRemoved -= m_gamepadRemovedEventToken;
   }

다시 컴파일하고 다시 배포합니다. 이제 게임 컨트롤러를 연결하거나 페어링하고 이를 사용하여 회전하는 큐브의 위치를 변경할 수 있습니다.

추가 정보