feat(input): retained mode capture system
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -2620,7 +2620,7 @@ checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "stardust-xr"
|
name = "stardust-xr"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
source = "git+https://github.com/StardustXR/core.git?branch=dev#8640276cc5b445fc486694f63f884323fc818860"
|
source = "git+https://github.com/StardustXR/core.git?branch=dev#d2964d8db079afaadb7faa4987e34814e62d6279"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cluFlock",
|
"cluFlock",
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
@@ -2641,7 +2641,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "stardust-xr-schemas"
|
name = "stardust-xr-schemas"
|
||||||
version = "1.5.3"
|
version = "1.5.3"
|
||||||
source = "git+https://github.com/StardustXR/core.git?branch=dev#8640276cc5b445fc486694f63f884323fc818860"
|
source = "git+https://github.com/StardustXR/core.git?branch=dev#d2964d8db079afaadb7faa4987e34814e62d6279"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flatbuffers",
|
"flatbuffers",
|
||||||
"flexbuffers",
|
"flexbuffers",
|
||||||
|
|||||||
@@ -103,6 +103,16 @@ impl<T: Send + Sync + ?Sized> Default for Registry<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Send + Sync + Sized> FromIterator<Arc<T>> for Registry<T> {
|
||||||
|
fn from_iter<I: IntoIterator<Item = Arc<T>>>(iter: I) -> Self {
|
||||||
|
Registry(MaybeLazy::NonLazy(
|
||||||
|
iter.into_iter()
|
||||||
|
.map(|i| (Arc::as_ptr(&i) as usize, Arc::downgrade(&i)))
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum MaybeLazy<T> {
|
enum MaybeLazy<T> {
|
||||||
Lazy(LazyLock<T>),
|
Lazy(LazyLock<T>),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pub struct InputMethod {
|
|||||||
handler_aliases: AliasList,
|
handler_aliases: AliasList,
|
||||||
handler_field_aliases: AliasList,
|
handler_field_aliases: AliasList,
|
||||||
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
|
pub(super) handler_order: Mutex<Vec<Weak<InputHandler>>>,
|
||||||
pub internal_capture_requests: Registry<InputHandler>,
|
pub capture_attempts: Registry<InputHandler>,
|
||||||
pub captures: Registry<InputHandler>,
|
pub captures: Registry<InputHandler>,
|
||||||
}
|
}
|
||||||
impl InputMethod {
|
impl InputMethod {
|
||||||
@@ -41,7 +41,7 @@ impl InputMethod {
|
|||||||
handler_aliases: AliasList::default(),
|
handler_aliases: AliasList::default(),
|
||||||
handler_field_aliases: AliasList::default(),
|
handler_field_aliases: AliasList::default(),
|
||||||
handler_order: Mutex::new(Vec::new()),
|
handler_order: Mutex::new(Vec::new()),
|
||||||
internal_capture_requests: Registry::new(),
|
capture_attempts: Registry::new(),
|
||||||
captures: Registry::new(),
|
captures: Registry::new(),
|
||||||
};
|
};
|
||||||
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
|
||||||
@@ -151,6 +151,16 @@ impl InputMethod {
|
|||||||
captured: self.captures.get_valid_contents().contains(handler),
|
captured: self.captures.get_valid_contents().contains(handler),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn cull_capture_attempts(&self) {
|
||||||
|
let sent = self
|
||||||
|
.handler_order
|
||||||
|
.lock()
|
||||||
|
.iter()
|
||||||
|
.filter_map(Weak::upgrade)
|
||||||
|
.collect::<Registry<InputHandler>>();
|
||||||
|
self.captures.retain(|handler| sent.contains(handler));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl InputMethodAspect for InputMethod {
|
impl InputMethodAspect for InputMethod {
|
||||||
#[doc = "Set the spatial input component of this input method. You must keep the same input data type throughout the entire thing."]
|
#[doc = "Set the spatial input component of this input method. You must keep the same input data type throughout the entire thing."]
|
||||||
@@ -213,8 +223,8 @@ impl Drop for InputMethod {
|
|||||||
|
|
||||||
pub struct InputMethodRef;
|
pub struct InputMethodRef;
|
||||||
impl InputMethodRefAspect for InputMethodRef {
|
impl InputMethodRefAspect for InputMethodRef {
|
||||||
#[doc = "Have the input handler that this method reference came from capture the method for the next frame."]
|
#[doc = "Try to capture the input method with the given handler. When the handler does not get input from the method, it will be released."]
|
||||||
fn request_capture(
|
fn try_capture(
|
||||||
node: Arc<Node>,
|
node: Arc<Node>,
|
||||||
_calling_client: Arc<Client>,
|
_calling_client: Arc<Client>,
|
||||||
handler: Arc<Node>,
|
handler: Arc<Node>,
|
||||||
@@ -222,9 +232,16 @@ impl InputMethodRefAspect for InputMethodRef {
|
|||||||
let input_method = node.get_aspect::<InputMethod>()?;
|
let input_method = node.get_aspect::<InputMethod>()?;
|
||||||
let input_handler = handler.get_aspect::<InputHandler>()?;
|
let input_handler = handler.get_aspect::<InputHandler>()?;
|
||||||
|
|
||||||
input_method
|
input_method.capture_attempts.add_raw(&input_handler);
|
||||||
.internal_capture_requests
|
Ok(())
|
||||||
.add_raw(&input_handler);
|
}
|
||||||
|
|
||||||
|
#[doc = "If captured by this handler, release it (e.g. the object is let go of after grabbing)."]
|
||||||
|
fn release(node: Arc<Node>, _calling_client: Arc<Client>, handler: Arc<Node>) -> Result<()> {
|
||||||
|
let input_method = node.get_aspect::<InputMethod>()?;
|
||||||
|
let input_handler = handler.get_aspect::<InputHandler>()?;
|
||||||
|
|
||||||
|
input_method.capture_attempts.remove(&input_handler);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,6 @@ pub fn process_input() {
|
|||||||
let _ = input_handler_client::input(&handler_node, &methods, &datas);
|
let _ = input_handler_client::input(&handler_node, &methods, &datas);
|
||||||
}
|
}
|
||||||
for method in methods {
|
for method in methods {
|
||||||
method.internal_capture_requests.clear();
|
method.cull_capture_attempts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ pub struct CaptureManager {
|
|||||||
pub capture: Option<Arc<InputHandler>>,
|
pub capture: Option<Arc<InputHandler>>,
|
||||||
}
|
}
|
||||||
impl CaptureManager {
|
impl CaptureManager {
|
||||||
pub fn update_capture(&mut self, pointer: &InputMethod) {
|
pub fn update_capture(&mut self, method: &InputMethod) {
|
||||||
if let Some(capture) = &self.capture {
|
if let Some(capture) = &self.capture {
|
||||||
if !pointer
|
if !method
|
||||||
.internal_capture_requests
|
.capture_attempts
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.contains(capture)
|
.contains(capture)
|
||||||
{
|
{
|
||||||
@@ -29,11 +29,11 @@ impl CaptureManager {
|
|||||||
}
|
}
|
||||||
pub fn set_new_capture(
|
pub fn set_new_capture(
|
||||||
&mut self,
|
&mut self,
|
||||||
pointer: &InputMethod,
|
method: &InputMethod,
|
||||||
distance_calculator: DistanceCalculator,
|
distance_calculator: DistanceCalculator,
|
||||||
) {
|
) {
|
||||||
if self.capture.is_none() {
|
if self.capture.is_none() {
|
||||||
self.capture = find_closest_capture(pointer, distance_calculator);
|
self.capture = find_closest_capture(method, distance_calculator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn apply_capture(&self, method: &InputMethod) {
|
pub fn apply_capture(&self, method: &InputMethod) {
|
||||||
@@ -52,7 +52,7 @@ pub fn find_closest_capture(
|
|||||||
distance_calculator: DistanceCalculator,
|
distance_calculator: DistanceCalculator,
|
||||||
) -> Option<Arc<InputHandler>> {
|
) -> Option<Arc<InputHandler>> {
|
||||||
method
|
method
|
||||||
.internal_capture_requests
|
.capture_attempts
|
||||||
.get_valid_contents()
|
.get_valid_contents()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|h| {
|
.filter_map(|h| {
|
||||||
|
|||||||
Reference in New Issue
Block a user