diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4266bab2a175..8be3b8437d0b 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -2952,6 +2952,12 @@
Maximum number of threads to be used by [WorkerThreadPool]. Value of [code]-1[/code] means no limit.
+
+ Enables the analog threshold binding modifier if supported by the XR runtime.
+
+
+ Enabled the dpad binding modifier if supported by the XR runtime.
+
Action map configuration to load by default.
diff --git a/editor/icons/Modifiers.svg b/editor/icons/Modifiers.svg
new file mode 100644
index 000000000000..1b25d620278d
--- /dev/null
+++ b/editor/icons/Modifiers.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/main/main.cpp b/main/main.cpp
index 5206e9b84c57..2d87ccde51f6 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2604,6 +2604,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false);
GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
+ // OpenXR Binding modifier settings
+ GLOBAL_DEF_BASIC("xr/openxr/binding_modifiers/analog_threshold", false);
+ GLOBAL_DEF_BASIC("xr/openxr/binding_modifiers/dpad_binding", false);
+
#ifdef TOOLS_ENABLED
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index f924386ecf15..1979f09e0293 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -107,14 +107,26 @@ void OpenXRActionMap::remove_action_set(Ref p_action_set) {
}
}
-void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
+void OpenXRActionMap::clear_interaction_profiles() {
+ // Interaction profiles held within our action map set should be released and destroyed but just in case they are still used some where else
+ if (interaction_profiles.size() == 0) {
+ return;
+ }
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref interaction_profile = interaction_profiles[i];
+ interaction_profile->action_map = nullptr;
+ }
interaction_profiles.clear();
+ emit_changed();
+}
+
+void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
+ clear_interaction_profiles();
for (int i = 0; i < p_interaction_profiles.size(); i++) {
- Ref interaction_profile = p_interaction_profiles[i];
- if (interaction_profile.is_valid() && !interaction_profiles.has(interaction_profile)) {
- interaction_profiles.push_back(interaction_profile);
- }
+ // add them anew so we verify our interaction profile pointer
+ add_interaction_profile(p_interaction_profiles[i]);
}
}
@@ -147,6 +159,13 @@ void OpenXRActionMap::add_interaction_profile(Ref p_in
ERR_FAIL_COND(p_interaction_profile.is_null());
if (!interaction_profiles.has(p_interaction_profile)) {
+ if (p_interaction_profile->action_map && p_interaction_profile->action_map != this) {
+ // interaction profiles should only relate to our action map
+ p_interaction_profile->action_map->remove_interaction_profile(p_interaction_profile);
+ }
+
+ p_interaction_profile->action_map = this;
+
interaction_profiles.push_back(p_interaction_profile);
emit_changed();
}
@@ -156,6 +175,10 @@ void OpenXRActionMap::remove_interaction_profile(Ref p
int idx = interaction_profiles.find(p_interaction_profile);
if (idx != -1) {
interaction_profiles.remove_at(idx);
+
+ ERR_FAIL_COND_MSG(p_interaction_profile->action_map != this, "Removing interaction profile that belongs to this action map but had incorrect action map pointer."); // this should never happen!
+ p_interaction_profile->action_map = nullptr;
+
emit_changed();
}
}
@@ -598,5 +621,5 @@ PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref p
OpenXRActionMap::~OpenXRActionMap() {
action_sets.clear();
- interaction_profiles.clear();
+ clear_interaction_profiles();
}
diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h
index 678b3d7fbc57..7239a8534c9f 100644
--- a/modules/openxr/action_map/openxr_action_map.h
+++ b/modules/openxr/action_map/openxr_action_map.h
@@ -57,6 +57,7 @@ class OpenXRActionMap : public Resource {
void add_action_set(Ref p_action_set); // Add an action set to our action map
void remove_action_set(Ref p_action_set); // Remove an action set from our action map
+ void clear_interaction_profiles(); // Remove all our interaction profiles
void set_interaction_profiles(Array p_interaction_profiles); // Set our interaction profiles by providing an array (for loading from resource)
Array get_interaction_profiles() const; // Get our interaction profiles as an array (for saving to resource)
diff --git a/modules/openxr/action_map/openxr_binding_modifier.cpp b/modules/openxr/action_map/openxr_binding_modifier.cpp
new file mode 100644
index 000000000000..29ed90104fcf
--- /dev/null
+++ b/modules/openxr/action_map/openxr_binding_modifier.cpp
@@ -0,0 +1,34 @@
+/**************************************************************************/
+/* openxr_binding_modifier.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_binding_modifier.h"
+
+void OpenXRBindingModifier::_bind_methods() {
+}
diff --git a/modules/openxr/action_map/openxr_binding_modifier.h b/modules/openxr/action_map/openxr_binding_modifier.h
new file mode 100644
index 000000000000..295ec9b807ea
--- /dev/null
+++ b/modules/openxr/action_map/openxr_binding_modifier.h
@@ -0,0 +1,66 @@
+/**************************************************************************/
+/* openxr_binding_modifier.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_BINDING_MODIFIER_H
+#define OPENXR_BINDING_MODIFIER_H
+
+#include "../action_map/openxr_action.h"
+#include "core/io/resource.h"
+
+// Part of implementation for:
+// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_KHR_binding_modification
+
+class OpenXRInteractionProfile;
+class OpenXRIPBinding;
+
+class OpenXRBindingModifier : public Resource {
+ GDCLASS(OpenXRBindingModifier, Resource);
+
+private:
+protected:
+ friend class OpenXRInteractionProfile;
+ friend class OpenXRIPBinding;
+
+ static void _bind_methods();
+
+ OpenXRInteractionProfile *interaction_profile = nullptr; // action belongs to this interaction profile (should only be set if record_on_binding() == false).
+ OpenXRIPBinding *ip_binding = nullptr; // action belongs to this binding (should only be set if record_on_binding() == true).
+
+public:
+ OpenXRInteractionProfile *get_interaction_profile() const { return interaction_profile; }
+ OpenXRIPBinding *get_ip_binding() const { return ip_binding; }
+
+ virtual bool record_on_binding() const { return true; } // If true, this binding modifier is recorded on a specific binding. If false, this binding modifier is recorded on the interaction profile.
+
+ virtual String get_description() const = 0; // Returns the description shown in the editor
+ virtual PackedByteArray get_ip_modification() = 0; // Return the XrBindingModificationsKHR binding modifier struct data used when calling xrSuggestInteractionProfileBindings
+};
+
+#endif // OPENXR_BINDING_MODIFIER_H
diff --git a/modules/openxr/action_map/openxr_haptic_feedback.cpp b/modules/openxr/action_map/openxr_haptic_feedback.cpp
new file mode 100644
index 000000000000..20d563e3ddd8
--- /dev/null
+++ b/modules/openxr/action_map/openxr_haptic_feedback.cpp
@@ -0,0 +1,92 @@
+/**************************************************************************/
+/* openxr_haptic_feedback.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+#include "openxr_haptic_feedback.h"
+
+////////////////////////////////////////////////////////////////////////////
+// OpenXRHapticBase
+
+void OpenXRHapticBase::_bind_methods() {
+}
+
+////////////////////////////////////////////////////////////////////////////
+// OpenXRHapticVibration
+
+void OpenXRHapticVibration::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_duration", "duration"), &OpenXRHapticVibration::set_duration);
+ ClassDB::bind_method(D_METHOD("get_duration"), &OpenXRHapticVibration::get_duration);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "duration"), "set_duration", "get_duration");
+
+ ClassDB::bind_method(D_METHOD("set_frequency", "frequency"), &OpenXRHapticVibration::set_frequency);
+ ClassDB::bind_method(D_METHOD("get_frequency"), &OpenXRHapticVibration::get_frequency);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency"), "set_frequency", "get_frequency");
+
+ ClassDB::bind_method(D_METHOD("set_amplitude", "amplitude"), &OpenXRHapticVibration::set_amplitude);
+ ClassDB::bind_method(D_METHOD("get_amplitude"), &OpenXRHapticVibration::get_amplitude);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_amplitude", "get_amplitude");
+}
+
+void OpenXRHapticVibration::set_duration(int64_t p_duration) {
+ haptic_vibration.duration = p_duration;
+ emit_changed();
+}
+
+int64_t OpenXRHapticVibration::get_duration() const {
+ return haptic_vibration.duration;
+}
+
+void OpenXRHapticVibration::set_frequency(float p_frequency) {
+ haptic_vibration.frequency = p_frequency;
+ emit_changed();
+}
+
+float OpenXRHapticVibration::get_frequency() const {
+ return haptic_vibration.frequency;
+}
+
+void OpenXRHapticVibration::set_amplitude(float p_amplitude) {
+ haptic_vibration.amplitude = p_amplitude;
+ emit_changed();
+}
+
+float OpenXRHapticVibration::get_amplitude() const {
+ return haptic_vibration.amplitude;
+}
+
+const XrHapticBaseHeader *OpenXRHapticVibration::get_xr_structure() {
+ return (XrHapticBaseHeader *)&haptic_vibration;
+}
+
+OpenXRHapticVibration::OpenXRHapticVibration() {
+ haptic_vibration.type = XR_TYPE_HAPTIC_VIBRATION;
+ haptic_vibration.next = nullptr;
+ haptic_vibration.duration = -1;
+ haptic_vibration.frequency = 0.0;
+ haptic_vibration.amplitude = 1.0;
+}
diff --git a/modules/openxr/action_map/openxr_haptic_feedback.h b/modules/openxr/action_map/openxr_haptic_feedback.h
new file mode 100644
index 000000000000..d16f1ab1694d
--- /dev/null
+++ b/modules/openxr/action_map/openxr_haptic_feedback.h
@@ -0,0 +1,72 @@
+/**************************************************************************/
+/* openxr_haptic_feedback.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_HAPTIC_FEEDBACK_H
+#define OPENXR_HAPTIC_FEEDBACK_H
+
+#include "core/io/resource.h"
+#include
+
+class OpenXRHapticBase : public Resource {
+ GDCLASS(OpenXRHapticBase, Resource);
+
+private:
+protected:
+ static void _bind_methods();
+
+public:
+ virtual const XrHapticBaseHeader *get_xr_structure() = 0;
+};
+
+class OpenXRHapticVibration : public OpenXRHapticBase {
+ GDCLASS(OpenXRHapticVibration, OpenXRHapticBase);
+
+private:
+ XrHapticVibration haptic_vibration;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_duration(int64_t p_duration);
+ int64_t get_duration() const;
+
+ void set_frequency(float p_frequency);
+ float get_frequency() const;
+
+ void set_amplitude(float p_amplitude);
+ float get_amplitude() const;
+
+ virtual const XrHapticBaseHeader *get_xr_structure() override;
+
+ OpenXRHapticVibration();
+};
+
+#endif // OPENXR_HAPTIC_FEEDBACK_H
diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp
index 907da5997230..cc9ba39d0f75 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile.cpp
@@ -39,6 +39,12 @@ void OpenXRIPBinding::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_binding_path"), &OpenXRIPBinding::get_binding_path);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "binding_path"), "set_binding_path", "get_binding_path");
+ ClassDB::bind_method(D_METHOD("get_binding_modifier_count"), &OpenXRIPBinding::get_binding_modifier_count);
+ ClassDB::bind_method(D_METHOD("get_binding_modifier", "index"), &OpenXRIPBinding::get_binding_modifier);
+ ClassDB::bind_method(D_METHOD("set_binding_modifiers", "binding_modifiers"), &OpenXRIPBinding::set_binding_modifiers);
+ ClassDB::bind_method(D_METHOD("get_binding_modifiers"), &OpenXRIPBinding::get_binding_modifiers);
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "binding_modifiers", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRBindingModifier", PROPERTY_USAGE_NO_EDITOR), "set_binding_modifiers", "get_binding_modifiers");
+
// Deprecated
ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
@@ -80,6 +86,76 @@ String OpenXRIPBinding::get_binding_path() const {
return binding_path;
}
+int OpenXRIPBinding::get_binding_modifier_count() const {
+ return binding_modifiers.size();
+}
+
+Ref OpenXRIPBinding::get_binding_modifier(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, binding_modifiers.size(), nullptr);
+
+ return binding_modifiers[p_index];
+}
+
+void OpenXRIPBinding::clear_binding_modifiers() {
+ // Binding modifiers held within our interaction profile set should be released and destroyed but just in case they are still used some where else
+ if (binding_modifiers.size() == 0) {
+ return;
+ }
+
+ for (int i = 0; i < binding_modifiers.size(); i++) {
+ Ref binding_modifier = binding_modifiers[i];
+ binding_modifier->ip_binding = nullptr;
+ }
+ binding_modifiers.clear();
+ emit_changed();
+}
+
+void OpenXRIPBinding::set_binding_modifiers(Array p_binding_modifiers) {
+ // Any binding modifier not retained in p_binding_modifiers should be freed automatically, those held within our Array will have be relinked to our interaction profile.
+ clear_binding_modifiers();
+
+ for (int i = 0; i < p_binding_modifiers.size(); i++) {
+ // add them anew so we verify our binding modifier pointer
+ add_binding_modifier(p_binding_modifiers[i]);
+ }
+}
+
+Array OpenXRIPBinding::get_binding_modifiers() const {
+ Array ret;
+ for (const Ref &binding_modifier : binding_modifiers) {
+ ret.push_back(binding_modifier);
+ }
+ return ret;
+}
+
+void OpenXRIPBinding::add_binding_modifier(Ref p_binding_modifier) {
+ ERR_FAIL_COND(p_binding_modifier.is_null());
+ ERR_FAIL_COND_MSG(!p_binding_modifier->record_on_binding(), "This binding modifier must be added to an interaction profile.");
+
+ if (!binding_modifiers.has(p_binding_modifier)) {
+ if (p_binding_modifier->ip_binding && p_binding_modifier->ip_binding != this) {
+ // binding modifier should only relate to our binding
+ p_binding_modifier->ip_binding->remove_binding_modifier(p_binding_modifier);
+ }
+
+ p_binding_modifier->ip_binding = this;
+ binding_modifiers.push_back(p_binding_modifier);
+ emit_changed();
+ }
+}
+
+void OpenXRIPBinding::remove_binding_modifier(Ref p_binding_modifier) {
+ int idx = binding_modifiers.find(p_binding_modifier);
+ if (idx != -1) {
+ binding_modifiers.remove_at(idx);
+
+ ERR_FAIL_COND_MSG(p_binding_modifier->ip_binding != this, "Removing binding modifier that belongs to this binding but had incorrect binding pointer."); // this should never happen!
+ p_binding_modifier->ip_binding = nullptr;
+
+ emit_changed();
+ }
+}
+
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) { // Deprecated, but needed for loading old action maps.
// Fallback logic, this should ONLY be called when loading older action maps.
// We'll parse this momentarily and extract individual bindings.
@@ -147,6 +223,12 @@ void OpenXRInteractionProfile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings);
ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings");
+
+ ClassDB::bind_method(D_METHOD("get_binding_modifier_count"), &OpenXRInteractionProfile::get_binding_modifier_count);
+ ClassDB::bind_method(D_METHOD("get_binding_modifier", "index"), &OpenXRInteractionProfile::get_binding_modifier);
+ ClassDB::bind_method(D_METHOD("set_binding_modifiers", "binding_modifiers"), &OpenXRInteractionProfile::set_binding_modifiers);
+ ClassDB::bind_method(D_METHOD("get_binding_modifiers"), &OpenXRInteractionProfile::get_binding_modifiers);
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "binding_modifiers", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRBindingModifier", PROPERTY_USAGE_NO_EDITOR), "set_binding_modifiers", "get_binding_modifiers");
}
Ref OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) {
@@ -274,6 +356,77 @@ bool OpenXRInteractionProfile::has_binding_for_action(const Ref p_
return false;
}
+int OpenXRInteractionProfile::get_binding_modifier_count() const {
+ return binding_modifiers.size();
+}
+
+Ref OpenXRInteractionProfile::get_binding_modifier(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, binding_modifiers.size(), nullptr);
+
+ return binding_modifiers[p_index];
+}
+
+void OpenXRInteractionProfile::clear_binding_modifiers() {
+ // Binding modifiers held within our interaction profile set should be released and destroyed but just in case they are still used some where else
+ if (binding_modifiers.size() == 0) {
+ return;
+ }
+
+ for (int i = 0; i < binding_modifiers.size(); i++) {
+ Ref binding_modifier = binding_modifiers[i];
+ binding_modifier->interaction_profile = nullptr;
+ }
+ binding_modifiers.clear();
+ emit_changed();
+}
+
+void OpenXRInteractionProfile::set_binding_modifiers(Array p_binding_modifiers) {
+ // Any binding modifier not retained in p_binding_modifiers should be freed automatically, those held within our Array will have be relinked to our interaction profile.
+ clear_binding_modifiers();
+
+ for (int i = 0; i < p_binding_modifiers.size(); i++) {
+ // add them anew so we verify our binding modifier pointer
+ add_binding_modifier(p_binding_modifiers[i]);
+ }
+}
+
+Array OpenXRInteractionProfile::get_binding_modifiers() const {
+ Array ret;
+ for (const Ref &binding_modifier : binding_modifiers) {
+ ret.push_back(binding_modifier);
+ }
+ return ret;
+}
+
+void OpenXRInteractionProfile::add_binding_modifier(Ref p_binding_modifier) {
+ ERR_FAIL_COND(p_binding_modifier.is_null());
+ ERR_FAIL_COND_MSG(p_binding_modifier->record_on_binding(), "This binding modifier must be added to a binding.");
+
+ if (!binding_modifiers.has(p_binding_modifier)) {
+ if (p_binding_modifier->interaction_profile && p_binding_modifier->interaction_profile != this) {
+ // binding modifier should only relate to our interaction profile
+ p_binding_modifier->interaction_profile->remove_binding_modifier(p_binding_modifier);
+ }
+
+ p_binding_modifier->interaction_profile = this;
+ binding_modifiers.push_back(p_binding_modifier);
+ emit_changed();
+ }
+}
+
+void OpenXRInteractionProfile::remove_binding_modifier(Ref p_binding_modifier) {
+ int idx = binding_modifiers.find(p_binding_modifier);
+ if (idx != -1) {
+ binding_modifiers.remove_at(idx);
+
+ ERR_FAIL_COND_MSG(p_binding_modifier->interaction_profile != this, "Removing binding modifier that belongs to this interaction profile but had incorrect interaction profile pointer."); // this should never happen!
+ p_binding_modifier->interaction_profile = nullptr;
+
+ emit_changed();
+ }
+}
+
OpenXRInteractionProfile::~OpenXRInteractionProfile() {
bindings.clear();
+ clear_binding_modifiers();
}
diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h
index d51e79fdf523..4b62dce24dfc 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.h
+++ b/modules/openxr/action_map/openxr_interaction_profile.h
@@ -32,29 +32,48 @@
#define OPENXR_INTERACTION_PROFILE_H
#include "openxr_action.h"
+#include "openxr_binding_modifier.h"
#include "openxr_interaction_profile_metadata.h"
#include "core/io/resource.h"
+class OpenXRActionMap;
+
class OpenXRIPBinding : public Resource {
GDCLASS(OpenXRIPBinding, Resource);
private:
Ref action;
String binding_path;
+ Vector[> binding_modifiers;
protected:
+ friend class OpenXRActionMap;
+
+ OpenXRActionMap *action_map = nullptr;
+
static void _bind_methods();
public:
static Ref new_binding(const Ref p_action, const String &p_binding_path); // Helper function for adding a new binding.
+ OpenXRActionMap *get_action_map() { return action_map; } // Return the action map we're a part of.
+
void set_action(const Ref p_action); // Set the action for this binding.
Ref get_action() const; // Get the action for this binding.
void set_binding_path(const String &path);
String get_binding_path() const;
+ int get_binding_modifier_count() const; // Retrieve the number of binding modifiers in this profile path
+ Ref get_binding_modifier(int p_index) const;
+ void clear_binding_modifiers(); // Remove all binding modifiers
+ void set_binding_modifiers(Array p_bindings); // Set the binding modifiers (for loading from a resource)
+ Array get_binding_modifiers() const; // Get the binding modifiers (for saving to a resource)
+
+ void add_binding_modifier(Ref p_binding_modifier); // Add a binding modifier object
+ void remove_binding_modifier(Ref p_binding_modifier); // Remove a binding modifier object
+
// Deprecated.
void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource), needed for loading old action maps.
PackedStringArray get_paths() const; // Get our paths (for saving to resource), needed for converted old action maps.
@@ -76,8 +95,13 @@ class OpenXRInteractionProfile : public Resource {
private:
String interaction_profile_path;
Array bindings;
+ Vector][> binding_modifiers;
protected:
+ friend class OpenXRActionMap;
+
+ OpenXRActionMap *action_map = nullptr;
+
static void _bind_methods();
public:
@@ -100,6 +124,15 @@ class OpenXRInteractionProfile : public Resource {
void remove_binding_for_action(const Ref p_action); // Remove all bindings for this action
bool has_binding_for_action(const Ref p_action); // Returns true if we have a binding for this action
+ int get_binding_modifier_count() const; // Retrieve the number of binding modifiers in this profile path
+ Ref get_binding_modifier(int p_index) const;
+ void clear_binding_modifiers(); // Remove all binding modifiers
+ void set_binding_modifiers(Array p_bindings); // Set the binding modifiers (for loading from a resource)
+ Array get_binding_modifiers() const; // Get the binding modifiers (for saving to a resource)
+
+ void add_binding_modifier(Ref p_binding_modifier); // Add a binding modifier object
+ void remove_binding_modifier(Ref p_binding_modifier); // Remove a binding modifier object
+
~OpenXRInteractionProfile();
};
diff --git a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp
index 6315c95a03d7..8cddaee666a1 100644
--- a/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile_metadata.cpp
@@ -225,179 +225,164 @@ void OpenXRInteractionProfileMetadata::_register_core_metadata() {
register_top_level_path("Gamepad", "/user/gamepad", "");
register_top_level_path("Treadmill", "/user/treadmill", "");
- // Fallback Khronos simple controller
- register_interaction_profile("Simple controller", "/interaction_profiles/khr/simple_controller", "");
- register_io_path("/interaction_profiles/khr/simple_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/khr/simple_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/khr/simple_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/khr/simple_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/khr/simple_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/khr/simple_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- register_io_path("/interaction_profiles/khr/simple_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/khr/simple_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/khr/simple_controller", "Select click", "/user/hand/left", "/user/hand/left/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/khr/simple_controller", "Select click", "/user/hand/right", "/user/hand/right/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/khr/simple_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- register_io_path("/interaction_profiles/khr/simple_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Original HTC Vive wands
- register_interaction_profile("HTC Vive wand", "/interaction_profiles/htc/vive_controller", "");
- register_io_path("/interaction_profiles/htc/vive_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/htc/vive_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/htc/vive_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/htc/vive_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/htc/vive_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/htc/vive_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- register_io_path("/interaction_profiles/htc/vive_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/htc/vive_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/htc/vive_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/htc/vive_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/htc/vive_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- register_io_path("/interaction_profiles/htc/vive_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Microsoft motion controller (original WMR controllers)
- register_interaction_profile("MS Motion controller", "/interaction_profiles/microsoft/motion_controller", "");
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- register_io_path("/interaction_profiles/microsoft/motion_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
- register_interaction_profile("Touch controller", "/interaction_profiles/oculus/touch_controller", "");
- register_io_path("/interaction_profiles/oculus/touch_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- register_io_path("/interaction_profiles/oculus/touch_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Valve Index controller
- register_interaction_profile("Index controller", "/interaction_profiles/valve/index_controller", "");
- register_io_path("/interaction_profiles/valve/index_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/valve/index_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/valve/index_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/valve/index_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/valve/index_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- register_io_path("/interaction_profiles/valve/index_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- register_io_path("/interaction_profiles/valve/index_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/valve/index_controller", "A click", "/user/hand/left", "/user/hand/left/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "A touch", "/user/hand/left", "/user/hand/left/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "B click", "/user/hand/left", "/user/hand/left/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "B touch", "/user/hand/left", "/user/hand/left/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/valve/index_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Squeeze force", "/user/hand/left", "/user/hand/left/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Squeeze force", "/user/hand/right", "/user/hand/right/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/valve/index_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/valve/index_controller", "Trackpad force", "/user/hand/left", "/user/hand/left/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- register_io_path("/interaction_profiles/valve/index_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- register_io_path("/interaction_profiles/valve/index_controller", "Trackpad force", "/user/hand/right", "/user/hand/right/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- register_io_path("/interaction_profiles/valve/index_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- register_io_path("/interaction_profiles/valve/index_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ { // Fallback Khronos simple controller
+ const String profile_path = "/interaction_profiles/khr/simple_controller";
+ register_interaction_profile("Simple controller", profile_path, "");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Select click", user_path, user_path + "/input/select/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
+
+ { // Original HTC Vive wands
+ const String profile_path = "/interaction_profiles/htc/vive_controller";
+ register_interaction_profile("HTC Vive wand", profile_path, "");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
+
+ { // Microsoft motion controller (original WMR controllers)
+ const String profile_path = "/interaction_profiles/microsoft/motion_controller";
+ register_interaction_profile("MS Motion controller", profile_path, "");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
+
+ { // Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
+ const String profile_path = "/interaction_profiles/oculus/touch_controller";
+ register_interaction_profile("Touch controller", profile_path, "");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+
+ { // Valve Index controller
+ const String profile_path = "/interaction_profiles/valve/index_controller";
+ register_interaction_profile("Index controller", profile_path, "");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "A click", user_path, user_path + "/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "A touch", user_path, user_path + "/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "B click", user_path, user_path + "/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "B touch", user_path, user_path + "/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path(profile_path, "Squeeze force", user_path, user_path + "/input/squeeze/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ register_io_path(profile_path, "Trackpad force", user_path, user_path + "/input/trackpad/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
}
diff --git a/modules/openxr/config.py b/modules/openxr/config.py
index 559aa2acf69c..2f02229955eb 100644
--- a/modules/openxr/config.py
+++ b/modules/openxr/config.py
@@ -27,6 +27,16 @@ def get_doc_classes():
"OpenXRCompositionLayerQuad",
"OpenXRCompositionLayerCylinder",
"OpenXRCompositionLayerEquirect",
+ "OpenXRBindingModifier",
+ "OpenXRAnalogThresholdModifier",
+ "OpenXRDpadBindingModifier",
+ "OpenXRInteractionProfileEditorBase",
+ "OpenXRInteractionProfileEditor",
+ "OpenXRBindingModifierEditor",
+ "OpenXRAnalogThresholdEditor",
+ "OpenXRDpadBindingEditor",
+ "OpenXRHapticBase",
+ "OpenXRHapticVibration",
]
diff --git a/modules/openxr/doc_classes/OpenXRAnalogThresholdEditor.xml b/modules/openxr/doc_classes/OpenXRAnalogThresholdEditor.xml
new file mode 100644
index 000000000000..3ab58b8ad365
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRAnalogThresholdEditor.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml b/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml
new file mode 100644
index 000000000000..bd0df01cf501
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRAnalogThresholdModifier.xml
@@ -0,0 +1,20 @@
+
+
+
+ The analog threshold binding modifier can modify a float input to a boolean input with specified thresholds.
+
+
+ The analog threshold binding modifier can modify a float input to a boolean input with specified thresholds.
+ See [url=https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_VALVE_analog_threshold]XR_VALVE_analog_threshold[/url] for indepth details.
+
+
+
+
+
+ When our input value falls below this, our output becomes false.
+
+
+ When our input value is equal or larger than this value, our output becomes true. It stays true until it falls under the [member off_threshold] value.
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRBindingModifier.xml b/modules/openxr/doc_classes/OpenXRBindingModifier.xml
new file mode 100644
index 000000000000..12af05ed9d74
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRBindingModifier.xml
@@ -0,0 +1,11 @@
+
+
+
+ Binding modifier base class.
+
+
+ Binding modifier base class. Subclasses implement various modifiers that alter how an OpenXR runtime processes inputs.
+
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml b/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml
new file mode 100644
index 000000000000..813c9cc6c2bb
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRBindingModifierEditor.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRDpadBindingEditor.xml b/modules/openxr/doc_classes/OpenXRDpadBindingEditor.xml
new file mode 100644
index 000000000000..4e0b826e1b61
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRDpadBindingEditor.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml b/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml
new file mode 100644
index 000000000000..1b54ef171087
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRDpadBindingModifier.xml
@@ -0,0 +1,35 @@
+
+
+
+ The DPad binding modifier converts an axis input to a dpad output.
+
+
+ The DPad binding modifier converts an axis input to a dpad output. New input paths for each dpad direction will be added to the interaction profile.
+ See [url=https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_dpad_binding]XR_EXT_dpad_binding[/url] for indepth details.
+
+
+
+
+
+ Action set for which this dpad binding modifier is active.
+
+
+ Center region in which our center position of our dpad return [code]true[/code].
+
+
+ Input path for this dpad binding modifier.
+
+
+ If [code]false[/code], when the joystick enters a new dpad zone this becomes true.
+ If [code]true[/code], when the joystick remains in active dpad zone, this remains true even if we overlap with another zone.
+
+
+ When our input value is equal or larger than this value, our dpad in that direction becomes true. It stays true until it falls under the [member threshold_released] value.
+
+
+ When our input value falls below this, our output becomes false.
+
+
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml
index c5d894811362..a4ce0234deb9 100644
--- a/modules/openxr/doc_classes/OpenXRIPBinding.xml
+++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml
@@ -16,6 +16,19 @@
Add an input/output path to this binding.
+
+
+
+
+ Get the [OpenXRBindingModifier] at this index.
+
+
+
+
+
+ Get the number of binding modifiers for this binding.
+
+
@@ -41,6 +54,9 @@
[OpenXRAction] that is bound to [member binding_path].
+
+ Binding modifiers for this binding.
+
Binding path that defines the input or output bound to [member action].
[b]Node:[/b] binding paths are suggestions, an XR runtime may choose to bind the action to a different input or output emulating this input or output.
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
index ed5113f83c9d..f6fddd0b69e7 100644
--- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
@@ -23,8 +23,24 @@
Get the number of bindings in this interaction profile.
+
+
+
+
+ Get the [OpenXRBindingModifier] at this index.
+
+
+
+
+
+ Get the number of binding modifiers in this interaction profile.
+
+
+
+ Binding modifiers for this interaction profile.
+
Action bindings for this interaction profile.
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml b/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml
new file mode 100644
index 000000000000..05c431000231
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfileEditor.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml b/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml
new file mode 100644
index 000000000000..430380a679a4
--- /dev/null
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfileEditorBase.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index a353073f215b..3688c3734992 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -37,7 +37,8 @@
#include "editor/gui/editor_file_dialog.h"
#include "editor/themes/editor_scale.h"
-// TODO implement redo/undo system
+HashMap OpenXRActionMapEditor::interaction_profile_editors;
+HashMap OpenXRActionMapEditor::binding_modifier_editors;
void OpenXRActionMapEditor::_bind_methods() {
ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor);
@@ -50,6 +51,9 @@ void OpenXRActionMapEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_do_remove_action_set_editor", "action_set_editor"), &OpenXRActionMapEditor::_do_remove_action_set_editor);
ClassDB::bind_method(D_METHOD("_do_add_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_add_interaction_profile_editor);
ClassDB::bind_method(D_METHOD("_do_remove_interaction_profile_editor", "interaction_profile_editor"), &OpenXRActionMapEditor::_do_remove_interaction_profile_editor);
+
+ ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_interaction_profile_editor", "interaction_profile_path", "editor_class"), &OpenXRActionMapEditor::register_interaction_profile_editor);
+ ClassDB::bind_static_method("OpenXRActionMapEditor", D_METHOD("register_binding_modifier_editor", "binding_modifier_class", "editor_class"), &OpenXRActionMapEditor::register_binding_modifier_editor);
}
void OpenXRActionMapEditor::_notification(int p_what) {
@@ -100,9 +104,17 @@ OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_prof
// need to instance the correct editor for our profile
OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr;
- if (profile_path == "placeholder_text") {
- // instance specific editor for this type
- } else {
+ if (interaction_profile_editors.has(profile_path)) {
+ Object *new_editor = ClassDB::instantiate(interaction_profile_editors[profile_path]);
+ if (new_editor) {
+ new_profile_editor = Object::cast_to(new_editor);
+ if (!new_profile_editor) {
+ WARN_PRINT("Interaction profile editor type mismatch for " + profile_path);
+ memfree(new_editor);
+ }
+ }
+ }
+ if (!new_profile_editor) {
// instance generic editor
new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile));
}
@@ -195,8 +207,19 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
Ref action_set = action_set_editor->get_action_set();
ERR_FAIL_COND(action_set.is_null());
+ // Remove all actions first.
action_set_editor->remove_all_actions();
+ // Make sure we update our interaction profiles.
+ for (int i = 0; i < tabs->get_tab_count(); i++) {
+ // First tab won't be an interaction profile editor, but being thorough..
+ OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to(tabs->get_tab_control(i));
+ if (interaction_profile_editor) {
+ interaction_profile_editor->remove_all_for_action_set(action_set);
+ }
+ }
+
+ // And now we can remove our action set.
undo_redo->create_action(TTR("Remove action set"));
undo_redo->add_do_method(this, "_do_remove_action_set_editor", action_set_editor);
undo_redo->add_undo_method(this, "_do_add_action_set_editor", action_set_editor);
@@ -210,7 +233,7 @@ void OpenXRActionMapEditor::_on_action_removed(Ref p_action) {
// First tab won't be an interaction profile editor, but being thorough..
OpenXRInteractionProfileEditorBase *interaction_profile_editor = Object::cast_to(tabs->get_tab_control(i));
if (interaction_profile_editor) {
- interaction_profile_editor->remove_all_bindings_for_action(p_action);
+ interaction_profile_editor->remove_all_for_action(p_action);
}
}
}
@@ -387,6 +410,22 @@ void OpenXRActionMapEditor::_clear_action_map() {
}
}
+void OpenXRActionMapEditor::register_interaction_profile_editor(const String &p_for_path, const String &p_editor_class) {
+ interaction_profile_editors[p_for_path] = p_editor_class;
+}
+
+void OpenXRActionMapEditor::register_binding_modifier_editor(const String &p_binding_modifier_class, const String &p_editor_class) {
+ binding_modifier_editors[p_binding_modifier_class] = p_editor_class;
+}
+
+String OpenXRActionMapEditor::get_binding_modifier_editor_class(const String &p_binding_modifier_class) {
+ if (binding_modifier_editors.has(p_binding_modifier_class)) {
+ return binding_modifier_editors[p_binding_modifier_class];
+ }
+
+ return "";
+}
+
OpenXRActionMapEditor::OpenXRActionMapEditor() {
undo_redo = EditorUndoRedoManager::get_singleton();
set_custom_minimum_size(Size2(0.0, 300.0));
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
index cfe5fed0955e..088bf0c613d0 100644
--- a/modules/openxr/editor/openxr_action_map_editor.h
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -36,6 +36,7 @@
#include "openxr_interaction_profile_editor.h"
#include "openxr_select_interaction_profile_dialog.h"
+#include "core/templates/hash_map.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/gui/box_container.h"
@@ -48,6 +49,9 @@ class OpenXRActionMapEditor : public VBoxContainer {
GDCLASS(OpenXRActionMapEditor, VBoxContainer);
private:
+ static HashMap interaction_profile_editors; // interaction profile path, interaction profile editor
+ static HashMap binding_modifier_editors; // binding modifier class, binding modifiers editor
+
EditorUndoRedoManager *undo_redo;
String edited_path;
Ref action_map;
@@ -100,6 +104,10 @@ class OpenXRActionMapEditor : public VBoxContainer {
void _do_remove_interaction_profile_editor(OpenXRInteractionProfileEditorBase *p_interaction_profile_editor);
public:
+ static void register_interaction_profile_editor(const String &p_for_path, const String &p_editor_class);
+ static void register_binding_modifier_editor(const String &p_binding_modifier_class, const String &p_editor_class);
+ static String get_binding_modifier_editor_class(const String &p_binding_modifier_class);
+
void open_action_map(String p_path);
OpenXRActionMapEditor();
diff --git a/modules/openxr/editor/openxr_binding_modifier_editor.cpp b/modules/openxr/editor/openxr_binding_modifier_editor.cpp
new file mode 100644
index 000000000000..27aad7e09c59
--- /dev/null
+++ b/modules/openxr/editor/openxr_binding_modifier_editor.cpp
@@ -0,0 +1,236 @@
+/**************************************************************************/
+/* openxr_binding_modifier_editor.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_binding_modifier_editor.h"
+
+#include "editor/editor_string_names.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// EditorPropertyActionSet
+
+void EditorPropertyActionSet::_set_read_only(bool p_read_only) {
+ options->set_disabled(p_read_only);
+}
+
+void EditorPropertyActionSet::_option_selected(int p_which) {
+ Ref val = options->get_item_metadata(p_which);
+ emit_changed(get_edited_property(), val);
+}
+
+void EditorPropertyActionSet::update_property() {
+ Variant current = get_edited_property_value();
+ if (current.get_type() == Variant::NIL) {
+ options->select(-1);
+ return;
+ }
+
+ Ref which = current;
+ for (int i = 0; i < options->get_item_count(); i++) {
+ if (which == (Ref)options->get_item_metadata(i)) {
+ options->select(i);
+ return;
+ }
+ }
+
+ // Couldn't find it? deselect..
+ options->select(-1);
+}
+
+void EditorPropertyActionSet::setup(const Ref &p_action_map) {
+ options->clear();
+
+ Array action_sets = p_action_map->get_action_sets();
+ for (Ref action_set : action_sets) {
+ options->add_item(action_set->get_localized_name());
+ options->set_item_metadata(-1, action_set);
+ }
+}
+
+void EditorPropertyActionSet::set_option_button_clip(bool p_enable) {
+ options->set_clip_text(p_enable);
+}
+
+EditorPropertyActionSet::EditorPropertyActionSet() {
+ options = memnew(OptionButton);
+ options->set_clip_text(true);
+ options->set_flat(true);
+ options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ add_child(options);
+ add_focusable(options);
+ options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyActionSet::_option_selected));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// EditorPropertyBindingPath
+
+void EditorPropertyBindingPath::_set_read_only(bool p_read_only) {
+ options->set_disabled(p_read_only);
+}
+
+void EditorPropertyBindingPath::_option_selected(int p_which) {
+ String val = options->get_item_metadata(p_which);
+ emit_changed(get_edited_property(), val);
+}
+
+void EditorPropertyBindingPath::update_property() {
+ Variant current = get_edited_property_value();
+ if (current.get_type() == Variant::NIL) {
+ options->select(-1);
+ return;
+ }
+
+ String which = current;
+ for (int i = 0; i < options->get_item_count(); i++) {
+ if (which == (String)options->get_item_metadata(i)) {
+ options->select(i);
+ return;
+ }
+ }
+
+ // Couldn't find it? deselect..
+ options->select(-1);
+}
+
+void EditorPropertyBindingPath::setup(const String &p_interaction_profile_path, Vector p_include_action_types) {
+ options->clear();
+
+ const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(p_interaction_profile_path);
+
+ // Determine toplevel paths
+ Vector top_level_paths;
+ for (const OpenXRInteractionProfileMetadata::IOPath &io_path : profile_def->io_paths) {
+ if (!top_level_paths.has(io_path.top_level_path)) {
+ top_level_paths.push_back(io_path.top_level_path);
+ }
+ }
+
+ for (const String &top_level_path : top_level_paths) {
+ String top_level_name = OpenXRInteractionProfileMetadata::get_singleton()->get_top_level_name(top_level_path);
+
+ for (const OpenXRInteractionProfileMetadata::IOPath &io_path : profile_def->io_paths) {
+ if (io_path.top_level_path == top_level_path && p_include_action_types.has(io_path.action_type)) {
+ options->add_item(top_level_name + "/" + io_path.display_name);
+ options->set_item_metadata(-1, io_path.openxr_path);
+ }
+ }
+ }
+}
+
+void EditorPropertyBindingPath::set_option_button_clip(bool p_enable) {
+ options->set_clip_text(p_enable);
+}
+
+EditorPropertyBindingPath::EditorPropertyBindingPath() {
+ options = memnew(OptionButton);
+ options->set_clip_text(true);
+ options->set_flat(true);
+ options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ add_child(options);
+ add_focusable(options);
+ options->connect(SceneStringName(item_selected), callable_mp(this, &EditorPropertyBindingPath::_option_selected));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRBindingModifierEditor
+
+void OpenXRBindingModifierEditor::_bind_methods() {
+ ClassDB::bind_method("_on_remove_binding_modifier", &OpenXRBindingModifierEditor::_on_remove_binding_modifier);
+
+ ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "binding_modifier_editor")));
+}
+
+void OpenXRBindingModifierEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ rem_binding_modifier_btn->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
+ } break;
+ }
+}
+
+void OpenXRBindingModifierEditor::_on_remove_binding_modifier() {
+ // Tell parent to remove us
+ emit_signal("remove", this);
+}
+
+void OpenXRBindingModifierEditor::add_property_editor(const String &p_property, EditorProperty *p_editor) {
+ p_editor->set_label(p_property.capitalize());
+ p_editor->connect("property_changed", callable_mp(this, &OpenXRBindingModifierEditor::_on_property_changed));
+ main_vb->add_child(p_editor);
+ property_editors[StringName(p_property)] = p_editor;
+}
+
+void OpenXRBindingModifierEditor::_on_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) {
+ ERR_FAIL_NULL(undo_redo);
+ ERR_FAIL_COND(binding_modifier.is_null());
+
+ undo_redo->create_action(vformat(TTR("Modify '%s' for binding modifier '%s'"), p_property, binding_modifier->get_description()));
+ undo_redo->add_do_property(binding_modifier.ptr(), p_property, p_value);
+ undo_redo->add_do_method(property_editors[p_property], "update_property");
+ undo_redo->add_undo_property(binding_modifier.ptr(), p_property, binding_modifier->get(p_property));
+ undo_redo->add_undo_method(property_editors[p_property], "update_property");
+ undo_redo->commit_action();
+}
+
+OpenXRBindingModifierEditor::OpenXRBindingModifierEditor() {
+ undo_redo = EditorUndoRedoManager::get_singleton();
+
+ set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ main_vb = memnew(VBoxContainer);
+ main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ add_child(main_vb);
+
+ header_hb = memnew(HBoxContainer);
+ header_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vb->add_child(header_hb);
+
+ binding_modifier_title = memnew(Label);
+ binding_modifier_title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ header_hb->add_child(binding_modifier_title);
+
+ rem_binding_modifier_btn = memnew(Button);
+ rem_binding_modifier_btn->set_tooltip_text(TTR("Remove binding modifier."));
+ rem_binding_modifier_btn->connect(SceneStringName(pressed), callable_mp(this, &OpenXRBindingModifierEditor::_on_remove_binding_modifier));
+ rem_binding_modifier_btn->set_flat(true);
+ header_hb->add_child(rem_binding_modifier_btn);
+}
+
+void OpenXRBindingModifierEditor::set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) {
+ action_map = p_action_map;
+ binding_modifier = p_binding_modifier;
+
+ binding_modifier_title->set_text(p_binding_modifier->get_description());
+
+ for (const KeyValue &editor : property_editors) {
+ editor.value->set_object_and_property(binding_modifier.ptr(), editor.key);
+ editor.value->update_property();
+ }
+}
diff --git a/modules/openxr/editor/openxr_binding_modifier_editor.h b/modules/openxr/editor/openxr_binding_modifier_editor.h
new file mode 100644
index 000000000000..5f040befd09d
--- /dev/null
+++ b/modules/openxr/editor/openxr_binding_modifier_editor.h
@@ -0,0 +1,110 @@
+/**************************************************************************/
+/* openxr_binding_modifier_editor.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_BINDING_MODIFIER_EDITOR_H
+#define OPENXR_BINDING_MODIFIER_EDITOR_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../action_map/openxr_action_set.h"
+#include "../action_map/openxr_binding_modifier.h"
+#include "editor/editor_inspector.h"
+#include "editor/editor_properties.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/panel_container.h"
+
+class EditorPropertyActionSet : public EditorProperty {
+ GDCLASS(EditorPropertyActionSet, EditorProperty);
+ OptionButton *options = nullptr;
+
+ void _option_selected(int p_which);
+
+protected:
+ virtual void _set_read_only(bool p_read_only) override;
+
+public:
+ void setup(const Ref &p_action_map);
+ virtual void update_property() override;
+ void set_option_button_clip(bool p_enable);
+ EditorPropertyActionSet();
+};
+
+class EditorPropertyBindingPath : public EditorProperty {
+ GDCLASS(EditorPropertyBindingPath, EditorProperty);
+ OptionButton *options = nullptr;
+
+ void _option_selected(int p_which);
+
+protected:
+ virtual void _set_read_only(bool p_read_only) override;
+
+public:
+ void setup(const String &p_interaction_profile_path, Vector p_include_action_types);
+ virtual void update_property() override;
+ void set_option_button_clip(bool p_enable);
+ EditorPropertyBindingPath();
+};
+
+class OpenXRBindingModifierEditor : public PanelContainer {
+ GDCLASS(OpenXRBindingModifierEditor, PanelContainer);
+
+private:
+ HBoxContainer *header_hb = nullptr;
+ Label *binding_modifier_title = nullptr;
+ Button *rem_binding_modifier_btn = nullptr;
+
+protected:
+ VBoxContainer *main_vb = nullptr;
+ HashMap property_editors;
+
+ EditorUndoRedoManager *undo_redo;
+ Ref binding_modifier;
+ Ref action_map;
+
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ void add_property_editor(const String &p_property, EditorProperty *p_editor);
+
+ void _on_remove_binding_modifier();
+
+public:
+ Ref get_binding_modifier() const { return binding_modifier; }
+
+ void _on_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing);
+
+ virtual void set_binding_modifier(Ref p_action_map, Ref p_binding_modifier);
+
+ OpenXRBindingModifierEditor();
+};
+
+#endif // OPENXR_BINDING_MODIFIER_EDITOR_H
diff --git a/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp b/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp
new file mode 100644
index 000000000000..7ccbf50bc607
--- /dev/null
+++ b/modules/openxr/editor/openxr_binding_modifiers_dialog.cpp
@@ -0,0 +1,266 @@
+/**************************************************************************/
+/* openxr_binding_modifiers_dialog.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_binding_modifiers_dialog.h"
+#include "../action_map/openxr_interaction_profile_metadata.h"
+#include "editor/editor_string_names.h"
+#include "openxr_action_map_editor.h"
+
+void OpenXRBindingModifiersDialog::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_on_add_binding_modifier"), &OpenXRBindingModifiersDialog::_on_add_binding_modifier);
+ ClassDB::bind_method(D_METHOD("_on_dialog_created"), &OpenXRBindingModifiersDialog::_on_dialog_created);
+
+ ClassDB::bind_method(D_METHOD("_do_add_binding_modifier_editor", "binding_modifier_editor"), &OpenXRBindingModifiersDialog::_do_add_binding_modifier_editor);
+ ClassDB::bind_method(D_METHOD("_do_remove_binding_modifier_editor", "binding_modifier_editor"), &OpenXRBindingModifiersDialog::_do_remove_binding_modifier_editor);
+}
+
+void OpenXRBindingModifiersDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_READY: {
+ _create_binding_modifiers();
+ } break;
+
+ case NOTIFICATION_THEME_CHANGED: {
+ if (binding_modifier_sc) {
+ binding_modifier_sc->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
+ }
+ } break;
+ }
+}
+
+OpenXRBindingModifierEditor *OpenXRBindingModifiersDialog::_add_binding_modifier_editor(Ref p_binding_modifier) {
+ ERR_FAIL_COND_V(p_binding_modifier.is_null(), nullptr);
+
+ String class_name = p_binding_modifier->get_class();
+ ERR_FAIL_COND_V(class_name.is_empty(), nullptr);
+ String editor_class = OpenXRActionMapEditor::get_binding_modifier_editor_class(class_name);
+ ERR_FAIL_COND_V(editor_class.is_empty(), nullptr);
+
+ OpenXRBindingModifierEditor *new_editor = nullptr;
+
+ Object *obj = ClassDB::instantiate(editor_class);
+ if (obj) {
+ new_editor = Object::cast_to(obj);
+ if (!new_editor) {
+ // Not of correct type?? Free it.
+ memfree(obj);
+ }
+ }
+ ERR_FAIL_NULL_V(new_editor, nullptr);
+
+ new_editor->set_binding_modifier(action_map, p_binding_modifier);
+ new_editor->connect("remove", callable_mp(this, &OpenXRBindingModifiersDialog::_on_remove_binding_modifier));
+
+ binding_modifiers_vb->add_child(new_editor);
+ new_editor->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
+
+ return new_editor;
+}
+
+void OpenXRBindingModifiersDialog::_create_binding_modifiers() {
+ Array new_binding_modifiers;
+
+ if (ip_binding.is_valid()) {
+ new_binding_modifiers = ip_binding->get_binding_modifiers();
+ } else if (interaction_profile.is_valid()) {
+ new_binding_modifiers = interaction_profile->get_binding_modifiers();
+ } else {
+ ERR_FAIL_MSG("No binding nor interaction profile specified.");
+ }
+
+ for (int i = 0; i < new_binding_modifiers.size(); i++) {
+ Ref binding_modifier = new_binding_modifiers[i];
+ _add_binding_modifier_editor(binding_modifier);
+ }
+}
+
+void OpenXRBindingModifiersDialog::_on_add_binding_modifier() {
+ create_dialog->popup_create(false);
+}
+
+void OpenXRBindingModifiersDialog::_on_remove_binding_modifier(Object *p_binding_modifier_editor) {
+ if (ip_binding.is_valid()) {
+ ip_binding->set_edited(true);
+ } else if (interaction_profile.is_valid()) {
+ interaction_profile->set_edited(true);
+ } else {
+ ERR_FAIL_MSG("No binding nor interaction profile specified.");
+ }
+
+ OpenXRBindingModifierEditor *binding_modifier_editor = Object::cast_to(p_binding_modifier_editor);
+ ERR_FAIL_NULL(binding_modifier_editor);
+ ERR_FAIL_COND(binding_modifier_editor->get_parent() != binding_modifiers_vb);
+
+ undo_redo->create_action(TTR("Remove binding modifier"));
+ undo_redo->add_do_method(this, "_do_remove_binding_modifier_editor", binding_modifier_editor);
+ undo_redo->add_undo_method(this, "_do_add_binding_modifier_editor", binding_modifier_editor);
+ undo_redo->commit_action(true);
+}
+
+void OpenXRBindingModifiersDialog::_on_dialog_created() {
+ // Instance new binding modifier object
+ Variant obj = create_dialog->instantiate_selected();
+ ERR_FAIL_COND(obj.get_type() != Variant::OBJECT);
+
+ Ref new_binding_modifier = obj;
+ ERR_FAIL_COND(new_binding_modifier.is_null());
+
+ if (ip_binding.is_valid()) {
+ // TODO these should be filtered out, and if we can't make this a nicer error...
+ ERR_FAIL_COND(!new_binding_modifier->record_on_binding());
+
+ // Add it to our binding.
+ ip_binding->add_binding_modifier(new_binding_modifier);
+ ip_binding->set_edited(true);
+ } else if (interaction_profile.is_valid()) {
+ // TODO these should be filtered out, and if we can't make this a nicer error...
+ ERR_FAIL_COND(new_binding_modifier->record_on_binding());
+
+ // Add it to our interaction profile.
+ interaction_profile->add_binding_modifier(new_binding_modifier);
+ interaction_profile->set_edited(true);
+ } else {
+ ERR_FAIL_MSG("No binding nor interaction profile specified.");
+ }
+
+ // Create our editor for this.
+ OpenXRBindingModifierEditor *binding_modifier_editor = _add_binding_modifier_editor(new_binding_modifier);
+ ERR_FAIL_NULL(binding_modifier_editor);
+
+ // Add undo/redo.
+ undo_redo->create_action(TTR("Add binding modifier"));
+ undo_redo->add_do_method(this, "_do_add_binding_modifier_editor", binding_modifier_editor);
+ undo_redo->add_undo_method(this, "_do_remove_binding_modifier_editor", binding_modifier_editor);
+ undo_redo->commit_action(false);
+}
+
+void OpenXRBindingModifiersDialog::_do_add_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor) {
+ Ref binding_modifier = p_binding_modifier_editor->get_binding_modifier();
+ ERR_FAIL_COND(binding_modifier.is_null());
+
+ if (ip_binding.is_valid()) {
+ // Add it to our binding
+ ip_binding->add_binding_modifier(binding_modifier);
+ } else if (interaction_profile.is_valid()) {
+ // Add it to our interaction profile
+ interaction_profile->add_binding_modifier(binding_modifier);
+ } else {
+ ERR_FAIL_MSG("No binding nor interaction profile specified.");
+ }
+
+ binding_modifiers_vb->add_child(p_binding_modifier_editor);
+}
+
+void OpenXRBindingModifiersDialog::_do_remove_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor) {
+ Ref binding_modifier = p_binding_modifier_editor->get_binding_modifier();
+ ERR_FAIL_COND(binding_modifier.is_null());
+
+ if (ip_binding.is_valid()) {
+ // Remove it from our binding.
+ ip_binding->remove_binding_modifier(binding_modifier);
+ } else if (interaction_profile.is_valid()) {
+ // Removed it to from interaction profile.
+ interaction_profile->remove_binding_modifier(binding_modifier);
+ } else {
+ ERR_FAIL_MSG("No binding nor interaction profile specified.");
+ }
+
+ binding_modifiers_vb->remove_child(p_binding_modifier_editor);
+}
+
+OpenXRBindingModifiersDialog::OpenXRBindingModifiersDialog() {
+ undo_redo = EditorUndoRedoManager::get_singleton();
+
+ set_transient(true);
+
+ binding_modifier_sc = memnew(ScrollContainer);
+ binding_modifier_sc->set_custom_minimum_size(Size2(350.0, 0.0));
+ binding_modifier_sc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ binding_modifier_sc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ binding_modifier_sc->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
+ add_child(binding_modifier_sc);
+
+ binding_modifiers_vb = memnew(VBoxContainer);
+ binding_modifiers_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ binding_modifier_sc->add_child(binding_modifiers_vb);
+
+ binding_warning_label = memnew(Label);
+ binding_warning_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
+ binding_warning_label->set_text(TTR("Note: modifiers will only be applied if supported on the host system."));
+ binding_modifiers_vb->add_child(binding_warning_label);
+
+ add_binding_modifier_btn = memnew(Button);
+ add_binding_modifier_btn->set_text(TTR("Add binding modifier"));
+ add_binding_modifier_btn->connect("pressed", callable_mp(this, &OpenXRBindingModifiersDialog::_on_add_binding_modifier));
+ binding_modifiers_vb->add_child(add_binding_modifier_btn);
+
+ // TODO may need to create our own dialog for this that can filter on binding modifiers recorded on interaction profiles or on individual bindings.
+
+ create_dialog = memnew(CreateDialog);
+ create_dialog->set_transient(true);
+ create_dialog->set_base_type("OpenXRBindingModifier");
+ create_dialog->connect("create", callable_mp(this, &OpenXRBindingModifiersDialog::_on_dialog_created));
+ add_child(create_dialog);
+}
+
+void OpenXRBindingModifiersDialog::setup(Ref p_action_map, Ref p_interaction_profile, Ref p_ip_binding) {
+ OpenXRInteractionProfileMetadata *meta_data = OpenXRInteractionProfileMetadata::get_singleton();
+ action_map = p_action_map;
+ interaction_profile = p_interaction_profile;
+ ip_binding = p_ip_binding;
+
+ String profile_path = interaction_profile->get_interaction_profile_path();
+
+ if (ip_binding.is_valid()) {
+ String action_name = "unset";
+ String path_name = "unset";
+
+ Ref action = p_ip_binding->get_action();
+ if (action.is_valid()) {
+ action_name = action->get_name_with_set();
+ }
+
+ const OpenXRInteractionProfileMetadata::IOPath *io_path = meta_data->get_io_path(profile_path, p_ip_binding->get_binding_path());
+ if (io_path != nullptr) {
+ path_name = io_path->display_name;
+ }
+
+ set_title(TTR("Binding modifiers for:") + " " + action_name + ": " + path_name);
+ } else if (interaction_profile.is_valid()) {
+ String profile_name = profile_path;
+
+ const OpenXRInteractionProfileMetadata::InteractionProfile *profile_def = meta_data->get_profile(profile_path);
+ if (profile_def != nullptr) {
+ profile_name = profile_def->display_name;
+ }
+
+ set_title(TTR("Binding modifiers for:") + " " + profile_name);
+ }
+}
diff --git a/modules/openxr/editor/openxr_binding_modifiers_dialog.h b/modules/openxr/editor/openxr_binding_modifiers_dialog.h
new file mode 100644
index 000000000000..c60a3760b38e
--- /dev/null
+++ b/modules/openxr/editor/openxr_binding_modifiers_dialog.h
@@ -0,0 +1,81 @@
+/**************************************************************************/
+/* openxr_binding_modifiers_dialog.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_BINDING_MODIFIERS_DIALOG_H
+#define OPENXR_BINDING_MODIFIERS_DIALOG_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../action_map/openxr_interaction_profile.h"
+#include "../editor/openxr_binding_modifier_editor.h"
+#include "editor/create_dialog.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/label.h"
+#include "scene/gui/scroll_container.h"
+
+class OpenXRBindingModifiersDialog : public AcceptDialog {
+ GDCLASS(OpenXRBindingModifiersDialog, AcceptDialog);
+
+private:
+ ScrollContainer *binding_modifier_sc = nullptr;
+ VBoxContainer *binding_modifiers_vb = nullptr;
+ Label *binding_warning_label = nullptr;
+ Button *add_binding_modifier_btn = nullptr;
+ CreateDialog *create_dialog = nullptr;
+
+ OpenXRBindingModifierEditor *_add_binding_modifier_editor(Ref p_binding_modifier);
+ void _create_binding_modifiers();
+
+ void _on_add_binding_modifier();
+ void _on_remove_binding_modifier(Object *p_binding_modifier_editor);
+ void _on_dialog_created();
+
+protected:
+ EditorUndoRedoManager *undo_redo;
+ Ref action_map;
+ Ref interaction_profile;
+ Ref ip_binding;
+
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ // used for undo/redo
+ void _do_add_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor);
+ void _do_remove_binding_modifier_editor(OpenXRBindingModifierEditor *p_binding_modifier_editor);
+
+public:
+ OpenXRBindingModifiersDialog();
+
+ void setup(Ref p_action_map, Ref p_interaction_profile, Ref p_ip_binding = Ref());
+};
+
+#endif // OPENXR_BINDING_MODIFIERS_DIALOG_H
diff --git a/modules/openxr/editor/openxr_editor_plugin.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp
index f6b7f2dd0c30..477dd9b01460 100644
--- a/modules/openxr/editor/openxr_editor_plugin.cpp
+++ b/modules/openxr/editor/openxr_editor_plugin.cpp
@@ -53,6 +53,9 @@ void OpenXREditorPlugin::make_visible(bool p_visible) {
}
OpenXREditorPlugin::OpenXREditorPlugin() {
+ OpenXRActionMapEditor::register_binding_modifier_editor("OpenXRAnalogThresholdModifier", "OpenXRAnalogThresholdEditor");
+ OpenXRActionMapEditor::register_binding_modifier_editor("OpenXRDpadBindingModifier", "OpenXRDpadBindingEditor");
+
action_map_editor = memnew(OpenXRActionMapEditor);
EditorNode::get_bottom_panel()->add_item(TTR("OpenXR Action Map"), action_map_editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_openxr_action_map_bottom_panel", TTR("Toggle OpenXR Action Map Bottom Panel")));
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
index 09a9a990ed9f..21d9be62829e 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -29,15 +29,8 @@
/**************************************************************************/
#include "openxr_interaction_profile_editor.h"
-
#include "editor/editor_string_names.h"
-#include "scene/gui/box_container.h"
-#include "scene/gui/button.h"
-#include "scene/gui/label.h"
-#include "scene/gui/line_edit.h"
-#include "scene/gui/panel_container.h"
-#include "scene/gui/separator.h"
-#include "scene/gui/text_edit.h"
+#include "openxr_action_map_editor.h"
///////////////////////////////////////////////////////////////////////////
// Interaction profile editor base
@@ -112,12 +105,36 @@ void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action,
}
}
-void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref p_action) {
+void OpenXRInteractionProfileEditorBase::_update_interaction_profile() {
+ if (!is_dirty) {
+ // no need to update
+ return;
+ }
+
+ // Nothing to do here for now..
+
+ // and we've updated it...
+ is_dirty = false;
+}
+
+void OpenXRInteractionProfileEditorBase::_theme_changed() {
+ if (binding_modifiers_btn) {
+ binding_modifiers_btn->set_icon(get_theme_icon(SNAME("Modifiers"), EditorStringName(EditorIcons)));
+ }
+}
+
+void OpenXRInteractionProfileEditorBase::remove_all_for_action_set(Ref p_action_set) {
+ // Note, don't need to remove bindings themselves as remove_all_for_action will be called for each before this is called.
+
+ // TODO update binding modifiers
+}
+
+void OpenXRInteractionProfileEditorBase::remove_all_for_action(Ref p_action) {
Vector][> bindings = interaction_profile->get_bindings_for_action(p_action);
if (bindings.size() > 0) {
String action_name = p_action->get_name_with_set();
- // for our undo/redo we process all paths
+ // For our undo/redo we process all paths
undo_redo->create_action(TTR("Remove action from interaction profile"));
for (const Ref &binding : bindings) {
undo_redo->add_do_method(this, "_remove_binding", action_name, binding->get_binding_path());
@@ -125,7 +142,7 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Refcommit_action(false);
- // but we take a shortcut here :)
+ // But remove them all in one go so we're more efficient in updating our UI.
for (const Ref &binding : bindings) {
interaction_profile->remove_binding(binding);
}
@@ -137,10 +154,39 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Refpopup_centered(Size2i(500, 400));
+}
+
+OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase() {
+ // Note, this class is not normally instantiated this way except when Godot does introspection.
+}
OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref p_action_map, Ref p_interaction_profile) {
undo_redo = EditorUndoRedoManager::get_singleton();
+ set_h_size_flags(SIZE_EXPAND_FILL);
+ set_v_size_flags(SIZE_EXPAND_FILL);
+
+ interaction_profile_sc = memnew(ScrollContainer);
+ interaction_profile_sc->set_h_size_flags(SIZE_EXPAND_FILL);
+ interaction_profile_sc->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(interaction_profile_sc);
+
+ binding_modifiers_dialog = memnew(OpenXRBindingModifiersDialog);
+ binding_modifiers_dialog->setup(p_action_map, p_interaction_profile);
+ add_child(binding_modifiers_dialog);
+
+ toolbar_vb = memnew(VBoxContainer);
+ toolbar_vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ add_child(toolbar_vb);
+
+ binding_modifiers_btn = memnew(Button);
+ binding_modifiers_btn->set_tooltip_text(TTR("Edit binding modifiers"));
+ binding_modifiers_btn->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditorBase::_on_open_binding_modifiers));
+ // TODO show visual difference if there are binding modifiers for this interaction profile
+ toolbar_vb->add_child(binding_modifiers_btn);
+
action_map = p_action_map;
interaction_profile = p_interaction_profile;
String profile_path = interaction_profile->get_interaction_profile_path();
@@ -152,8 +198,6 @@ OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Refset_h_size_flags(Control::SIZE_EXPAND_FILL);
action_hb->add_child(action_label);
+ OpenXRBindingModifiersDialog *action_binding_modifiers_dialog = memnew(OpenXRBindingModifiersDialog);
+ action_binding_modifiers_dialog->setup(action_map, interaction_profile, binding);
+ action_hb->add_child(action_binding_modifiers_dialog);
+
+ Button *action_binding_modifiers_btn = memnew(Button);
+ action_binding_modifiers_btn->set_flat(true);
+ action_binding_modifiers_btn->set_icon(get_theme_icon(SNAME("Modifiers"), EditorStringName(EditorIcons)));
+ action_binding_modifiers_btn->connect(SceneStringName(pressed), callable_mp((Window *)action_binding_modifiers_dialog, &Window::popup_centered).bind(Size2i(500, 400)));
+ // TODO change style of button if there are binding modifiers
+ action_hb->add_child(action_binding_modifiers_btn);
+
Button *action_rem = memnew(Button);
action_rem->set_flat(true);
action_rem->set_icon(get_theme_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
@@ -262,8 +317,8 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
}
// out with the old...
- while (main_hb->get_child_count() > 0) {
- memdelete(main_hb->get_child(0));
+ while (interaction_profile_hb->get_child_count() > 0) {
+ memdelete(interaction_profile_hb->get_child(0));
}
// in with the new...
@@ -281,7 +336,7 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
for (int i = 0; i < top_level_paths.size(); i++) {
PanelContainer *panel = memnew(PanelContainer);
panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- main_hb->add_child(panel);
+ interaction_profile_hb->add_child(panel);
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")));
VBoxContainer *container = memnew(VBoxContainer);
@@ -299,23 +354,30 @@ void OpenXRInteractionProfileEditor::_update_interaction_profile() {
}
}
- // and we've updated it...
- is_dirty = false;
+ OpenXRInteractionProfileEditorBase::_update_interaction_profile();
}
void OpenXRInteractionProfileEditor::_theme_changed() {
- for (int i = 0; i < main_hb->get_child_count(); i++) {
- Control *panel = Object::cast_to(main_hb->get_child(i));
+ OpenXRInteractionProfileEditorBase::_theme_changed();
+
+ interaction_profile_sc->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("Tree")));
+
+ for (int i = 0; i < interaction_profile_hb->get_child_count(); i++) {
+ Control *panel = Object::cast_to(interaction_profile_hb->get_child(i));
if (panel) {
panel->add_theme_style_override(SceneStringName(panel), get_theme_stylebox(SceneStringName(panel), SNAME("TabContainer")));
}
}
}
+OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor() {
+ // Note, this class is not normally instantiated this way except when Godot does introspection.
+}
+
OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref p_action_map, Ref p_interaction_profile) :
OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) {
- main_hb = memnew(HBoxContainer);
- add_child(main_hb);
+ interaction_profile_hb = memnew(HBoxContainer);
+ interaction_profile_sc->add_child(interaction_profile_hb);
select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map));
select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected));
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
index 2ec72127cfcf..f65eedd8d697 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.h
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -34,19 +34,29 @@
#include "../action_map/openxr_action_map.h"
#include "../action_map/openxr_interaction_profile.h"
#include "../action_map/openxr_interaction_profile_metadata.h"
+#include "../editor/openxr_binding_modifiers_dialog.h"
+#include "editor/editor_undo_redo_manager.h"
#include "openxr_select_action_dialog.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
-#include "editor/editor_undo_redo_manager.h"
-#include "scene/gui/scroll_container.h"
+class OpenXRInteractionProfileEditorBase : public HBoxContainer {
+ GDCLASS(OpenXRInteractionProfileEditorBase, HBoxContainer);
+
+private:
+ OpenXRBindingModifiersDialog *binding_modifiers_dialog = nullptr;
+ VBoxContainer *toolbar_vb = nullptr;
+ Button *binding_modifiers_btn = nullptr;
-class OpenXRInteractionProfileEditorBase : public ScrollContainer {
- GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
+ void _on_open_binding_modifiers();
protected:
EditorUndoRedoManager *undo_redo;
Ref interaction_profile;
Ref action_map;
+ ScrollContainer *interaction_profile_sc = nullptr;
+
bool is_dirty = false;
static void _bind_methods();
@@ -57,15 +67,17 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer {
public:
Ref get_interaction_profile() { return interaction_profile; }
- virtual void _update_interaction_profile() {}
- virtual void _theme_changed() {}
+ virtual void _update_interaction_profile();
+ virtual void _theme_changed();
void _do_update_interaction_profile();
void _add_binding(const String p_action, const String p_path);
void _remove_binding(const String p_action, const String p_path);
- void remove_all_bindings_for_action(Ref p_action);
+ void remove_all_for_action_set(Ref p_action_set);
+ void remove_all_for_action(Ref p_action);
+ OpenXRInteractionProfileEditorBase();
OpenXRInteractionProfileEditorBase(Ref p_action_map, Ref p_interaction_profile);
};
@@ -74,7 +86,8 @@ class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase
private:
String selecting_for_io_path;
- HBoxContainer *main_hb = nullptr;
+ HBoxContainer *interaction_profile_hb = nullptr;
+
OpenXRSelectActionDialog *select_action_dialog = nullptr;
void _add_io_path(VBoxContainer *p_container, const OpenXRInteractionProfileMetadata::IOPath *p_io_path);
@@ -86,6 +99,7 @@ class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase
virtual void _update_interaction_profile() override;
virtual void _theme_changed() override;
+ OpenXRInteractionProfileEditor();
OpenXRInteractionProfileEditor(Ref p_action_map, Ref p_interaction_profile);
};
diff --git a/modules/openxr/extensions/openxr_dpad_binding_extension.cpp b/modules/openxr/extensions/openxr_dpad_binding_extension.cpp
new file mode 100644
index 000000000000..70b7d796e31e
--- /dev/null
+++ b/modules/openxr/extensions/openxr_dpad_binding_extension.cpp
@@ -0,0 +1,339 @@
+/**************************************************************************/
+/* openxr_dpad_binding_extension.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_dpad_binding_extension.h"
+#include "../action_map/openxr_interaction_profile_metadata.h"
+#include "../openxr_api.h"
+#include "core/math/math_funcs.h"
+
+// Implementation for:
+// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_dpad_binding
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRDPadBindingExtension
+
+OpenXRDPadBindingExtension *OpenXRDPadBindingExtension::singleton = nullptr;
+
+OpenXRDPadBindingExtension *OpenXRDPadBindingExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRDPadBindingExtension::OpenXRDPadBindingExtension() {
+ singleton = this;
+}
+
+OpenXRDPadBindingExtension::~OpenXRDPadBindingExtension() {
+ singleton = nullptr;
+}
+
+HashMap OpenXRDPadBindingExtension::get_requested_extensions() {
+ HashMap request_extensions;
+
+ // Note, we're dependent on the binding modifier extension, this may be requested by multiple extension wrappers.
+ request_extensions[XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME] = &binding_modifier_ext;
+ request_extensions[XR_EXT_DPAD_BINDING_EXTENSION_NAME] = &dpad_binding_ext;
+
+ return request_extensions;
+}
+
+bool OpenXRDPadBindingExtension::is_available() {
+ return binding_modifier_ext && dpad_binding_ext;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRDpadBindingModifier
+
+void OpenXRDpadBindingModifier::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_action_set", "action_set"), &OpenXRDpadBindingModifier::set_action_set);
+ ClassDB::bind_method(D_METHOD("get_action_set"), &OpenXRDpadBindingModifier::get_action_set);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action_set", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet"), "set_action_set", "get_action_set");
+
+ ClassDB::bind_method(D_METHOD("set_input_path", "input_path"), &OpenXRDpadBindingModifier::set_input_path);
+ ClassDB::bind_method(D_METHOD("get_input_path"), &OpenXRDpadBindingModifier::get_input_path);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_path"), "set_input_path", "get_input_path");
+
+ ClassDB::bind_method(D_METHOD("set_threshold", "threshold"), &OpenXRDpadBindingModifier::set_threshold);
+ ClassDB::bind_method(D_METHOD("get_threshold"), &OpenXRDpadBindingModifier::get_threshold);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_threshold", "get_threshold");
+
+ ClassDB::bind_method(D_METHOD("set_threshold_released", "threshold_released"), &OpenXRDpadBindingModifier::set_threshold_released);
+ ClassDB::bind_method(D_METHOD("get_threshold_released"), &OpenXRDpadBindingModifier::get_threshold_released);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold_released", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_threshold_released", "get_threshold_released");
+
+ ClassDB::bind_method(D_METHOD("set_center_region", "center_region"), &OpenXRDpadBindingModifier::set_center_region);
+ ClassDB::bind_method(D_METHOD("get_center_region"), &OpenXRDpadBindingModifier::get_center_region);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "center_region", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_center_region", "get_center_region");
+
+ ClassDB::bind_method(D_METHOD("set_wedge_angle", "wedge_angle"), &OpenXRDpadBindingModifier::set_wedge_angle);
+ ClassDB::bind_method(D_METHOD("get_wedge_angle"), &OpenXRDpadBindingModifier::get_wedge_angle);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wedge_angle"), "set_wedge_angle", "get_wedge_angle");
+
+ ClassDB::bind_method(D_METHOD("set_is_sticky", "is_sticky"), &OpenXRDpadBindingModifier::set_is_sticky);
+ ClassDB::bind_method(D_METHOD("get_is_sticky"), &OpenXRDpadBindingModifier::get_is_sticky);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "is_sticky"), "set_is_sticky", "get_is_sticky");
+
+ ClassDB::bind_method(D_METHOD("set_on_haptic", "haptic"), &OpenXRDpadBindingModifier::set_on_haptic);
+ ClassDB::bind_method(D_METHOD("get_on_haptic"), &OpenXRDpadBindingModifier::get_on_haptic);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "on_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_on_haptic", "get_on_haptic");
+
+ ClassDB::bind_method(D_METHOD("set_off_haptic", "haptic"), &OpenXRDpadBindingModifier::set_off_haptic);
+ ClassDB::bind_method(D_METHOD("get_off_haptic"), &OpenXRDpadBindingModifier::get_off_haptic);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "off_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_off_haptic", "get_off_haptic");
+}
+
+OpenXRDpadBindingModifier::OpenXRDpadBindingModifier() {
+ ERR_FAIL_COND(dpad_bindings_data.resize_zeroed(sizeof(XrInteractionProfileDpadBindingEXT)) != OK);
+ dpad_bindings = (XrInteractionProfileDpadBindingEXT *)dpad_bindings_data.ptrw();
+
+ dpad_bindings->type = XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT;
+ dpad_bindings->next = nullptr;
+
+ dpad_bindings->forceThreshold = 0.6;
+ dpad_bindings->forceThresholdReleased = 0.4;
+ dpad_bindings->centerRegion = 0.1;
+ dpad_bindings->wedgeAngle = Math::deg_to_rad(90.0);
+ dpad_bindings->isSticky = false;
+}
+
+void OpenXRDpadBindingModifier::set_action_set(const Ref p_action_set) {
+ action_set = p_action_set;
+}
+
+Ref OpenXRDpadBindingModifier::get_action_set() const {
+ return action_set;
+}
+
+void OpenXRDpadBindingModifier::set_input_path(const String &p_input_path) {
+ input_path = p_input_path;
+ emit_changed();
+}
+
+String OpenXRDpadBindingModifier::get_input_path() const {
+ return input_path;
+}
+
+void OpenXRDpadBindingModifier::set_threshold(float p_threshold) {
+ ERR_FAIL_NULL(dpad_bindings);
+ ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0);
+
+ dpad_bindings->forceThreshold = p_threshold;
+ emit_changed();
+}
+
+float OpenXRDpadBindingModifier::get_threshold() const {
+ ERR_FAIL_NULL_V(dpad_bindings, 0.0);
+ return dpad_bindings->forceThresholdReleased;
+}
+
+void OpenXRDpadBindingModifier::set_threshold_released(float p_threshold) {
+ ERR_FAIL_NULL(dpad_bindings);
+ ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0);
+
+ dpad_bindings->forceThresholdReleased = p_threshold;
+ emit_changed();
+}
+
+float OpenXRDpadBindingModifier::get_threshold_released() const {
+ ERR_FAIL_NULL_V(dpad_bindings, 0.0);
+ return dpad_bindings->forceThresholdReleased;
+}
+
+void OpenXRDpadBindingModifier::set_center_region(float p_center_region) {
+ ERR_FAIL_NULL(dpad_bindings);
+ ERR_FAIL_COND(p_center_region < 0.0 || p_center_region > 1.0);
+
+ dpad_bindings->centerRegion = p_center_region;
+ emit_changed();
+}
+
+float OpenXRDpadBindingModifier::get_center_region() const {
+ ERR_FAIL_NULL_V(dpad_bindings, 0.0);
+ return dpad_bindings->centerRegion;
+}
+
+void OpenXRDpadBindingModifier::set_wedge_angle(float p_wedge_angle) {
+ ERR_FAIL_NULL(dpad_bindings);
+ dpad_bindings->wedgeAngle = p_wedge_angle;
+ emit_changed();
+}
+
+float OpenXRDpadBindingModifier::get_wedge_angle() const {
+ ERR_FAIL_NULL_V(dpad_bindings, 0.0);
+ return dpad_bindings->wedgeAngle;
+}
+
+void OpenXRDpadBindingModifier::set_wedge_angle_deg(float p_wedge_angle) {
+ ERR_FAIL_NULL(dpad_bindings);
+ dpad_bindings->wedgeAngle = Math::deg_to_rad(p_wedge_angle);
+ emit_changed();
+}
+
+float OpenXRDpadBindingModifier::get_wedge_angle_deg() const {
+ ERR_FAIL_NULL_V(dpad_bindings, 0.0);
+ return Math::rad_to_deg(dpad_bindings->wedgeAngle);
+}
+
+void OpenXRDpadBindingModifier::set_is_sticky(bool p_sticky) {
+ ERR_FAIL_NULL(dpad_bindings);
+ dpad_bindings->isSticky = p_sticky;
+ emit_changed();
+}
+
+bool OpenXRDpadBindingModifier::get_is_sticky() const {
+ ERR_FAIL_NULL_V(dpad_bindings, false);
+ return dpad_bindings->isSticky;
+}
+
+void OpenXRDpadBindingModifier::set_on_haptic(const Ref p_haptic) {
+ on_haptic = p_haptic;
+ emit_changed();
+}
+
+Ref OpenXRDpadBindingModifier::get_on_haptic() const {
+ return on_haptic;
+}
+
+void OpenXRDpadBindingModifier::set_off_haptic(const Ref p_haptic) {
+ off_haptic = p_haptic;
+ emit_changed();
+}
+
+Ref OpenXRDpadBindingModifier::get_off_haptic() const {
+ return off_haptic;
+}
+
+PackedByteArray OpenXRDpadBindingModifier::get_ip_modification() {
+ ERR_FAIL_NULL_V(dpad_bindings, PackedByteArray());
+
+ OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
+ ERR_FAIL_NULL_V(openxr_api, PackedByteArray());
+
+ OpenXRDPadBindingExtension *dpad_binding_ext = OpenXRDPadBindingExtension::get_singleton();
+ if (!dpad_binding_ext || !dpad_binding_ext->is_available()) {
+ // Extension not enabled!
+ WARN_PRINT("DPad binding extension is not enabled or available.");
+ return PackedByteArray();
+ }
+
+ dpad_bindings->binding = openxr_api->get_xr_path(input_path);
+ ERR_FAIL_COND_V(dpad_bindings->binding == XR_NULL_PATH, PackedByteArray());
+
+ // Get our action set
+ ERR_FAIL_COND_V(!action_set.is_valid(), PackedByteArray());
+ RID action_set_rid = openxr_api->find_action_set(action_set->get_name());
+ ERR_FAIL_COND_V(!action_set_rid.is_valid(), PackedByteArray());
+ dpad_bindings->actionSet = openxr_api->action_set_get_handle(action_set_rid);
+
+ // These are set already:
+ // - forceThreshold
+ // - forceThresholdReleased
+ // - centerRegion
+ // - wedgeAngle
+ // - isSticky
+
+ if (on_haptic.is_valid()) {
+ dpad_bindings->onHaptic = on_haptic->get_xr_structure();
+ } else {
+ dpad_bindings->onHaptic = nullptr;
+ }
+
+ if (off_haptic.is_valid()) {
+ dpad_bindings->offHaptic = off_haptic->get_xr_structure();
+ } else {
+ dpad_bindings->offHaptic = nullptr;
+ }
+
+ return dpad_bindings_data;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRDpadBindingEditor
+
+#ifdef TOOLS_ENABLED
+
+void OpenXRDpadBindingEditor::_bind_methods() {
+}
+
+OpenXRDpadBindingEditor::OpenXRDpadBindingEditor() {
+ action_set_property = memnew(EditorPropertyActionSet);
+ add_property_editor("action_set", action_set_property);
+
+ input_path_property = memnew(EditorPropertyBindingPath);
+ add_property_editor("input_path", input_path_property);
+
+ threshold_property = memnew(EditorPropertyFloat);
+ threshold_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false);
+ add_property_editor("threshold", threshold_property);
+
+ threshold_release_property = memnew(EditorPropertyFloat);
+ threshold_release_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false);
+ add_property_editor("threshold_released", threshold_release_property);
+
+ center_region_property = memnew(EditorPropertyFloat);
+ center_region_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false);
+ add_property_editor("center_region", center_region_property);
+
+ wedge_angle_property = memnew(EditorPropertyFloat);
+ wedge_angle_property->setup(0.0, 360.0, 1.0, false, false, false, false, "", true);
+ add_property_editor("wedge_angle", wedge_angle_property);
+
+ is_sticky_property = memnew(EditorPropertyCheck);
+ add_property_editor("is_sticky", is_sticky_property);
+
+ on_haptic_property = memnew(EditorPropertyResource);
+ // on_haptic_property->set_use_sub_inspector(false);
+ add_property_editor("on_haptic", on_haptic_property);
+
+ off_haptic_property = memnew(EditorPropertyResource);
+ // off_haptic_property->set_use_sub_inspector(false);
+ add_property_editor("off_haptic", off_haptic_property);
+}
+
+void OpenXRDpadBindingEditor::set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) {
+ if (p_action_map.is_valid()) {
+ action_set_property->setup(p_action_map);
+ }
+
+ if (p_binding_modifier.is_valid()) {
+ OpenXRInteractionProfile *interaction_profile = p_binding_modifier->get_interaction_profile();
+ if (interaction_profile) {
+ Vector action_types;
+ action_types.push_back(OpenXRAction::OPENXR_ACTION_VECTOR2);
+ input_path_property->setup(interaction_profile->get_interaction_profile_path(), action_types);
+ }
+
+ on_haptic_property->setup(p_binding_modifier.ptr(), "on_haptic", "OpenXRHapticBase");
+ off_haptic_property->setup(p_binding_modifier.ptr(), "off_haptic", "OpenXRHapticBase");
+ }
+
+ OpenXRBindingModifierEditor::set_binding_modifier(p_action_map, p_binding_modifier);
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/openxr/extensions/openxr_dpad_binding_extension.h b/modules/openxr/extensions/openxr_dpad_binding_extension.h
new file mode 100644
index 000000000000..2caf8d6e3113
--- /dev/null
+++ b/modules/openxr/extensions/openxr_dpad_binding_extension.h
@@ -0,0 +1,141 @@
+/**************************************************************************/
+/* openxr_dpad_binding_extension.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_DPAD_BINDING_EXTENSION_H
+#define OPENXR_DPAD_BINDING_EXTENSION_H
+
+#include "../action_map/openxr_action_set.h"
+#include "../action_map/openxr_binding_modifier.h"
+#include "../action_map/openxr_haptic_feedback.h"
+#include "../util.h"
+#include "openxr_extension_wrapper.h"
+
+#ifdef TOOLS_ENABLED
+#include "../editor/openxr_binding_modifier_editor.h"
+#endif // TOOLS_ENABLED
+
+class OpenXRDPadBindingExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRDPadBindingExtension *get_singleton();
+
+ OpenXRDPadBindingExtension();
+ virtual ~OpenXRDPadBindingExtension() override;
+
+ virtual HashMap get_requested_extensions() override;
+
+ bool is_available();
+
+private:
+ static OpenXRDPadBindingExtension *singleton;
+
+ bool binding_modifier_ext = false;
+ bool dpad_binding_ext = false;
+};
+
+class OpenXRDpadBindingModifier : public OpenXRBindingModifier {
+ GDCLASS(OpenXRDpadBindingModifier, OpenXRBindingModifier);
+
+private:
+ PackedByteArray dpad_bindings_data;
+ XrInteractionProfileDpadBindingEXT *dpad_bindings = nullptr;
+ String input_path;
+ Ref action_set;
+ Ref on_haptic;
+ Ref off_haptic;
+
+protected:
+ static void _bind_methods();
+
+public:
+ OpenXRDpadBindingModifier();
+
+ void set_action_set(const Ref p_action_set);
+ Ref get_action_set() const;
+
+ void set_input_path(const String &p_input_path);
+ String get_input_path() const;
+
+ void set_threshold(float p_threshold);
+ float get_threshold() const;
+
+ void set_threshold_released(float p_threshold);
+ float get_threshold_released() const;
+
+ void set_center_region(float p_center_region);
+ float get_center_region() const;
+
+ void set_wedge_angle(float p_wedge_angle);
+ float get_wedge_angle() const;
+
+ void set_wedge_angle_deg(float p_wedge_angle);
+ float get_wedge_angle_deg() const;
+
+ void set_is_sticky(bool p_sticky);
+ bool get_is_sticky() const;
+
+ void set_on_haptic(const Ref p_haptic);
+ Ref get_on_haptic() const;
+
+ void set_off_haptic(const Ref p_haptic);
+ Ref get_off_haptic() const;
+
+ virtual bool record_on_binding() const override { return false; }
+ virtual String get_description() const override { return "DPad modifier"; }
+ virtual PackedByteArray get_ip_modification() override;
+};
+
+#ifdef TOOLS_ENABLED
+
+class OpenXRDpadBindingEditor : public OpenXRBindingModifierEditor {
+ GDCLASS(OpenXRDpadBindingEditor, OpenXRBindingModifierEditor);
+
+private:
+ EditorPropertyActionSet *action_set_property = nullptr;
+ EditorPropertyBindingPath *input_path_property = nullptr;
+ EditorPropertyFloat *threshold_property = nullptr;
+ EditorPropertyFloat *threshold_release_property = nullptr;
+ EditorPropertyFloat *center_region_property = nullptr;
+ EditorPropertyFloat *wedge_angle_property = nullptr;
+ EditorPropertyCheck *is_sticky_property = nullptr;
+ EditorPropertyResource *on_haptic_property = nullptr;
+ EditorPropertyResource *off_haptic_property = nullptr;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) override;
+
+ OpenXRDpadBindingEditor();
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // OPENXR_DPAD_BINDING_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.cpp b/modules/openxr/extensions/openxr_htc_controller_extension.cpp
index 416934fa47ce..36894cb0cea3 100644
--- a/modules/openxr/extensions/openxr_htc_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_controller_extension.cpp
@@ -61,96 +61,88 @@ void OpenXRHTCControllerExtension::on_register_metadata() {
metadata->register_top_level_path("HTC left hand tracker", "/user/hand_htc/left", XR_HTC_HAND_INTERACTION_EXTENSION_NAME);
metadata->register_top_level_path("HTC right hand tracker", "/user/hand_htc/right", XR_HTC_HAND_INTERACTION_EXTENSION_NAME);
- // HTC Vive Cosmos controller
- metadata->register_interaction_profile("Vive Cosmos controller", "/interaction_profiles/htc/vive_cosmos_controller", XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/left", "/user/hand/left/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Shoulder click", "/user/hand/right", "/user/hand/right/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_cosmos_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // HTC Vive Focus 3 controller
- metadata->register_interaction_profile("Vive Focus 3 controller", "/interaction_profiles/htc/vive_focus3_controller", XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/left", "/user/hand/left/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/right", "/user/hand/right/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // HTC Hand interaction profile
- metadata->register_interaction_profile("HTC Hand interaction", "/interaction_profiles/htc/hand_interaction", XR_HTC_HAND_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Grip pose", "/user/hand_htc/left", "/user/hand_htc/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Grip pose", "/user/hand_htc/right", "/user/hand_htc/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Aim pose", "/user/hand_htc/left", "/user/hand_htc/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Aim pose", "/user/hand_htc/right", "/user/hand_htc/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Select (pinch)", "/user/hand_htc/left", "/user/hand_htc/left/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Select (pinch)", "/user/hand_htc/right", "/user/hand_htc/right/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Squeeze (grab)", "/user/hand_htc/left", "/user/hand_htc/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/hand_interaction", "Squeeze (grab)", "/user/hand_htc/right", "/user/hand_htc/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ { // HTC Vive Cosmos controller
+ const String profile_path = "/interaction_profiles/htc/vive_cosmos_controller";
+ metadata->register_interaction_profile("Vive Cosmos controller", profile_path, XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Shoulder click", user_path, user_path + "/input/shoulder/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+
+ { // HTC Vive Focus 3 controller
+ const String profile_path = "/interaction_profiles/htc/vive_focus3_controller";
+ metadata->register_interaction_profile("Vive Focus 3 controller", profile_path, XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Squeeze touch", user_path, user_path + "/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+
+ { // HTC Hand interaction profile
+ const String profile_path = "/interaction_profiles/htc/hand_interaction";
+ metadata->register_interaction_profile("HTC Hand interaction", profile_path, XR_HTC_HAND_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand_htc/left", "/user/hand_htc/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Select (pinch)", user_path, user_path + "/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ }
+ }
}
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
index b2ddf71f5ef4..20c07cd25425 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
@@ -83,134 +83,45 @@ void OpenXRHTCViveTrackerExtension::on_register_metadata() {
metadata->register_top_level_path("Camera tracker", "/user/vive_tracker_htcx/role/camera", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
metadata->register_top_level_path("Keyboard tracker", "/user/vive_tracker_htcx/role/keyboard", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
- // HTC Vive tracker
- // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec.
- // I think this can be supported through attachments on the trackers.
- metadata->register_interaction_profile("HTC Vive tracker", "/interaction_profiles/htc/vive_tracker_htcx", XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Menu click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trigger click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Squeeze click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad click", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Trackpad touch", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- // register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Grip pose", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
-
- // metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/handheld_object", "/user/vive_tracker_htcx/role/handheld_object/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_foot", "/user/vive_tracker_htcx/role/left_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_foot", "/user/vive_tracker_htcx/role/right_foot/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_shoulder", "/user/vive_tracker_htcx/role/left_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_shoulder", "/user/vive_tracker_htcx/role/right_shoulder/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_elbow", "/user/vive_tracker_htcx/role/left_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_elbow", "/user/vive_tracker_htcx/role/right_elbow/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/left_knee", "/user/vive_tracker_htcx/role/left_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/right_knee", "/user/vive_tracker_htcx/role/right_knee/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/waist", "/user/vive_tracker_htcx/role/waist/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/chest", "/user/vive_tracker_htcx/role/chest/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/camera", "/user/vive_tracker_htcx/role/camera/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/htc/vive_tracker_htcx", "Haptic output", "/user/vive_tracker_htcx/role/keyboard", "/user/vive_tracker_htcx/role/keyboard/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ { // HTC Vive tracker
+ // Interestingly enough trackers don't have buttons or inputs, yet these are defined in the spec.
+ // I think this can be supported through attachments on the trackers.
+ const String profile_path = "/interaction_profiles/htc/vive_tracker_htcx";
+ metadata->register_interaction_profile("HTC Vive tracker", profile_path, XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : {
+ /* "/user/vive_tracker_htcx/role/handheld_object", */
+ "/user/vive_tracker_htcx/role/left_foot",
+ "/user/vive_tracker_htcx/role/right_foot",
+ "/user/vive_tracker_htcx/role/left_shoulder",
+ "/user/vive_tracker_htcx/role/right_shoulder",
+ "/user/vive_tracker_htcx/role/left_elbow",
+ "/user/vive_tracker_htcx/role/right_elbow",
+ "/user/vive_tracker_htcx/role/left_knee",
+ "/user/vive_tracker_htcx/role/right_knee",
+ "/user/vive_tracker_htcx/role/waist",
+ "/user/vive_tracker_htcx/role/chest",
+ "/user/vive_tracker_htcx/role/camera",
+ "/user/vive_tracker_htcx/role/keyboard",
+ }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
}
bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &event) {
diff --git a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp
index baa6d6ded85c..844ce22d20d5 100644
--- a/modules/openxr/extensions/openxr_huawei_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_huawei_controller_extension.cpp
@@ -48,37 +48,33 @@ void OpenXRHuaweiControllerExtension::on_register_metadata() {
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
ERR_FAIL_NULL(metadata);
- // Huawei controller
- metadata->register_interaction_profile("Huawei controller", "/interaction_profiles/huawei/controller", XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ { // Huawei controller
+ const String profile_path = "/interaction_profiles/huawei/controller";
+ metadata->register_interaction_profile("Huawei controller", profile_path, XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/left", "/user/hand/left/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Home click", "/user/hand/right", "/user/hand/right/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/left", "/user/hand/left/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Back click", "/user/hand/right", "/user/hand/right/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Home click", user_path, user_path + "/input/home/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Back click", user_path, user_path + "/input/back/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/left", "/user/hand/left/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume up click", "/user/hand/right", "/user/hand/right/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/left", "/user/hand/left/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Volume down click", "/user/hand/right", "/user/hand/right/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Volume up click", user_path, user_path + "/input/volume_up/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Volume down click", user_path, user_path + "/input/volume_down/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/huawei/controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
}
diff --git a/modules/openxr/extensions/openxr_meta_controller_extension.cpp b/modules/openxr/extensions/openxr_meta_controller_extension.cpp
index 72dc74bf64e8..ad62f584c138 100644
--- a/modules/openxr/extensions/openxr_meta_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_meta_controller_extension.cpp
@@ -52,133 +52,110 @@ void OpenXRMetaControllerExtension::on_register_metadata() {
// Note, we register controllers regardless if they are supported on the current hardware.
- // Normal touch controller is part of the core spec, but we do have some extensions.
- metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/oculus/touch_controller", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
-
- // Touch controller pro (Quest Pro)
- metadata->register_interaction_profile("Touch controller pro", "/interaction_profiles/facebook/touch_controller_pro", "XR_FB_touch_controller_pro");
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/left", "/user/hand/left/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Thumbrest force", "/user/hand/right", "/user/hand/right/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/left", "/user/hand/left/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Stylus force", "/user/hand/right", "/user/hand/right/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/left", "/user/hand/left/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/left", "/user/hand/left/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic trigger output", "/user/hand/right", "/user/hand/right/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/facebook/touch_controller_pro", "Haptic thumb output", "/user/hand/right", "/user/hand/right/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Touch controller plus (Quest 3)
- metadata->register_interaction_profile("Touch controller plus", "/interaction_profiles/meta/touch_controller_plus", "XR_META_touch_controller_plus");
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/left", "/user/hand/left/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/left", "/user/hand/left/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/left", "/user/hand/left/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/left", "/user/hand/left/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger proximity", "/user/hand/right", "/user/hand/right/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger curl", "/user/hand/right", "/user/hand/right/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger slide", "/user/hand/right", "/user/hand/right/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Trigger force", "/user/hand/right", "/user/hand/right/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/left", "/user/hand/left/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumb proximity", "/user/hand/right", "/user/hand/right/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/left", "/user/hand/left/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/left", "/user/hand/left/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick X", "/user/hand/right", "/user/hand/right/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick Y", "/user/hand/right", "/user/hand/right/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/meta/touch_controller_plus", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ { // Normal touch controller is part of the core spec, but we do have some extensions.
+ const String profile_path = "/interaction_profiles/oculus/touch_controller";
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb ", "XR_FB_touch_controller_proximity", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+ }
+
+ { // Touch controller pro (Quest Pro)
+ const String profile_path = "/interaction_profiles/facebook/touch_controller_pro";
+ metadata->register_interaction_profile("Touch controller pro", profile_path, "XR_FB_touch_controller_pro");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger curl", user_path, user_path + "/input/trigger/curl_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger slide", user_path, user_path + "/input/trigger/slide_fb", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger force", user_path, user_path + "/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_fb/proximity_fb", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick X", user_path, user_path + "/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Thumbstick Y", user_path, user_path + "/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbrest force", user_path, user_path + "/input/thumbrest/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Stylus force", user_path, user_path + "/input/stylus_fb/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path(profile_path, "Haptic trigger output", user_path, user_path + "/output/haptic_trigger_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ metadata->register_io_path(profile_path, "Haptic thumb output", user_path, user_path + "/output/haptic_thumb_fb", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+
+ { // Touch controller plus (Quest 3)
+ const String profile_path = "/interaction_profiles/meta/touch_controller_plus";
+ metadata->register_interaction_profile("Touch controller plus", profile_path, "XR_META_touch_controller_plus");
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger proximity", user_path, user_path + "/input/trigger/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trigger curl", user_path, user_path + "/input/trigger/curl_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger slide", user_path, user_path + "/input/trigger/slide_meta", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger force", user_path, user_path + "/input/trigger/force", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Thumb proximity", user_path, user_path + "/input/thumb_meta/proximity_meta", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick X", user_path, user_path + "/input/thumbstick/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Thumbstick Y", user_path, user_path + "/input/thumbstick/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbrest touch", user_path, user_path + "/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
}
diff --git a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp
index 979ac22d087f..f36273658d53 100644
--- a/modules/openxr/extensions/openxr_ml2_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_ml2_controller_extension.cpp
@@ -50,7 +50,7 @@ void OpenXRML2ControllerExtension::on_register_metadata() {
// Magic Leap 2 Controller
const String profile_path = "/interaction_profiles/ml/ml2_controller";
- metadata->register_interaction_profile("Magic Leap 2 controller", "/interaction_profiles/ml/ml2_controller", XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ metadata->register_interaction_profile("Magic Leap 2 controller", profile_path, XR_ML_ML2_CONTROLLER_INTERACTION_EXTENSION_NAME);
for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
@@ -66,6 +66,11 @@ void OpenXRML2ControllerExtension::on_register_metadata() {
metadata->register_io_path(profile_path, "Trackpad X", user_path, user_path + "/input/trackpad/x", "", OpenXRAction::OPENXR_ACTION_FLOAT);
metadata->register_io_path(profile_path, "Trackpad Y", user_path, user_path + "/input/trackpad/y", "", OpenXRAction::OPENXR_ACTION_FLOAT);
metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
}
diff --git a/modules/openxr/extensions/openxr_pico_controller_extension.cpp b/modules/openxr/extensions/openxr_pico_controller_extension.cpp
index f2901d49f779..b4419d103d10 100644
--- a/modules/openxr/extensions/openxr_pico_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_pico_controller_extension.cpp
@@ -55,85 +55,79 @@ void OpenXRPicoControllerExtension::on_register_metadata() {
// Make sure we switch to our new name.
metadata->register_profile_rename("/interaction_profiles/pico/neo3_controller", "/interaction_profiles/bytedance/pico_neo3_controller");
- // Pico neo 3 controller.
- metadata->register_interaction_profile("Pico Neo3 controller", "/interaction_profiles/bytedance/pico_neo3_controller", XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/bytedance/pico_neo3_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Pico 4 controller.
- metadata->register_interaction_profile("Pico 4 controller", "/interaction_profiles/bytedance/pico4_controller", XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- // Note, no menu on right controller!
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "System click", "/user/hand/left", "/user/hand/left/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "System click", "/user/hand/right", "/user/hand/right/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick touch", "/user/hand/left", "/user/hand/left/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/bytedance/pico4_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ { // Pico neo 3 controller.
+ const String profile_path = "/interaction_profiles/bytedance/pico_neo3_controller";
+ metadata->register_interaction_profile("Pico Neo3 controller", profile_path, XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+
+ { // Pico 4 controller.
+ const String profile_path = "/interaction_profiles/bytedance/pico4_controller";
+ metadata->register_interaction_profile("Pico 4 controller", profile_path, XR_BD_CONTROLLER_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "System click", user_path, user_path + "/input/system/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger touch", user_path, user_path + "/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick touch", user_path, user_path + "/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ // Note, no menu on right controller!
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "X touch", "/user/hand/left", "/user/hand/left/input/x/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y touch", "/user/hand/left", "/user/hand/left/input/y/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A touch", "/user/hand/right", "/user/hand/right/input/a/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B touch", "/user/hand/right", "/user/hand/right/input/b/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
}
diff --git a/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp
new file mode 100644
index 000000000000..eb59c19bb35a
--- /dev/null
+++ b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp
@@ -0,0 +1,216 @@
+/**************************************************************************/
+/* openxr_valve_analog_threshold_extension.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "openxr_valve_analog_threshold_extension.h"
+#include "../action_map/openxr_action_set.h"
+#include "../openxr_api.h"
+
+// Implementation for:
+// https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_VALVE_analog_threshold
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRValveAnalogThresholdExtension
+
+OpenXRValveAnalogThresholdExtension *OpenXRValveAnalogThresholdExtension::singleton = nullptr;
+
+OpenXRValveAnalogThresholdExtension *OpenXRValveAnalogThresholdExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRValveAnalogThresholdExtension::OpenXRValveAnalogThresholdExtension() {
+ singleton = this;
+}
+
+OpenXRValveAnalogThresholdExtension::~OpenXRValveAnalogThresholdExtension() {
+ singleton = nullptr;
+}
+
+HashMap OpenXRValveAnalogThresholdExtension::get_requested_extensions() {
+ HashMap request_extensions;
+
+ // Note, we're dependent on the binding modifier extension, this may be requested by multiple extension wrappers.
+ request_extensions[XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME] = &binding_modifier_ext;
+ request_extensions[XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME] = &threshold_ext;
+
+ return request_extensions;
+}
+
+bool OpenXRValveAnalogThresholdExtension::is_available() {
+ return binding_modifier_ext && threshold_ext;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRAnalogThresholdModifier
+
+void OpenXRAnalogThresholdModifier::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_on_threshold", "on_threshold"), &OpenXRAnalogThresholdModifier::set_on_threshold);
+ ClassDB::bind_method(D_METHOD("get_on_threshold"), &OpenXRAnalogThresholdModifier::get_on_threshold);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "on_threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_on_threshold", "get_on_threshold");
+
+ ClassDB::bind_method(D_METHOD("set_off_threshold", "off_threshold"), &OpenXRAnalogThresholdModifier::set_off_threshold);
+ ClassDB::bind_method(D_METHOD("get_off_threshold"), &OpenXRAnalogThresholdModifier::get_off_threshold);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "off_threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_off_threshold", "get_off_threshold");
+
+ ClassDB::bind_method(D_METHOD("set_on_haptic", "haptic"), &OpenXRAnalogThresholdModifier::set_on_haptic);
+ ClassDB::bind_method(D_METHOD("get_on_haptic"), &OpenXRAnalogThresholdModifier::get_on_haptic);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "on_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_on_haptic", "get_on_haptic");
+
+ ClassDB::bind_method(D_METHOD("set_off_haptic", "haptic"), &OpenXRAnalogThresholdModifier::set_off_haptic);
+ ClassDB::bind_method(D_METHOD("get_off_haptic"), &OpenXRAnalogThresholdModifier::get_off_haptic);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "off_haptic", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRHapticBase"), "set_off_haptic", "get_off_haptic");
+}
+
+OpenXRAnalogThresholdModifier::OpenXRAnalogThresholdModifier() {
+ analog_threshold.type = XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE;
+ analog_threshold.next = nullptr;
+
+ analog_threshold.onThreshold = 0.6;
+ analog_threshold.offThreshold = 0.4;
+}
+
+void OpenXRAnalogThresholdModifier::set_on_threshold(float p_threshold) {
+ ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0);
+
+ analog_threshold.onThreshold = p_threshold;
+ emit_changed();
+}
+
+float OpenXRAnalogThresholdModifier::get_on_threshold() const {
+ return analog_threshold.onThreshold;
+}
+
+void OpenXRAnalogThresholdModifier::set_off_threshold(float p_threshold) {
+ ERR_FAIL_COND(p_threshold < 0.0 || p_threshold > 1.0);
+
+ analog_threshold.offThreshold = p_threshold;
+ emit_changed();
+}
+
+float OpenXRAnalogThresholdModifier::get_off_threshold() const {
+ return analog_threshold.offThreshold;
+}
+
+void OpenXRAnalogThresholdModifier::set_on_haptic(const Ref p_haptic) {
+ on_haptic = p_haptic;
+ emit_changed();
+}
+
+Ref OpenXRAnalogThresholdModifier::get_on_haptic() const {
+ return on_haptic;
+}
+
+void OpenXRAnalogThresholdModifier::set_off_haptic(const Ref p_haptic) {
+ off_haptic = p_haptic;
+ emit_changed();
+}
+
+Ref OpenXRAnalogThresholdModifier::get_off_haptic() const {
+ return off_haptic;
+}
+
+PackedByteArray OpenXRAnalogThresholdModifier::get_ip_modification() {
+ PackedByteArray ret;
+
+ OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
+ ERR_FAIL_NULL_V(openxr_api, ret);
+
+ OpenXRValveAnalogThresholdExtension *analog_threshold_ext = OpenXRValveAnalogThresholdExtension::get_singleton();
+ if (!analog_threshold_ext || !analog_threshold_ext->is_available()) {
+ // Extension not enabled!
+ WARN_PRINT("Analog threshold extension is not enabled or available.");
+ return ret;
+ }
+
+ ERR_FAIL_NULL_V(ip_binding, ret);
+
+ Ref action = ip_binding->get_action();
+ ERR_FAIL_COND_V(!action.is_valid(), ret);
+
+ // Get our action set
+ Ref action_set = action->get_action_set();
+ ERR_FAIL_COND_V(!action_set.is_valid(), ret);
+ RID action_set_rid = openxr_api->find_action_set(action_set->get_name());
+ ERR_FAIL_COND_V(!action_set_rid.is_valid(), ret);
+
+ // Get our action
+ RID action_rid = openxr_api->find_action(action->get_name(), action_set_rid);
+ ERR_FAIL_COND_V(!action_rid.is_valid(), ret);
+
+ analog_threshold.action = openxr_api->action_get_handle(action_rid);
+
+ analog_threshold.binding = openxr_api->get_xr_path(ip_binding->get_binding_path());
+ ERR_FAIL_COND_V(analog_threshold.binding == XR_NULL_PATH, ret);
+
+ // These are set already:
+ // - analog_threshold.onThreshold
+ // - analog_threshold.offThreshold
+
+ if (on_haptic.is_valid()) {
+ analog_threshold.onHaptic = on_haptic->get_xr_structure();
+ } else {
+ analog_threshold.onHaptic = nullptr;
+ }
+
+ if (off_haptic.is_valid()) {
+ analog_threshold.offHaptic = off_haptic->get_xr_structure();
+ } else {
+ analog_threshold.offHaptic = nullptr;
+ }
+
+ // Copy into byte array so we can return it.
+ ERR_FAIL_COND_V(ret.resize(sizeof(XrInteractionProfileAnalogThresholdVALVE)) != OK, ret);
+ memcpy(&analog_threshold, ret.ptrw(), sizeof(XrInteractionProfileAnalogThresholdVALVE));
+
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// OpenXRAnalogThresholdEditor
+
+#ifdef TOOLS_ENABLED
+
+void OpenXRAnalogThresholdEditor::_bind_methods() {
+}
+
+OpenXRAnalogThresholdEditor::OpenXRAnalogThresholdEditor() {
+ on_threshold_property = memnew(EditorPropertyFloat);
+ on_threshold_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false);
+ add_property_editor("on_threshold", on_threshold_property);
+
+ off_threshold_property = memnew(EditorPropertyFloat);
+ off_threshold_property->setup(0.0, 1.0, 0.01, false, false, false, false, "", false);
+ add_property_editor("off_threshold", off_threshold_property);
+}
+
+void OpenXRAnalogThresholdEditor::set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) {
+ OpenXRBindingModifierEditor::set_binding_modifier(p_action_map, p_binding_modifier);
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h
new file mode 100644
index 000000000000..7f517949d80d
--- /dev/null
+++ b/modules/openxr/extensions/openxr_valve_analog_threshold_extension.h
@@ -0,0 +1,112 @@
+/**************************************************************************/
+/* openxr_valve_analog_threshold_extension.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H
+#define OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H
+
+#include "../action_map/openxr_binding_modifier.h"
+#include "../action_map/openxr_haptic_feedback.h"
+#include "../util.h"
+#include "core/io/resource.h"
+#include "openxr_extension_wrapper.h"
+
+#ifdef TOOLS_ENABLED
+#include "../editor/openxr_binding_modifier_editor.h"
+#endif // TOOLS_ENABLED
+
+class OpenXRValveAnalogThresholdExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRValveAnalogThresholdExtension *get_singleton();
+
+ OpenXRValveAnalogThresholdExtension();
+ virtual ~OpenXRValveAnalogThresholdExtension() override;
+
+ virtual HashMap get_requested_extensions() override;
+
+ bool is_available();
+
+private:
+ static OpenXRValveAnalogThresholdExtension *singleton;
+
+ bool binding_modifier_ext = false;
+ bool threshold_ext = false;
+};
+
+class OpenXRAnalogThresholdModifier : public OpenXRBindingModifier {
+ GDCLASS(OpenXRAnalogThresholdModifier, OpenXRBindingModifier);
+
+private:
+ XrInteractionProfileAnalogThresholdVALVE analog_threshold;
+ Ref on_haptic;
+ Ref off_haptic;
+
+protected:
+ static void _bind_methods();
+
+public:
+ OpenXRAnalogThresholdModifier();
+
+ void set_on_threshold(float p_threshold);
+ float get_on_threshold() const;
+
+ void set_off_threshold(float p_threshold);
+ float get_off_threshold() const;
+
+ void set_on_haptic(const Ref p_haptic);
+ Ref get_on_haptic() const;
+
+ void set_off_haptic(const Ref p_haptic);
+ Ref get_off_haptic() const;
+
+ virtual String get_description() const override { return "Analog threshold modifier"; }
+ virtual PackedByteArray get_ip_modification() override;
+};
+
+#ifdef TOOLS_ENABLED
+
+class OpenXRAnalogThresholdEditor : public OpenXRBindingModifierEditor {
+ GDCLASS(OpenXRAnalogThresholdEditor, OpenXRBindingModifierEditor);
+
+private:
+ EditorPropertyFloat *on_threshold_property = nullptr;
+ EditorPropertyFloat *off_threshold_property = nullptr;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void set_binding_modifier(Ref p_action_map, Ref p_binding_modifier) override;
+
+ OpenXRAnalogThresholdEditor();
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // OPENXR_VALVE_ANALOG_THRESHOLD_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp
index 343732045211..6b0ccca3ea43 100644
--- a/modules/openxr/extensions/openxr_wmr_controller_extension.cpp
+++ b/modules/openxr/extensions/openxr_wmr_controller_extension.cpp
@@ -51,90 +51,85 @@ void OpenXRWMRControllerExtension::on_register_metadata() {
OpenXRInteractionProfileMetadata *metadata = OpenXRInteractionProfileMetadata::get_singleton();
ERR_FAIL_NULL(metadata);
- // HP MR controller (newer G2 controllers)
- metadata->register_interaction_profile("HPMR controller", "/interaction_profiles/hp/mixed_reality_controller", XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Squeeze", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/hp/mixed_reality_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // Samsung Odyssey controller
- metadata->register_interaction_profile("Samsung Odyssey controller", "/interaction_profiles/samsung/odyssey_controller", XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/left", "/user/hand/left/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Menu click", "/user/hand/right", "/user/hand/right/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/left", "/user/hand/left/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/left", "/user/hand/left/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Squeeze click", "/user/hand/right", "/user/hand/right/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/left", "/user/hand/left/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/left", "/user/hand/left/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick", "/user/hand/right", "/user/hand/right/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/left", "/user/hand/left/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/left", "/user/hand/left/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/left", "/user/hand/left/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad", "/user/hand/right", "/user/hand/right/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad click", "/user/hand/right", "/user/hand/right/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Trackpad touch", "/user/hand/right", "/user/hand/right/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
-
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
- metadata->register_io_path("/interaction_profiles/samsung/odyssey_controller", "Haptic output", "/user/hand/right", "/user/hand/right/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
-
- // MSFT Hand interaction profile, also supported by other headsets
- metadata->register_interaction_profile("MSFT Hand interaction", "/interaction_profiles/microsoft/hand_interaction", XR_MSFT_HAND_INTERACTION_EXTENSION_NAME);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Grip pose", "/user/hand/left", "/user/hand/left/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Grip pose", "/user/hand/right", "/user/hand/right/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Aim pose", "/user/hand/left", "/user/hand/left/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Aim pose", "/user/hand/right", "/user/hand/right/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Pinch pose", "/user/hand/left", "/user/hand/left/input/pinch_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Pinch pose", "/user/hand/right", "/user/hand/right/input/pinch_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Poke pose", "/user/hand/left", "/user/hand/left/input/poke_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Poke pose", "/user/hand/right", "/user/hand/right/input/poke_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Palm pose", "/user/hand/left", "/user/hand/left/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Palm pose", "/user/hand/right", "/user/hand/right/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
-
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Select (pinch)", "/user/hand/left", "/user/hand/left/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Select (pinch)", "/user/hand/right", "/user/hand/right/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
-
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Squeeze (grab)", "/user/hand/left", "/user/hand/left/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
- metadata->register_io_path("/interaction_profiles/microsoft/hand_interaction", "Squeeze (grab)", "/user/hand/right", "/user/hand/right/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ { // HP MR controller (newer G2 controllers)
+ const String profile_path = "/interaction_profiles/hp/mixed_reality_controller";
+ metadata->register_interaction_profile("HPMR controller", profile_path, XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Squeeze", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+
+ metadata->register_io_path(profile_path, "X click", "/user/hand/left", "/user/hand/left/input/x/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Y click", "/user/hand/left", "/user/hand/left/input/y/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "A click", "/user/hand/right", "/user/hand/right/input/a/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "B click", "/user/hand/right", "/user/hand/right/input/b/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ }
+
+ { // Samsung Odyssey controller
+ const String profile_path = "/interaction_profiles/samsung/odyssey_controller";
+ metadata->register_interaction_profile("Samsung Odyssey controller", profile_path, XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Menu click", user_path, user_path + "/input/menu/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trigger", user_path, user_path + "/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ metadata->register_io_path(profile_path, "Trigger click", user_path, user_path + "/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Squeeze click", user_path, user_path + "/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Thumbstick", user_path, user_path + "/input/thumbstick", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Thumbstick click", user_path, user_path + "/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Up", user_path, user_path + "/input/thumbstick/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Down", user_path, user_path + "/input/thumbstick/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Left", user_path, user_path + "/input/thumbstick/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Thumbstick Dpad Right", user_path, user_path + "/input/thumbstick/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Trackpad", user_path, user_path + "/input/trackpad", "", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ metadata->register_io_path(profile_path, "Trackpad click", user_path, user_path + "/input/trackpad/click", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad touch", user_path, user_path + "/input/trackpad/touch", "", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Up", user_path, user_path + "/input/trackpad/dpad_up", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Down", user_path, user_path + "/input/trackpad/dpad_down", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Left", user_path, user_path + "/input/trackpad/dpad_left", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Right", user_path, user_path + "/input/trackpad/dpad_right", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+ metadata->register_io_path(profile_path, "Trackpad Dpad Center", user_path, user_path + "/input/trackpad/dpad_center", "XR_EXT_dpad_binding", OpenXRAction::OPENXR_ACTION_BOOL);
+
+ metadata->register_io_path(profile_path, "Haptic output", user_path, user_path + "/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ }
+ }
+
+ { // MSFT Hand interaction profile, also supported by other headsets
+ const String profile_path = "/interaction_profiles/microsoft/hand_interaction";
+ metadata->register_interaction_profile("MSFT Hand interaction", profile_path, XR_MSFT_HAND_INTERACTION_EXTENSION_NAME);
+ for (const String user_path : { "/user/hand/left", "/user/hand/right" }) {
+ metadata->register_io_path(profile_path, "Grip pose", user_path, user_path + "/input/grip/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Aim pose", user_path, user_path + "/input/aim/pose", "", OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Pinch pose", user_path, user_path + "/input/pinch_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Poke pose", user_path, user_path + "/input/poke_ext/pose", XR_EXT_HAND_INTERACTION_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+ metadata->register_io_path(profile_path, "Palm pose", user_path, user_path + "/input/palm_ext/pose", XR_EXT_PALM_POSE_EXTENSION_NAME, OpenXRAction::OPENXR_ACTION_POSE);
+
+ metadata->register_io_path(profile_path, "Select (pinch)", user_path, user_path + "/input/select/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+
+ metadata->register_io_path(profile_path, "Squeeze (grab)", user_path, user_path + "/input/squeeze/value", "", OpenXRAction::OPENXR_ACTION_FLOAT);
+ }
+ }
}
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index c67be5a2b313..8215a9ee035c 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -542,11 +542,23 @@ bool OpenXRAPI::create_instance() {
// Set this extension as supported.
*requested_extension.value = true;
- // And record that we want to enable it.
- enabled_extensions.push_back(requested_extension.key.ascii());
+ // And record that we want to enable it (dependent extensions may be requested multiple times).
+ CharString ext_name = requested_extension.key.ascii();
+ if (!enabled_extensions.has(ext_name)) {
+ enabled_extensions.push_back(ext_name);
+ } else {
+ // just testing
+ print_line("Extension " + requested_extension.key + " was already requested.");
+ }
} else {
- // Record that we want to enable this.
- enabled_extensions.push_back(requested_extension.key.ascii());
+ // Record that we want to enable this (dependent extensions may be requested multiple times).
+ CharString ext_name = requested_extension.key.ascii();
+ if (!enabled_extensions.has(ext_name)) {
+ enabled_extensions.push_back(ext_name);
+ } else {
+ // just testing
+ print_line("Extension " + requested_extension.key + " was already requested.");
+ }
}
}
@@ -2763,6 +2775,25 @@ bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const
return false;
}
+XrPath OpenXRAPI::get_xr_path(const String &p_path) {
+ ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, XR_NULL_PATH);
+
+ if (p_path.is_empty()) {
+ // This isn't necesairily an issue, so silently return a null path.
+ return XR_NULL_PATH;
+ }
+
+ XrPath path = XR_NULL_PATH;
+
+ XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &path);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]");
+ return XR_NULL_PATH;
+ }
+
+ return path;
+}
+
RID OpenXRAPI::get_tracker_rid(XrPath p_path) {
List current;
tracker_owner.get_owned_list(¤t);
@@ -2797,11 +2828,8 @@ RID OpenXRAPI::tracker_create(const String p_name) {
new_tracker.toplevel_path = XR_NULL_PATH;
new_tracker.active_profile_rid = RID();
- XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_tracker.toplevel_path);
- if (XR_FAILED(result)) {
- print_line("OpenXR: failed to get path for ", p_name, "! [", get_error_string(result), "]");
- return RID();
- }
+ new_tracker.toplevel_path = get_xr_path(p_name);
+ ERR_FAIL_COND_V(new_tracker.toplevel_path == XR_NULL_PATH, RID());
return tracker_owner.make_rid(new_tracker);
}
@@ -2892,6 +2920,19 @@ RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_n
return action_set_owner.make_rid(action_set);
}
+RID OpenXRAPI::find_action_set(const String p_name) {
+ List current;
+ action_set_owner.get_owned_list(¤t);
+ for (const RID &E : current) {
+ ActionSet *action_set = action_set_owner.get_or_null(E);
+ if (action_set && action_set->name == p_name) {
+ return E;
+ }
+ }
+
+ return RID();
+}
+
String OpenXRAPI::action_set_get_name(RID p_action_set) {
if (p_action_set.is_null()) {
return String("None");
@@ -2903,6 +2944,17 @@ String OpenXRAPI::action_set_get_name(RID p_action_set) {
return action_set->name;
}
+XrActionSet OpenXRAPI::action_set_get_handle(RID p_action_set) {
+ if (p_action_set.is_null()) {
+ return XR_NULL_HANDLE;
+ }
+
+ ActionSet *action_set = action_set_owner.get_or_null(p_action_set);
+ ERR_FAIL_NULL_V(action_set, XR_NULL_HANDLE);
+
+ return action_set->handle;
+}
+
bool OpenXRAPI::attach_action_sets(const Vector &p_action_sets) {
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
@@ -2985,12 +3037,12 @@ RID OpenXRAPI::get_action_rid(XrAction p_action) {
return RID();
}
-RID OpenXRAPI::find_action(const String &p_name) {
+RID OpenXRAPI::find_action(const String &p_name, const RID &p_action_set) {
List current;
action_owner.get_owned_list(¤t);
for (const RID &E : current) {
Action *action = action_owner.get_or_null(E);
- if (action && action->name == p_name) {
+ if (action && action->name == p_name && (p_action_set.is_null() || action->action_set_rid == p_action_set)) {
return E;
}
}
@@ -3080,6 +3132,17 @@ String OpenXRAPI::action_get_name(RID p_action) {
return action->name;
}
+XrAction OpenXRAPI::action_get_handle(RID p_action) {
+ if (p_action.is_null()) {
+ return XR_NULL_HANDLE;
+ }
+
+ Action *action = action_owner.get_or_null(p_action);
+ ERR_FAIL_NULL_V(action, XR_NULL_HANDLE);
+
+ return action->handle;
+}
+
void OpenXRAPI::action_free(RID p_action) {
Action *action = action_owner.get_or_null(p_action);
ERR_FAIL_NULL(action);
@@ -3156,29 +3219,41 @@ void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) {
ip->bindings.clear();
}
-bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {
+int OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) {
InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
- ERR_FAIL_NULL_V(ip, false);
+ ERR_FAIL_NULL_V(ip, -1);
if (!interaction_profile_supports_io_path(ip->name, p_path)) {
- return false;
+ return -1;
}
XrActionSuggestedBinding binding;
Action *action = action_owner.get_or_null(p_action);
- ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, false);
+ ERR_FAIL_COND_V(action == nullptr || action->handle == XR_NULL_HANDLE, -1);
binding.action = action->handle;
XrResult result = xrStringToPath(instance, p_path.utf8().get_data(), &binding.binding);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to get path for ", p_path, "! [", get_error_string(result), "]");
- return false;
+ return -1;
}
ip->bindings.push_back(binding);
+ return ip->bindings.size() - 1;
+}
+
+bool OpenXRAPI::interaction_profile_add_modifier(RID p_interaction_profile, const PackedByteArray &p_modifier) {
+ InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
+ ERR_FAIL_NULL_V(ip, false);
+
+ if (!p_modifier.is_empty()) {
+ // Add it to our stack.
+ ip->modifiers.push_back(p_modifier);
+ }
+
return true;
}
@@ -3188,9 +3263,26 @@ bool OpenXRAPI::interaction_profile_suggest_bindings(RID p_interaction_profile)
InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile);
ERR_FAIL_NULL_V(ip, false);
+ void *next = nullptr;
+
+ // Note, extensions should only add binding modifiers if they are supported, else this may fail.
+ XrBindingModificationsKHR binding_modifiers;
+ Vector modifiers;
+ if (!ip->modifiers.is_empty()) {
+ for (const PackedByteArray &modifier : ip->modifiers) {
+ modifiers.push_back((const XrBindingModificationBaseHeaderKHR *)modifier.ptr());
+ }
+
+ binding_modifiers.type = XR_TYPE_BINDING_MODIFICATIONS_KHR;
+ binding_modifiers.next = next;
+ binding_modifiers.bindingModificationCount = modifiers.size();
+ binding_modifiers.bindingModifications = modifiers.ptr();
+ next = &binding_modifiers;
+ }
+
const XrInteractionProfileSuggestedBinding suggested_bindings = {
XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, // type
- nullptr, // next
+ next, // next
ip->path, // interactionProfile
uint32_t(ip->bindings.size()), // countSuggestedBindings
ip->bindings.ptr() // suggestedBindings
@@ -3229,6 +3321,7 @@ void OpenXRAPI::interaction_profile_free(RID p_interaction_profile) {
ERR_FAIL_NULL(ip);
ip->bindings.clear();
+ ip->modifiers.clear();
interaction_profile_owner.free(p_interaction_profile);
}
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 0d1e4eb414ac..537ce5a4b635 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -300,6 +300,7 @@ class OpenXRAPI {
String name; // Name of the interaction profile (i.e. "/interaction_profiles/valve/index_controller")
XrPath path; // OpenXR path for this profile
Vector bindings; // OpenXR action bindings
+ Vector modifiers; // Array of modifiers we'll add into XrBindingModificationsKHR
};
RID_Owner interaction_profile_owner;
RID get_interaction_profile_rid(XrPath p_path);
@@ -410,8 +411,8 @@ class OpenXRAPI {
XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform);
XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform);
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
-
bool xr_result(XrResult result, const char *format, Array args = Array()) const;
+ XrPath get_xr_path(const String &p_path);
bool is_top_level_path_supported(const String &p_toplevel_path);
bool is_interaction_profile_supported(const String &p_ip_path);
bool interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path);
@@ -515,22 +516,26 @@ class OpenXRAPI {
RID action_set_create(const String p_name, const String p_localized_name, const int p_priority);
String action_set_get_name(RID p_action_set);
+ XrActionSet action_set_get_handle(RID p_action_set);
bool attach_action_sets(const Vector &p_action_sets);
void action_set_free(RID p_action_set);
RID action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector &p_trackers);
String action_get_name(RID p_action);
+ XrAction action_get_handle(RID p_action);
void action_free(RID p_action);
RID interaction_profile_create(const String p_name);
String interaction_profile_get_name(RID p_interaction_profile);
void interaction_profile_clear_bindings(RID p_interaction_profile);
- bool interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path);
+ int interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path);
+ bool interaction_profile_add_modifier(RID p_interaction_profile, const PackedByteArray &p_modifier);
bool interaction_profile_suggest_bindings(RID p_interaction_profile);
void interaction_profile_free(RID p_interaction_profile);
RID find_tracker(const String &p_name);
- RID find_action(const String &p_name);
+ RID find_action_set(const String p_name);
+ RID find_action(const String &p_name, const RID &p_action_set = RID());
bool sync_action_sets(const Vector p_active_sets);
bool get_action_bool(RID p_action, RID p_tracker);
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 500a58acc37b..3c396d36efe8 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -287,6 +287,13 @@ void OpenXRInterface::_load_action_map() {
if (ip.is_valid()) {
openxr_api->interaction_profile_clear_bindings(ip);
+ for (const Ref &xr_binding_modifier : xr_interaction_profile->get_binding_modifiers()) {
+ PackedByteArray bm = xr_binding_modifier->get_ip_modification();
+ if (!bm.is_empty()) {
+ openxr_api->interaction_profile_add_modifier(ip, bm);
+ }
+ }
+
Array xr_bindings = xr_interaction_profile->get_bindings();
for (int j = 0; j < xr_bindings.size(); j++) {
Ref xr_binding = xr_bindings[j];
@@ -300,7 +307,18 @@ void OpenXRInterface::_load_action_map() {
continue;
}
- openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path());
+ int binding_no = openxr_api->interaction_profile_add_binding(ip, action->action_rid, xr_binding->get_binding_path());
+ if (binding_no >= 0) {
+ for (const Ref &xr_binding_modifier : xr_binding->get_binding_modifiers()) {
+ // Binding modifiers on bindings can be added to the interaction profile.
+ PackedByteArray bm = xr_binding_modifier->get_ip_modification();
+ if (!bm.is_empty()) {
+ openxr_api->interaction_profile_add_modifier(ip, bm);
+ }
+
+ // And possibly in the future on the binding itself, we're just preparing for that eventuality.
+ }
+ }
}
// Now submit our suggestions
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index f3fda2517ce6..2a4f4ce6e551 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -33,6 +33,7 @@
#include "action_map/openxr_action.h"
#include "action_map/openxr_action_map.h"
#include "action_map/openxr_action_set.h"
+#include "action_map/openxr_haptic_feedback.h"
#include "action_map/openxr_interaction_profile.h"
#include "action_map/openxr_interaction_profile_metadata.h"
#include "openxr_interface.h"
@@ -49,6 +50,7 @@
#include "extensions/openxr_composition_layer_depth_extension.h"
#include "extensions/openxr_composition_layer_extension.h"
#include "extensions/openxr_debug_utils_extension.h"
+#include "extensions/openxr_dpad_binding_extension.h"
#include "extensions/openxr_eye_gaze_interaction.h"
#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_hand_interaction_extension.h"
@@ -62,6 +64,7 @@
#include "extensions/openxr_mxink_extension.h"
#include "extensions/openxr_palm_pose_extension.h"
#include "extensions/openxr_pico_controller_extension.h"
+#include "extensions/openxr_valve_analog_threshold_extension.h"
#include "extensions/openxr_visibility_mask_extension.h"
#include "extensions/openxr_wmr_controller_extension.h"
@@ -78,6 +81,10 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
+
+#include "editor/openxr_binding_modifier_editor.h"
+#include "editor/openxr_interaction_profile_editor.h"
+
#endif
static OpenXRAPI *openxr_api = nullptr;
@@ -140,6 +147,14 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
if (GLOBAL_GET("xr/openxr/extensions/hand_tracking")) {
OpenXRAPI::register_extension_wrapper(memnew(OpenXRHandTrackingExtension));
}
+
+ // register gated binding modifiers
+ if (GLOBAL_GET("xr/openxr/binding_modifiers/analog_threshold")) {
+ OpenXRAPI::register_extension_wrapper(memnew(OpenXRValveAnalogThresholdExtension));
+ }
+ if (GLOBAL_GET("xr/openxr/binding_modifiers/dpad_binding")) {
+ OpenXRAPI::register_extension_wrapper(memnew(OpenXRDPadBindingExtension));
+ }
}
if (OpenXRAPI::openxr_is_enabled()) {
@@ -181,6 +196,13 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(OpenXRIPBinding);
GDREGISTER_CLASS(OpenXRInteractionProfile);
+ GDREGISTER_ABSTRACT_CLASS(OpenXRBindingModifier);
+ GDREGISTER_CLASS(OpenXRAnalogThresholdModifier);
+ GDREGISTER_CLASS(OpenXRDpadBindingModifier);
+
+ GDREGISTER_ABSTRACT_CLASS(OpenXRHapticBase);
+ GDREGISTER_CLASS(OpenXRHapticVibration);
+
GDREGISTER_ABSTRACT_CLASS(OpenXRCompositionLayer);
GDREGISTER_CLASS(OpenXRCompositionLayerEquirect);
GDREGISTER_CLASS(OpenXRCompositionLayerCylinder);
@@ -201,6 +223,12 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
}
#ifdef TOOLS_ENABLED
+ GDREGISTER_ABSTRACT_CLASS(OpenXRInteractionProfileEditorBase);
+ GDREGISTER_CLASS(OpenXRInteractionProfileEditor);
+ GDREGISTER_ABSTRACT_CLASS(OpenXRBindingModifierEditor);
+ GDREGISTER_CLASS(OpenXRAnalogThresholdEditor);
+ GDREGISTER_CLASS(OpenXRDpadBindingEditor);
+
EditorNode::add_init_callback(_editor_init);
#endif
}
]