Vulkan Schnee 0.0.1 (22840dc8)
High-performance rendering engine
Loading...
Searching...
No Matches
Input Handling

Input handling has two layers. Input::XrInputHandler samples raw OpenXR state, and Input::InputManager exposes named actions for gameplay code.

Use Input::InputManager from actors and components. Use Input::XrInputHandler only when adding a new device binding or raw OpenXR action.

Source Files

  • Engine/include/Engine/Input/InputManager.h - named action API
  • Engine/src/Engine/Input/InputManager.cpp - action sampling and callback dispatch
  • Engine/include/Engine/Input/XrInputHandler.h - raw OpenXR input state
  • Engine/include/Engine/Input/XrRig.h - resolved world-space tracked poses
  • Engine/src/Engine/Core/Engine.cpp - input frame order and default XR bindings

Frame Order

Input is sampled once per frame before logic tick.

xrInputHandler->syncInputs(...)
inputManager->beginFrame()
GameModule::preTick()
ITickable::preTick()
GameModule::tick(deltaTime)
ITickable::tick(deltaTime) with priority > TrackedPoseStep
xrRig->resolveTrackedPoses()
inputManager->dispatchCallbacks()
ITickable::tick(deltaTime) with priority <= TrackedPoseStep
GameModule::postTick()
ITickable::postTick()

Callbacks dispatch after XrRig resolves tracked poses. Callback code can read current-frame world-space hand poses.

Polling reads the sampled input snapshot for the current frame. Poll from tick() when the code needs continuous values.

Built-In XR Actions

The engine binds these actions in Engine::EngineKern::createInputManager().

Action Type Value
Input::Actions::XrLeftTrigger float Left trigger value, 0.0 to 1.0
Input::Actions::XrRightTrigger float Right trigger value, 0.0 to 1.0
Input::Actions::XrLeftGrip float Left grip value, 0.0 to 1.0
Input::Actions::XrRightGrip float Right grip value, 0.0 to 1.0
Input::Actions::XrLeftThumbstick glm::vec2 Left thumbstick axis
Input::Actions::XrRightThumbstick glm::vec2 Right thumbstick axis
Input::Actions::XrRightAButton bool Right controller A button pressed state
Input::Actions::XrRightBButton bool Right controller B button pressed state

Action Types

Input::InputManager supports three value types.

Type Bind method Poll method Callback method
bool bindBoolAction() getBoolAction() onBoolAction()
float bindFloatAction() getFloatAction() onFloatAction()
glm::vec2 bindVec2Action() getVec2Action() onVec2Action()

Bind methods return Input::InputManager::ProviderHandle. Callback methods return Input::InputManager::CallbackHandle.

Boolean actions also have edge helpers:

inputManager->onBoolPressed("Action.Name", []() { /* pressed */ });
inputManager->onBoolReleased("Action.Name", []() { /* released */ });

Dispatch Rules

Rule bool float glm::vec2
EveryFrame Dispatches every frame Dispatches every frame Dispatches every frame
Changed Dispatches when value changes Dispatches when value changes by more than 0.0001 Dispatches when squared delta is greater than 0.000001
Pressed Dispatches on false-to-true edge Not used Not used
Released Dispatches on true-to-false edge Not used Not used

Use bool actions for edges. Derive them from analog inputs when the game needs thresholds. For button edges, register callbacks directly on the built-in button action instead of binding a bool action that reads another bool action.

Register A Gameplay Action

Register gameplay actions in beginPlay(). Store provider and callback handles in Input::InputBindingScope.

