Skip to content

Commit 9ce3783

Browse files
smlptskalarproduktraum
authored andcommitted
Extract VR button mapping to scenery VRInputMapper
1 parent 18f059c commit 9ce3783

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package graphics.scenery.controls
2+
3+
import graphics.scenery.utils.lazyLogger
4+
import graphics.scenery.controls.OpenVRHMD.OpenVRButton
5+
import graphics.scenery.controls.OpenVRHMD.Manufacturer
6+
import org.scijava.ui.behaviour.Behaviour
7+
8+
/**
9+
* Maps action names to VR controller buttons across different controller types.
10+
* Use [registerProfile] to create a new set of bindings for a given manufacturer.
11+
* Loading registered profiles is done with [loadProfile] or [loadProfileForHMD].
12+
* Bind behaviors to existing action names in a profile via [bind]. Controller sides (roles) and buttons
13+
* are combined into a single [ButtonMapping] data class.
14+
*/
15+
class VRInputMapper {
16+
private val logger by lazyLogger()
17+
18+
private val profiles = mutableMapOf<Manufacturer, Map<String, ButtonMapping>>()
19+
private var currentProfile: Manufacturer? = null
20+
21+
/**
22+
* Register a controller profile for a specific manufacturer.
23+
*/
24+
fun registerProfile(manufacturer: Manufacturer, mappings: Map<String, ButtonMapping>) {
25+
profiles[manufacturer] = mappings
26+
logger.debug("Registered profile for $manufacturer with ${mappings.size} mappings")
27+
}
28+
29+
/**
30+
* Load a profile for the given manufacturer.
31+
* @return true if profile exists and was loaded
32+
*/
33+
fun loadProfile(manufacturer: Manufacturer): Boolean {
34+
return if (profiles.containsKey(manufacturer)) {
35+
currentProfile = manufacturer
36+
logger.info("Loaded input profile for $manufacturer")
37+
true
38+
} else {
39+
logger.warn("No profile registered for $manufacturer")
40+
false
41+
}
42+
}
43+
44+
/**
45+
* Auto-load profile based on HMD manufacturer.
46+
*/
47+
fun loadProfileForHMD(hmd: OpenVRHMD): Boolean {
48+
return loadProfile(hmd.manufacturer)
49+
}
50+
51+
/**
52+
* Get the button mapping for an action name.
53+
*/
54+
fun getMapping(actionName: String): ButtonMapping? {
55+
val profile = currentProfile ?: return null
56+
return profiles[profile]?.get(actionName)
57+
}
58+
59+
/**
60+
* Get all mappings for the current profile.
61+
*/
62+
fun getCurrentMappings(): Map<String, ButtonMapping>? {
63+
val profile = currentProfile ?: return null
64+
return profiles[profile]
65+
}
66+
67+
/** Get the currently active profile as [Manufacturer]. */
68+
fun getCurrentProfile(): Manufacturer? {
69+
return currentProfile
70+
}
71+
72+
/**
73+
* Bind an action to a behavior on the HMD.
74+
* @return true if binding succeeded
75+
*/
76+
fun bind(hmd: OpenVRHMD, actionName: String, behavior: Behaviour): Boolean {
77+
val mapping = getMapping(actionName) ?: return false
78+
hmd.addKeyBinding(actionName, mapping.role, mapping.button)
79+
hmd.addBehaviour(actionName, behavior)
80+
logger.debug("Bound '$actionName' to ${mapping.role} ${mapping.button}")
81+
return true
82+
}
83+
}
84+
85+
86+
/**
87+
* Represents a physical button on a VR controller.
88+
*/
89+
data class ButtonMapping(
90+
val role: TrackerRole,
91+
val button: OpenVRButton
92+
)

0 commit comments

Comments
 (0)