feat(input): retained mode capture system

This commit is contained in:
Nova
2025-04-07 08:41:48 -07:00
parent 7f8718ad17
commit cefd1a17c1
5 changed files with 43 additions and 16 deletions

4
Cargo.lock generated
View File

@@ -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",

View File

@@ -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>),

View File

@@ -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(())
} }
} }

View File

@@ -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();
} }
} }

View File

@@ -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| {