#[doc = include_str!("../README.md")]
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bevy_input::{touch::touch_screen_input_system, touch::TouchInput};
use bevy_log::*;
use bevy_math::prelude::*;
#[derive(Resource, Default)]
pub struct AdditionalTouchOffset(pub Vec2);
#[derive(Resource, Default)]
pub struct TouchOffset(pub Vec2);
#[derive(Resource)]
pub struct PrimaryCanvasId(pub String);
impl Default for PrimaryCanvasId {
fn default() -> Self {
Self("main-canvas".to_string())
}
}
#[derive(Event)]
pub struct TouchOffsetChangeEvent(pub Vec2);
#[derive(Default)]
pub struct WasmTouchFixPlugin;
impl Plugin for WasmTouchFixPlugin {
fn build(&self, app: &mut App) {
app
.add_systems(
PreUpdate,
(check_canvas_offset, offset_touch_input_events)
.chain()
.before(touch_screen_input_system),
)
.add_event::<TouchOffsetChangeEvent>()
.init_resource::<TouchOffset>()
.init_resource::<AdditionalTouchOffset>()
.init_resource::<PrimaryCanvasId>();
}
}
pub fn check_canvas_offset(
primary_canvas_id: Res<PrimaryCanvasId>,
mut touch_offset: ResMut<TouchOffset>,
mut touch_offset_change_event_writer: EventWriter<TouchOffsetChangeEvent>,
mut error_count: Local<u32>,
) {
if let Some(curr_offset) = web_sys::window()
.and_then(|window| window.document())
.and_then(|document| document.get_element_by_id(&primary_canvas_id.0))
.map(|element| element.get_bounding_client_rect())
.map(|rect| Vec2::new(rect.left() as f32, rect.top() as f32))
{
if curr_offset != touch_offset.0 {
touch_offset.0 = curr_offset;
touch_offset_change_event_writer.send(TouchOffsetChangeEvent(curr_offset));
info!("New touch offset calculated: {:?}", curr_offset);
}
} else {
*error_count += 1;
if *error_count < 10 {
error!("Failed to get the canvas offset using element id '{}', touch inputs may be impacted", primary_canvas_id.0);
} else if *error_count == 10 {
error!("Continued failure to get the canvas offset, silencing future error of this type. Make sure you properly set the canvas ID and that it matches the one set in the resource");
}
}
}
pub fn offset_touch_input_events(
mut touch_input_events: ResMut<Events<TouchInput>>,
touch_offset: Res<TouchOffset>,
additional_touch_offset: Res<AdditionalTouchOffset>,
) {
if !touch_input_events.is_empty() {
debug!("Touch Events Pre-Transform: {:?}", touch_input_events);
let old_events = touch_input_events
.update_drain()
.map(|mut e| {
e.position -= touch_offset.0 + additional_touch_offset.0;
e
})
.collect::<Vec<_>>();
let new_events = touch_input_events
.update_drain()
.map(|mut e| {
e.position -= touch_offset.0 + additional_touch_offset.0;
e
})
.collect::<Vec<_>>();
for old_event in old_events.into_iter() {
touch_input_events.send(old_event);
}
touch_input_events.update();
for transformed_event in new_events.into_iter() {
touch_input_events.send(transformed_event);
}
debug!("Touch Events Post-Transform: {:?}", touch_input_events);
}
}