Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use std::collections::{HashMap, HashSet, VecDeque};
use std::ffi::{CStr, CString, c_char, c_void};
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::ops::Sub;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
Expand Down Expand Up @@ -930,14 +931,17 @@ impl<C: openxr_data::Compositor> vr::IVRInput010_Interface for Input<C> {
_ => return vr::EVRInputError::WrongType,
};

let update_time = state.last_change_time.sub(self.openxr.display_time.get());
*out.value = vr::InputAnalogActionData_t {
bActive: state.is_active,
activeOrigin: active_hand,
x: state.current_state.x,
deltaX: delta.x,
y: state.current_state.y,
z: 0.0, // TODO: support 3D axes?
deltaX: delta.x,
deltaY: delta.y,
..Default::default()
deltaZ: 0.0, // TODO: support 3D axes?
fUpdateTime: update_time.as_nanos().saturating_div(1_000_000) as f32,
};

vr::EVRInputError::None
Expand Down Expand Up @@ -975,12 +979,13 @@ impl<C: openxr_data::Compositor> vr::IVRInput010_Interface for Input<C> {
active_hand = binding_source;
}

let update_time = state.last_change_time.sub(self.openxr.display_time.get());
*out.value = vr::InputDigitalActionData_t {
bActive: state.is_active,
bState: state.current_state,
activeOrigin: active_hand,
bChanged: state.changed_since_last_sync,
fUpdateTime: 0.0, // TODO
fUpdateTime: update_time.as_nanos().saturating_div(1_000_000) as f32,
};

