Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable wasm, when it works #30

Merged
merged 5 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.wasm32-unknown-unknown]
runner = "wasm-server-runner"
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ debug-render = []
metrics = []

[dependencies]
arboard = "3.4"
bevy = "0.14"
bevy_mod_picking = "0.20"
bevy_vello = { version = "0.5", features = ["svg"] }
bevy-inspector-egui = "0.25"
Expand All @@ -27,10 +25,22 @@ taffy = { version = "0.5", features = ["flexbox", "grid"] }
thiserror = "1.0"
unicode-segmentation = "1.10.0"
usvg = "0.42"
web-time = "1.1"

# Local
woodpecker_ui_macros.path = "crates/woodpecker_ui_macros" # TODO: Make this crates.io friendly..

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
arboard = "3.4"
bevy = "0.14"

[target.'cfg(target_arch = "wasm32")'.dependencies]
bevy = { version = "0.14", default-features = false, features = ["webgpu"] }
web-sys = "0.3"
wasm-bindgen-futures = "0.4"
futures-channel = "0.3"


[dev-dependencies]
calc = { version = "0.4.0", default-features = false }
bevy = { version = "0.14", features = ["jpeg"] }
Expand Down
89 changes: 77 additions & 12 deletions src/keyboard_input.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::time::{Duration, Instant};
use web_time::{Duration, Instant};

use bevy::{
input::{
Expand Down Expand Up @@ -53,6 +53,14 @@ pub struct WidgetPasteEvent {
pub paste: smol_str::SmolStr,
}

#[cfg(target_arch = "wasm32")]
#[derive(Component)]
pub struct WidgetPasteEventWasm {
/// The target of this event
pub target: Entity,
pub receiver: futures_channel::oneshot::Receiver<String>,
}

#[derive(Debug, Deref, DerefMut)]
pub(crate) struct TimeSinceLastPaste(Instant);
impl Default for TimeSinceLastPaste {
Expand All @@ -61,13 +69,34 @@ impl Default for TimeSinceLastPaste {
}
}

#[cfg(target_arch = "wasm32")]
pub(crate) fn read_paste_events(
mut commands: Commands,
mut query: Query<(Entity, &mut WidgetPasteEventWasm)>,
mut paste_event_writer: EventWriter<WidgetPasteEvent>,
mut time_since_last_paste: Local<TimeSinceLastPaste>,
) {
for (entity, mut event) in &mut query {
let Ok(Some(text)) = event.receiver.try_recv() else {
continue;
};
*time_since_last_paste = TimeSinceLastPaste::default();
paste_event_writer.send(WidgetPasteEvent {
target: event.target,
paste: smol_str::SmolStr::new(text.to_string()),
});
commands.entity(entity).despawn_recursive();
}
}

pub(crate) fn runner(
#[cfg(target_arch = "wasm32")] mut commands: Commands,
mut time_since_last_paste: Local<TimeSinceLastPaste>,
mut ctrl_pressed: Local<bool>,
mut key_event: EventReader<KeyboardInput>,
mut char_event_writer: EventWriter<WidgetKeyboardCharEvent>,
mut button_event_writer: EventWriter<WidgetKeyboardButtonEvent>,
mut paste_event_writer: EventWriter<WidgetPasteEvent>,
#[cfg(not(target_arch = "wasm32"))] mut paste_event_writer: EventWriter<WidgetPasteEvent>,
current_focus: Res<CurrentFocus>,
) {
let mut v_pressed = false;
Expand Down Expand Up @@ -97,18 +126,54 @@ pub(crate) fn runner(
if time_since_last_paste.elapsed().as_secs_f32() < 0.1 {
return;
}
let Ok(mut clipboard) = arboard::Clipboard::new() else {

#[cfg(not(target_arch = "wasm32"))]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should be able to use this as an alternative:
https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Clipboard.html

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I think Clipboard is going to work. Its necessarily async which is a bit of a pain since EventWriters, Commands, etc are going to get moved out of the loop (and can't be) but worst-case scenario I think we can AsyncTask it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a look at it tonight. TaskPool::scope would work (and is seemingly the Right Way) for passing the EventWriter in and such... except that it panics when awaiting the clipboard future.

This seems like a long-standing issue: bevyengine/bevy#1924

I pushed up some code that gets the clipboard text, but its not working as we'll need a workaround for scope not panning out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#ecs says use a channel so I'll do that

{
let Ok(mut clipboard) = arboard::Clipboard::new() else {
return;
};
let Ok(text) = clipboard.get_text() else {
return;
};
*time_since_last_paste = TimeSinceLastPaste::default();
paste_event_writer.send(WidgetPasteEvent {
target: current_focus.get(),
paste: smol_str::SmolStr::new(text),
});
return;
};
let Ok(text) = clipboard.get_text() else {
}

#[cfg(target_arch = "wasm32")]
{
let Some(clipboard) =
web_sys::window().and_then(|window| window.navigator().clipboard())
else {
warn!("no clipboard");
return;
};
let promise = clipboard.read_text();
let future = wasm_bindgen_futures::JsFuture::from(promise);

let (sender, receiver) = futures_channel::oneshot::channel::<String>();

let pool = bevy::tasks::TaskPool::new();
pool.spawn(async move {
let Ok(text) = future.await else {
return;
};
let Some(text) = text.as_string() else {
return;
};
let _ = sender.send(text);
});

commands.spawn(WidgetPasteEventWasm {
target: current_focus.get(),
receiver,
});

return;
};
*time_since_last_paste = TimeSinceLastPaste::default();
paste_event_writer.send(WidgetPasteEvent {
target: current_focus.get(),
paste: smol_str::SmolStr::new(text),
});
return;
}
}
match &event.logical_key {
Key::Character(c) => {
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod entity_mapping;
mod focus;
mod font;
mod hook_helper;
mod image;
mod keyboard_input;
mod layout;
mod metrics;
Expand All @@ -30,7 +31,6 @@ mod styles;
mod svg;
mod vello_svg;
mod widgets;
mod image;

/// A module that exports all publicly exposed types.
pub mod prelude {
Expand Down Expand Up @@ -120,7 +120,10 @@ impl Plugin for WoodpeckerUIPlugin {
(
runner::system,
focus::CurrentFocus::click_focus,
#[cfg(not(target_arch = "wasm32"))]
keyboard_input::runner,
#[cfg(target_arch = "wasm32")]
(keyboard_input::runner, keyboard_input::read_paste_events).chain(),
hook_helper::HookHelper::update_context_helper,
)
.run_if(has_root()),
Expand Down
2 changes: 1 addition & 1 deletion src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::time::Instant;
use web_time::Instant;

use bevy::prelude::*;

Expand Down
2 changes: 1 addition & 1 deletion src/widgets/text_box.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::time::Instant;
use web_time::Instant;

use crate::{
keyboard_input::{WidgetKeyboardButtonEvent, WidgetPasteEvent},
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/transition.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::prelude::*;
use interpolation::Ease;
use interpolation::EaseFunction;
use std::time::Instant;
use web_time::Instant;

use crate::prelude::*;

Expand Down