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.

Follow Step Into Vision