Поделиться через


Ввод с клавиатуры, мыши и контроллера (C++)

Эта статья относится к устаревшим собственным API WinRT. Для новых проектов собственных приложений рекомендуется использовать API OpenXR.

Фрагменты кода в этой статье в настоящее время демонстрируют использование C++/CX, а не C++17-совместимого C++/WinRT, как используется в шаблоне голографического проекта C++. Эти понятия эквивалентны для проекта 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.
       //
   }

Ввод с виртуальной клавиатуры

Для иммерсивных настольных гарнитур можно поддерживать виртуальные клавиатуры, отображаемые Windows в иммерсивном представлении, реализовав CoreTextEditContext. Это позволяет Windows понять состояние текстовых полей, отрисованных приложением, чтобы виртуальная клавиатура правильно вносила в текст текст.

Дополнительные сведения о реализации поддержки CoreTextEditContext см. в примере CoreTextEditContext.

Ввод с помощью мыши

Вы также можете использовать ввод с помощью мыши, опять же с помощью обработчиков событий ввода UWP CoreWindow. Ниже описано, как изменить шаблон приложения Windows Holographic для поддержки щелчков мышью так же, как при нажатии жестов. После внесения этого изменения щелчок мышью при ношении иммерсивного устройства гарнитуры изменит положение куба.

Примечание

Приложения UWP также могут получать необработанные данные XY для мыши с помощью API MouseDevice .

Начните с объявления нового обработчика OnPointerPressed в AppView.h:

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

Только что добавленный обработчик событий является сквозной передачей в шаблон main классе. Давайте изменим класс main для поддержки этой сквозной передачи. Добавьте это объявление открытого метода в файл заголовка:

// Handle mouse input.
       void OnPointerPressed();

Вам также потребуется эта частная переменная-член:

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

Наконец, мы обновим класс main с помощью новой логики для поддержки щелчков мышью. Начните с добавления этого обработчика событий. Обязательно обновите имя класса:

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;

Перекомпиляция и повторное развертывание. Обратите внимание, что щелчок мыши теперь изменит положение куба в иммерсивной гарнитуре или HoloLens с подключенной мышью Bluetooth.

Поддержка игровых контроллеров

Игровые контроллеры могут быть забавным и удобным способом, позволяющим пользователю управлять иммерсивным Windows Mixed Reality взаимодействием.

Добавьте следующие закрытые объявления членов в класс заголовка для файла main:

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

Инициализируйте события геймпада и все подключенные в данный момент геймпады в конструкторе класса main:

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

Добавьте эти обработчики событий в класс main. Обязательно обновите имя класса:

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 переменную, описанную в разделе выше, для добавления событий мыши. Добавьте его в метод Update непосредственно перед тем, как он проверяет наличие 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;

Не забудьте отменить регистрацию событий при очистке класса main:

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

Перекомпиляция и повторное развертывание. Теперь вы можете подключить или связать игровой контроллер и использовать его для изменения положения вращающегося куба.

См. также раздел