Develop

Controller Input and Tracking Best Practices

Updated: Apr 14, 2026

Overview

This page covers best practices for controller input and tracking in your Unreal Engine project.

Use controller visuals to improve the user experience

Add an OculusXRController component as a child of each MotionController component (Left and Right) in your custom Pawn class. Set the SkeletonType property to Left or Right to match each hand. The component automatically loads the correct controller mesh based on the detected controller type (Meta Quest Touch, Touch Pro, or Touch Plus).
Note: For the full setup procedure, see Getting Started with Controller Input and Tracking.

Use controller-driven hand poses

The Meta XR Plugin supports three controller-driven hand pose modes via EOculusXRControllerDrivenHandPoseTypes:
  • None: Controllers do not generate hand poses.
  • Natural: Controller button inputs generate a natural hand pose.
  • Controller: Controller button inputs generate a hand pose holding a controller.
Set the mode with UOculusXRInputFunctionLibrary::SetControllerDrivenHandPoses() and query the current mode with GetControllerDrivenHandPoses().
To allow both hand tracking and controllers to be active at the same time, call UOculusXRInputFunctionLibrary::SetSimultaneousHandsAndControllersEnabled(true).
See Manage controller visibility for controller mesh display options when using hand poses.

Manage controller visibility

The OculusXRController component automatically hides controller meshes when hand tracking is enabled. The RenderWhenUsingControllerDrivenHands property overrides this behavior when the hand pose mode is set to Controller.
Use UOculusXRFunctionLibrary::HasInputFocus() to hide controllers when the application loses input focus, for example when a system UI overlay appears. Check this value in your actor’s Tick event and set controller visibility accordingly.

Use haptic feedback

The Meta XR Plugin provides haptic playback methods through UOculusXRInputFunctionLibrary:
  • PlayCurveHapticEffect(): Play a curve-based haptic effect.
  • PlayBufferHapticEffect(): Play a buffer-based haptic effect.
  • PlayAmplitudeEnvelopeHapticEffect(): Play amplitude envelope haptics.
  • PlaySoundWaveHapticEffect(): Play audio-driven haptics.
  • SetHapticsByValue(): Set haptic frequency and amplitude directly.
  • StopHapticEffect(): Stop playback.
PlayCurveHapticEffect(), PlayBufferHapticEffect(), SetHapticsByValue(), and StopHapticEffect() accept an EOculusXRHandHapticsLocation parameter for location targeting: Hand (whole controller), Thumb, or Index.
Note: For controller-specific haptic capabilities, see Touch Plus Controllers.

Detect controller type at runtime

Use UOculusXRFunctionLibrary::GetControllerType() to determine which controller is connected and adapt input bindings or feature sets accordingly. The returned EOculusXRControllerType includes:
  • MetaQuestTouch: Meta Quest Touch controllers (Meta Quest 2).
  • MetaQuestTouchPro: Meta Quest Touch Pro controllers (Meta Quest Pro).
  • MetaQuestTouchPlus: Meta Quest Touch Plus controllers (Meta Quest 3, Meta Quest 3S).
The OculusXRController component uses this value internally to load the correct controller mesh.

Use Enhanced Input for action bindings

Controller input mapping uses the Enhanced Input system in Unreal Engine. The Meta XR Plugin depends on Enhanced Input at the plugin level but does not provide pre-built Input Action or Input Mapping Context assets. Create your own following this pattern:
  1. Create Input Action and Input Mapping Context assets in the editor.
  2. Add the mapping context in BeginPlay.
  3. Bind actions in SetupPlayerInputComponent.
Note: For the full Enhanced Input setup, see Epic’s Enhanced Input documentation.

Learn more

To learn more about using controllers in XR applications in Unreal Engine, see the following guides: