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, &m_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, &m_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 = m_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 (m_bindings.find(interaction_path) != m_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 m_bindings.insert({interaction_path, sbinding.binding});
109 if (m_subaction_data.find(subaction_path_str) == m_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(
162 if (it == r_bindings.end()) {
164 .emplace(std::piecewise_construct, std::make_tuple(m_profile), std::make_tuple())
168 std::vector<XrActionSuggestedBinding> &sbindings = it->second;
170 for (
auto &[path, binding] : m_bindings) {
171 XrActionSuggestedBinding sbinding;
172 sbinding.action = action;
173 sbinding.binding = binding;
175 sbindings.push_back(std::move(sbinding));
187 XrActionSet action_set,
188 const GHOST_XrActionInfo &info)
190 m_states(info.states),
191 m_float_thresholds(info.float_thresholds),
192 m_axis_flags(info.axis_flags),
196 m_subaction_paths.resize(info.count_subaction_paths);
198 for (
uint32_t i = 0; i < info.count_subaction_paths; ++i) {
199 const char *subaction_path_str = info.subaction_paths[i];
200 CHECK_XR(xrStringToPath(instance, subaction_path_str, &m_subaction_paths[i]),
201 (std::string(
"Failed to get user path \"") + subaction_path_str +
"\".").
data());
202 m_subaction_indices.insert({subaction_path_str, i});
205 XrActionCreateInfo action_info{XR_TYPE_ACTION_CREATE_INFO};
206 strcpy(action_info.actionName, info.name);
209 strcpy(action_info.localizedActionName, info.name);
212 case GHOST_kXrActionTypeBooleanInput:
213 action_info.actionType = XR_ACTION_TYPE_BOOLEAN_INPUT;
215 case GHOST_kXrActionTypeFloatInput:
216 action_info.actionType = XR_ACTION_TYPE_FLOAT_INPUT;
218 case GHOST_kXrActionTypeVector2fInput:
219 action_info.actionType = XR_ACTION_TYPE_VECTOR2F_INPUT;
221 case GHOST_kXrActionTypePoseInput:
222 action_info.actionType = XR_ACTION_TYPE_POSE_INPUT;
224 case GHOST_kXrActionTypeVibrationOutput:
225 action_info.actionType = XR_ACTION_TYPE_VIBRATION_OUTPUT;
228 action_info.countSubactionPaths = info.count_subaction_paths;
229 action_info.subactionPaths = m_subaction_paths.data();
231 CHECK_XR(xrCreateAction(action_set, &action_info, &m_action),
232 (std::string(
"Failed to create action \"") + info.name +
233 "\". Action name and/or paths are invalid. Name must not contain upper "
234 "case letters or special characters other than '-', '_', or '.'.")
247 const GHOST_XrActionProfileInfo &info)
249 if (m_profiles.find(info.profile_path) != m_profiles.end()) {
253 m_profiles.emplace(std::piecewise_construct,
254 std::make_tuple(info.profile_path),
255 std::make_tuple(instance, session, m_action, m_type, info));
267 const char *action_name,
268 XrSpace reference_space,
269 const XrTime &predicted_display_time)
271 const bool is_float_action = (m_type == GHOST_kXrActionTypeFloatInput ||
272 m_type == GHOST_kXrActionTypeVector2fInput);
273 const bool is_button_action = (is_float_action || m_type == GHOST_kXrActionTypeBooleanInput);
275 XrActionStateGetInfo state_info{XR_TYPE_ACTION_STATE_GET_INFO};
276 state_info.action = m_action;
278 const size_t count_subaction_paths = m_subaction_paths.size();
279 for (
size_t subaction_idx = 0; subaction_idx < count_subaction_paths; ++subaction_idx) {
280 state_info.subactionPath = m_subaction_paths[subaction_idx];
283 XrInteractionProfileState profile_state{XR_TYPE_INTERACTION_PROFILE_STATE};
284 CHECK_XR(xrGetCurrentInteractionProfile(session, state_info.subactionPath, &profile_state),
285 "Failed to get current interaction profile.");
288 for (
auto &[profile_path, profile] : m_profiles) {
289 if (profile.getProfile() == profile_state.interactionProfile) {
290 subaction = profile.getSubaction(state_info.subactionPath);
295 if (subaction !=
nullptr) {
296 if (is_float_action) {
299 if (is_button_action) {
300 m_axis_flags[subaction_idx] = subaction->
axis_flag;
305 case GHOST_kXrActionTypeBooleanInput: {
306 XrActionStateBoolean
state{XR_TYPE_ACTION_STATE_BOOLEAN};
307 CHECK_XR(xrGetActionStateBoolean(session, &state_info, &
state),
308 (std::string(
"Failed to get state for boolean action \"") + action_name +
"\".")
310 if (
state.isActive) {
311 ((
bool *)m_states)[subaction_idx] =
state.currentState;
315 case GHOST_kXrActionTypeFloatInput: {
316 XrActionStateFloat
state{XR_TYPE_ACTION_STATE_FLOAT};
318 xrGetActionStateFloat(session, &state_info, &
state),
319 (std::string(
"Failed to get state for float action \"") + action_name +
"\".").
data());
320 if (
state.isActive) {
321 ((
float *)m_states)[subaction_idx] =
state.currentState;
325 case GHOST_kXrActionTypeVector2fInput: {
326 XrActionStateVector2f
state{XR_TYPE_ACTION_STATE_VECTOR2F};
327 CHECK_XR(xrGetActionStateVector2f(session, &state_info, &
state),
328 (std::string(
"Failed to get state for vector2f action \"") + action_name +
"\".")
330 if (
state.isActive) {
331 memcpy(((
float(*)[2])m_states)[subaction_idx], &
state.currentState,
sizeof(
float[2]));
335 case GHOST_kXrActionTypePoseInput: {
337 if (predicted_display_time > 0) {
338 XrActionStatePose
state{XR_TYPE_ACTION_STATE_POSE};
340 (std::string(
"Failed to get state for pose action \"") + action_name +
"\".")
342 ((GHOST_XrPose *)m_states)[subaction_idx].is_active =
state.isActive;
343 if (
state.isActive) {
344 XrSpace pose_space = ((subaction !=
nullptr) && (subaction->
space !=
nullptr)) ?
345 subaction->
space->getSpace() :
347 if (pose_space != XR_NULL_HANDLE) {
348 XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
351 pose_space, reference_space, predicted_display_time, &space_location),
352 (std::string(
"Failed to query pose space for action \"") + action_name +
"\".")
355 ((GHOST_XrPose *)m_states)[subaction_idx]);
361 case GHOST_kXrActionTypeVibrationOutput: {
369 const char *action_name,
370 const char *subaction_path_str,
372 const float &frequency,
373 const float &litude)
375 XrHapticVibration vibration{XR_TYPE_HAPTIC_VIBRATION};
376 vibration.duration = (duration == 0) ? XR_MIN_HAPTIC_DURATION :
377 static_cast<XrDuration
>(duration);
378 vibration.frequency = frequency;
379 vibration.amplitude = amplitude;
381 XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
382 haptic_info.action = m_action;
384 if (subaction_path_str !=
nullptr) {
385 SubactionIndexMap::iterator it = m_subaction_indices.find(subaction_path_str);
386 if (it != m_subaction_indices.end()) {
387 haptic_info.subactionPath = m_subaction_paths[it->second];
389 xrApplyHapticFeedback(session, &haptic_info, (
const XrHapticBaseHeader *)&vibration),
390 (std::string(
"Failed to apply haptic action \"") + action_name +
"\".").
data());
394 for (
const XrPath &subaction_path : m_subaction_paths) {
395 haptic_info.subactionPath = subaction_path;
397 xrApplyHapticFeedback(session, &haptic_info, (
const XrHapticBaseHeader *)&vibration),
398 (std::string(
"Failed to apply haptic action \"") + action_name +
"\".").
data());
404 const char *action_name,
405 const char *subaction_path_str)
407 XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
408 haptic_info.action = m_action;
410 if (subaction_path_str !=
nullptr) {
411 SubactionIndexMap::iterator it = m_subaction_indices.find(subaction_path_str);
412 if (it != m_subaction_indices.end()) {
413 haptic_info.subactionPath = m_subaction_paths[it->second];
414 CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
415 (std::string(
"Failed to stop haptic action \"") + action_name +
"\".").
data());
419 for (
const XrPath &subaction_path : m_subaction_paths) {
420 haptic_info.subactionPath = subaction_path;
421 CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
422 (std::string(
"Failed to stop haptic action \"") + action_name +
"\".").
data());
454 XrActionSetCreateInfo action_set_info{XR_TYPE_ACTION_SET_CREATE_INFO};
455 strcpy(action_set_info.actionSetName, info.name);
458 strcpy(action_set_info.localizedActionSetName, info.name);
460 action_set_info.priority = 0;
462 CHECK_XR(xrCreateActionSet(instance, &action_set_info, &m_action_set),
463 (std::string(
"Failed to create action set \"") + info.name +
464 "\". Name must not contain upper case letters or special characters "
465 "other than '-', '_', or '.'.")
482 if (m_actions.find(info.name) != m_actions.end()) {
486 m_actions.emplace(std::piecewise_construct,
487 std::make_tuple(info.name),
488 std::make_tuple(instance, m_action_set, info));