Skip to content

Commit

Permalink
Fix clipboard error handling, wasm clipboard and logs (#347)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladbat00 authored Jan 5, 2025
1 parent ace4aee commit 6c4e192
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 32 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,4 @@ web-sys = { version = "0.3.74", features = [
js-sys = "0.3.63"
wasm-bindgen = "0.2.84"
wasm-bindgen-futures = "0.4.36"
log = "0.4"
crossbeam-channel = "0.5.8"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ A basic WASM example is live at [vladbat00.github.io/bevy_egui/ui](https://vladb
- Opening URLs
- Multiple windows support (see [./examples/two_windows.rs](https://github.com/vladbat00/bevy_egui/blob/v0.31.1/examples/two_windows.rs))
- Paint callback support (see [./examples/paint_callback.rs](https://github.com/vladbat00/bevy_egui/blob/v0.31.1/examples/paint_callback.rs))
- Mobile web virtual keyboard (still rough support and only works without prevent_default_event_handling set to false on the WindowPlugin primary_window)
- Mobile web virtual keyboard (still rough around the edges and only works without `prevent_default_event_handling` set to `false` in the `WindowPlugin` settings)

![bevy_egui](bevy_egui.png)

Expand Down
5 changes: 3 additions & 2 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use bevy_input::{
touch::TouchInput,
ButtonState,
};
use bevy_log as log;
use bevy_time::{Real, Time};
use bevy_window::{CursorMoved, Ime, Window};
use egui::Modifiers;
Expand Down Expand Up @@ -783,12 +784,12 @@ pub fn write_egui_input_system(
) {
for EguiInputEvent { context, event } in egui_input_event_reader.read() {
#[cfg(feature = "log_input_events")]
bevy_log::info!("{context:?}: {event:?}");
log::warn!("{context:?}: {event:?}");

let (_, mut egui_input, _) = match egui_contexts.get_mut(*context) {
Ok(egui_input) => egui_input,
Err(err) => {
bevy_log::error!(
log::error!(
"Failed to get an Egui context ({context:?}) for an event ({event:?}): {err:?}"
);
continue;
Expand Down
43 changes: 23 additions & 20 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ use bevy_ecs::{
#[cfg(feature = "render")]
use bevy_image::{Image, ImageSampler};
use bevy_input::InputSystem;
use bevy_log as log;
#[cfg(feature = "render")]
use bevy_picking::{
backend::{HitData, PointerHits},
Expand Down Expand Up @@ -655,7 +656,7 @@ impl EguiUserTextures {
.free_list
.pop()
.expect("free list must contain at least 1 element");
bevy_log::debug!("Add a new image (id: {}, handle: {:?})", id, image);
log::debug!("Add a new image (id: {}, handle: {:?})", id, image);
if self.free_list.is_empty() {
self.free_list.push(id.checked_add(1).expect("out of ids"));
}
Expand All @@ -667,7 +668,7 @@ impl EguiUserTextures {
/// Removes the image handle and an Egui texture id associated with it.
pub fn remove_image(&mut self, image: &Handle<Image>) -> Option<egui::TextureId> {
let id = self.textures.remove(image);
bevy_log::debug!("Remove image (id: {:?}, handle: {:?})", id, image);
log::debug!("Remove image (id: {:?}, handle: {:?})", id, image);
if let Some(id) = id {
self.free_list.push(id);
}
Expand Down Expand Up @@ -828,7 +829,7 @@ impl Plugin for EguiPlugin {
);

// Startup systems.
#[cfg(all(feature = "manage_clipboard", target_arch = "wasm32",))]
#[cfg(all(feature = "manage_clipboard", target_arch = "wasm32"))]
{
app.add_systems(PreStartup, web_clipboard::startup_setup_web_events_system);
}
Expand Down Expand Up @@ -944,17 +945,6 @@ impl Plugin for EguiPlugin {
.in_set(EguiInputSet::ReadBevyEvents),
);

#[cfg(feature = "manage_clipboard")]
app.add_systems(
PreUpdate,
web_clipboard::write_web_clipboard_events_system
.run_if(input_system_is_enabled(|s| {
s.run_write_web_clipboard_events_system
}))
.in_set(EguiPreUpdateSet::ProcessInput)
.in_set(EguiInputSet::ReadBevyEvents),
);

if is_mobile_safari() {
app.add_systems(
PostUpdate,
Expand All @@ -963,6 +953,17 @@ impl Plugin for EguiPlugin {
);
}
}

#[cfg(feature = "manage_clipboard")]
app.add_systems(
PreUpdate,
web_clipboard::write_web_clipboard_events_system
.run_if(input_system_is_enabled(|s| {
s.run_write_web_clipboard_events_system
}))
.in_set(EguiPreUpdateSet::ProcessInput)
.in_set(EguiInputSet::ReadBevyEvents),
);
}

// PostUpdate systems.
Expand Down Expand Up @@ -1108,7 +1109,7 @@ impl EguiClipboard {
fn set_contents_impl(&mut self, contents: &str) {
if let Some(mut clipboard) = self.get() {
if let Err(err) = clipboard.set_text(contents.to_owned()) {
bevy_log::error!("Failed to set clipboard contents: {:?}", err);
log::error!("Failed to set clipboard contents: {:?}", err);
}
}
}
Expand All @@ -1123,7 +1124,9 @@ impl EguiClipboard {
if let Some(mut clipboard) = self.get() {
match clipboard.get_text() {
Ok(contents) => return Some(contents),
Err(err) => bevy_log::error!("Failed to get clipboard contents: {:?}", err),
// We don't want to spam with this error as it usually means that the clipboard is either empty or has an incompatible format (e.g. image).
Err(arboard::Error::ContentNotAvailable) => return Some("".to_string()),
Err(err) => log::error!("Failed to get clipboard contents: {:?}", err),
}
};
None
Expand All @@ -1142,7 +1145,7 @@ impl EguiClipboard {
Clipboard::new()
.map(RefCell::new)
.map_err(|err| {
bevy_log::error!("Failed to initialize clipboard: {:?}", err);
log::error!("Failed to initialize clipboard: {:?}", err);
})
.ok()
})
Expand Down Expand Up @@ -1217,7 +1220,7 @@ pub fn update_egui_textures_system(
egui_node::color_image_as_bevy_image(&managed_texture.color_image, sampler);
managed_texture.handle = image_assets.add(image);
} else {
bevy_log::warn!("Partial update of a missing texture (id: {:?})", texture_id);
log::warn!("Partial update of a missing texture (id: {:?})", texture_id);
}
} else {
// Full update.
Expand Down Expand Up @@ -1371,12 +1374,12 @@ pub fn update_ui_size_and_scale_system(
scale_factor: 1.0,
})
} else {
bevy_log::warn!("Invalid EguiRenderToImage handle: {handle:?}");
log::warn!("Invalid EguiRenderToImage handle: {handle:?}");
}
}

let Some(new_render_target_size) = render_target_size else {
bevy_log::error!("bevy_egui context without window or render to texture!");
log::error!("bevy_egui context without window or render to texture!");
continue;
};
let width = new_render_target_size.physical_width
Expand Down
17 changes: 9 additions & 8 deletions src/text_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
EguiContext, EguiContextSettings, EguiInput, EguiOutput, EventClosure, SubscribedEvents,
};
use bevy_ecs::prelude::*;
use bevy_log as log;
use bevy_window::{PrimaryWindow, RequestRedraw};
use crossbeam_channel::{unbounded, Receiver, Sender};
use std::sync::{LazyLock, Mutex};
Expand Down Expand Up @@ -174,7 +175,7 @@ pub fn install_text_agent_system(
let sender_clone = sender.clone();
let closure = Closure::wrap(Box::new(move |event: web_sys::InputEvent| {
#[cfg(feature = "log_input_events")]
log::info!(
log::warn!(
"Input event: is_composing={}, data={:?}",
event.is_composing(),
event.data()
Expand Down Expand Up @@ -206,7 +207,7 @@ pub fn install_text_agent_system(
let sender_clone = sender.clone();
let closure = Closure::wrap(Box::new(move |_event: web_sys::CompositionEvent| {
#[cfg(feature = "log_input_events")]
log::info!("Composition start: data={:?}", _event.data());
log::warn!("Composition start: data={:?}", _event.data());
input_clone.set_value("");
let _ = sender_clone.send(egui::Event::Ime(egui::ImeEvent::Enabled));
}) as Box<dyn FnMut(_)>);
Expand All @@ -227,7 +228,7 @@ pub fn install_text_agent_system(
let sender_clone = sender.clone();
let closure = Closure::wrap(Box::new(move |event: web_sys::CompositionEvent| {
#[cfg(feature = "log_input_events")]
log::info!("Composition update: data={:?}", event.data());
log::warn!("Composition update: data={:?}", event.data());
let Some(text) = event.data() else { return };
let event = egui::Event::Ime(egui::ImeEvent::Preedit(text));
let _ = sender_clone.send(event);
Expand All @@ -250,7 +251,7 @@ pub fn install_text_agent_system(
let sender_clone = sender.clone();
let closure = Closure::wrap(Box::new(move |event: web_sys::CompositionEvent| {
#[cfg(feature = "log_input_events")]
log::info!("Composition end: data={:?}", event.data());
log::warn!("Composition end: data={:?}", event.data());
let Some(text) = event.data() else { return };
input_clone.set_value("");
let event = egui::Event::Ime(egui::ImeEvent::Commit(text));
Expand All @@ -275,7 +276,7 @@ pub fn install_text_agent_system(
let safari_sender = safari_virtual_keyboard_touch_state.sender.clone();
let closure = Closure::wrap(Box::new(move |_event: web_sys::TouchEvent| {
#[cfg(feature = "log_input_events")]
log::info!("Touch start: {:?}", _event);
log::warn!("Touch start: {:?}", _event);
let _ = safari_sender.send(());
}) as Box<dyn FnMut(_)>);
document
Expand All @@ -293,7 +294,7 @@ pub fn install_text_agent_system(
let safari_touch_info_lock = safari_virtual_keyboard_touch_state.touch_info;
let closure = Closure::wrap(Box::new(move |_event: web_sys::TouchEvent| {
#[cfg(feature = "log_input_events")]
log::info!("Touch end: {:?}", _event);
log::warn!("Touch end: {:?}", _event);
match safari_touch_info_lock.lock() {
Ok(touch_info) => {
update_text_agent(touch_info.editing_text);
Expand All @@ -319,7 +320,7 @@ pub fn install_text_agent_system(
let sender_clone = sender.clone();
let closure = Closure::wrap(Box::new(move |event: web_sys::KeyboardEvent| {
#[cfg(feature = "log_input_events")]
log::info!("Keyboard event: {:?}", event);
log::warn!("Keyboard event: {:?}", event);
if event.is_composing() || event.key_code() == 229 {
// https://www.fxsitecompat.dev/en-CA/docs/2018/keydown-and-keyup-events-are-now-fired-during-ime-composition/
return;
Expand Down Expand Up @@ -352,7 +353,7 @@ pub fn install_text_agent_system(
let sender_clone = sender.clone();
let closure = Closure::wrap(Box::new(move |event: web_sys::KeyboardEvent| {
#[cfg(feature = "log_input_events")]
log::info!("{:?}", event);
log::warn!("{:?}", event);
input_clone.focus().ok();
if "Backspace" == event.key() {
let _ = sender_clone.send(egui::Event::Key {
Expand Down

0 comments on commit 6c4e192

Please sign in to comment.