#include "Engine/Core/Engine.h"
#include "Engine/Input/InputManager.h"
class WindBenderCharacter : public PlayerActor
{
public:
void beginPlay() override;
void endPlay() override;
private:
static constexpr const char* ShootAction = "WindBender.Shoot";
Input::InputManager* inputManager_ = nullptr;
Input::InputBindingScope inputBindings_;
};
void WindBenderCharacter::beginPlay()
{
PlayerActor::beginPlay();
inputManager_ = engine != nullptr ? engine->getInputManager() : nullptr;
if (inputManager_ == nullptr) {
return;
}
inputBindings_.add(
*inputManager_,
inputManager_->bindBoolAction(
ShootAction,
[inputManager = inputManager_]()
{
return inputManager != nullptr &&
inputManager->getFloatAction(Input::Actions::XrRightTrigger) > 0.75f;
}
)
);
inputBindings_.add(
*inputManager_,
inputManager_->onBoolPressed(
ShootAction,
[this]()
{
shoot();
}
)
);
}
void WindBenderCharacter::endPlay()
{
if (inputManager_ != nullptr) {
inputBindings_.reset();
inputManager_ = nullptr;
}
PlayerActor::endPlay();
}
Owns the engine runtime and provides access to engine subsystems.
Definition Engine.h:67
Input::InputManager * getInputManager() const
Returns the input action manager.
Definition Engine.h:188
static EngineManager & getInstance()
Returns the singleton engine manager instance.
EngineKern * getEngineModule()
Returns the active engine.
RAII owner for input provider and callback registrations.
Action-based input dispatcher for polled input values and callbacks.

Poll Continuous Values

Use polling for movement, aiming, charging, and debug UI.

void MyActor::tick(double deltaTimeSeconds)
{
Actor::tick(deltaTimeSeconds);
Input::InputManager* input = engine != nullptr ? engine->getInputManager() : nullptr;
if (input == nullptr) {
return;
}
const glm::vec2 move = input->getVec2Action(Input::Actions::XrRightThumbstick);
const float grip = input->getFloatAction(Input::Actions::XrRightGrip);
// Apply movement or charging logic here.
}
float getFloatAction(const std::string &name) const
Returns the latest sampled float value for a named action.
glm::vec2 getVec2Action(const std::string &name) const
Returns the latest sampled vec2 value for a named action.
constexpr auto XrRightThumbstick
Right controller thumbstick vector.
constexpr auto XrRightGrip
Right controller grip axis, in the range supplied by XR runtime.

Use Hand Poses In Callbacks

Callbacks dispatch after XrRig resolves tracked poses. Read hand poses from XrRig, not from XrInputHandler.

void WindBenderCharacter::shoot()
{
Input::XrRig* xrRig = engine != nullptr ? engine->getXrRig() : nullptr;
if (xrRig == nullptr) {
return;
}
if (!rightHand.isValid) {
return;
}
const glm::vec3 spawnPosition = rightHand.position;
const glm::quat spawnOrientation = rightHand.orientation;
}
Input::XrRig & getXrRig() const
Returns resolved XR rig poses.
Definition Engine.h:194
Resolves raw XR play-space poses into world-space tracked hand poses.
Definition XrRig.h:44
TrackedHandPose getHandPose(Hand hand) const
Returns the last resolved world-space pose for a hand.
@ RIGHT
Right hand, stored at index 1.
World-space pose for one tracked XR hand.
Definition XrRig.h:21
bool isValid
True when the pose was resolved from valid tracking data.
Definition XrRig.h:25
glm::quat orientation
World-space hand orientation.
Definition XrRig.h:35
glm::vec3 position
World-space hand position.
Definition XrRig.h:30

Binding Custom Actions

Actions are named strings. Use a subsystem prefix to avoid collisions.

inputManager->bindFloatAction(
"Glider.LeftGrip",
[inputManager]()
{
return inputManager->getFloatAction(Input::Actions::XrLeftGrip);
}
);
constexpr auto XrLeftGrip
Left controller grip axis, in the range supplied by XR runtime.

Bindings are providers. beginFrame() calls each provider and stores previous and current values.

Use InputBindingScope for gameplay-owned providers and callbacks. The scope removes callbacks and then removes providers when reset() runs or the scope is destroyed. Provider removal is generation-checked, so an old scope cannot clear a newer provider registered under the same action name.

Do not capture temporary objects in providers or callbacks. Prefer providers that read engine-owned actions from InputManager instead of raw XrInputHandler state.

Ownership

Engine::EngineKern owns the input objects.

Input::XrInputHandler* EngineKern::getXrInputHandler() const;
Input::InputManager* EngineKern::getInputManager() const;
Input::XrRig* EngineKern::getXrRig() const;
Creates OpenXR controller actions from the profile registry and samples the input state.

Actors store raw pointers only as cached access. They do not delete input objects.

Related Documentation