Controller Input and Tracking Best Practices
Updated: Apr 14, 2026
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).
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).
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.
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.
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.
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:
- Create Input Action and Input Mapping Context assets in the editor.
- Add the mapping context in
BeginPlay. - Bind actions in
SetupPlayerInputComponent.
To learn more about using controllers in XR applications in Unreal Engine, see the following guides: