mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #24362 - Manishearth:input-selections, r=asajeffrey
Support input tracking loss and selection events in XR Fixes https://github.com/servo/servo/issues/24192 Requires https://github.com/servo/webxr/pull/65 r? @jdm @asajeffrey <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/24362) <!-- Reviewable:end -->
This commit is contained in:
commit
ea4e3aee91
10 changed files with 185 additions and 44 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -5522,7 +5522,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "webxr"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#72d85b8254f8ce5d10f91d59ed35cd5969d15ed8"
|
||||
source = "git+https://github.com/servo/webxr#a7e8cae09a5fc3cd3434e644b6e9e2b7697b438c"
|
||||
dependencies = [
|
||||
"bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -5540,7 +5540,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "webxr-api"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#72d85b8254f8ce5d10f91d59ed35cd5969d15ed8"
|
||||
source = "git+https://github.com/servo/webxr#a7e8cae09a5fc3cd3434e644b6e9e2b7697b438c"
|
||||
dependencies = [
|
||||
"euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
|
@ -102,6 +102,8 @@ search
|
|||
seeked
|
||||
seeking
|
||||
select
|
||||
selectend
|
||||
selectstart
|
||||
serif
|
||||
signalingstatechange
|
||||
srclang
|
||||
|
|
|
@ -549,6 +549,7 @@ pub mod xmlserializer;
|
|||
pub mod xr;
|
||||
pub mod xrframe;
|
||||
pub mod xrinputsource;
|
||||
pub mod xrinputsourceevent;
|
||||
pub mod xrpose;
|
||||
pub mod xrreferencespace;
|
||||
pub mod xrrenderstate;
|
||||
|
|
17
components/script/dom/webidls/XRInputSourceEvent.webidl
Normal file
17
components/script/dom/webidls/XRInputSourceEvent.webidl
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// https://immersive-web.github.io/webxr/#xrinputsourceevent-interface
|
||||
|
||||
[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
|
||||
interface XRInputSourceEvent : Event {
|
||||
[Throws] constructor(DOMString type, XRInputSourceEventInit eventInitDict);
|
||||
[SameObject] readonly attribute XRFrame frame;
|
||||
[SameObject] readonly attribute XRInputSource inputSource;
|
||||
};
|
||||
|
||||
dictionary XRInputSourceEventInit : EventInit {
|
||||
required XRFrame frame;
|
||||
required XRInputSource inputSource;
|
||||
};
|
|
@ -39,8 +39,8 @@ interface XRSession : EventTarget {
|
|||
// attribute EventHandler onblur;
|
||||
// attribute EventHandler onfocus;
|
||||
attribute EventHandler onend;
|
||||
// attribute EventHandler onselect;
|
||||
attribute EventHandler onselect;
|
||||
// attribute EventHandler oninputsourceschange;
|
||||
// attribute EventHandler onselectstart;
|
||||
// attribute EventHandler onselectend;
|
||||
attribute EventHandler onselectstart;
|
||||
attribute EventHandler onselectend;
|
||||
};
|
||||
|
|
|
@ -93,8 +93,16 @@ impl XRFrameMethods for XRFrame {
|
|||
if !self.active.get() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
let space = space.get_pose(&self.data);
|
||||
let relative_to = relative_to.get_pose(&self.data);
|
||||
let space = if let Some(space) = space.get_pose(&self.data) {
|
||||
space
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
let relative_to = if let Some(r) = relative_to.get_pose(&self.data) {
|
||||
r
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
let pose = relative_to.inverse().pre_transform(&space);
|
||||
Ok(Some(XRPose::new(&self.global(), pose)))
|
||||
}
|
||||
|
|
90
components/script/dom/xrinputsourceevent.rs
Normal file
90
components/script/dom/xrinputsourceevent.rs
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XRInputSourceEventBinding::{
|
||||
self, XRInputSourceEventMethods,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::xrframe::XRFrame;
|
||||
use crate::dom::xrinputsource::XRInputSource;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_atoms::Atom;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRInputSourceEvent {
|
||||
event: Event,
|
||||
frame: Dom<XRFrame>,
|
||||
source: Dom<XRInputSource>,
|
||||
}
|
||||
|
||||
impl XRInputSourceEvent {
|
||||
#[allow(unrooted_must_root)]
|
||||
fn new_inherited(frame: &XRFrame, source: &XRInputSource) -> XRInputSourceEvent {
|
||||
XRInputSourceEvent {
|
||||
event: Event::new_inherited(),
|
||||
frame: Dom::from_ref(frame),
|
||||
source: Dom::from_ref(source),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
type_: Atom,
|
||||
bubbles: bool,
|
||||
cancelable: bool,
|
||||
frame: &XRFrame,
|
||||
source: &XRInputSource,
|
||||
) -> DomRoot<XRInputSourceEvent> {
|
||||
let trackevent = reflect_dom_object(
|
||||
Box::new(XRInputSourceEvent::new_inherited(frame, source)),
|
||||
global,
|
||||
XRInputSourceEventBinding::Wrap,
|
||||
);
|
||||
{
|
||||
let event = trackevent.upcast::<Event>();
|
||||
event.init_event(type_, bubbles, cancelable);
|
||||
}
|
||||
trackevent
|
||||
}
|
||||
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
type_: DOMString,
|
||||
init: &XRInputSourceEventBinding::XRInputSourceEventInit,
|
||||
) -> Fallible<DomRoot<XRInputSourceEvent>> {
|
||||
Ok(XRInputSourceEvent::new(
|
||||
&window.global(),
|
||||
Atom::from(type_),
|
||||
init.parent.bubbles,
|
||||
init.parent.cancelable,
|
||||
&init.frame,
|
||||
&init.inputSource,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl XRInputSourceEventMethods for XRInputSourceEvent {
|
||||
// https://immersive-web.github.io/webxr/#dom-xrinputsourceeventinit-frame
|
||||
fn Frame(&self) -> DomRoot<XRFrame> {
|
||||
DomRoot::from_ref(&*self.frame)
|
||||
}
|
||||
|
||||
// https://immersive-web.github.io/webxr/#dom-xrinputsourceeventinit-inputsource
|
||||
fn InputSource(&self) -> DomRoot<XRInputSource> {
|
||||
DomRoot::from_ref(&*self.source)
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-event-istrusted
|
||||
fn IsTrusted(&self) -> bool {
|
||||
self.event.IsTrusted()
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@ use crate::dom::promise::Promise;
|
|||
use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot;
|
||||
use crate::dom::xrframe::XRFrame;
|
||||
use crate::dom::xrinputsource::XRInputSource;
|
||||
use crate::dom::xrinputsourceevent::XRInputSourceEvent;
|
||||
use crate::dom::xrreferencespace::XRReferenceSpace;
|
||||
use crate::dom::xrrenderstate::XRRenderState;
|
||||
use crate::dom::xrsessionevent::XRSessionEvent;
|
||||
|
@ -48,7 +49,7 @@ use profile_traits::ipc;
|
|||
use std::cell::Cell;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use webxr_api::{self, Event as XREvent, Frame, Session};
|
||||
use webxr_api::{self, Event as XREvent, Frame, SelectEvent, Session};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRSession {
|
||||
|
@ -170,6 +171,52 @@ impl XRSession {
|
|||
let event = XRSessionEvent::new(&self.global(), atom!("end"), false, false, self);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
},
|
||||
XREvent::Select(input, kind, frame) => {
|
||||
// https://immersive-web.github.io/webxr/#primary-action
|
||||
let source = self
|
||||
.input_sources
|
||||
.borrow_mut()
|
||||
.iter()
|
||||
.find(|s| s.id() == input)
|
||||
.map(|x| DomRoot::from_ref(&**x));
|
||||
if let Some(source) = source {
|
||||
let frame = XRFrame::new(&self.global(), self, frame);
|
||||
frame.set_active(true);
|
||||
if kind == SelectEvent::Start {
|
||||
let event = XRInputSourceEvent::new(
|
||||
&self.global(),
|
||||
atom!("selectstart"),
|
||||
false,
|
||||
false,
|
||||
&frame,
|
||||
&source,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
} else {
|
||||
if kind == SelectEvent::Select {
|
||||
let event = XRInputSourceEvent::new(
|
||||
&self.global(),
|
||||
atom!("select"),
|
||||
false,
|
||||
false,
|
||||
&frame,
|
||||
&source,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
let event = XRInputSourceEvent::new(
|
||||
&self.global(),
|
||||
atom!("selectend"),
|
||||
false,
|
||||
false,
|
||||
&frame,
|
||||
&source,
|
||||
);
|
||||
event.upcast::<Event>().fire(self.upcast());
|
||||
}
|
||||
frame.set_active(false);
|
||||
}
|
||||
},
|
||||
_ => (), // XXXManishearth TBD
|
||||
}
|
||||
}
|
||||
|
@ -244,6 +291,15 @@ impl XRSessionMethods for XRSession {
|
|||
/// https://immersive-web.github.io/webxr/#eventdef-xrsession-end
|
||||
event_handler!(end, GetOnend, SetOnend);
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#eventdef-xrsession-select
|
||||
event_handler!(select, GetOnselect, SetOnselect);
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectstart
|
||||
event_handler!(selectstart, GetOnselectstart, SetOnselectstart);
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectend
|
||||
event_handler!(selectend, GetOnselectend, SetOnselectend);
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xrsession-mode
|
||||
fn Mode(&self) -> XRSessionMode {
|
||||
XRSessionMode::Immersive_vr
|
||||
|
|
|
@ -57,9 +57,9 @@ impl XRSpace {
|
|||
/// The reference origin used is common between all
|
||||
/// get_pose calls for spaces from the same device, so this can be used to compare
|
||||
/// with other spaces
|
||||
pub fn get_pose(&self, base_pose: &Frame) -> ApiPose {
|
||||
pub fn get_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
|
||||
if let Some(reference) = self.downcast::<XRReferenceSpace>() {
|
||||
reference.get_pose(base_pose)
|
||||
Some(reference.get_pose(base_pose))
|
||||
} else if let Some(source) = self.input_source.get() {
|
||||
// XXXManishearth we should be able to request frame information
|
||||
// for inputs when necessary instead of always loading it
|
||||
|
@ -72,7 +72,7 @@ impl XRSpace {
|
|||
.iter()
|
||||
.find(|i| i.id == id)
|
||||
.expect("no input found");
|
||||
cast_transform(frame.target_ray_origin)
|
||||
frame.target_ray_origin.map(cast_transform)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
|
@ -53,18 +53,9 @@
|
|||
[XRWebGLLayer interface: operation getNativeFramebufferScaleFactor(XRSession)]
|
||||
expected: FAIL
|
||||
|
||||
[XRSession interface: attribute onselectend]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface: attribute frame]
|
||||
expected: FAIL
|
||||
|
||||
[XRRay interface: attribute matrix]
|
||||
expected: FAIL
|
||||
|
||||
[XRSession interface: attribute onselect]
|
||||
expected: FAIL
|
||||
|
||||
[XRReferenceSpaceEvent interface object length]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -74,24 +65,12 @@
|
|||
[XRInputSourcesChangeEvent interface: attribute added]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface: attribute inputSource]
|
||||
expected: FAIL
|
||||
|
||||
[XRBoundedReferenceSpace interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface object name]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourcesChangeEvent interface: attribute removed]
|
||||
expected: FAIL
|
||||
|
||||
[XRSession interface: attribute onselectstart]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[XRReferenceSpaceEvent interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -110,9 +89,6 @@
|
|||
[XRInputSourceArray interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface: existence and properties of interface prototype object's @@unscopables property]
|
||||
expected: FAIL
|
||||
|
||||
[XRRay interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -164,12 +140,6 @@
|
|||
[XRRay interface: existence and properties of interface prototype object]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface: existence and properties of interface object]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceArray interface object length]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -206,9 +176,6 @@
|
|||
[XRInputSourceArray interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSourceEvent interface object length]
|
||||
expected: FAIL
|
||||
|
||||
[XRSession interface: attribute oninputsourceschange]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue