Skip to content
This repository was archived by the owner on Feb 16, 2025. It is now read-only.

Add a gesture to open up a context menu; fix quitting #144

Merged
merged 3 commits into from
Mar 30, 2020
Merged
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
94 changes: 77 additions & 17 deletions webxr/openxr/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use webxr_api::InputId;
use webxr_api::Native;
use webxr_api::SelectEvent;

/// Number of frames to wait with the menu gesture before
/// opening the menu.
const MENU_GESTURE_SUSTAIN_THRESHOLD: u8 = 60;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ClickState {
Clicking,
Expand All @@ -20,6 +24,14 @@ enum ClickState {
Done,
}

/// All the information on a single input frame
pub struct Frame {
pub frame: InputFrame,
pub select: Option<SelectEvent>,
pub squeeze: Option<SelectEvent>,
pub menu_selected: bool,
}

impl ClickState {
fn update(
&mut self,
Expand Down Expand Up @@ -75,23 +87,28 @@ pub struct OpenXRInput {
action_grip_space: Space,
action_click: Action<bool>,
action_squeeze: Action<bool>,
hand: &'static str,
handedness: Handedness,
click_state: ClickState,
squeeze_state: ClickState,
menu_gesture_sustain: u8,
}

fn hand_str(h: Handedness) -> &'static str {
match h {
Handedness::Right => "right",
Handedness::Left => "left",
_ => panic!("We don't support unknown handedness in openxr"),
}
}

impl OpenXRInput {
pub fn new(
id: InputId,
hand: Handedness,
handedness: Handedness,
action_set: &ActionSet,
session: &Session<D3D11>,
) -> Self {
let hand = match hand {
Handedness::Right => "right",
Handedness::Left => "left",
_ => panic!("We don't support unknown handedness in openxr"),
};
let hand = hand_str(handedness);
let action_aim_pose: Action<Posef> = action_set
.create_action(
&format!("{}_hand_aim", hand),
Expand Down Expand Up @@ -134,9 +151,10 @@ impl OpenXRInput {
action_grip_space,
action_click,
action_squeeze,
hand,
handedness,
click_state: ClickState::Done,
squeeze_state: ClickState::Done,
menu_gesture_sustain: 0,
}
}

Expand Down Expand Up @@ -182,23 +200,24 @@ impl OpenXRInput {
select_name: &str,
squeeze_name: Option<&str>,
) -> Vec<Binding> {
let hand = hand_str(self.handedness);
let path_aim_pose = instance
.string_to_path(&format!("/user/hand/{}/input/aim/pose", self.hand))
.string_to_path(&format!("/user/hand/{}/input/aim/pose", hand))
.unwrap();
let binding_aim_pose = Binding::new(&self.action_aim_pose, path_aim_pose);
let path_grip_pose = instance
.string_to_path(&format!("/user/hand/{}/input/grip/pose", self.hand))
.string_to_path(&format!("/user/hand/{}/input/grip/pose", hand))
.unwrap();
let binding_grip_pose = Binding::new(&self.action_grip_pose, path_grip_pose);
let path_click = instance
.string_to_path(&format!("/user/hand/{}/input/{}", self.hand, select_name))
.string_to_path(&format!("/user/hand/{}/input/{}", hand, select_name))
.unwrap();
let binding_click = Binding::new(&self.action_click, path_click);

let mut ret = vec![binding_aim_pose, binding_grip_pose, binding_click];
if let Some(squeeze_name) = squeeze_name {
let path_squeeze = instance
.string_to_path(&format!("/user/hand/{}/input/{}", self.hand, squeeze_name))
.string_to_path(&format!("/user/hand/{}/input/{}", hand, squeeze_name))
.unwrap();
let binding_squeeze = Binding::new(&self.action_squeeze, path_squeeze);
ret.push(binding_squeeze);
Expand All @@ -211,17 +230,53 @@ impl OpenXRInput {
session: &Session<D3D11>,
frame_state: &FrameState,
base_space: &Space,
) -> (InputFrame, Option<SelectEvent>, Option<SelectEvent>) {
) -> Frame {
use euclid::Vector3D;
let target_ray_origin = pose_for(&self.action_aim_space, frame_state, base_space);

let grip_origin = pose_for(&self.action_grip_space, frame_state, base_space);

let mut menu_selected = false;
// Check if the palm is facing up. This is our "menu" gesture.
if let Some(grip_origin) = grip_origin {
// The X axis of the grip is perpendicular to the palm, however its
// direction is the opposite for each hand
//
// We obtain a unit vector poking out of the palm
let x_dir = if let Handedness::Left = self.handedness {
1.0
} else {
-1.0
};

// Rotate it by the grip to obtain the desired vector
let grip_x = grip_origin
.rotation
.transform_vector3d(Vector3D::new(x_dir, 0.0, 0.0));

// Dot product it with the "up" vector to see if it's pointing up
let angle = grip_x.dot(Vector3D::new(0.0, 1.0, 0.0));

// If the angle is close enough to 0, its cosine will be
// close to 1
if angle > 0.9 {
self.menu_gesture_sustain += 1;
if self.menu_gesture_sustain > MENU_GESTURE_SUSTAIN_THRESHOLD {
menu_selected = true;
self.menu_gesture_sustain = 0;
}
} else {
self.menu_gesture_sustain = 0;
}
} else {
self.menu_gesture_sustain = 0;
}

let click = self.action_click.state(session, Path::NULL).unwrap();
let squeeze = self.action_squeeze.state(session, Path::NULL).unwrap();

let (click_is_active, click_select_event) =
self.click_state.update(&self.action_click, session);
let (squeeze_is_active, squeeze_select_event) =
let (click_is_active, click_event) = self.click_state.update(&self.action_click, session);
let (squeeze_is_active, squeeze_event) =
self.squeeze_state.update(&self.action_squeeze, session);

let input_frame = InputFrame {
Expand All @@ -232,7 +287,12 @@ impl OpenXRInput {
grip_origin,
};

(input_frame, click_select_event, squeeze_select_event)
Frame {
frame: input_frame,
select: click_event,
squeeze: squeeze_event,
menu_selected,
}
}
}

Expand Down
Loading