From fe9ae8225ce4fba83b5262d6ed43dea810f0778f Mon Sep 17 00:00:00 2001 From: Nova Date: Mon, 7 Apr 2025 08:41:48 -0700 Subject: [PATCH] feat(input): retained mode capture system --- Cargo.lock | 4 ++-- src/core/registry.rs | 10 ++++++++++ src/nodes/input/method.rs | 31 ++++++++++++++++++++++++------- src/nodes/input/mod.rs | 2 +- src/objects/input/mod.rs | 12 ++++++------ 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc7eeda..7ee767a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2620,7 +2620,7 @@ checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d" [[package]] name = "stardust-xr" 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 = [ "cluFlock", "color-eyre", @@ -2641,7 +2641,7 @@ dependencies = [ [[package]] name = "stardust-xr-schemas" 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 = [ "flatbuffers", "flexbuffers", diff --git a/src/core/registry.rs b/src/core/registry.rs index d1e5431..22556e8 100644 --- a/src/core/registry.rs +++ b/src/core/registry.rs @@ -103,6 +103,16 @@ impl Default for Registry { } } +impl FromIterator> for Registry { + fn from_iter>>(iter: I) -> Self { + Registry(MaybeLazy::NonLazy( + iter.into_iter() + .map(|i| (Arc::as_ptr(&i) as usize, Arc::downgrade(&i))) + .collect(), + )) + } +} + #[derive(Debug)] enum MaybeLazy { Lazy(LazyLock), diff --git a/src/nodes/input/method.rs b/src/nodes/input/method.rs index 39d5d4b..663f03b 100644 --- a/src/nodes/input/method.rs +++ b/src/nodes/input/method.rs @@ -24,7 +24,7 @@ pub struct InputMethod { handler_aliases: AliasList, handler_field_aliases: AliasList, pub(super) handler_order: Mutex>>, - pub internal_capture_requests: Registry, + pub capture_attempts: Registry, pub captures: Registry, } impl InputMethod { @@ -41,7 +41,7 @@ impl InputMethod { handler_aliases: AliasList::default(), handler_field_aliases: AliasList::default(), handler_order: Mutex::new(Vec::new()), - internal_capture_requests: Registry::new(), + capture_attempts: Registry::new(), captures: Registry::new(), }; for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() { @@ -151,6 +151,16 @@ impl InputMethod { 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::>(); + self.captures.retain(|handler| sent.contains(handler)); + } } 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."] @@ -213,8 +223,8 @@ impl Drop for InputMethod { pub struct InputMethodRef; impl InputMethodRefAspect for InputMethodRef { - #[doc = "Have the input handler that this method reference came from capture the method for the next frame."] - fn request_capture( + #[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 try_capture( node: Arc, _calling_client: Arc, handler: Arc, @@ -222,9 +232,16 @@ impl InputMethodRefAspect for InputMethodRef { let input_method = node.get_aspect::()?; let input_handler = handler.get_aspect::()?; - input_method - .internal_capture_requests - .add_raw(&input_handler); + input_method.capture_attempts.add_raw(&input_handler); + Ok(()) + } + + #[doc = "If captured by this handler, release it (e.g. the object is let go of after grabbing)."] + fn release(node: Arc, _calling_client: Arc, handler: Arc) -> Result<()> { + let input_method = node.get_aspect::()?; + let input_handler = handler.get_aspect::()?; + + input_method.capture_attempts.remove(&input_handler); Ok(()) } } diff --git a/src/nodes/input/mod.rs b/src/nodes/input/mod.rs index 60aaa08..2ae32a6 100644 --- a/src/nodes/input/mod.rs +++ b/src/nodes/input/mod.rs @@ -165,6 +165,6 @@ pub fn process_input() { let _ = input_handler_client::input(&handler_node, &methods, &datas); } for method in methods { - method.internal_capture_requests.clear(); + method.cull_capture_attempts(); } } diff --git a/src/objects/input/mod.rs b/src/objects/input/mod.rs index 252a3c0..3209e53 100644 --- a/src/objects/input/mod.rs +++ b/src/objects/input/mod.rs @@ -16,10 +16,10 @@ pub struct CaptureManager { pub capture: Option>, } 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 !pointer - .internal_capture_requests + if !method + .capture_attempts .get_valid_contents() .contains(capture) { @@ -29,11 +29,11 @@ impl CaptureManager { } pub fn set_new_capture( &mut self, - pointer: &InputMethod, + method: &InputMethod, distance_calculator: DistanceCalculator, ) { 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) { @@ -52,7 +52,7 @@ pub fn find_closest_capture( distance_calculator: DistanceCalculator, ) -> Option> { method - .internal_capture_requests + .capture_attempts .get_valid_contents() .into_iter() .filter_map(|h| {