26 const char *action_name,
27 const char *profile_path,
28 XrPath subaction_path,
29 const char *subaction_path_str,
30 const GHOST_XrPose &pose)
32 XrActionSpaceCreateInfo action_space_info{XR_TYPE_ACTION_SPACE_CREATE_INFO};
33 action_space_info.action = action;
34 action_space_info.subactionPath = subaction_path;
37 CHECK_XR(xrCreateActionSpace(session, &action_space_info, &space_),
38 (std::string(
"Failed to create space \"") + subaction_path_str +
"\" for action \"" +
39 action_name +
"\" and profile \"" + profile_path +
"\".")
65 GHOST_XrActionType type,
66 const GHOST_XrActionProfileInfo &info)
68 CHECK_XR(xrStringToPath(instance, info.profile_path, &profile_),
69 (std::string(
"Failed to get interaction profile path \"") + info.profile_path +
"\".")
72 const bool is_float_action = (type == GHOST_kXrActionTypeFloatInput ||
73 type == GHOST_kXrActionTypeVector2fInput);
74 const bool is_button_action = (is_float_action || type == GHOST_kXrActionTypeBooleanInput);
75 const bool is_pose_action = (type == GHOST_kXrActionTypePoseInput);
78 XrInteractionProfileSuggestedBinding bindings_info{
79 XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING};
80 bindings_info.interactionProfile = profile_;
81 bindings_info.countSuggestedBindings = 1;
83 for (uint32_t subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
84 const char *subaction_path_str = info.subaction_paths[subaction_idx];
85 const GHOST_XrActionBindingInfo &binding_info = info.bindings[subaction_idx];
87 const std::string interaction_path = std::string(subaction_path_str) +
88 binding_info.component_path;
89 if (bindings_.find(interaction_path) != bindings_.end()) {
93 XrActionSuggestedBinding sbinding;
94 sbinding.action = action;
95 CHECK_XR(xrStringToPath(instance, interaction_path.data(), &sbinding.binding),
96 (std::string(
"Failed to get interaction path \"") + interaction_path +
"\".").data());
97 bindings_info.suggestedBindings = &sbinding;
101 CHECK_XR(xrSuggestInteractionProfileBindings(instance, &bindings_info),
102 (std::string(
"Failed to create binding for action \"") + info.action_name +
103 "\" and profile \"" + info.profile_path +
104 "\". Are the action and profile paths correct?")
107 bindings_.insert({interaction_path, sbinding.binding});
109 if (subaction_data_.find(subaction_path_str) == subaction_data_.end()) {
110 std::map<std::string, GHOST_XrSubactionData>::iterator it =
113 std::piecewise_construct, std::make_tuple(subaction_path_str), std::make_tuple())
118 (std::string(
"Failed to get user path \"") + subaction_path_str +
"\".").data());
120 if (is_float_action || is_button_action) {
121 if (is_float_action) {
124 if (is_button_action) {
125 subaction.
axis_flag = binding_info.axis_flag;
128 else if (is_pose_action) {
130 subaction.
space = std::make_unique<GHOST_XrActionSpace>(session,
158 XrAction action, std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings)
const
160 std::map<XrPath, std::vector<XrActionSuggestedBinding>>::iterator it = r_bindings.find(profile_);
161 if (it == r_bindings.end()) {
162 it = r_bindings.emplace(std::piecewise_construct, std::make_tuple(profile_), std::make_tuple())
166 std::vector<XrActionSuggestedBinding> &sbindings = it->second;
168 for (
auto &[path, binding] : bindings_) {
169 XrActionSuggestedBinding sbinding;
170 sbinding.action = action;
171 sbinding.binding = binding;
173 sbindings.push_back(std::move(sbinding));
185 XrActionSet action_set,
186 const GHOST_XrActionInfo &info)
188 states_(info.states),
189 float_thresholds_(info.float_thresholds),
190 axis_flags_(info.axis_flags),
194 subaction_paths_.resize(info.count_subaction_paths);
196 for (uint32_t
i = 0;
i < info.count_subaction_paths; ++
i) {
197 const char *subaction_path_str = info.subaction_paths[
i];
198 CHECK_XR(xrStringToPath(instance, subaction_path_str, &subaction_paths_[
i]),
199 (std::string(
"Failed to get user path \"") + subaction_path_str +
"\".").
data());
200 subaction_indices_.insert({subaction_path_str,
i});
203 XrActionCreateInfo action_info{XR_TYPE_ACTION_CREATE_INFO};
204 strcpy(action_info.actionName, info.name);
207 strcpy(action_info.localizedActionName, info.name);
210 case GHOST_kXrActionTypeBooleanInput:
211 action_info.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
213 case GHOST_kXrActionTypeFloatInput:
214 action_info.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
216 case GHOST_kXrActionTypeVector2fInput:
217 action_info.actionType = XR_ACTION_TYPE_VECTOR2F_INPUT;
219 case GHOST_kXrActionTypePoseInput:
220 action_info.actionType = XR_ACTION_TYPE_POSE_INPUT;
222 case GHOST_kXrActionTypeVibrationOutput:
223 action_info.actionType = XR_ACTION_TYPE_VIBRATION_OUTPUT;
226 action_info.countSubactionPaths = info.count_subaction_paths;
227 action_info.subactionPaths = subaction_paths_.data();
229 CHECK_XR(xrCreateAction(action_set, &action_info, &action_),
230 (std::string(
"Failed to create action \"") + info.name +
231 "\". Action name and/or paths are invalid. Name must not contain upper "
232 "case letters or special characters other than '-', '_', or '.'.")
245 const GHOST_XrActionProfileInfo &info)
247 if (profiles_.find(info.profile_path) != profiles_.end()) {
251 profiles_.emplace(std::piecewise_construct,
252 std::make_tuple(info.profile_path),
253 std::make_tuple(instance, session, action_, type_, info));
265 const char *action_name,
266 XrSpace reference_space,
267 const XrTime &predicted_display_time)
269 const bool is_float_action = (type_ == GHOST_kXrActionTypeFloatInput ||
270 type_ == GHOST_kXrActionTypeVector2fInput);
271 const bool is_button_action = (is_float_action || type_ == GHOST_kXrActionTypeBooleanInput);
273 XrActionStateGetInfo state_info{XR_TYPE_ACTION_STATE_GET_INFO};
274 state_info.action = action_;
276 const size_t count_subaction_paths = subaction_paths_.size();
277 for (
size_t subaction_idx = 0; subaction_idx < count_subaction_paths; ++subaction_idx) {
278 state_info.subactionPath = subaction_paths_[subaction_idx];
281 XrInteractionProfileState profile_state{XR_TYPE_INTERACTION_PROFILE_STATE};
282 CHECK_XR(xrGetCurrentInteractionProfile(session, state_info.subactionPath, &profile_state),
283 "Failed to get current interaction profile.");
286 for (
auto &[profile_path, profile] : profiles_) {
287 if (profile.getProfile() == profile_state.interactionProfile) {
288 subaction = profile.getSubaction(state_info.subactionPath);
293 if (subaction !=
nullptr) {
294 if (is_float_action) {
297 if (is_button_action) {
298 axis_flags_[subaction_idx] = subaction->
axis_flag;
303 case GHOST_kXrActionTypeBooleanInput: {
304 XrActionStateBoolean
state{XR_TYPE_ACTION_STATE_BOOLEAN};
305 CHECK_XR(xrGetActionStateBoolean(session, &state_info, &
state),
306 (std::string(
"Failed to get state for boolean action \"") + action_name +
"\".")
308 if (
state.isActive) {
309 ((
bool *)states_)[subaction_idx] =
state.currentState;
313 case GHOST_kXrActionTypeFloatInput: {
314 XrActionStateFloat
state{XR_TYPE_ACTION_STATE_FLOAT};
316 xrGetActionStateFloat(session, &state_info, &
state),
317 (std::string(
"Failed to get state for float action \"") + action_name +
"\".").
data());
318 if (
state.isActive) {
319 ((
float *)states_)[subaction_idx] =
state.currentState;
323 case GHOST_kXrActionTypeVector2fInput: {
324 XrActionStateVector2f
state{XR_TYPE_ACTION_STATE_VECTOR2F};
325 CHECK_XR(xrGetActionStateVector2f(session, &state_info, &
state),
326 (std::string(
"Failed to get state for vector2f action \"") + action_name +
"\".")
328 if (
state.isActive) {
329 memcpy(((
float (*)[2])states_)[subaction_idx], &
state.currentState,
sizeof(
float[2]));
333 case GHOST_kXrActionTypePoseInput: {
335 if (predicted_display_time > 0) {
336 XrActionStatePose
state{XR_TYPE_ACTION_STATE_POSE};
338 (std::string(
"Failed to get state for pose action \"") + action_name +
"\".")
340 ((GHOST_XrPose *)states_)[subaction_idx].is_active =
state.isActive;
341 if (
state.isActive) {
342 XrSpace pose_space = ((subaction !=
nullptr) && (subaction->
space !=
nullptr)) ?
343 subaction->
space->getSpace() :
345 if (pose_space != XR_NULL_HANDLE) {
346 XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
349 pose_space, reference_space, predicted_display_time, &space_location),
350 (std::string(
"Failed to query pose space for action \"") + action_name +
"\".")
353 ((GHOST_XrPose *)states_)[subaction_idx]);
359 case GHOST_kXrActionTypeVibrationOutput: {
367 const char *action_name,
368 const char *subaction_path_str,
370 const float &frequency,
371 const float &litude)
373 XrHapticVibration vibration{XR_TYPE_HAPTIC_VIBRATION};
374 vibration.duration = (duration == 0) ? XR_MIN_HAPTIC_DURATION :
375 static_cast<XrDuration
>(duration);
376 vibration.frequency = frequency;
377 vibration.amplitude = amplitude;
379 XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
380 haptic_info.action = action_;
382 if (subaction_path_str !=
nullptr) {
383 SubactionIndexMap::iterator it = subaction_indices_.find(subaction_path_str);
384 if (it != subaction_indices_.end()) {
385 haptic_info.subactionPath = subaction_paths_[it->second];
387 xrApplyHapticFeedback(session, &haptic_info, (
const XrHapticBaseHeader *)&vibration),
388 (std::string(
"Failed to apply haptic action \"") + action_name +
"\".").
data());
392 for (
const XrPath &subaction_path : subaction_paths_) {
393 haptic_info.subactionPath = subaction_path;
395 xrApplyHapticFeedback(session, &haptic_info, (
const XrHapticBaseHeader *)&vibration),
396 (std::string(
"Failed to apply haptic action \"") + action_name +
"\".").
data());
402 const char *action_name,
403 const char *subaction_path_str)
405 XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
406 haptic_info.action = action_;
408 if (subaction_path_str !=
nullptr) {
409 SubactionIndexMap::iterator it = subaction_indices_.find(subaction_path_str);
410 if (it != subaction_indices_.end()) {
411 haptic_info.subactionPath = subaction_paths_[it->second];
412 CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
413 (std::string(
"Failed to stop haptic action \"") + action_name +
"\".").
data());
417 for (
const XrPath &subaction_path : subaction_paths_) {
418 haptic_info.subactionPath = subaction_path;
419 CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
420 (std::string(
"Failed to stop haptic action \"") + action_name +
"\".").
data());
452 XrActionSetCreateInfo action_set_info{XR_TYPE_ACTION_SET_CREATE_INFO};
453 strcpy(action_set_info.actionSetName, info.name);
456 strcpy(action_set_info.localizedActionSetName, info.name);
458 action_set_info.priority = 0;
460 CHECK_XR(xrCreateActionSet(instance, &action_set_info, &action_set_),
461 (std::string(
"Failed to create action set \"") + info.name +
462 "\". Name must not contain upper case letters or special characters "
463 "other than '-', '_', or '.'.")
480 if (actions_.find(info.name) != actions_.end()) {
484 actions_.emplace(std::piecewise_construct,
485 std::make_tuple(info.name),
486 std::make_tuple(instance, action_set_, info));