1
0
Evan Almloff 1 жил өмнө
parent
commit
8ba1c05a93

+ 1 - 0
packages/desktop/src/element.rs

@@ -3,6 +3,7 @@ use dioxus_html::{geometry::euclid::Rect, MountedResult, RenderedElementBacking}
 
 use crate::{desktop_context::DesktopContext, query::QueryEngine};
 
+#[derive(Clone)]
 /// A mounted element passed to onmounted events
 pub struct DesktopElement {
     id: ElementId,

+ 147 - 0
packages/desktop/src/events.rs

@@ -1,7 +1,10 @@
 //! Convert a serialized event to an event trigger
 
+use dioxus_html::*;
 use serde::{Deserialize, Serialize};
 
+use crate::element::DesktopElement;
+
 #[derive(Deserialize, Serialize, Debug, Clone)]
 pub struct IpcMessage {
     method: String,
@@ -17,3 +20,147 @@ impl IpcMessage {
         self.params
     }
 }
+
+pub(crate) struct SerializedHtmlEventConverter;
+
+impl HtmlEventConverter for SerializedHtmlEventConverter {
+    fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData {
+        event
+            .downcast::<SerializedAnimationData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData {
+        event
+            .downcast::<SerializedClipboardData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData {
+        event
+            .downcast::<SerializedCompositionData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_drag_data(&self, event: &PlatformEventData) -> DragData {
+        event
+            .downcast::<SerializedDragData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData {
+        event
+            .downcast::<SerializedFocusData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_form_data(&self, event: &PlatformEventData) -> FormData {
+        event
+            .downcast::<SerializedFormData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_image_data(&self, event: &PlatformEventData) -> ImageData {
+        event
+            .downcast::<SerializedImageData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData {
+        event
+            .downcast::<SerializedKeyboardData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_media_data(&self, event: &PlatformEventData) -> MediaData {
+        event
+            .downcast::<SerializedMediaData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_mounted_data(&self, event: &PlatformEventData) -> MountedData {
+        event.downcast::<DesktopElement>().cloned().unwrap().into()
+    }
+
+    fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData {
+        event
+            .downcast::<SerializedMouseData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData {
+        event
+            .downcast::<SerializedPointerData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData {
+        event
+            .downcast::<SerializedScrollData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData {
+        event
+            .downcast::<SerializedSelectionData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData {
+        event
+            .downcast::<SerializedToggleData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData {
+        event
+            .downcast::<SerializedTouchData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData {
+        event
+            .downcast::<SerializedTransitionData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+
+    fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData {
+        event
+            .downcast::<SerializedWheelData>()
+            .cloned()
+            .unwrap()
+            .into()
+    }
+}

+ 10 - 5
packages/desktop/src/lib.rs

@@ -28,9 +28,10 @@ pub use desktop_context::{
 use desktop_context::{EventData, UserWindowEvent, WebviewQueue, WindowEventHandlers};
 use dioxus_core::*;
 use dioxus_html::{native_bind::NativeFileEngine, HtmlEvent};
-use dioxus_html::{FileEngine, HasFormData, MountedData};
+use dioxus_html::{FileEngine, HasFormData, MountedData, PlatformEventData};
 use element::DesktopElement;
 use eval::init_eval;
+use events::SerializedHtmlEventConverter;
 use futures_util::{pin_mut, FutureExt};
 use shortcut::ShortcutRegistry;
 pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError};
@@ -136,6 +137,9 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
         }
     });
 
+    // Set the event converter
+    dioxus_html::set_event_converter(Box::new(SerializedHtmlEventConverter));
+
     // We start the tokio runtime *on this thread*
     // Any future we poll later will use this runtime to spawn tasks and for IO
     let rt = tokio::runtime::Builder::new_multi_thread()
@@ -292,7 +296,7 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
                         let element =
                             DesktopElement::new(element, view.desktop_context.clone(), query);
 
-                        Rc::new(MountedData::new(element))
+                        Rc::new(PlatformEventData::new(Box::new(MountedData::new(element))))
                     } else {
                         data.into_any()
                     };
@@ -358,9 +362,10 @@ pub fn launch_with_props<P: 'static>(root: Component<P>, props: P, cfg: Config)
                         let event_name = &file_diolog.event;
                         let event_bubbles = file_diolog.bubbles;
                         let files = file_upload::get_file_event(&file_diolog);
-                        let data = Rc::new(DesktopFileUploadForm {
-                            files: Arc::new(NativeFileEngine::new(files)),
-                        });
+                        let data =
+                            Rc::new(PlatformEventData::new(Box::new(DesktopFileUploadForm {
+                                files: Arc::new(NativeFileEngine::new(files)),
+                            })));
 
                         let view = webviews.get_mut(&event.1).unwrap();
 

+ 17 - 37
packages/html/src/events/drag.rs

@@ -1,5 +1,6 @@
 use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
 use crate::input_data::{MouseButton, MouseButtonSet};
+use crate::prelude::PointInteraction;
 
 use dioxus_core::Event;
 use keyboard_types::Modifiers;
@@ -43,58 +44,45 @@ impl PartialEq for DragData {
 }
 
 impl DragData {
-    /// The event's coordinates relative to the application's viewport (as opposed to the coordinate within the page).
-    ///
-    /// For example, clicking in the top left corner of the viewport will always result in a mouse event with client coordinates (0., 0.), regardless of whether the page is scrolled horizontally.
-    pub fn client_coordinates(&self) -> ClientPoint {
+    /// Downcast this event data to a specific type
+    pub fn downcast<T: 'static>(&self) -> Option<&T> {
+        self.inner.as_any().downcast_ref::<T>()
+    }
+}
+
+impl PointInteraction for DragData {
+    fn client_coordinates(&self) -> ClientPoint {
         self.inner.client_coordinates()
     }
 
-    /// The event's coordinates relative to the padding edge of the target element
-    ///
-    /// For example, clicking in the top left corner of an element will result in element coordinates (0., 0.)
-    pub fn element_coordinates(&self) -> ElementPoint {
+    fn element_coordinates(&self) -> ElementPoint {
         self.inner.element_coordinates()
     }
 
-    /// The event's coordinates relative to the entire document. This includes any portion of the document not currently visible.
-    ///
-    /// For example, if the page is scrolled 200 pixels to the right and 300 pixels down, clicking in the top left corner of the viewport would result in page coordinates (200., 300.)
-    pub fn page_coordinates(&self) -> PagePoint {
+    fn page_coordinates(&self) -> PagePoint {
         self.inner.page_coordinates()
     }
 
-    /// The event's coordinates relative to the entire screen. This takes into account the window's offset.
-    pub fn screen_coordinates(&self) -> ScreenPoint {
+    fn screen_coordinates(&self) -> ScreenPoint {
         self.inner.screen_coordinates()
     }
 
-    pub fn coordinates(&self) -> Coordinates {
+    fn coordinates(&self) -> Coordinates {
         self.inner.coordinates()
     }
 
-    /// The set of modifier keys which were pressed when the event occurred
-    pub fn modifiers(&self) -> Modifiers {
+    fn modifiers(&self) -> Modifiers {
         self.inner.modifiers()
     }
 
-    /// The set of mouse buttons which were held when the event occurred.
-    pub fn held_buttons(&self) -> MouseButtonSet {
+    fn held_buttons(&self) -> MouseButtonSet {
         self.inner.held_buttons()
     }
 
-    /// The mouse button that triggered the event
-    ///
     // todo the following is kind of bad; should we just return None when the trigger_button is unreliable (and frankly irrelevant)? i guess we would need the event_type here
-    /// This is only guaranteed to indicate which button was pressed during events caused by pressing or releasing a button. As such, it is not reliable for events such as mouseenter, mouseleave, mouseover, mouseout, or mousemove. For example, a value of MouseButton::Primary may also indicate that no button was pressed.
-    pub fn trigger_button(&self) -> Option<MouseButton> {
+    fn trigger_button(&self) -> Option<MouseButton> {
         self.inner.trigger_button()
     }
-
-    /// Downcast this event data to a specific type
-    pub fn downcast<T: 'static>(&self) -> Option<&T> {
-        self.inner.as_any().downcast_ref::<T>()
-    }
 }
 
 #[cfg(feature = "serialize")]
@@ -108,15 +96,7 @@ pub struct SerializedDragData {
 impl From<&DragData> for SerializedDragData {
     fn from(data: &DragData) -> Self {
         Self {
-            mouse: crate::point_interaction::SerializedPointInteraction {
-                client_coordinates: data.client_coordinates(),
-                element_coordinates: data.element_coordinates(),
-                page_coordinates: data.page_coordinates(),
-                screen_coordinates: data.screen_coordinates(),
-                modifiers: data.modifiers(),
-                held_buttons: data.held_buttons(),
-                trigger_button: data.trigger_button(),
-            },
+            mouse: crate::point_interaction::SerializedPointInteraction::from(data),
         }
     }
 }

+ 52 - 21
packages/html/src/events/keyboard.rs

@@ -81,30 +81,46 @@ impl KeyboardData {
 /// A serialized version of KeyboardData
 #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
 pub struct SerializedKeyboardData {
-    auto_repeating: bool,
+    char_code: u32,
+    key: String,
+    key_code: KeyCode,
     #[serde(deserialize_with = "resilient_deserialize_code")]
     code: Code,
-    key: Key,
-    location: Location,
-    modifiers: Modifiers,
+    alt_key: bool,
+    ctrl_key: bool,
+    meta_key: bool,
+    shift_key: bool,
+    location: usize,
+    repeat: bool,
+    which: usize,
 }
 
 #[cfg(feature = "serialize")]
 impl SerializedKeyboardData {
     /// Create a new SerializedKeyboardData
     pub fn new(
-        auto_repeating: bool,
-        code: Code,
         key: Key,
+        code: Code,
         location: Location,
+        is_auto_repeating: bool,
         modifiers: Modifiers,
     ) -> Self {
         Self {
-            auto_repeating,
+            char_code: key.legacy_charcode(),
+            key: key.to_string(),
+            key_code: KeyCode::from_raw_code(
+                std::convert::TryInto::try_into(key.legacy_keycode())
+                    .expect("could not convert keycode to u8"),
+            ),
             code,
-            key,
-            location,
-            modifiers,
+            alt_key: modifiers.contains(Modifiers::ALT),
+            ctrl_key: modifiers.contains(Modifiers::CONTROL),
+            meta_key: modifiers.contains(Modifiers::META),
+            shift_key: modifiers.contains(Modifiers::SHIFT),
+            location: crate::input_data::encode_key_location(location),
+            repeat: is_auto_repeating,
+            which: std::convert::TryInto::try_into(key.legacy_charcode())
+                .expect("could not convert charcode to usize"),
         }
     }
 }
@@ -112,20 +128,20 @@ impl SerializedKeyboardData {
 #[cfg(feature = "serialize")]
 impl From<&KeyboardData> for SerializedKeyboardData {
     fn from(data: &KeyboardData) -> Self {
-        Self {
-            auto_repeating: data.is_auto_repeating(),
-            code: data.code(),
-            key: data.key(),
-            location: data.location(),
-            modifiers: data.modifiers(),
-        }
+        Self::new(
+            data.key(),
+            data.code(),
+            data.location(),
+            data.is_auto_repeating(),
+            data.modifiers(),
+        )
     }
 }
 
 #[cfg(feature = "serialize")]
 impl HasKeyboardData for SerializedKeyboardData {
     fn key(&self) -> Key {
-        self.key.clone()
+        std::str::FromStr::from_str(&self.key).unwrap_or(Key::Unidentified)
     }
 
     fn code(&self) -> Code {
@@ -133,15 +149,30 @@ impl HasKeyboardData for SerializedKeyboardData {
     }
 
     fn modifiers(&self) -> Modifiers {
-        self.modifiers
+        let mut modifiers = Modifiers::empty();
+
+        if self.alt_key {
+            modifiers.insert(Modifiers::ALT);
+        }
+        if self.ctrl_key {
+            modifiers.insert(Modifiers::CONTROL);
+        }
+        if self.meta_key {
+            modifiers.insert(Modifiers::META);
+        }
+        if self.shift_key {
+            modifiers.insert(Modifiers::SHIFT);
+        }
+
+        modifiers
     }
 
     fn location(&self) -> Location {
-        self.location
+        crate::input_data::decode_key_location(self.location)
     }
 
     fn is_auto_repeating(&self) -> bool {
-        self.auto_repeating
+        self.repeat
     }
 
     fn as_any(&self) -> &dyn std::any::Any {

+ 6 - 12
packages/html/src/events/mouse.rs

@@ -191,23 +191,17 @@ pub struct SerializedMouseData {
 impl SerializedMouseData {
     /// Create a new instance of SerializedMouseData
     pub fn new(
-        client_coordinates: ClientPoint,
-        element_coordinates: ElementPoint,
-        page_coordinates: PagePoint,
-        screen_coordinates: ScreenPoint,
-        modifiers: Modifiers,
-        held_buttons: MouseButtonSet,
         trigger_button: Option<MouseButton>,
+        held_buttons: MouseButtonSet,
+        coordinates: Coordinates,
+        modifiers: Modifiers,
     ) -> Self {
         Self {
             point_data: crate::point_interaction::SerializedPointInteraction::new(
-                client_coordinates,
-                element_coordinates,
-                page_coordinates,
-                screen_coordinates,
-                modifiers,
-                held_buttons,
                 trigger_button,
+                held_buttons,
+                coordinates,
+                modifiers,
             ),
         }
     }

+ 18 - 6
packages/html/src/events/wheel.rs

@@ -46,30 +46,42 @@ impl WheelData {
 /// A serialized version of WheelData
 #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
 pub struct SerializedWheelData {
-    delta: WheelDelta,
+    pub delta_mode: u32,
+    pub delta_x: f64,
+    pub delta_y: f64,
+    pub delta_z: f64,
 }
 
 #[cfg(feature = "serialize")]
 impl SerializedWheelData {
     /// Create a new SerializedWheelData
     pub fn new(delta: WheelDelta) -> Self {
-        Self { delta }
+        let delta_mode = match delta {
+            WheelDelta::Pixels(_) => 0,
+            WheelDelta::Lines(_) => 1,
+            WheelDelta::Pages(_) => 2,
+        };
+        let delta_raw = delta.strip_units();
+        Self {
+            delta_mode,
+            delta_x: delta_raw.x,
+            delta_y: delta_raw.y,
+            delta_z: delta_raw.z,
+        }
     }
 }
 
 #[cfg(feature = "serialize")]
 impl From<&WheelData> for SerializedWheelData {
     fn from(data: &WheelData) -> Self {
-        Self {
-            delta: data.inner.delta(),
-        }
+        Self::new(data.delta())
     }
 }
 
 #[cfg(feature = "serialize")]
 impl HasWheelData for SerializedWheelData {
     fn delta(&self) -> WheelDelta {
-        self.delta
+        WheelDelta::from_web_attributes(self.delta_mode, self.delta_x, self.delta_y, self.delta_z)
     }
 
     fn as_any(&self) -> &dyn std::any::Any {

+ 113 - 48
packages/html/src/point_interaction.rs

@@ -41,35 +41,98 @@ pub trait PointInteraction: std::any::Any {
 #[cfg(feature = "serialize")]
 #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Default)]
 pub(crate) struct SerializedPointInteraction {
-    pub(crate) client_coordinates: ClientPoint,
-    pub(crate) element_coordinates: ElementPoint,
-    pub(crate) page_coordinates: PagePoint,
-    pub(crate) screen_coordinates: ScreenPoint,
-    pub(crate) modifiers: Modifiers,
-    pub(crate) held_buttons: MouseButtonSet,
-    pub(crate) trigger_button: Option<MouseButton>,
+    pub alt_key: bool,
+
+    /// The button number that was pressed (if applicable) when the mouse event was fired.
+    pub button: i16,
+
+    /// Indicates which buttons are pressed on the mouse (or other input device) when a mouse event is triggered.
+    ///
+    /// Each button that can be pressed is represented by a given number (see below). If more than one button is pressed, the button values are added together to produce a new number. For example, if the secondary (2) and auxiliary (4) buttons are pressed simultaneously, the value is 6 (i.e., 2 + 4).
+    ///
+    /// - 1: Primary button (usually the left button)
+    /// - 2: Secondary button (usually the right button)
+    /// - 4: Auxiliary button (usually the mouse wheel button or middle button)
+    /// - 8: 4th button (typically the "Browser Back" button)
+    /// - 16 : 5th button (typically the "Browser Forward" button)
+    pub buttons: u16,
+
+    /// The horizontal coordinate within the application's viewport at which the event occurred (as opposed to the coordinate within the page).
+    ///
+    /// For example, clicking on the left edge of the viewport will always result in a mouse event with a clientX value of 0, regardless of whether the page is scrolled horizontally.
+    pub client_x: i32,
+
+    /// The vertical coordinate within the application's viewport at which the event occurred (as opposed to the coordinate within the page).
+    ///
+    /// For example, clicking on the top edge of the viewport will always result in a mouse event with a clientY value of 0, regardless of whether the page is scrolled vertically.
+    pub client_y: i32,
+
+    /// True if the control key was down when the mouse event was fired.
+    pub ctrl_key: bool,
+
+    /// True if the meta key was down when the mouse event was fired.
+    pub meta_key: bool,
+
+    /// The offset in the X coordinate of the mouse pointer between that event and the padding edge of the target node.
+    pub offset_x: i32,
+
+    /// The offset in the Y coordinate of the mouse pointer between that event and the padding edge of the target node.
+    pub offset_y: i32,
+
+    /// The X (horizontal) coordinate (in pixels) of the mouse, relative to the left edge of the entire document. This includes any portion of the document not currently visible.
+    ///
+    /// Being based on the edge of the document as it is, this property takes into account any horizontal scrolling of the page. For example, if the page is scrolled such that 200 pixels of the left side of the document are scrolled out of view, and the mouse is clicked 100 pixels inward from the left edge of the view, the value returned by pageX will be 300.
+    pub page_x: i32,
+
+    /// The Y (vertical) coordinate in pixels of the event relative to the whole document.
+    ///
+    /// See `page_x`.
+    pub page_y: i32,
+
+    /// The X coordinate of the mouse pointer in global (screen) coordinates.
+    pub screen_x: i32,
+
+    /// The Y coordinate of the mouse pointer in global (screen) coordinates.
+    pub screen_y: i32,
+
+    /// True if the shift key was down when the mouse event was fired.
+    pub shift_key: bool,
 }
 
 #[cfg(feature = "serialize")]
 impl SerializedPointInteraction {
-    /// Create a new serialized point interaction.
     pub fn new(
-        client_coordinates: ClientPoint,
-        element_coordinates: ElementPoint,
-        page_coordinates: PagePoint,
-        screen_coordinates: ScreenPoint,
-        modifiers: Modifiers,
-        held_buttons: MouseButtonSet,
         trigger_button: Option<MouseButton>,
+        held_buttons: MouseButtonSet,
+        coordinates: Coordinates,
+        modifiers: Modifiers,
     ) -> Self {
+        let alt_key = modifiers.contains(Modifiers::ALT);
+        let ctrl_key = modifiers.contains(Modifiers::CONTROL);
+        let meta_key = modifiers.contains(Modifiers::META);
+        let shift_key = modifiers.contains(Modifiers::SHIFT);
+
+        let [client_x, client_y]: [i32; 2] = coordinates.client().cast().into();
+        let [offset_x, offset_y]: [i32; 2] = coordinates.element().cast().into();
+        let [page_x, page_y]: [i32; 2] = coordinates.page().cast().into();
+        let [screen_x, screen_y]: [i32; 2] = coordinates.screen().cast().into();
         Self {
-            client_coordinates,
-            element_coordinates,
-            page_coordinates,
-            screen_coordinates,
-            modifiers,
-            held_buttons,
-            trigger_button,
+            button: trigger_button
+                .map_or(MouseButton::default(), |b| b)
+                .into_web_code(),
+            buttons: crate::input_data::encode_mouse_button_set(held_buttons),
+            meta_key,
+            ctrl_key,
+            shift_key,
+            alt_key,
+            client_x,
+            client_y,
+            screen_x,
+            screen_y,
+            offset_x,
+            offset_y,
+            page_x,
+            page_y,
         }
     }
 }
@@ -77,54 +140,56 @@ impl SerializedPointInteraction {
 #[cfg(feature = "serialize")]
 impl<E: PointInteraction> From<&E> for SerializedPointInteraction {
     fn from(data: &E) -> Self {
-        Self {
-            client_coordinates: data.client_coordinates(),
-            element_coordinates: data.element_coordinates(),
-            page_coordinates: data.page_coordinates(),
-            screen_coordinates: data.screen_coordinates(),
-            modifiers: data.modifiers(),
-            held_buttons: data.held_buttons(),
-            trigger_button: data.trigger_button(),
-        }
+        let trigger_button = data.trigger_button();
+        let held_buttons = data.held_buttons();
+        let coordinates = data.coordinates();
+        let modifiers = data.modifiers();
+        Self::new(trigger_button, held_buttons, coordinates, modifiers)
     }
 }
 
 #[cfg(feature = "serialize")]
 impl PointInteraction for SerializedPointInteraction {
     fn client_coordinates(&self) -> ClientPoint {
-        self.client_coordinates
+        ClientPoint::new(self.client_x.into(), self.client_y.into())
+    }
+
+    fn screen_coordinates(&self) -> ScreenPoint {
+        ScreenPoint::new(self.screen_x.into(), self.screen_y.into())
     }
 
     fn element_coordinates(&self) -> ElementPoint {
-        self.element_coordinates
+        ElementPoint::new(self.offset_x.into(), self.offset_y.into())
     }
 
     fn page_coordinates(&self) -> PagePoint {
-        self.page_coordinates
+        PagePoint::new(self.page_x.into(), self.page_y.into())
     }
 
-    fn screen_coordinates(&self) -> ScreenPoint {
-        self.screen_coordinates
-    }
+    fn modifiers(&self) -> Modifiers {
+        let mut modifiers = Modifiers::empty();
 
-    fn coordinates(&self) -> Coordinates {
-        Coordinates::new(
-            self.screen_coordinates(),
-            self.client_coordinates(),
-            self.element_coordinates(),
-            self.page_coordinates(),
-        )
-    }
+        if self.alt_key {
+            modifiers.insert(Modifiers::ALT);
+        }
+        if self.ctrl_key {
+            modifiers.insert(Modifiers::CONTROL);
+        }
+        if self.meta_key {
+            modifiers.insert(Modifiers::META);
+        }
+        if self.shift_key {
+            modifiers.insert(Modifiers::SHIFT);
+        }
 
-    fn modifiers(&self) -> Modifiers {
-        self.modifiers
+        modifiers
     }
 
     fn held_buttons(&self) -> MouseButtonSet {
-        self.held_buttons
+        crate::input_data::decode_mouse_button_set(self.buttons)
     }
 
     fn trigger_button(&self) -> Option<MouseButton> {
-        self.trigger_button
+        Some(MouseButton::from_web_code(self.button))
     }
 }

+ 71 - 35
packages/html/src/transit.rs

@@ -4,6 +4,7 @@ use crate::events::*;
 use dioxus_core::ElementId;
 use serde::{Deserialize, Serialize};
 
+#[cfg(feature = "serialize")]
 #[derive(Serialize, Debug, PartialEq)]
 pub struct HtmlEvent {
     pub element: ElementId,
@@ -12,6 +13,7 @@ pub struct HtmlEvent {
     pub data: EventData,
 }
 
+#[cfg(feature = "serialize")]
 impl<'de> Deserialize<'de> for HtmlEvent {
     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     where
@@ -41,6 +43,7 @@ impl<'de> Deserialize<'de> for HtmlEvent {
     }
 }
 
+#[cfg(feature = "serialize")]
 fn fun_name(
     name: &str,
     data: serde_value::Value,
@@ -130,6 +133,7 @@ fn fun_name(
     Ok(data)
 }
 
+#[cfg(feature = "serialize")]
 impl HtmlEvent {
     pub fn bubbles(&self) -> bool {
         event_bubbles(&self.name)
@@ -140,47 +144,79 @@ impl HtmlEvent {
 #[serde(untagged)]
 #[non_exhaustive]
 pub enum EventData {
-    Mouse(MouseData),
-    Clipboard(ClipboardData),
-    Composition(CompositionData),
-    Keyboard(KeyboardData),
-    Focus(FocusData),
-    Form(FormData),
-    Drag(DragData),
-    Pointer(PointerData),
-    Selection(SelectionData),
-    Touch(TouchData),
-    Scroll(ScrollData),
-    Wheel(WheelData),
-    Media(MediaData),
-    Animation(AnimationData),
-    Transition(TransitionData),
-    Toggle(ToggleData),
-    Image(ImageData),
+    Mouse(SerializedMouseData),
+    Clipboard(SerializedClipboardData),
+    Composition(SerializedCompositionData),
+    Keyboard(SerializedKeyboardData),
+    Focus(SerializedFocusData),
+    Form(SerializedFormData),
+    Drag(SerializedDragData),
+    Pointer(SerializedPointerData),
+    Selection(SerializedSelectionData),
+    Touch(SerializedTouchData),
+    Scroll(SerializedScrollData),
+    Wheel(SerializedWheelData),
+    Media(SerializedMediaData),
+    Animation(SerializedAnimationData),
+    Transition(SerializedTransitionData),
+    Toggle(SerializedToggleData),
+    Image(SerializedImageData),
     Mounted,
 }
 
 impl EventData {
     pub fn into_any(self) -> Rc<dyn Any> {
         match self {
-            EventData::Mouse(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Clipboard(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Composition(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Keyboard(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Focus(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Form(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Drag(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Pointer(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Selection(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Touch(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Scroll(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Wheel(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Media(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Animation(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Transition(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Toggle(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Image(data) => Rc::new(data) as Rc<dyn Any>,
-            EventData::Mounted => Rc::new(MountedData::new(())) as Rc<dyn Any>,
+            EventData::Mouse(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Clipboard(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Composition(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Keyboard(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Focus(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Form(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
+            EventData::Drag(data) => Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>,
+            EventData::Pointer(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Selection(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Touch(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Scroll(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Wheel(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Media(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Animation(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Transition(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Toggle(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Image(data) => {
+                Rc::new(PlatformEventData::new(Box::new(data))) as Rc<dyn Any>
+            }
+            EventData::Mounted => {
+                Rc::new(PlatformEventData::new(Box::new(MountedData::new(())))) as Rc<dyn Any>
+            }
         }
     }
 }

+ 31 - 23
packages/rink/src/hooks.rs

@@ -11,7 +11,9 @@ use dioxus_native_core::real_dom::NodeImmutable;
 use rustc_hash::{FxHashMap, FxHashSet};
 
 use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D};
-use dioxus_html::geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint, WheelDelta};
+use dioxus_html::geometry::{
+    ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint, WheelDelta,
+};
 use dioxus_html::input_data::keyboard_types::{Code, Key, Location, Modifiers};
 use dioxus_html::input_data::{
     MouseButton as DioxusMouseButton, MouseButtonSet as DioxusMouseButtons,
@@ -148,13 +150,15 @@ impl InnerInputState {
 
                 let coordinates = m.coordinates();
                 let new_mouse_data = SerializedMouseData::new(
-                    m.client_coordinates(),
-                    coordinates.element(),
-                    m.page_coordinates(),
-                    m.screen_coordinates(),
-                    m.modifiers(),
-                    held_buttons,
                     m.trigger_button(),
+                    held_buttons,
+                    Coordinates::new(
+                        m.screen_coordinates(),
+                        m.client_coordinates(),
+                        coordinates.element(),
+                        m.page_coordinates(),
+                    ),
+                    m.modifiers(),
                 );
 
                 self.mouse = Some(new_mouse_data.clone());
@@ -311,13 +315,15 @@ impl InnerInputState {
                 .cast_unit();
 
             SerializedMouseData::new(
-                mouse_data.client_coordinates(),
-                new_client_coordinates,
-                mouse_data.page_coordinates(),
-                mouse_data.screen_coordinates(),
-                mouse_data.modifiers(),
-                mouse_data.held_buttons(),
                 mouse_data.trigger_button(),
+                mouse_data.held_buttons(),
+                Coordinates::new(
+                    mouse_data.screen_coordinates(),
+                    mouse_data.client_coordinates(),
+                    new_client_coordinates,
+                    mouse_data.page_coordinates(),
+                ),
+                mouse_data.modifiers(),
             )
         }
 
@@ -727,17 +733,19 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
 
                 // held mouse buttons get set later by maintaining state, as crossterm does not provide them
                 EventData::Mouse(SerializedMouseData::new(
-                    // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively.
-                    // todo?
-                    // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway.
-                    ClientPoint::new(x, y),
-                    // offset x/y are set when the origin of the event is assigned to an element
-                    ElementPoint::new(0., 0.),
-                    PagePoint::new(x, y),
-                    ScreenPoint::new(x, y),
-                    modifiers,
-                    DioxusMouseButtons::empty(),
                     button,
+                    DioxusMouseButtons::empty(),
+                    Coordinates::new(
+                        // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively.
+                        // todo?
+                        // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway.
+                        ScreenPoint::new(x, y),
+                        ClientPoint::new(x, y),
+                        // offset x/y are set when the origin of the event is assigned to an element
+                        ElementPoint::new(0., 0.),
+                        PagePoint::new(x, y),
+                    ),
+                    modifiers,
                 ))
             };
 

+ 11 - 7
packages/web/src/dom.rs

@@ -11,13 +11,13 @@ use dioxus_core::{
 };
 use dioxus_html::{
     event_bubbles, FileEngine, FormData, HasFormData, HasImageData, HtmlEventConverter, ImageData,
-    MountedData, ScrollData,
+    MountedData, PlatformEventData, ScrollData,
 };
 use dioxus_interpreter_js::{get_node, minimal_bindings, save_template, Channel};
 use futures_channel::mpsc;
 use js_sys::Array;
 use rustc_hash::FxHashMap;
-use std::{any::Any, collections::HashMap, rc::Rc};
+use std::{any::Any, collections::HashMap};
 use wasm_bindgen::{closure::Closure, prelude::wasm_bindgen, JsCast, JsValue};
 use web_sys::{Document, Element, Event};
 
@@ -37,7 +37,7 @@ pub struct UiEvent {
     pub name: String,
     pub bubbles: bool,
     pub element: ElementId,
-    pub data: Rc<dyn Any>,
+    pub data: PlatformEventData,
 }
 
 impl WebsysDom {
@@ -96,6 +96,7 @@ impl WebsysDom {
             root.clone().unchecked_into(),
             handler.as_ref().unchecked_ref(),
         );
+        dioxus_html::set_event_converter(Box::new(WebEventConverter));
         handler.forget();
         Self {
             document,
@@ -256,7 +257,7 @@ impl WebsysDom {
             if let Some(element) = node.dyn_ref::<Element>() {
                 log::info!("mounted event fired: {}", id.0);
                 let data: MountedData = element.into();
-                let data = Rc::new(data);
+                let data = PlatformEventData::new(Box::new(data));
                 let _ = self.event_channel.unbounded_send(UiEvent {
                     name: "mounted".to_string(),
                     bubbles: false,
@@ -394,11 +395,14 @@ struct GenericWebSysEvent {
 
 // todo: some of these events are being casted to the wrong event type.
 // We need tests that simulate clicks/etc and make sure every event type works.
-pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) -> Rc<dyn Any> {
-    Rc::new(GenericWebSysEvent {
+pub fn virtual_event_from_websys_event(
+    event: web_sys::Event,
+    target: Element,
+) -> PlatformEventData {
+    PlatformEventData::new(Box::new(GenericWebSysEvent {
         raw: event,
         element: target,
-    })
+    }))
 }
 
 pub(crate) fn load_document() -> Document {

+ 8 - 1
packages/web/src/lib.rs

@@ -53,6 +53,8 @@
 //     - Do the VDOM work during the idlecallback
 //     - Do DOM work in the next requestAnimationFrame callback
 
+use std::rc::Rc;
+
 pub use crate::cfg::Config;
 #[cfg(feature = "file_engine")]
 pub use crate::file_engine::WebFileEngineExt;
@@ -276,7 +278,12 @@ pub async fn run_with_props<T: 'static>(root: fn(Scope<T>) -> Element, root_prop
         // Dequeue all of the events from the channel in send order
         // todo: we should re-order these if possible
         while let Some(evt) = res {
-            dom.handle_event(evt.name.as_str(), evt.data, evt.element, evt.bubbles);
+            dom.handle_event(
+                evt.name.as_str(),
+                Rc::new(evt.data),
+                evt.element,
+                evt.bubbles,
+            );
             res = rx.try_next().transpose().unwrap().ok();
         }