vr::EVRInputError::None
Expand Down
50 changes: 28 additions & 22 deletions src/input/action_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ impl<C: openxr_data::Compositor> Input<C> {
) -> Result<(), vr::EVRInputError> {
match self.loaded_actions_path.get() {
Some(p) => {
assert_eq!(p, manifest_path);
if p != manifest_path {
error!(
"Tried to load action manifest {}, but {} is already loaded!",
manifest_path.display(),
p.display()
);
return Err(vr::EVRInputError::MismatchedActionManifest);
}
if session_data.input_data.actions.get().is_some() {
return Ok(());
}
Expand Down Expand Up @@ -255,12 +262,19 @@ impl<C: openxr_data::Compositor> Input<C> {
bindings: Vec<actions::DefaultBindings>,
context: &mut context::BindingsLoadContext,
) {
let mut it = bindings.into_iter().peekable();
while let Some(actions::DefaultBindings {
let mut processed_types = HashSet::new();
for actions::DefaultBindings {
binding_url,
controller_type,
}) = it.next()
} in bindings
{
if !processed_types.insert(controller_type.clone()) {
debug!(
"skipping duplicate bindings in {:?} for {controller_type:?}",
binding_url
);
continue;
}
let custom_path = if let Ok(custom_dir) = std::env::var("XRIZER_CUSTOM_BINDINGS_DIR") {
PathBuf::from(custom_dir)
} else {
Expand Down Expand Up @@ -294,7 +308,7 @@ impl<C: openxr_data::Compositor> Input<C> {

match controller_type {
actions::ControllerType::Unknown(ref other) => {
info!("Ignoring bindings for unknown profile {other}")
debug!("Ignoring bindings for unknown profile {other}")
}
ref other => {
let mut runner = Runner(self, context, bindings);
Expand All @@ -321,10 +335,6 @@ impl<C: openxr_data::Compositor> Input<C> {
}
}
}

while let Some(b) = it.next_if(|b| b.controller_type == controller_type) {
info!("skipping bindings in {:?}", b.binding_url);
}
}
}

Expand Down Expand Up @@ -357,25 +367,21 @@ impl<C: openxr_data::Compositor> Input<C> {

let set = set.clone();

if let Some(bindings) = &bindings.haptics {
bindings::handle_haptic_bindings(&self.openxr.instance, context, bindings);
if let Some(haptics) = &bindings.haptics {
bindings::handle_haptic_bindings(&self.openxr.instance, context, haptics);
}

if let Some(bindings) = &bindings.poses {
bindings::handle_pose_bindings(context, bindings);
if let Some(poses) = &bindings.poses {
bindings::handle_pose_bindings(context, poses);
}

if let Some(bindings) = &bindings.skeleton {
bindings::handle_skeleton_bindings(context, bindings);
if let Some(skeleton) = &bindings.skeleton {
bindings::handle_skeleton_bindings(context, skeleton);
}

bindings::handle_sources(
&path_validator,
context,
action_set_name,
&set,
&bindings.sources,
);
if let Some(sources) = &bindings.sources {
bindings::handle_sources(&path_validator, context, action_set_name, &set, sources);
}
}

let info_action_binding = *legacy_bindings
Expand Down
29 changes: 23 additions & 6 deletions src/input/action_manifest/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub struct Bindings {

#[derive(Deserialize)]
pub struct ActionSetBinding {
pub sources: Vec<ActionBinding>,
pub sources: Option<Vec<ActionBinding>>,
pub poses: Option<Vec<PoseBinding>>,
pub haptics: Option<Vec<SimpleActionBinding>>,
pub skeleton: Option<Vec<SimpleActionBinding>>,
Expand Down Expand Up @@ -102,6 +102,21 @@ fn parse_pose_binding<'de, D: serde::Deserializer<'de>>(
let hand = match hand {
"/user/hand/left/pose" => Hand::Left,
"/user/hand/right/pose" => Hand::Right,
"/user/camera/pose"
| "/user/chest/pose"
| "/user/keyboard/pose"
| "/user/elbow/left/pose"
| "/user/elbow/right/pose"
| "/user/foot/left/pose"
| "/user/foot/right/pose"
| "/user/knee/left/pose"
| "/user/knee/right/pose"
| "/user/shoulder/left/pose"
| "/user/shoulder/right/pose"
| "/user/waist/pose" => {
debug!("Got pose binding for {pose_path} - ignoring");
return Ok((Hand::Left, BoundPoseType::Raw)); // Hand doesn't matter since we'll ignore it
}
_ => {
return Err(D::Error::unknown_variant(
hand,
Expand All @@ -115,7 +130,7 @@ fn parse_pose_binding<'de, D: serde::Deserializer<'de>>(
"tip" => BoundPoseType::Tip,
"gdc2015" => BoundPoseType::Gdc2015,
other => {
warn!("Unknown pose type: {other:?}");
debug!("Unknown pose type: {other:?}");
BoundPoseType::Raw
}
};
Expand Down Expand Up @@ -725,12 +740,14 @@ pub fn handle_sources(
return None;
};

if validate_path(path).is_none() {
InvalidActionPath(path, s).warn();
return None;
if let Some(path) = validate_path(path)
.map(|path| context.instance.string_to_path(&path.to_string()).unwrap())
{
return Some(path);
}

Some(context.instance.string_to_path(&path.to_string()).unwrap())
InvalidActionPath(path, s).warn();
None
},
path,
action_set_name,
Expand Down
7 changes: 5 additions & 2 deletions src/input/profiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ pub mod paths {
Squeeze::<Click, Value, Force, Touch>,
Thumbstick::<Click, Touch, Vec2X, Vec2Y>,
Trackpad::<Click, Touch, Force, Vec2X, Vec2Y>,
Thumbrest::<Touch>
Thumbrest::<Touch>,
Pinch::<Value, Force, Touch>
);

// Vec2 impls
Expand All @@ -555,11 +556,13 @@ pub mod paths {
"b" => Some(Self::B),
"x" => Some(Self::X),
"y" => Some(Self::Y),
"application_menu" => Some(Self::Menu),
"application_menu" | "system" => Some(Self::Menu),
"trigger" => Some(Self::Trigger),
"grip" => Some(Self::Squeeze),
"thumbstick" | "joystick" => Some(Self::Thumbstick),
"thumbrest" => Some(Self::Thumbrest),
"trackpad" => Some(Self::Trackpad),
"pinch" => Some(Self::Pinch),
_ => None,
}
}
Expand Down
24 changes: 24 additions & 0 deletions src/input/profiles/knuckles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,24 @@ impl InteractionProfile for Knuckles {
component: Some(DynComponent::Click),
..
} => Some(p.with_component(DynComponent::Force)),
p @ DynInputPath {
subpath: DynSubpath::Squeeze,
component: Some(DynComponent::Touch),
..
} => Some(p.with_component(DynComponent::Value)),
DynInputPath {
subpath: DynSubpath::Pinch,
component: Some(component @ (DynComponent::Force | DynComponent::Value)),
..
} => Some(DynInputPath {
subpath: match component {
DynComponent::Force => DynSubpath::Trackpad,
DynComponent::Value => DynSubpath::Trigger,
DynComponent::Touch => DynSubpath::Thumbrest,
_ => unreachable!(),
},
..path
}),
_ => None,
}
}
Expand Down Expand Up @@ -185,6 +203,12 @@ mod tests {
],
);

f.verify_bindings::<f32>(
path,
c"/user/hand/left/input/trackpad/click-/actions/set1",
["/user/hand/left/input/trackpad/force".into()],
);

let handle = f.get_action_handle(c"/actions/set1/in/boolact");
let data = f.input.openxr.session_data.get();
let actions = data.input_data.get_loaded_actions().unwrap();
Expand Down
17 changes: 16 additions & 1 deletion src/input/profiles/oculus_touch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{
};
use crate::button_mask_from_ids;
use crate::input::legacy::{self, LegacyBindings, button_mask_from_id};
use crate::input::profiles::InputToXrPath;
use crate::input::profiles::{DynInputPath, InputToXrPath};
use crate::openxr_data::Hand;
use glam::{EulerRot, Mat4, Quat, Vec3};

Expand Down Expand Up @@ -59,6 +59,21 @@ impl InteractionProfile for OculusTouch {
};
&DEVICE_PROPERTIES
}
fn translate_path(path: DynInputPath) -> Option<DynInputPath> {
match path {
p @ DynInputPath {
subpath: DynSubpath::Squeeze | DynSubpath::Trigger,
component: Some(DynComponent::Click),
..
} => Some(p.with_component(DynComponent::Value)),
p @ DynInputPath {
subpath: DynSubpath::A | DynSubpath::B | DynSubpath::X | DynSubpath::Y,
component: Some(DynComponent::Value),
..
} => Some(p.with_component(DynComponent::Click)),
_ => None,
}
}
fn profile_path() -> &'static str {
"/interaction_profiles/oculus/touch_controller"
}
Expand Down
25 changes: 22 additions & 3 deletions src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,11 +544,26 @@ impl vr::IVRSystem023_Interface for System {
// The Unity OpenVR sample appears to have a hard requirement on these first three properties returning
// something to even get the game to recognize the HMD's location. However, the value
// itself doesn't appear to be that important.
vr::ETrackedDeviceProperty::SerialNumber_String
| vr::ETrackedDeviceProperty::ManufacturerName_String
| vr::ETrackedDeviceProperty::ControllerType_String => {
// vr::ETrackedDeviceProperty::SerialNumber_String
// | vr::ETrackedDeviceProperty::ManufacturerName_String
// | vr::ETrackedDeviceProperty::ControllerType_String => {
// Some(CString::new("<unknown>").unwrap())
// }
vr::ETrackedDeviceProperty::SerialNumber_String => {
Some(CString::new("oculus/WMHD315M3010GV").unwrap())
}
vr::ETrackedDeviceProperty::ManufacturerName_String => {
Some(CString::new("Oculus").unwrap())
}
vr::ETrackedDeviceProperty::ModelNumber_String => {
Some(CString::new("Miramar").unwrap())
}
vr::ETrackedDeviceProperty::ControllerType_String => {
Some(CString::new("<unknown>").unwrap())
}
vr::ETrackedDeviceProperty::TrackingSystemName_String => {
Some(CString::new("oculus").unwrap())
}
_ => None,
},
_ => self
Expand All @@ -559,6 +574,10 @@ impl vr::IVRSystem023_Interface for System {

let Some(data) = data else {
if let Some(error) = unsafe { error.as_mut() } {
warn!(
target: log_tags::TRACKED_PROP,
"unknown property requested: {prop:?} ({device_index})"
);
*error = vr::ETrackedPropertyError::UnknownProperty;
}
return 0;
Expand Down
12 changes: 12 additions & 0 deletions tests/input_data/knuckles.json
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,18 @@
},
"mode": "joystick",
"path": "/user/hand/right/input/trackpad"
},
{
"inputs": {
"north": {
"output": "/actions/set1/in/boolact"
}
},
"mode": "dpad",
"path": "/user/hand/left/input/trackpad",
"parameters": {
"sub_mode": "click"
}
}
]
}
Expand Down
Loading