use super::{ input_method_client, InputData, InputDataTrait, InputDataType, InputHandler, InputMethodAspect, InputMethodRefAspect, INPUT_HANDLER_REGISTRY, INPUT_METHOD_REF_ASPECT_ALIAS_INFO, INPUT_METHOD_REGISTRY, }; use crate::{ core::{client::Client, registry::Registry}, nodes::{ alias::{Alias, AliasList}, fields::{Field, FIELD_ALIAS_INFO}, spatial::Spatial, Aspect, Node, }, }; use color_eyre::eyre::Result; use parking_lot::Mutex; use stardust_xr::values::Datamap; use std::sync::{Arc, Weak}; pub struct InputMethod { pub spatial: Arc, pub data: Mutex, pub datamap: Mutex, handler_aliases: AliasList, handler_field_aliases: AliasList, pub(super) handler_order: Mutex>>, pub internal_capture_requests: Registry, pub captures: Registry, } impl InputMethod { pub fn add_to( node: &Arc, data: InputDataType, datamap: Datamap, ) -> Result> { let method = InputMethod { spatial: node.get_aspect::().unwrap().clone(), data: Mutex::new(data), datamap: Mutex::new(datamap), handler_aliases: AliasList::default(), handler_field_aliases: AliasList::default(), handler_order: Mutex::new(Vec::new()), internal_capture_requests: Registry::new(), captures: Registry::new(), }; ::add_node_members(node); ::add_node_members(node); for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() { method.handle_new_handler(&handler); } let method = INPUT_METHOD_REGISTRY.add(method); node.add_aspect_raw(method.clone()); Ok(method) } pub fn distance(&self, to: &Field) -> f32 { self.data.lock().distance(&self.spatial, to) } pub fn set_handler_order<'a>(&self, handlers: impl Iterator>) { *self.handler_order.lock() = handlers.map(Arc::downgrade).collect(); } pub(super) fn make_alias(&self, handler: &InputHandler) { let Some(method_node) = self.spatial.node() else { return; }; let Some(handler_node) = handler.spatial.node() else { return; }; let Some(client) = handler_node.get_client() else { return; }; let Ok(method_alias) = Alias::create( &method_node, &client, INPUT_METHOD_REF_ASPECT_ALIAS_INFO.clone(), Some(&handler.method_aliases), ) else { return; }; method_alias.set_enabled(false); } pub(super) fn handle_new_handler(&self, handler: &InputHandler) { self.make_alias(handler); let Some(method_node) = self.spatial.node() else { return; }; let Some(method_client) = method_node.get_client() else { return; }; let Some(handler_node) = handler.spatial.node() else { return; }; // Receiver itself let Ok(handler_alias) = Alias::create( &handler_node, &method_client, INPUT_METHOD_REF_ASPECT_ALIAS_INFO.clone(), Some(&self.handler_aliases), ) else { return; }; let Some(handler_field_node) = handler.field.spatial.node() else { return; }; // Handler's field let Ok(rx_field_alias) = Alias::create( &handler_field_node, &method_client, FIELD_ALIAS_INFO.clone(), Some(&self.handler_field_aliases), ) else { return; }; let _ = input_method_client::create_handler(&method_node, &handler_alias, &rx_field_alias); } pub(super) fn handle_drop_handler(&self, handler: &InputHandler) { let Some(tx_node) = self.spatial.node() else { return; }; let Some(handler_alias) = self.handler_aliases.get_from_aspect(handler) else { return; }; let _ = input_method_client::destroy_handler(&tx_node, handler_alias.id); self.handler_aliases.remove_aspect(handler); self.handler_field_aliases .remove_aspect(handler.field.as_ref()); } pub(super) fn serialize(&self, alias_id: u64, handler: &Arc) -> InputData { let mut input = self.data.lock().clone(); input.transform(self, handler); InputData { id: alias_id, input, distance: self.distance(&handler.field), datamap: self.datamap.lock().clone(), order: self .handler_order .lock() .iter() .enumerate() .find(|(_, h)| h.ptr_eq(&Arc::downgrade(handler))) .unwrap() .0 as u32, captured: self.captures.get_valid_contents().contains(handler), } } } impl Aspect for InputMethod { const NAME: &'static str = "InputMethod"; } impl InputMethodRefAspect for InputMethod { #[doc = "Have the input handler that this method reference came from capture the method for the next frame."] fn request_capture( node: Arc, _calling_client: Arc, handler: Arc, ) -> Result<()> { let input_method = node.get_aspect::()?; let input_handler = handler.get_aspect::()?; input_method .internal_capture_requests .add_raw(&input_handler); Ok(()) } } 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."] fn set_input( node: Arc, _calling_client: Arc, input: InputDataType, ) -> Result<()> { let input_method = node.get_aspect::()?; *input_method.data.lock() = input; Ok(()) } #[doc = "Set the datmap of this input method"] fn set_datamap(node: Arc, _calling_client: Arc, datamap: Datamap) -> Result<()> { let input_method = node.get_aspect::()?; *input_method.datamap.lock() = datamap; Ok(()) } #[doc = "Manually set the order of handlers to propagate input to, or else let the server decide."] fn set_handler_order( node: Arc, _calling_client: Arc, handlers: Vec>, ) -> Result<()> { let input_method = node.get_aspect::()?; let handlers = handlers .into_iter() .filter_map(|p| p.get_aspect::().ok()) .map(|i| Arc::downgrade(&i)) .collect::>(); *input_method.handler_order.lock() = handlers; Ok(()) } #[doc = "Set which handlers are captured."] fn set_captures( node: Arc, _calling_client: Arc, handlers: Vec>, ) -> Result<()> { let input_method = node.get_aspect::()?; input_method.captures.clear(); for handler in handlers { let Ok(handler) = handler.get_aspect::() else { continue; }; input_method.captures.add_raw(&handler); } Ok(()) } } impl Drop for InputMethod { fn drop(&mut self) { INPUT_METHOD_REGISTRY.remove(self); } }