Reading input data from Manipulation Component
We can use chirality and kind to customize input based on the user’s hand or input device.
Overview
We’ve covered a lot on Manipulation Component. See our previous posts to learn how to get started.
- Getting started with Manipulation Component
- Using events with Manipulation Component
- Using custom sounds with Manipulation Component
- Redirect input with Manipulation Component
- Constrain position with Manipulation Component
Manipulation Component can surface some additional data such as chirality (left or right hand), kind (input type). We can read this during a Manipulation Event by checking the InputDevice. For example,
_ = content.subscribe(to: ManipulationEvents.WillBegin.self) { event in
guard let inputDevice = event.inputDeviceSet.first else { return }
let chirality = inputDevice.chirality
let kind = inputDevice.kind
}This can be useful when we need different behaviors for left vs. right hands. Or perhaps we want to apply components based on input type. For example, in Project Graveyard, I add a Billboard component when a user starts manipulating an entity. It looks great when using indirectPinch, but it seems kind of odd when using directPinch. I plan to update my app to check the kind and only add the Billboard when it is needed.
For this article, we’ll write the kind to either a left or right variable.
Example Code
struct Example104: View {
@State private var leftKind = ""
@State private var rightKind = ""
var body: some View {
RealityView { content in
let subject = createStepDemoBox()
// We'll use configureEntity to set up input and collision on the subject
ManipulationComponent
.configureEntity(
subject,
hoverEffect: .spotlight(.default),
collisionShapes: [.generateBox(width: 0.25, height: 0.25, depth: 0.25)]
)
_ = content.subscribe(to: ManipulationEvents.WillBegin.self) { event in
guard let inputDevice = event.inputDeviceSet.first else { return }
unpackChirality(inputDevice.chirality, value: unpackKind(inputDevice.kind)) // track the kind per hand/device
}
_ = content.subscribe(to: ManipulationEvents.DidHandOff.self) { event in
guard let oldInputDeviceSet = event.oldInputDeviceSet.first else { return }
unpackChirality(oldInputDeviceSet.chirality, value: "") // track the kind per hand/device
guard let newInputDeviceSet = event.newInputDeviceSet.first else { return }
unpackChirality(newInputDeviceSet.chirality, value: unpackKind(newInputDeviceSet.kind)) // track the kind per hand/device
}
_ = content.subscribe(to: ManipulationEvents.WillRelease.self) { event in
guard let inputDevice = event.inputDeviceSet.first else { return }
unpackChirality(inputDevice.chirality, value: "") // clear the correct value on release
}
content.add(subject)
}
.ornament(attachmentAnchor: .scene(.topLeading), ornament: {
Text(leftKind)
.frame(width: 160)
.padding()
.background(leftKind.isEmpty ? .clear : .green)
.glassBackgroundEffect()
})
.ornament(attachmentAnchor: .scene(.topTrailing), ornament: {
Text(rightKind)
.frame(width: 160)
.padding()
.background(rightKind.isEmpty ? .clear : .green)
.glassBackgroundEffect()
})
}
func unpackChirality(_ chirality: ManipulationComponent.InputDevice.Chirality?, value: String) {
switch chirality {
case .left:
leftKind = value
case .right:
rightKind = value
case .none:
return
@unknown default:
return
}
}
func unpackKind(_ kind: ManipulationComponent.InputDevice.Kind) -> String {
switch kind {
case .pointer:
return "pointer"
case .directPinch:
return "directPinch"
case .indirectPinch:
return "indirectPinch"
default:
return ""
}
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.

Follow Step Into Vision