Wprowadzanie klawiatury, myszy i kontrolera (C++)

Ten artykuł dotyczy starszych natywnych interfejsów API winRT. W przypadku nowych projektów aplikacji natywnych zalecamy użycie interfejsu API OpenXR.

Fragmenty kodu w tym artykule przedstawiają obecnie użycie języka C++/CX zamiast C++17 zgodnego z językiem C++/WinRT jako używanego w szablonie projektu holograficznego języka C++. Pojęcia te są równoważne projektowi C++/WinRT, ale trzeba będzie przetłumaczyć kod.

Subskrybowanie zdarzeń wejściowych CoreWindow

Dane wejściowe klawiatury

W szablonie aplikacji Systemu Windows Holographic dołączamy procedurę obsługi zdarzeń dla danych wejściowych klawiatury, podobnie jak w przypadku każdej innej aplikacji platformy UWP. Aplikacja używa danych wejściowych klawiatury w taki sam sposób, jak w Windows Mixed Reality.

Z aplikacji 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.
       //
   }

Dane wejściowe klawiatury wirtualnej

W przypadku immersyjnych zestawów słuchawkowych dla komputerów stacjonarnych można obsługiwać klawiatury wirtualne renderowane przez system Windows w widoku immersyjnym, implementując element CoreTextEditContext. Dzięki temu system Windows rozumie stan własnych pól tekstowych renderowanych przez aplikację, dzięki czemu wirtualna klawiatura może poprawnie współtworzyć tekst.

Aby uzyskać więcej informacji na temat implementowania obsługi coreTextEditContext, zobacz przykład CoreTextEditContext.

Wprowadzanie myszy

Możesz również użyć danych wejściowych myszy, ponownie za pośrednictwem programów obsługi zdarzeń wejściowych platformy UWP CoreWindow. Poniżej przedstawiono sposób modyfikowania szablonu aplikacji Windows Holographic w celu obsługi kliknięć myszy w taki sam sposób jak gesty naciśnięcia. Po wprowadzeniu tej modyfikacji kliknięcie myszy podczas noszenia immersyjnego urządzenia nagłownego zmieni położenie modułu.

Uwaga

Aplikacje platformy UWP mogą również pobierać nieprzetworzone dane XY dla myszy przy użyciu interfejsu API MouseDevice .

Zacznij od zadeklarowania nowej procedury obsługi OnPointerPressed w aplikacji AppView.h:

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

W pliku AppView.cpp dodaj ten kod do polecenia SetWindow:

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

Następnie umieść tę definicję dla elementu OnPointerPressed w dolnej części pliku:

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();
       }
   }

Właśnie dodawana procedura obsługi zdarzeń jest przekazywaniem do głównej klasy szablonu. Zmodyfikujmy klasę główną w celu obsługi tego przekazywania. Dodaj tę deklarację metody publicznej do pliku nagłówka:

// Handle mouse input.
       void OnPointerPressed();

Potrzebna będzie również ta prywatna zmienna składowa:

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

Na koniec zaktualizujemy klasę główną przy użyciu nowej logiki w celu obsługi kliknięć myszy. Zacznij od dodania tej procedury obsługi zdarzeń. Pamiętaj, aby zaktualizować nazwę klasy:

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

Teraz w metodzie Update zastąp istniejącą logikę pobierania wskaźnika następującą pozycją:

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;

Przekompiluj i ponownie wdróż. Zwróć uwagę, że kliknięcie myszy zmieni teraz położenie modułu w immersywnym zestawie słuchawkowym — lub HoloLens z podłączoną myszą bluetooth.

Obsługa kontrolera gier

Kontrolery gier mogą być zabawnym i wygodnym sposobem umożliwienia użytkownikowi kontrolowania immersyjnego środowiska Windows Mixed Reality.

dodaj następujące prywatne deklaracje składowe do klasy nagłówka dla pliku głównego:

// 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;

Zainicjuj zdarzenia gamepadu i wszystkie aktualnie dołączone gamepady w konstruktorze klasy głównej:

// 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);
   }

Dodaj te programy obsługi zdarzeń do klasy głównej. Pamiętaj, aby zaktualizować nazwę klasy:

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());
   }

Na koniec zaktualizuj logikę wejściową, aby rozpoznać zmiany w stanie kontrolera. W tym miejscu użyjemy tej samej zmiennej m_pointerPressed omówionej w powyższej sekcji w celu dodania zdarzeń myszy. Dodaj tę metodę do metody Update tuż przed sprawdzeniem lokalizacji elementu SpatialPointerPose:

// 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;

Nie zapomnij wyrejestrować zdarzeń podczas czyszczenia klasy głównej:

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

Ponowne kompiluj i ponownie wdróż. Teraz możesz dołączyć lub sparować kontroler gry i użyć go do zmiany położenia modułu wirującego.

Zobacz też