Path: blob/master/modules/openxr/action_map/openxr_action_map.cpp
10278 views
/**************************************************************************/1/* openxr_action_map.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "openxr_action_map.h"3132void OpenXRActionMap::_bind_methods() {33ClassDB::bind_method(D_METHOD("set_action_sets", "action_sets"), &OpenXRActionMap::set_action_sets);34ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets);35ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets");3637ClassDB::bind_method(D_METHOD("get_action_set_count"), &OpenXRActionMap::get_action_set_count);38ClassDB::bind_method(D_METHOD("find_action_set", "name"), &OpenXRActionMap::find_action_set);39ClassDB::bind_method(D_METHOD("get_action_set", "idx"), &OpenXRActionMap::get_action_set);40ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set);41ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set);4243ClassDB::bind_method(D_METHOD("set_interaction_profiles", "interaction_profiles"), &OpenXRActionMap::set_interaction_profiles);44ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles);45ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles");4647ClassDB::bind_method(D_METHOD("get_interaction_profile_count"), &OpenXRActionMap::get_interaction_profile_count);48ClassDB::bind_method(D_METHOD("find_interaction_profile", "name"), &OpenXRActionMap::find_interaction_profile);49ClassDB::bind_method(D_METHOD("get_interaction_profile", "idx"), &OpenXRActionMap::get_interaction_profile);50ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile);51ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile);5253ClassDB::bind_method(D_METHOD("create_default_action_sets"), &OpenXRActionMap::create_default_action_sets);54}5556void OpenXRActionMap::set_action_sets(Array p_action_sets) {57action_sets.clear();5859for (int i = 0; i < p_action_sets.size(); i++) {60Ref<OpenXRActionSet> action_set = p_action_sets[i];61if (action_set.is_valid() && !action_sets.has(action_set)) {62action_sets.push_back(action_set);63}64}65}6667Array OpenXRActionMap::get_action_sets() const {68return action_sets;69}7071int OpenXRActionMap::get_action_set_count() const {72return action_sets.size();73}7475Ref<OpenXRActionSet> OpenXRActionMap::find_action_set(String p_name) const {76for (int i = 0; i < action_sets.size(); i++) {77Ref<OpenXRActionSet> action_set = action_sets[i];78if (action_set->get_name() == p_name) {79return action_set;80}81}8283return Ref<OpenXRActionSet>();84}8586Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const {87ERR_FAIL_INDEX_V(p_idx, action_sets.size(), Ref<OpenXRActionSet>());8889return action_sets[p_idx];90}9192void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {93ERR_FAIL_COND(p_action_set.is_null());9495if (!action_sets.has(p_action_set)) {96action_sets.push_back(p_action_set);97emit_changed();98}99}100101void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {102int idx = action_sets.find(p_action_set);103if (idx != -1) {104action_sets.remove_at(idx);105emit_changed();106}107}108109void OpenXRActionMap::clear_interaction_profiles() {110if (interaction_profiles.is_empty()) {111return;112}113114// Interaction profiles held within our action map set should be released and destroyed but just in case they are still used some where else.115for (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {116interaction_profile->action_map = nullptr;117}118interaction_profiles.clear();119emit_changed();120}121122void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {123clear_interaction_profiles();124125for (const Variant &interaction_profile : p_interaction_profiles) {126// Add them anew so we verify our interaction profile pointer.127add_interaction_profile(interaction_profile);128}129}130131Array OpenXRActionMap::get_interaction_profiles() const {132return interaction_profiles;133}134135int OpenXRActionMap::get_interaction_profile_count() const {136return interaction_profiles.size();137}138139Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const {140for (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {141if (interaction_profile->get_interaction_profile_path() == p_path) {142return interaction_profile;143}144}145146return Ref<OpenXRInteractionProfile>();147}148149Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx) const {150ERR_FAIL_INDEX_V(p_idx, interaction_profiles.size(), Ref<OpenXRInteractionProfile>());151152return interaction_profiles[p_idx];153}154155void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {156ERR_FAIL_COND(p_interaction_profile.is_null());157158if (!interaction_profiles.has(p_interaction_profile)) {159if (p_interaction_profile->action_map && p_interaction_profile->action_map != this) {160// Interaction profiles should only relate to our action map.161p_interaction_profile->action_map->remove_interaction_profile(p_interaction_profile);162}163164p_interaction_profile->action_map = this;165166interaction_profiles.push_back(p_interaction_profile);167emit_changed();168}169}170171void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {172int idx = interaction_profiles.find(p_interaction_profile);173if (idx != -1) {174interaction_profiles.remove_at(idx);175176ERR_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!177p_interaction_profile->action_map = nullptr;178179emit_changed();180}181}182183void OpenXRActionMap::create_default_action_sets() {184// Note:185// - if you make changes here make sure to delete your default_action_map.tres file of it will load an old version.186// - our palm pose is only available if the relevant extension is supported,187// we still want it to be part of our action map as we may deploy the same game to platforms that do and don't support it.188// - the same applies for interaction profiles that are only supported if the relevant extension is supported.189190// Create our Godot action set.191Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set");192add_action_set(action_set);193194// Create our actions.195Ref<OpenXRAction> trigger = action_set->add_new_action("trigger", "Trigger", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");196Ref<OpenXRAction> trigger_click = action_set->add_new_action("trigger_click", "Trigger click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");197Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");198Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");199Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");200Ref<OpenXRAction> grip_force = action_set->add_new_action("grip_force", "Grip force", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");201Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");202Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");203Ref<OpenXRAction> primary_touch = action_set->add_new_action("primary_touch", "Primary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");204Ref<OpenXRAction> secondary = action_set->add_new_action("secondary", "Secondary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");205Ref<OpenXRAction> secondary_click = action_set->add_new_action("secondary_click", "Secondary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");206Ref<OpenXRAction> secondary_touch = action_set->add_new_action("secondary_touch", "Secondary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");207Ref<OpenXRAction> menu_button = action_set->add_new_action("menu_button", "Menu button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");208Ref<OpenXRAction> select_button = action_set->add_new_action("select_button", "Select button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");209Ref<OpenXRAction> ax_button = action_set->add_new_action("ax_button", "A/X button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");210Ref<OpenXRAction> ax_touch = action_set->add_new_action("ax_touch", "A/X touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");211Ref<OpenXRAction> by_button = action_set->add_new_action("by_button", "B/Y button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");212Ref<OpenXRAction> by_touch = action_set->add_new_action("by_touch", "B/Y touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");213Ref<OpenXRAction> default_pose = action_set->add_new_action("default_pose", "Default pose", OpenXRAction::OPENXR_ACTION_POSE,214"/user/hand/left,"215"/user/hand/right,"216// "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one.217"/user/vive_tracker_htcx/role/left_foot,"218"/user/vive_tracker_htcx/role/right_foot,"219"/user/vive_tracker_htcx/role/left_shoulder,"220"/user/vive_tracker_htcx/role/right_shoulder,"221"/user/vive_tracker_htcx/role/left_elbow,"222"/user/vive_tracker_htcx/role/right_elbow,"223"/user/vive_tracker_htcx/role/left_knee,"224"/user/vive_tracker_htcx/role/right_knee,"225"/user/vive_tracker_htcx/role/waist,"226"/user/vive_tracker_htcx/role/chest,"227"/user/vive_tracker_htcx/role/camera,"228"/user/vive_tracker_htcx/role/keyboard,"229"/user/vive_tracker_htcx/role/left_wrist,"230"/user/vive_tracker_htcx/role/right_wrist,"231"/user/vive_tracker_htcx/role/left_ankle,"232"/user/vive_tracker_htcx/role/right_ankle,"233"/user/eyes_ext");234Ref<OpenXRAction> aim_pose = action_set->add_new_action("aim_pose", "Aim pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");235Ref<OpenXRAction> grip_pose = action_set->add_new_action("grip_pose", "Grip pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");236Ref<OpenXRAction> palm_pose = action_set->add_new_action("palm_pose", "Palm pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");237Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC,238"/user/hand/left,"239"/user/hand/right,"240// "/user/vive_tracker_htcx/role/handheld_object," <-- getting errors on this one.241"/user/vive_tracker_htcx/role/left_foot,"242"/user/vive_tracker_htcx/role/right_foot,"243"/user/vive_tracker_htcx/role/left_shoulder,"244"/user/vive_tracker_htcx/role/right_shoulder,"245"/user/vive_tracker_htcx/role/left_elbow,"246"/user/vive_tracker_htcx/role/right_elbow,"247"/user/vive_tracker_htcx/role/left_knee,"248"/user/vive_tracker_htcx/role/right_knee,"249"/user/vive_tracker_htcx/role/waist,"250"/user/vive_tracker_htcx/role/chest,"251"/user/vive_tracker_htcx/role/camera,"252"/user/vive_tracker_htcx/role/keyboard,"253"/user/vive_tracker_htcx/role/left_wrist,"254"/user/vive_tracker_htcx/role/right_wrist,"255"/user/vive_tracker_htcx/role/left_ankle,"256"/user/vive_tracker_htcx/role/right_ankle");257258// Create our interaction profiles.259Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller");260profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");261profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");262profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");263profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");264profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");265profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click");266// generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs.267profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");268add_interaction_profile(profile);269270// Create our Vive controller profile.271profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller");272profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");273profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");274profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");275profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");276profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");277profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click");278// wmr controller has no a/b/x/y buttons.279profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");280profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");281profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float.282profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");283// primary on our vive controller is our trackpad.284profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");285profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");286profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");287// vive controllers have no secondary input.288profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");289add_interaction_profile(profile);290291// Create our WMR controller profile.292profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller");293profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");294profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");295profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");296profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");297// wmr controllers have no select button we can use.298profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");299// wmr controller has no a/b/x/y buttons.300profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");301profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will convert float to bool.302profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float.303profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");304// primary on our wmr controller is our thumbstick, no touch.305profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");306profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");307// secondary on our wmr controller is our trackpad.308profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");309profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");310profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");311profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");312add_interaction_profile(profile);313314// Create our Meta touch controller profile.315profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller");316profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");317profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");318profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");319profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");320// touch controllers have no select button we can use.321profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available.322profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.323profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch");324profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.325profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch");326profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");327profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean.328profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");329profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean.330profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");331// primary on our touch controller is our thumbstick.332profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");333profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");334profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");335// touch controller has no secondary input.336profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");337add_interaction_profile(profile);338339// Create our Pico 4 controller profile.340profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/bytedance/pico4_controller");341profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");342profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");343profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");344profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");345profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click"); // system click may not be available.346profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");347profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.348profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch");349profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.350profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch");351profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");352profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean.353profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");354profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean.355profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");356// primary on our pico controller is our thumbstick.357profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");358profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");359profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");360// pico controller has no secondary input.361profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");362add_interaction_profile(profile);363364// Create our Valve index controller profile.365profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller");366profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");367profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");368profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");369profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");370// index controllers have no select button we can use.371profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click");372profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers.373profile->add_new_binding(ax_touch, "/user/hand/left/input/a/touch,/user/hand/right/input/a/touch");374profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers.375profile->add_new_binding(by_touch, "/user/hand/left/input/b/touch,/user/hand/right/input/b/touch");376profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");377profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");378profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");379profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");380profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion.381profile->add_new_binding(grip_force, "/user/hand/left/input/squeeze/force,/user/hand/right/input/squeeze/force"); // grip force seems to be unique to the Valve Index.382// primary on our index controller is our thumbstick.383profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");384profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");385profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");386// secondary on our index controller is our trackpad.387profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");388profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/force,/user/hand/right/input/trackpad/force"); // not sure if this will work but doesn't seem to support click...389profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");390profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");391add_interaction_profile(profile);392393// Create our HP MR controller profile.394profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");395profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");396profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");397profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");398profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");399// hpmr controllers have no select button we can use.400profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");401// hpmr controllers only register click, not touch, on our a/b/x/y buttons.402profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.403profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.404profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");405profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");406profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");407profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");408// primary on our hpmr controller is our thumbstick.409profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");410profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");411// No secondary on our hpmr controller.412profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");413add_interaction_profile(profile);414415// Create our Samsung Odyssey controller profile,416// Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller.417profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller");418profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");419profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");420profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");421profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");422// Odyssey controllers have no select button we can use.423profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");424// Odyssey controller has no a/b/x/y buttons.425profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");426profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");427profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");428profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");429// primary on our Odyssey controller is our thumbstick, no touch.430profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");431profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");432// secondary on our Odyssey controller is our trackpad.433profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");434profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");435profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");436profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");437add_interaction_profile(profile);438439// Create our Vive Cosmos controller.440profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller");441profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");442profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");443profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");444profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");445profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");446profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select.447profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.448profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.449profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");450profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");451profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");452profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");453// primary on our Cosmos controller is our thumbstick.454profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");455profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");456profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");457// No secondary on our cosmos controller.458profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");459add_interaction_profile(profile);460461// Create our Vive Focus 3 controller.462// Note, Vive Focus 3 currently is not yet supported as a stand alone device463// however HTC currently has a beta OpenXR runtime in testing we may support in the near future.464profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller");465profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");466profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");467profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");468profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");469profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");470profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select.471profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand.472profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand.473profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");474profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");475profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");476profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");477profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");478// primary on our Focus 3 controller is our thumbstick.479profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");480profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");481profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");482// We only have a thumb rest.483profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch");484profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");485add_interaction_profile(profile);486487// Create our Huawei controller.488profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller");489profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");490profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");491profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");492profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");493profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click");494profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");495profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");496// primary on our Huawei controller is our trackpad.497profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");498profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");499profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");500profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");501add_interaction_profile(profile);502503// Create our HTC Vive tracker profile.504profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_tracker_htcx");505profile->add_new_binding(default_pose,506// "/user/vive_tracker_htcx/role/handheld_object/input/grip/pose," <-- getting errors on this one.507"/user/vive_tracker_htcx/role/left_foot/input/grip/pose,"508"/user/vive_tracker_htcx/role/right_foot/input/grip/pose,"509"/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose,"510"/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose,"511"/user/vive_tracker_htcx/role/left_elbow/input/grip/pose,"512"/user/vive_tracker_htcx/role/right_elbow/input/grip/pose,"513"/user/vive_tracker_htcx/role/left_knee/input/grip/pose,"514"/user/vive_tracker_htcx/role/right_knee/input/grip/pose,"515"/user/vive_tracker_htcx/role/waist/input/grip/pose,"516"/user/vive_tracker_htcx/role/chest/input/grip/pose,"517"/user/vive_tracker_htcx/role/camera/input/grip/pose,"518"/user/vive_tracker_htcx/role/keyboard/input/grip/pose,"519"/user/vive_tracker_htcx/role/left_wrist/input/grip/pose,"520"/user/vive_tracker_htcx/role/right_wrist/input/grip/pose,"521"/user/vive_tracker_htcx/role/left_ankle/input/grip/pose,"522"/user/vive_tracker_htcx/role/right_ankle/input/grip/pose");523profile->add_new_binding(haptic,524// "/user/vive_tracker_htcx/role/handheld_object/output/haptic," <-- getting errors on this one.525"/user/vive_tracker_htcx/role/left_foot/output/haptic,"526"/user/vive_tracker_htcx/role/right_foot/output/haptic,"527"/user/vive_tracker_htcx/role/left_shoulder/output/haptic,"528"/user/vive_tracker_htcx/role/right_shoulder/output/haptic,"529"/user/vive_tracker_htcx/role/left_elbow/output/haptic,"530"/user/vive_tracker_htcx/role/right_elbow/output/haptic,"531"/user/vive_tracker_htcx/role/left_knee/output/haptic,"532"/user/vive_tracker_htcx/role/right_knee/output/haptic,"533"/user/vive_tracker_htcx/role/waist/output/haptic,"534"/user/vive_tracker_htcx/role/chest/output/haptic,"535"/user/vive_tracker_htcx/role/camera/output/haptic,"536"/user/vive_tracker_htcx/role/keyboard/output/haptic,"537"/user/vive_tracker_htcx/role/left_wrist/output/haptic,"538"/user/vive_tracker_htcx/role/right_wrist/output/haptic,"539"/user/vive_tracker_htcx/role/left_ankle/output/haptic,"540"/user/vive_tracker_htcx/role/right_ankle/output/haptic");541add_interaction_profile(profile);542543// Create our eye gaze interaction profile.544profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/ext/eye_gaze_interaction");545profile->add_new_binding(default_pose, "/user/eyes_ext/input/gaze_ext/pose");546add_interaction_profile(profile);547548// Create our hand interaction profile.549profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/ext/hand_interaction_ext");550profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");551profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");552profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");553profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");554555// Use pinch as primary.556profile->add_new_binding(primary, "/user/hand/left/input/pinch_ext/value,/user/hand/right/input/pinch_ext/value");557profile->add_new_binding(primary_click, "/user/hand/left/input/pinch_ext/ready_ext,/user/hand/right/input/pinch_ext/ready_ext");558559// Use activation as secondary.560profile->add_new_binding(secondary, "/user/hand/left/input/aim_activate_ext/value,/user/hand/right/input/aim_activate_ext/value");561profile->add_new_binding(secondary_click, "/user/hand/left/input/aim_activate_ext/ready_ext,/user/hand/right/input/aim_activate_ext/ready_ext");562563// We link grasp to our grip.564profile->add_new_binding(grip, "/user/hand/left/input/grasp_ext/value,/user/hand/right/input/grasp_ext/value");565profile->add_new_binding(grip_click, "/user/hand/left/input/grasp_ext/ready_ext,/user/hand/right/input/grasp_ext/ready_ext");566add_interaction_profile(profile);567}568569void OpenXRActionMap::create_editor_action_sets() {570// TODO implement571}572573Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const {574PackedStringArray paths = p_path.split("/", false);575ERR_FAIL_COND_V(paths.size() != 2, Ref<OpenXRAction>());576577Ref<OpenXRActionSet> action_set = find_action_set(paths[0]);578if (action_set.is_valid()) {579return action_set->get_action(paths[1]);580}581582return Ref<OpenXRAction>();583}584585void OpenXRActionMap::remove_action(const String p_path, bool p_remove_interaction_profiles) {586Ref<OpenXRAction> action = get_action(p_path);587if (action.is_valid()) {588for (Ref<OpenXRInteractionProfile> interaction_profile : interaction_profiles) {589if (p_remove_interaction_profiles) {590// Remove any bindings for this action591interaction_profile->remove_binding_for_action(action);592} else {593ERR_FAIL_COND(interaction_profile->has_binding_for_action(action));594}595}596597OpenXRActionSet *action_set = action->get_action_set();598if (action_set != nullptr) {599// Remove the action from this action set600action_set->remove_action(action);601}602}603}604605PackedStringArray OpenXRActionMap::get_top_level_paths(const Ref<OpenXRAction> p_action) {606PackedStringArray arr;607608for (Ref<OpenXRInteractionProfile> ip : interaction_profiles) {609const OpenXRInteractionProfileMetadata::InteractionProfile *profile = OpenXRInteractionProfileMetadata::get_singleton()->get_profile(ip->get_interaction_profile_path());610611if (profile != nullptr) {612Vector<Ref<OpenXRIPBinding>> bindings = ip->get_bindings_for_action(p_action);613for (const Ref<OpenXRIPBinding> &binding : bindings) {614String binding_path = binding->get_binding_path();615const OpenXRInteractionProfileMetadata::IOPath *io_path = profile->get_io_path(binding_path);616if (io_path != nullptr) {617String top_path = io_path->top_level_path;618619if (!arr.has(top_path)) {620arr.push_back(top_path);621}622}623}624}625}626627// print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr);628629return arr;630}631632OpenXRActionMap::~OpenXRActionMap() {633action_sets.clear();634clear_interaction_profiles();635}636637638