mirror of https://github.com/wayvr-org/wayvr.git
move bindings const to wlx-common, cleanups
This commit is contained in:
parent
b906bc6656
commit
a3b1fdcd0d
|
|
@ -49,15 +49,21 @@
|
|||
"Y_AXIS": "Y axis"
|
||||
},
|
||||
"TYPE": {
|
||||
"TRIGGER": "Trigger",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"THUMBSTICK": "Thumbstick",
|
||||
"BUMPER": "Bumper",
|
||||
"DPAD_UP": "D-pad Up",
|
||||
"DPAD_DOWN": "D-pad Down",
|
||||
"DPAD_LEFT": "D-pad Left",
|
||||
"DPAD_RIGHT": "D-pad Right",
|
||||
"JOYSTICK": "Joystick",
|
||||
"MENU": "Menu",
|
||||
"SHOULDER": "Shoulder",
|
||||
"SQUEEZE": "Grip",
|
||||
"SYSTEM": "System",
|
||||
"THUMBREST": "Thumbrest",
|
||||
"SHOULDER": "Shoulder",
|
||||
"SQUEEZE": "Grip"
|
||||
"THUMBSTICK": "Thumbstick",
|
||||
"TRACKPAD": "Trackpad",
|
||||
"TRIGGER": "Trigger",
|
||||
"VIEW": "View"
|
||||
},
|
||||
"CLICK": {
|
||||
"ANY": "Any",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
pub mod cached_fetcher;
|
||||
pub mod networking;
|
||||
pub mod openxr_bindings_schema;
|
||||
pub mod openxr_controller_profiles;
|
||||
pub mod openxr_bindings;
|
||||
pub mod pactl_wrapper;
|
||||
pub mod popup_manager;
|
||||
pub mod steam_utils;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use anyhow::{Context, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{AsRefStr, EnumProperty, EnumString};
|
||||
use wgui::i18n::Translation;
|
||||
use wlx_common::openxr_bindings_schema::{XrInputComponent, XrInputSide, XrInputSubpathKind};
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr, EnumProperty)]
|
||||
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
|
||||
pub enum ClickType {
|
||||
#[default]
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.CLICK.ANY"))]
|
||||
Any,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.CLICK.DOUBLE"))]
|
||||
Double,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.CLICK.TRIPLE"))]
|
||||
Triple,
|
||||
}
|
||||
|
||||
pub trait BindingsDropdown {
|
||||
fn translation(&self) -> Translation;
|
||||
fn action_str(&self, action: &str, side: XrInputSide) -> Rc<str>;
|
||||
fn clear_str(action: &str, side: XrInputSide) -> Option<Rc<str>>;
|
||||
}
|
||||
|
||||
impl BindingsDropdown for ClickType {
|
||||
fn translation(&self) -> Translation {
|
||||
self
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.or_else(|| self.get_str("Text").map(Translation::from_raw_text))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(self.as_ref()))
|
||||
}
|
||||
fn action_str(&self, action: &str, _side: XrInputSide) -> Rc<str> {
|
||||
let value = self.as_ref();
|
||||
format!("click;{action};-;{value}").into()
|
||||
}
|
||||
fn clear_str(_action: &str, _side: XrInputSide) -> Option<Rc<str>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl BindingsDropdown for XrInputSubpathKind {
|
||||
fn translation(&self) -> Translation {
|
||||
self
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.unwrap_or_else(|| {
|
||||
let mut chars = self.as_ref().chars();
|
||||
let capitalized = match chars.next() {
|
||||
None => String::new(),
|
||||
Some(first) => first.to_ascii_uppercase().to_string() + chars.as_str(),
|
||||
};
|
||||
Translation::from_raw_text(&capitalized)
|
||||
})
|
||||
}
|
||||
fn action_str(&self, action: &str, side: XrInputSide) -> Rc<str> {
|
||||
let value = self.as_ref();
|
||||
let side = side.as_ref();
|
||||
format!("subpath;{action};{side};{value}").into()
|
||||
}
|
||||
fn clear_str(action: &str, side: XrInputSide) -> Option<Rc<str>> {
|
||||
let side = side.as_ref();
|
||||
Some(format!("clear;{action};{side};-").into())
|
||||
}
|
||||
}
|
||||
|
||||
impl BindingsDropdown for XrInputComponent {
|
||||
fn translation(&self) -> Translation {
|
||||
self
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.or_else(|| self.get_str("Text").map(Translation::from_raw_text))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(self.as_ref()))
|
||||
}
|
||||
fn action_str(&self, action: &str, side: XrInputSide) -> Rc<str> {
|
||||
let value = self.as_ref();
|
||||
let side = side.as_ref();
|
||||
format!("comp;{action};{side};{value}").into()
|
||||
}
|
||||
fn clear_str(_action: &str, _side: XrInputSide) -> Option<Rc<str>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct ParsedOpenXrInputPath {
|
||||
pub side: XrInputSide,
|
||||
pub subpath: XrInputSubpathKind,
|
||||
pub component: XrInputComponent,
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for ParsedOpenXrInputPath {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(path: &str) -> anyhow::Result<Self> {
|
||||
let (side, rest) = if let Some(rest) = path.strip_prefix("/user/hand/left/") {
|
||||
(XrInputSide::Left, rest)
|
||||
} else if let Some(rest) = path.strip_prefix("/user/hand/right/") {
|
||||
(XrInputSide::Right, rest)
|
||||
} else {
|
||||
bail!("missing hand prefix");
|
||||
};
|
||||
|
||||
let (input, rest) = rest.split_once('/').context("path too short")?;
|
||||
if input != "input" {
|
||||
bail!("missing input prefix");
|
||||
}
|
||||
|
||||
let (identifier, component) = rest.rsplit_once('/').context("missing identifier or component")?;
|
||||
|
||||
if identifier.is_empty() || component.is_empty() {
|
||||
bail!("identifier or component empty");
|
||||
}
|
||||
|
||||
let component = XrInputComponent::try_from(component).context("bad component")?;
|
||||
let subpath = XrInputSubpathKind::try_from(identifier).context("bad subpath")?;
|
||||
|
||||
Ok(Self {
|
||||
side,
|
||||
subpath,
|
||||
component,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use anyhow::{Context, bail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{AsRefStr, EnumProperty, EnumString};
|
||||
use wgui::i18n::Translation;
|
||||
|
||||
pub struct ControllerProfile {
|
||||
pub display_name: &'static str,
|
||||
pub profile_id: &'static str,
|
||||
pub user_paths: &'static [ControllerUserPath],
|
||||
}
|
||||
|
||||
impl ControllerProfile {
|
||||
pub fn find_userpath(&self, side: Side) -> Option<&ControllerUserPath> {
|
||||
self.user_paths.iter().find(|x| x.hand == side)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ControllerUserPath {
|
||||
pub hand: Side,
|
||||
pub paths: &'static [Subpath],
|
||||
}
|
||||
|
||||
impl ControllerUserPath {
|
||||
pub fn find_subpath(&self, subpath: SubpathKind) -> Option<&Subpath> {
|
||||
self.paths.iter().find(|x| x.kind == subpath)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Subpath {
|
||||
pub kind: SubpathKind,
|
||||
pub components: &'static [Component],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr, EnumProperty)]
|
||||
#[strum(ascii_case_insensitive)]
|
||||
pub enum SubpathKind {
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.TRIGGER"))]
|
||||
Trigger,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.TRACKPAD"))]
|
||||
Trackpad,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.THUMBSTICK"))]
|
||||
Thumbstick,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.JOYSTICK"))]
|
||||
Joystick,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.SYSTEM"))]
|
||||
System,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.MENU"))]
|
||||
Menu,
|
||||
|
||||
Primary,
|
||||
Secondary,
|
||||
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
Start,
|
||||
Home,
|
||||
End,
|
||||
Select,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.THUMBREST"))]
|
||||
Thumbrest,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.SHOULDER"))]
|
||||
Shoulder,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.SQUEEZE"))]
|
||||
Squeeze,
|
||||
|
||||
#[strum(props(Hidden = true))]
|
||||
Grip,
|
||||
#[strum(props(Hidden = true))]
|
||||
Aim,
|
||||
#[strum(props(Hidden = true))]
|
||||
Haptic,
|
||||
}
|
||||
|
||||
impl BindingsDropdown for SubpathKind {
|
||||
fn translation(&self) -> Translation {
|
||||
self
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.or_else(|| self.get_str("Text").map(Translation::from_raw_text))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(self.as_ref()))
|
||||
}
|
||||
fn action_str(&self, action: &str, side: Side) -> Rc<str> {
|
||||
let value = self.as_ref();
|
||||
let side = side.as_ref();
|
||||
format!("subpath;{action};{side};{value}").into()
|
||||
}
|
||||
fn clear_str(action: &str, side: Side) -> Option<Rc<str>> {
|
||||
let side = side.as_ref();
|
||||
Some(format!("clear;{action};{side};-").into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr, EnumProperty)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(ascii_case_insensitive)]
|
||||
pub enum Component {
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.CLICK"))]
|
||||
Click,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.FORCE"))]
|
||||
Force,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.TOUCH"))]
|
||||
Touch,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.VALUE"))]
|
||||
Value,
|
||||
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.PROXIMITY"))]
|
||||
Proximity,
|
||||
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.X_AXIS"))]
|
||||
X,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.Y_AXIS"))]
|
||||
Y,
|
||||
|
||||
// below are hidden
|
||||
Pose,
|
||||
}
|
||||
|
||||
impl Component {
|
||||
pub fn is_analog(&self) -> bool {
|
||||
matches!(self, Component::Force | Component::Value | Component::X | Component::Y)
|
||||
}
|
||||
}
|
||||
|
||||
impl BindingsDropdown for Component {
|
||||
fn translation(&self) -> Translation {
|
||||
self
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.or_else(|| self.get_str("Text").map(Translation::from_raw_text))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(self.as_ref()))
|
||||
}
|
||||
fn action_str(&self, action: &str, side: Side) -> Rc<str> {
|
||||
let value = self.as_ref();
|
||||
let side = side.as_ref();
|
||||
format!("comp;{action};{side};{value}").into()
|
||||
}
|
||||
fn clear_str(_action: &str, _side: Side) -> Option<Rc<str>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(ascii_case_insensitive)]
|
||||
pub enum Side {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct ParsedOpenXrInputPath {
|
||||
pub side: Side,
|
||||
pub subpath: SubpathKind,
|
||||
pub component: Component,
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for ParsedOpenXrInputPath {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(path: &str) -> anyhow::Result<Self> {
|
||||
let (side, rest) = if let Some(rest) = path.strip_prefix("/user/hand/left/") {
|
||||
(Side::Left, rest)
|
||||
} else if let Some(rest) = path.strip_prefix("/user/hand/right/") {
|
||||
(Side::Right, rest)
|
||||
} else {
|
||||
bail!("missing hand prefix");
|
||||
};
|
||||
|
||||
let (input, rest) = rest.split_once('/').context("path too short")?;
|
||||
if input != "input" {
|
||||
bail!("missing input prefix");
|
||||
}
|
||||
|
||||
let (identifier, component) = rest.rsplit_once('/').context("missing identifier or component")?;
|
||||
|
||||
if identifier.is_empty() || component.is_empty() {
|
||||
bail!("identifier or component empty");
|
||||
}
|
||||
|
||||
let component = Component::try_from(component).context("bad component")?;
|
||||
|
||||
let identifier = SubpathKind::try_from(identifier).context("bad subpath")?;
|
||||
|
||||
Ok(Self {
|
||||
side,
|
||||
subpath: identifier,
|
||||
component,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr, EnumProperty)]
|
||||
#[strum(ascii_case_insensitive)]
|
||||
pub enum ClickType {
|
||||
#[default]
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.CLICK.ANY"))]
|
||||
Any,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.CLICK.DOUBLE"))]
|
||||
Double,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.CLICK.TRIPLE"))]
|
||||
Triple,
|
||||
}
|
||||
|
||||
impl BindingsDropdown for ClickType {
|
||||
fn translation(&self) -> Translation {
|
||||
self
|
||||
.get_str("Translation")
|
||||
.map(Translation::from_translation_key)
|
||||
.or_else(|| self.get_str("Text").map(Translation::from_raw_text))
|
||||
.unwrap_or_else(|| Translation::from_raw_text(self.as_ref()))
|
||||
}
|
||||
fn action_str(&self, action: &str, _side: Side) -> Rc<str> {
|
||||
let value = self.as_ref();
|
||||
format!("click;{action};-;{value}").into()
|
||||
}
|
||||
fn clear_str(_action: &str, _side: Side) -> Option<Rc<str>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BindingsDropdown {
|
||||
fn translation(&self) -> Translation;
|
||||
fn action_str(&self, action: &str, side: Side) -> Rc<str>;
|
||||
fn clear_str(action: &str, side: Side) -> Option<Rc<str>>;
|
||||
}
|
||||
|
|
@ -1,465 +0,0 @@
|
|||
use crate::util::openxr_bindings_schema::{
|
||||
Component, ControllerProfile, ControllerUserPath, Side, Subpath, SubpathKind,
|
||||
};
|
||||
|
||||
pub const OPENXR_INPUT_PROFILES: &[&ControllerProfile] = &[
|
||||
&VALVE_INDEX_CONTROLLER_PROFILE,
|
||||
&OCULUS_TOUCH_CONTROLLER_PROFILE,
|
||||
&HTC_VIVE_CONTROLLER_PROFILE,
|
||||
&HP_MIXED_REALITY_CONTROLLER_PROFILE,
|
||||
&MICROSOFT_MOTION_CONTROLLER_PROFILE,
|
||||
&SAMSUNG_ODYSSEY_CONTROLLER_PROFILE,
|
||||
&KHR_GENERIC_CONTROLLER_PROFILE,
|
||||
];
|
||||
|
||||
pub const VALVE_INDEX_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "Valve Index Controller",
|
||||
profile_id: "/interaction_profiles/valve/index_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: VALVE_INDEX_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: VALVE_INDEX_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const VALVE_INDEX_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::System,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::A,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::B,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Value, Component::Force],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Click, Component::Value, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trackpad,
|
||||
components: &[Component::Force, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const OCULUS_TOUCH_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "Touch Controller",
|
||||
profile_id: "/interaction_profiles/oculus/touch_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: OCULUS_TOUCH_LEFT_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: OCULUS_TOUCH_RIGHT_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const OCULUS_TOUCH_LEFT_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::X,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Y,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Menu,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbrest,
|
||||
components: &[Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
const OCULUS_TOUCH_RIGHT_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::A,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::B,
|
||||
components: &[Component::Click, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::System,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value, Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbrest,
|
||||
components: &[Component::Touch],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const HP_MIXED_REALITY_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "HP Reverb G2 Controller",
|
||||
profile_id: "/interaction_profiles/hp/mixed_reality_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: HP_MIXED_REALITY_LEFT_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: HP_MIXED_REALITY_RIGHT_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const HP_MIXED_REALITY_LEFT_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::X,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Y,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Menu,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
const HP_MIXED_REALITY_RIGHT_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::A,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::B,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Menu,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const SAMSUNG_ODYSSEY_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "Samsung Odyssey Controller",
|
||||
profile_id: "/interaction_profiles/samsung/odyssey_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: SAMSUNG_ODYSSEY_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: SAMSUNG_ODYSSEY_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const SAMSUNG_ODYSSEY_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::Menu,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trackpad,
|
||||
components: &[Component::Click, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const HTC_VIVE_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "HTC Vive Controller",
|
||||
profile_id: "/interaction_profiles/htc/vive_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: HTC_VIVE_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: HTC_VIVE_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const HTC_VIVE_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::System,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Menu,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Click, Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trackpad,
|
||||
components: &[Component::Click, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const MICROSOFT_MOTION_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "Microsoft WMR Controller",
|
||||
profile_id: "/interaction_profiles/microsoft/motion_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: MICROSOFT_MOTION_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: MICROSOFT_MOTION_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const MICROSOFT_MOTION_CONTROLLER_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::Menu,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trackpad,
|
||||
components: &[Component::Click, Component::Touch, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const KHR_GENERIC_CONTROLLER_PROFILE: ControllerProfile = ControllerProfile {
|
||||
display_name: "Khronos Generic Controller",
|
||||
profile_id: "/interaction_profiles/khr/generic_controller",
|
||||
user_paths: &[
|
||||
ControllerUserPath {
|
||||
hand: Side::Left,
|
||||
paths: KHR_GENERIC_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
ControllerUserPath {
|
||||
hand: Side::Right,
|
||||
paths: KHR_GENERIC_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const KHR_GENERIC_CONTROLLER_USER_PATHS: &[Subpath] = &[
|
||||
Subpath {
|
||||
kind: SubpathKind::Primary,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Secondary,
|
||||
components: &[Component::Click],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Thumbstick,
|
||||
components: &[Component::Click, Component::X, Component::Y],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Squeeze,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Trigger,
|
||||
components: &[Component::Value],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Grip,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Aim,
|
||||
components: &[Component::Pose],
|
||||
},
|
||||
Subpath {
|
||||
kind: SubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
|
@ -20,15 +20,14 @@ use wgui::{
|
|||
use wlx_common::{
|
||||
config_io,
|
||||
openxr_actions::{OneOrMany, OpenXrInputAction, OpenXrInputProfile, load_xr_input_profiles},
|
||||
openxr_bindings_schema::{XrControllerProfile, XrInputComponent, XrInputSide, XrInputSubpathKind},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
frontend::{FrontendTask, FrontendTasks},
|
||||
tab::settings::horiz_cell,
|
||||
util::{
|
||||
openxr_bindings_schema::{
|
||||
BindingsDropdown, ClickType, Component, ControllerProfile, ParsedOpenXrInputPath, Side, SubpathKind,
|
||||
},
|
||||
openxr_bindings::{BindingsDropdown, ClickType, ParsedOpenXrInputPath},
|
||||
popup_manager::{MountPopupOnceParams, MountPopupOnceParamsExtra, PopupHolder, PopupPadding},
|
||||
wgui_simple,
|
||||
},
|
||||
|
|
@ -40,14 +39,14 @@ enum Task {
|
|||
Save,
|
||||
Cancel,
|
||||
OpenContextMenu(glam::Vec2, Vec<context_menu::Cell>),
|
||||
UpdateThreshold(Rc<str>, Side, f32, f32),
|
||||
UpdateThreshold(Rc<str>, XrInputSide, f32, f32),
|
||||
}
|
||||
|
||||
pub struct Params<'a> {
|
||||
pub globals: WguiGlobals,
|
||||
pub layout: &'a mut Layout,
|
||||
pub parent_id: WidgetID,
|
||||
pub controller_profile: &'static ControllerProfile,
|
||||
pub controller_profile: &'static XrControllerProfile,
|
||||
pub close_callback: Box<dyn FnOnce()>,
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +58,7 @@ pub struct View {
|
|||
profiles: Vec<OpenXrInputProfile>,
|
||||
cur_profile_idx: usize,
|
||||
context_menu: context_menu::ContextMenu,
|
||||
controller_profile: &'static ControllerProfile,
|
||||
controller_profile: &'static XrControllerProfile,
|
||||
close_callback: Option<Box<dyn FnOnce()>>,
|
||||
}
|
||||
|
||||
|
|
@ -90,10 +89,12 @@ impl ViewTrait for View {
|
|||
});
|
||||
}
|
||||
Task::UpdateThreshold(action_name, side, lo, hi) => {
|
||||
log::warn!("UpdateThreshold {action_name} {lo:.2} {hi:.2}");
|
||||
|
||||
let cur_profile = &mut self.profiles[self.cur_profile_idx];
|
||||
let action_mut = get_action_mut(cur_profile, &*action_name);
|
||||
|
||||
if matches!(side, Side::Right) {
|
||||
if matches!(side, XrInputSide::Right) {
|
||||
action_mut.threshold_right = Some([lo, hi]);
|
||||
} else {
|
||||
action_mut.threshold_left = Some([lo, hi]);
|
||||
|
|
@ -108,11 +109,6 @@ impl ViewTrait for View {
|
|||
let mut s = name.splitn(4, ';');
|
||||
(s.next(), s.next(), s.next(), s.next())
|
||||
} {
|
||||
let side = side.to_lowercase();
|
||||
let value = value.to_lowercase();
|
||||
|
||||
log::warn!("{action_name}");
|
||||
|
||||
let cur_profile = &mut self.profiles[self.cur_profile_idx];
|
||||
let action_mut = get_action_mut(cur_profile, action_name);
|
||||
let side_mut = if side == "right" {
|
||||
|
|
@ -131,7 +127,7 @@ impl ViewTrait for View {
|
|||
"comp" => {
|
||||
apply_comp(side_mut, &side, &value);
|
||||
}
|
||||
"click" => match value.as_str() {
|
||||
"click" => match value {
|
||||
"triple" => {
|
||||
action_mut.triple_click = Some(true);
|
||||
action_mut.double_click = None;
|
||||
|
|
@ -257,8 +253,8 @@ impl View {
|
|||
fn ensure_pose_and_haptics(&mut self) {
|
||||
let cur_profile = &mut self.profiles[self.cur_profile_idx];
|
||||
|
||||
let profile_left = self.controller_profile.find_userpath(Side::Left);
|
||||
let profile_right = self.controller_profile.find_userpath(Side::Right);
|
||||
let profile_left = self.controller_profile.find_userpath(XrInputSide::Left);
|
||||
let profile_right = self.controller_profile.find_userpath(XrInputSide::Right);
|
||||
|
||||
let action = cur_profile.pose.get_or_insert_default();
|
||||
|
||||
|
|
@ -275,7 +271,7 @@ impl View {
|
|||
let action = cur_profile.haptic.get_or_insert_default();
|
||||
|
||||
let has_haptic = profile_left
|
||||
.map(|x| x.find_subpath(SubpathKind::Haptic).is_some())
|
||||
.map(|x| x.find_subpath(XrInputSubpathKind::Haptic).is_some())
|
||||
.unwrap_or_default();
|
||||
if action.left.is_none() && has_haptic {
|
||||
let path = "/user/hand/left/output/haptic";
|
||||
|
|
@ -283,7 +279,7 @@ impl View {
|
|||
}
|
||||
|
||||
let has_haptic = profile_right
|
||||
.map(|x| x.find_subpath(SubpathKind::Haptic).is_some())
|
||||
.map(|x| x.find_subpath(XrInputSubpathKind::Haptic).is_some())
|
||||
.unwrap_or_default();
|
||||
if action.right.is_none() && has_haptic {
|
||||
let path = "/user/hand/right/output/haptic";
|
||||
|
|
@ -316,7 +312,7 @@ pub fn mount_popup(
|
|||
frontend_tasks: FrontendTasks,
|
||||
globals: WguiGlobals,
|
||||
popup: PopupHolder<View>,
|
||||
controller_profile: &'static ControllerProfile,
|
||||
controller_profile: &'static XrControllerProfile,
|
||||
) {
|
||||
frontend_tasks
|
||||
.clone()
|
||||
|
|
@ -353,7 +349,7 @@ fn input_controls_for_action(
|
|||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
action: Rc<str>,
|
||||
profile: &ControllerProfile,
|
||||
profile: &XrControllerProfile,
|
||||
current: &mut OpenXrInputAction,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
|
|
@ -391,7 +387,7 @@ fn input_controls_for_action(
|
|||
mp,
|
||||
parent,
|
||||
current_left,
|
||||
Side::Left,
|
||||
XrInputSide::Left,
|
||||
action.clone(),
|
||||
click_type,
|
||||
profile,
|
||||
|
|
@ -407,7 +403,7 @@ fn input_controls_for_action(
|
|||
mp,
|
||||
parent,
|
||||
current_right,
|
||||
Side::Right,
|
||||
XrInputSide::Right,
|
||||
action,
|
||||
click_type,
|
||||
profile,
|
||||
|
|
@ -419,10 +415,10 @@ fn input_controls_for_hand(
|
|||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
current: Option<&str>,
|
||||
side: Side,
|
||||
side: XrInputSide,
|
||||
action: Rc<str>,
|
||||
click_type: ClickType,
|
||||
profile: &ControllerProfile,
|
||||
profile: &XrControllerProfile,
|
||||
threshold: Option<[f32; 2]>,
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(user_path) = profile.find_userpath(side) else {
|
||||
|
|
@ -433,14 +429,14 @@ fn input_controls_for_hand(
|
|||
|
||||
let parent = horiz_cell(mp.layout, parent)?;
|
||||
|
||||
let available_components: Rc<[Component]> = current
|
||||
let available_components: Rc<[XrInputComponent]> = current
|
||||
.as_ref()
|
||||
.and_then(|par| user_path.find_subpath(par.subpath))
|
||||
.map(|subp| subp.components)
|
||||
.unwrap_or_default()
|
||||
.into();
|
||||
|
||||
let available_subpaths: Rc<[SubpathKind]> = user_path
|
||||
let available_subpaths: Rc<[XrInputSubpathKind]> = user_path
|
||||
.paths
|
||||
.iter()
|
||||
.filter(|x| !x.kind.get_bool("Hidden").unwrap_or_default())
|
||||
|
|
@ -482,9 +478,9 @@ fn subpath_dropdown(
|
|||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
action: Rc<str>,
|
||||
side: Side,
|
||||
available: Rc<[SubpathKind]>,
|
||||
current: Option<SubpathKind>,
|
||||
side: XrInputSide,
|
||||
available: Rc<[XrInputSubpathKind]>,
|
||||
current: Option<XrInputSubpathKind>,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||
params.insert(Rc::from("tooltip"), Rc::from("APP_SETTINGS.BINDINGS.SUBPATH"));
|
||||
|
|
@ -495,7 +491,7 @@ fn subpath_dropdown(
|
|||
mp.layout,
|
||||
parent,
|
||||
Vec2::new(32.0, 32.0),
|
||||
AssetPath::BuiltIn(&format!("dashboard/hand_{}.svg", side.as_ref().to_lowercase())),
|
||||
AssetPath::BuiltIn(&format!("dashboard/hand_{}.svg", side.as_ref())),
|
||||
)?;
|
||||
|
||||
let current_text = current
|
||||
|
|
@ -511,9 +507,9 @@ fn component_dropdown(
|
|||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
action: Rc<str>,
|
||||
side: Side,
|
||||
available: Rc<[Component]>,
|
||||
current: Option<Component>,
|
||||
side: XrInputSide,
|
||||
available: Rc<[XrInputComponent]>,
|
||||
current: Option<XrInputComponent>,
|
||||
) -> anyhow::Result<bool> {
|
||||
if available.is_empty() {
|
||||
return Ok(false);
|
||||
|
|
@ -541,7 +537,7 @@ fn clicks_dropdown(mp: &mut MacroParams, parent: WidgetID, action: Rc<str>, curr
|
|||
|
||||
let current_text = current.translation();
|
||||
let available = [ClickType::Any, ClickType::Double, ClickType::Triple].into();
|
||||
create_dropdown(mp, parent, params, action, Side::Left, current_text, available)?;
|
||||
create_dropdown(mp, parent, params, action, XrInputSide::Left, current_text, available)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -550,7 +546,7 @@ fn threshold_slider(
|
|||
mp: &mut MacroParams,
|
||||
parent: WidgetID,
|
||||
action: Rc<str>,
|
||||
side: Side,
|
||||
side: XrInputSide,
|
||||
current: Option<[f32; 2]>,
|
||||
) -> anyhow::Result<()> {
|
||||
let id = mp.idx.to_string();
|
||||
|
|
@ -590,7 +586,7 @@ fn create_dropdown<B: 'static + BindingsDropdown>(
|
|||
parent: WidgetID,
|
||||
mut params: HashMap<Rc<str>, Rc<str>>,
|
||||
action: Rc<str>,
|
||||
side: Side,
|
||||
side: XrInputSide,
|
||||
current_text: Translation,
|
||||
available: Rc<[B]>,
|
||||
) -> anyhow::Result<()> {
|
||||
|
|
@ -651,16 +647,19 @@ fn apply_subpath(
|
|||
side_mut: &mut Option<OneOrMany<String>>,
|
||||
side_str: &str,
|
||||
subpath_str: &str,
|
||||
profile: &ControllerProfile,
|
||||
profile: &XrControllerProfile,
|
||||
) {
|
||||
let (Ok(side), Ok(subpath)) = (Side::try_from(side_str), SubpathKind::try_from(subpath_str)) else {
|
||||
let (Ok(side), Ok(subpath)) = (
|
||||
XrInputSide::try_from(side_str),
|
||||
XrInputSubpathKind::try_from(subpath_str),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
let Some(subpath_obj) = profile.find_userpath(side).and_then(|p| p.find_subpath(subpath)) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let comp: Component = if let Some(first) = side_mut.as_ref().map(|x| match x {
|
||||
let comp: XrInputComponent = if let Some(first) = side_mut.as_ref().map(|x| match x {
|
||||
OneOrMany::One(x) => x.as_str(),
|
||||
OneOrMany::Many(x) => x.first().unwrap().as_str(),
|
||||
}) {
|
||||
|
|
@ -677,8 +676,7 @@ fn apply_subpath(
|
|||
*subpath_obj.components.first().unwrap()
|
||||
};
|
||||
|
||||
let comp_str = comp.as_ref().to_lowercase();
|
||||
|
||||
let comp_str = comp.as_ref();
|
||||
*side_mut = Some(OneOrMany::One(format!(
|
||||
"/user/hand/{side_str}/input/{subpath_str}/{comp_str}"
|
||||
)));
|
||||
|
|
@ -698,7 +696,7 @@ fn apply_comp(side_mut: &mut Option<OneOrMany<String>>, side: &str, comp: &str)
|
|||
return;
|
||||
};
|
||||
|
||||
let subpath = parsed.subpath.as_ref().to_lowercase();
|
||||
let subpath = parsed.subpath.as_ref();
|
||||
|
||||
*side_mut = Some(OneOrMany::One(format!("/user/hand/{side}/input/{subpath}/{comp}")));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,20 +9,17 @@ use wgui::{
|
|||
parser::{Fetchable, ParseDocumentParams},
|
||||
task::Tasks,
|
||||
};
|
||||
use wlx_common::{openxr_bindings_schema::XrControllerProfile, openxr_controller_profiles::OPENXR_INPUT_PROFILES};
|
||||
|
||||
use crate::{
|
||||
frontend::{FrontendTask, FrontendTasks},
|
||||
util::{
|
||||
openxr_bindings_schema::ControllerProfile,
|
||||
openxr_controller_profiles::OPENXR_INPUT_PROFILES,
|
||||
popup_manager::{MountPopupOnceParams, PopupHolder},
|
||||
},
|
||||
util::popup_manager::{MountPopupOnceParams, PopupHolder},
|
||||
views::{self, ViewTrait, ViewUpdateParams, bindings},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Task {
|
||||
SelectProfile(&'static ControllerProfile),
|
||||
SelectProfile(&'static XrControllerProfile),
|
||||
}
|
||||
|
||||
pub struct Params<'a> {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ pub mod desktop_finder;
|
|||
mod handle;
|
||||
pub mod locale;
|
||||
pub mod openxr_actions;
|
||||
pub mod openxr_bindings_schema;
|
||||
pub mod openxr_controller_profiles;
|
||||
pub mod overlays;
|
||||
pub mod timestep;
|
||||
pub mod windowing;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use strum::{AsRefStr, EnumProperty, EnumString};
|
||||
|
||||
pub struct XrControllerProfile {
|
||||
pub display_name: &'static str,
|
||||
pub profile_id: &'static str,
|
||||
pub extension: Option<&'static str>,
|
||||
pub user_paths: &'static [XrControllerUserPath],
|
||||
}
|
||||
|
||||
impl XrControllerProfile {
|
||||
pub fn find_userpath(&self, side: XrInputSide) -> Option<&XrControllerUserPath> {
|
||||
self.user_paths.iter().find(|x| x.hand == side)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XrControllerUserPath {
|
||||
pub hand: XrInputSide,
|
||||
pub paths: &'static [XrInputSubpath],
|
||||
}
|
||||
|
||||
impl XrControllerUserPath {
|
||||
pub fn find_subpath(&self, subpath: XrInputSubpathKind) -> Option<&XrInputSubpath> {
|
||||
self.paths.iter().find(|x| x.kind == subpath)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XrInputSubpath {
|
||||
pub kind: XrInputSubpathKind,
|
||||
pub components: &'static [XrInputComponent],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr, EnumProperty)]
|
||||
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
|
||||
pub enum XrInputSubpathKind {
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.TRIGGER"))]
|
||||
Trigger,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.TRACKPAD"))]
|
||||
Trackpad,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.THUMBSTICK"))]
|
||||
Thumbstick,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.JOYSTICK"))]
|
||||
Joystick,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.SYSTEM"))]
|
||||
System,
|
||||
Menu,
|
||||
View,
|
||||
|
||||
Primary,
|
||||
Secondary,
|
||||
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
Start,
|
||||
Home,
|
||||
End,
|
||||
Select,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.THUMBREST"))]
|
||||
Thumbrest,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.SHOULDER"))]
|
||||
Shoulder,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.SQUEEZE"))]
|
||||
Squeeze,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.BUMPER"))]
|
||||
Bumper,
|
||||
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.DPAD_UP"))]
|
||||
DpadUp,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.DPAD_DOWN"))]
|
||||
DpadDown,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.DPAD_LEFT"))]
|
||||
DpadLeft,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.TYPE.DPAD_RIGHT"))]
|
||||
DpadRight,
|
||||
|
||||
#[strum(props(Hidden = true))]
|
||||
Grip,
|
||||
#[strum(props(Hidden = true))]
|
||||
Aim,
|
||||
#[strum(props(Hidden = true))]
|
||||
Haptic,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr, EnumProperty)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
|
||||
pub enum XrInputComponent {
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.CLICK"))]
|
||||
Click,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.FORCE"))]
|
||||
Force,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.TOUCH"))]
|
||||
Touch,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.VALUE"))]
|
||||
Value,
|
||||
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.PROXIMITY"))]
|
||||
Proximity,
|
||||
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.X_AXIS"))]
|
||||
X,
|
||||
#[strum(props(Translation = "APP_SETTINGS.BINDINGS.COMP.Y_AXIS"))]
|
||||
Y,
|
||||
|
||||
// below are hidden
|
||||
Pose,
|
||||
}
|
||||
|
||||
impl XrInputComponent {
|
||||
pub fn is_analog(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
XrInputComponent::Force | XrInputComponent::Value | XrInputComponent::X | XrInputComponent::Y
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, EnumString, AsRefStr)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[strum(ascii_case_insensitive, serialize_all = "snake_case")]
|
||||
pub enum XrInputSide {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
|
@ -0,0 +1,664 @@
|
|||
use crate::openxr_bindings_schema::{
|
||||
XrControllerProfile, XrControllerUserPath, XrInputComponent, XrInputSide, XrInputSubpath, XrInputSubpathKind,
|
||||
};
|
||||
|
||||
pub const OPENXR_INPUT_PROFILES: &[&XrControllerProfile] = &[
|
||||
&OCULUS_TOUCH_CONTROLLER_PROFILE,
|
||||
&VALVE_INDEX_CONTROLLER_PROFILE,
|
||||
&VALVE_FRAME_CONTROLLER_VALVE_PROFILE,
|
||||
&HTC_VIVE_CONTROLLER_PROFILE,
|
||||
&HP_MIXED_REALITY_CONTROLLER_PROFILE,
|
||||
&MICROSOFT_MOTION_CONTROLLER_PROFILE,
|
||||
&SAMSUNG_ODYSSEY_CONTROLLER_PROFILE,
|
||||
&KHR_GENERIC_CONTROLLER_PROFILE,
|
||||
];
|
||||
|
||||
pub const VALVE_INDEX_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "Valve Index Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/valve/index_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: VALVE_INDEX_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: VALVE_INDEX_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const VALVE_INDEX_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::System,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::A,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::B,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Value, XrInputComponent::Force],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Value,
|
||||
XrInputComponent::Touch,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trackpad,
|
||||
components: &[
|
||||
XrInputComponent::Force,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub static VALVE_FRAME_CONTROLLER_VALVE_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "Steam Frame Controller",
|
||||
extension: Some("XR_VALVE_frame_controller_interaction"),
|
||||
profile_id: "/interaction_profiles/valve/frame_controller_valve",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: VALVE_FRAME_CONTROLLER_VALVE_LEFT_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: VALVE_FRAME_CONTROLLER_VALVE_RIGHT_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
static VALVE_FRAME_CONTROLLER_VALVE_RIGHT_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::A,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::B,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::X,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Y,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::System,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Bumper,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::Value,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::Value,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
static VALVE_FRAME_CONTROLLER_VALVE_LEFT_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::DpadUp,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::DpadLeft,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::DpadDown,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::DpadRight,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::View,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::System,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Bumper,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::Value,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::Value,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const OCULUS_TOUCH_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "Touch Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/oculus/touch_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: OCULUS_TOUCH_LEFT_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: OCULUS_TOUCH_RIGHT_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const OCULUS_TOUCH_LEFT_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::X,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Y,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbrest,
|
||||
components: &[XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
const OCULUS_TOUCH_RIGHT_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::A,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::B,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::System,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value, XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbrest,
|
||||
components: &[XrInputComponent::Touch],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const HP_MIXED_REALITY_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "HP Reverb G2 Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/hp/mixed_reality_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: HP_MIXED_REALITY_LEFT_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: HP_MIXED_REALITY_RIGHT_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const HP_MIXED_REALITY_LEFT_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::X,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Y,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::X, XrInputComponent::Y],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
const HP_MIXED_REALITY_RIGHT_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::A,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::B,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::X, XrInputComponent::Y],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const SAMSUNG_ODYSSEY_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "Samsung Odyssey Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/samsung/odyssey_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: SAMSUNG_ODYSSEY_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: SAMSUNG_ODYSSEY_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const SAMSUNG_ODYSSEY_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::X, XrInputComponent::Y],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trackpad,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const HTC_VIVE_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "HTC Vive Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/htc/vive_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: HTC_VIVE_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: HTC_VIVE_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const HTC_VIVE_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::System,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trackpad,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const MICROSOFT_MOTION_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "Microsoft WMR Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/microsoft/motion_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: MICROSOFT_MOTION_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: MICROSOFT_MOTION_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const MICROSOFT_MOTION_CONTROLLER_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Menu,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::X, XrInputComponent::Y],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trackpad,
|
||||
components: &[
|
||||
XrInputComponent::Click,
|
||||
XrInputComponent::Touch,
|
||||
XrInputComponent::X,
|
||||
XrInputComponent::Y,
|
||||
],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
|
||||
pub const KHR_GENERIC_CONTROLLER_PROFILE: XrControllerProfile = XrControllerProfile {
|
||||
display_name: "Khronos Generic Controller",
|
||||
extension: None,
|
||||
profile_id: "/interaction_profiles/khr/generic_controller",
|
||||
user_paths: &[
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Left,
|
||||
paths: KHR_GENERIC_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
XrControllerUserPath {
|
||||
hand: XrInputSide::Right,
|
||||
paths: KHR_GENERIC_CONTROLLER_USER_PATHS,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const KHR_GENERIC_CONTROLLER_USER_PATHS: &[XrInputSubpath] = &[
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Primary,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Secondary,
|
||||
components: &[XrInputComponent::Click],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Thumbstick,
|
||||
components: &[XrInputComponent::Click, XrInputComponent::X, XrInputComponent::Y],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Squeeze,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Trigger,
|
||||
components: &[XrInputComponent::Value],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Grip,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Aim,
|
||||
components: &[XrInputComponent::Pose],
|
||||
},
|
||||
XrInputSubpath {
|
||||
kind: XrInputSubpathKind::Haptic,
|
||||
components: &[],
|
||||
},
|
||||
];
|
||||
Loading…
Reference in New Issue