From da67a524a5004a86bad246d1f302e65b4809dcef Mon Sep 17 00:00:00 2001 From: Ivy Date: Thu, 8 Aug 2024 17:10:29 -0700 Subject: [PATCH] more updates stolen from upstream and other edits --- src/lib.rs | 47 ++++++++++++++++---------------- src/systems.rs | 24 ++++++++++------- src/text_agent.rs | 69 ++++++++++++++++++++++++++++------------------- 3 files changed, 80 insertions(+), 60 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 67fde69c1..6ace33d2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -656,9 +656,11 @@ impl Plugin for EguiPlugin { world.init_non_send_resource::>(); // virtual keyboard events for text_agent #[cfg(target_arch = "wasm32")] + world.init_non_send_resource::>(); + #[cfg(target_arch = "wasm32")] world.init_non_send_resource::>(); #[cfg(target_arch = "wasm32")] - world.init_non_send_resource::>(); + world.init_non_send_resource::>(); #[cfg(feature = "render")] world.init_resource::(); #[cfg(feature = "render")] @@ -725,29 +727,28 @@ impl Plugin for EguiPlugin { app.add_systems( PreStartup, - |channel: Res, - mut subscribed_input_events: NonSendMut< + (|channel: Res, + mut subscribed_keyboard_events: NonSendMut< + SubscribedEvents, + >, + mut subscribed_input_events: NonSendMut< SubscribedEvents, >, - mut subscribed_keyboard_events: NonSendMut< - SubscribedEvents, + mut subscribed_touch_events: NonSendMut< + SubscribedEvents, >| { text_agent::install_text_agent( - &mut subscribed_input_events, &mut subscribed_keyboard_events, + &mut subscribed_input_events, + &mut subscribed_touch_events, channel.sender.clone(), ) .unwrap(); - }, - ); - - app.add_systems( - PreStartup, - text_agent::virtual_keyboard_handler - .in_set(EguiSet::ProcessInput) - .after(process_input_system) - .after(InputSystem) - .after(EguiSet::InitContexts), + }) + .in_set(EguiSet::ProcessInput) + .after(process_input_system) + .after(InputSystem) + .after(EguiSet::InitContexts), ); app.add_systems( @@ -962,6 +963,13 @@ pub fn string_from_js_value(value: &JsValue) -> String { value.as_string().unwrap_or_else(|| format!("{value:#?}")) } +#[cfg(target_arch = "wasm32")] +struct EventClosure { + target: web_sys::EventTarget, + event_name: String, + closure: wasm_bindgen::closure::Closure, +} + /// Stores event listeners. #[cfg(target_arch = "wasm32")] pub struct SubscribedEvents { @@ -1000,13 +1008,6 @@ impl SubscribedEvents { } } -#[cfg(target_arch = "wasm32")] -struct EventClosure { - target: web_sys::EventTarget, - event_name: String, - closure: wasm_bindgen::closure::Closure, -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/systems.rs b/src/systems.rs index fdde4f637..5d62336e5 100644 --- a/src/systems.rs +++ b/src/systems.rs @@ -21,7 +21,7 @@ use bevy::{ use std::marker::PhantomData; #[cfg(target_arch = "wasm32")] -use crate::text_agent::VIRTUAL_KEYBOARD_GLOBAL; +use crate::text_agent::{is_mobile_safari, update_text_agent, VIRTUAL_KEYBOARD_GLOBAL}; #[allow(missing_docs)] #[derive(SystemParam)] @@ -414,15 +414,6 @@ pub fn process_input_system( .egui_input .events .push(egui::Event::PointerGone); - #[cfg(target_arch = "wasm32")] - match VIRTUAL_KEYBOARD_GLOBAL.lock() { - Ok(mut touch_info) => { - touch_info.editing_text = editing_text; - } - Err(poisoned) => { - let _unused = poisoned.into_inner(); - } - }; } bevy::input::touch::TouchPhase::Canceled => { window_context.ctx.pointer_touch_id = None; @@ -432,6 +423,19 @@ pub fn process_input_system( .push(egui::Event::PointerGone); } } + #[cfg(target_arch = "wasm32")] + if is_mobile_safari() { + match VIRTUAL_KEYBOARD_GLOBAL.lock() { + Ok(mut touch_info) => { + touch_info.editing_text = editing_text; + } + Err(poisoned) => { + let _unused = poisoned.into_inner(); + } + }; + } else { + update_text_agent(editing_text); + } } } diff --git a/src/text_agent.rs b/src/text_agent.rs index 53d412cd9..2db7d74d1 100644 --- a/src/text_agent.rs +++ b/src/text_agent.rs @@ -58,6 +58,19 @@ pub fn propagate_text( } } +// stolen from https://github.com/emilk/egui/pull/4855 +pub fn is_mobile_safari() -> bool { + (|| { + let user_agent = web_sys::window()?.navigator().user_agent().ok()?; + let is_ios = user_agent.contains("iPhone") + || user_agent.contains("iPad") + || user_agent.contains("iPod"); + let is_safari = user_agent.contains("Safari"); + Some(is_ios && is_safari) + })() + .unwrap_or(false) +} + fn is_mobile() -> Option { const MOBILE_DEVICE: [&str; 6] = ["Android", "iPhone", "iPad", "iPod", "webOS", "BlackBerry"]; @@ -68,8 +81,9 @@ fn is_mobile() -> Option { /// Text event handler, pub fn install_text_agent( - subscribed_input_events: &mut SubscribedEvents, subscribed_keyboard_events: &mut SubscribedEvents, + subscribed_input_events: &mut SubscribedEvents, + subscribed_touch_events: &mut SubscribedEvents, sender: Sender, ) -> Result<(), JsValue> { let window = web_sys::window().unwrap(); @@ -101,7 +115,7 @@ pub fn install_text_agent( input.set_autofocus(true); input.set_hidden(true); - { + if let Some(true) = is_mobile() { let input_clone = input.clone(); let sender_clone = sender.clone(); let closure = Closure::wrap(Box::new(move |_event: web_sys::InputEvent| { @@ -125,9 +139,32 @@ pub fn install_text_agent( event_name: "virtual_keyboard_input".to_owned(), closure, }); - } - if let Some(true) = is_mobile() { + // mobile safari doesn't let you set input focus outside of an event handler + if is_mobile_safari() { + let closure = Closure::wrap(Box::new(move |_event: web_sys::TouchEvent| { + match VIRTUAL_KEYBOARD_GLOBAL.lock() { + Ok(touch_info) => { + update_text_agent(touch_info.editing_text); + } + Err(poisoned) => { + let _unused = poisoned.into_inner(); + } + }; + }) as Box); + document + .add_event_listener_with_callback("touchend", closure.as_ref().unchecked_ref()) + .unwrap(); + subscribed_touch_events.event_closures.push(EventClosure { + target: >::as_ref( + &document, + ) + .clone(), + event_name: "virtual_keyboard_touchend".to_owned(), + closure, + }); + } + // keydown let sender_clone = sender.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::KeyboardEvent| { @@ -156,9 +193,7 @@ pub fn install_text_agent( event_name: "virtual_keyboard_keydown".to_owned(), closure, }); - } - if let Some(true) = is_mobile() { // keyup let input_clone = input.clone(); let sender_clone = sender.clone(); @@ -192,28 +227,8 @@ pub fn install_text_agent( Ok(()) } -pub fn virtual_keyboard_handler() { - let document = web_sys::window().unwrap().document().unwrap(); - { - let closure = Closure::wrap(Box::new(move |_event: web_sys::TouchEvent| { - match VIRTUAL_KEYBOARD_GLOBAL.lock() { - Ok(touch_info) => { - update_text_agent(touch_info.editing_text); - } - Err(poisoned) => { - let _unused = poisoned.into_inner(); - } - }; - }) as Box); - document - .add_event_listener_with_callback("touchstart", closure.as_ref().unchecked_ref()) - .unwrap(); - closure.forget(); - } -} - /// Focus or blur text agent to toggle mobile keyboard. -fn update_text_agent(editing_text: bool) { +pub fn update_text_agent(editing_text: bool) { use web_sys::HtmlInputElement; let window = match web_sys::window() {