Tastatur-, Maus- und Controllereingabe (C++)

Dieser Artikel bezieht sich auf die älteren nativen WinRT-APIs. Für neue native App-Projekte empfehlen wir die Verwendung der OpenXR-API.

Die Codeausschnitte in diesem Artikel veranschaulichen derzeit die Verwendung von C++/CX anstelle von C++17-kompatiblem C++/WinRT, wie sie in der holografischen C++-Projektvorlage verwendet wird. Die Konzepte sind für ein C++/WinRT-Projekt gleichwertig, obwohl Sie den Code übersetzen müssen.

Abonnieren von CoreWindow-Eingabeereignissen

Tastatureingabe

In der Windows Holographic-App-Vorlage enthalten wir einen Ereignishandler für Tastatureingaben wie jede andere UWP-App. Ihre App verwendet Tastatureingabedaten auf die gleiche Weise in Windows Mixed Reality.

Über 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.
       //
   }

Eingabe der virtuellen Tastatur

Für immersive Desktop-Headsets können Sie virtuelle Tastaturen unterstützen, die von Windows über Ihre immersive Ansicht gerendert werden, indem Sie CoreTextEditContext implementieren. Dadurch kann Windows den Zustand Ihrer eigenen von der App gerenderten Textfelder verstehen, sodass die virtuelle Tastatur korrekt zum Text beitragen kann.

Weitere Informationen zur Implementierung der CoreTextEditContext-Unterstützung finden Sie im CoreTextEditContext-Beispiel.

Mauseingabe

Sie können auch die Mauseingabe verwenden, wiederum über die UWP CoreWindow-Eingabeereignishandler. Hier erfahren Sie, wie Sie die Windows Holographic-App-Vorlage so ändern, dass Sie Mausklicks auf die gleiche Weise wie gedrückte Gesten unterstützt. Nach dieser Änderung positioniert ein Mausklick beim Tragen eines immersiven Headset-Geräts den Würfel neu.

Hinweis

UWP-Apps können auch unformatierte XY-Daten für die Maus abrufen, indem sie die MouseDevice-API verwenden.

Beginnen Sie mit dem Deklarieren eines neuen OnPointerPressed-Handlers in AppView.h:

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

Fügen Sie in AppView.cpp den folgenden Code zu SetWindow hinzu:

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

Platzieren Sie dann diese Definition für OnPointerPressed am unteren Rand der Datei:

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

Der soeben hinzugefügte Ereignishandler ist ein Passthrough für die Vorlage Standard Klasse. Lassen Sie uns die Standard-Klasse ändern, um dieses Passthrough zu unterstützen. Fügen Sie der Headerdatei diese öffentliche Methodendeklaration hinzu:

// Handle mouse input.
       void OnPointerPressed();

Sie benötigen auch diese private Membervariable:

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

Schließlich aktualisieren wir die Standard-Klasse mit neuer Logik, um Mausklicks zu unterstützen. Fügen Sie zunächst diesen Ereignishandler hinzu. Aktualisieren Sie unbedingt den Klassennamen:

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

Ersetzen Sie nun in der Update-Methode die vorhandene Logik zum Abrufen einer Zeigerpose durch folgendes:

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;

Kompilieren Sie neu, und stellen Sie sie erneut bereit. Beachten Sie, dass der Würfel mit dem Mausklick nun in Ihrem immersiven Headset oder holoLens mit angeschlossener Bluetooth-Maus neu positioniert wird.

Unterstützung des Gamecontrollers

Spielcontroller können eine unterhaltsame und bequeme Möglichkeit sein, es dem Benutzer zu ermöglichen, eine immersive Windows Mixed Reality Erfahrung zu steuern.

Fügen Sie der Headerklasse für Ihre Standard-Datei die folgenden privaten Memberdeklarationen hinzu:

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

Initialisieren Sie Gamepadereignisse und alle aktuell angefügten Gamepads im Konstruktor für Ihre Standard-Klasse:

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

Fügen Sie diese Ereignishandler Ihrer Standard-Klasse hinzu. Aktualisieren Sie unbedingt den Klassennamen:

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

Aktualisieren Sie abschließend die Eingabelogik, um Änderungen im Controllerstatus zu erkennen. Hier verwenden wir dieselbe m_pointerPressed Variable, die im obigen Abschnitt erläutert wurde, um Mausereignisse hinzuzufügen. Fügen Sie dies der Update-Methode hinzu, bevor sie nach SpatialPointerPose sucht:

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

Vergessen Sie nicht, die Registrierung der Ereignisse aufzuheben, wenn Sie die Standard-Klasse bereinigen:

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

Kompilieren Sie neu, und stellen Sie sie erneut bereit. Sie können jetzt einen Gamecontroller anfügen oder koppeln und ihn verwenden, um den sich drehenden Würfel neu zu positionieren.

Weitere Informationen